diff --git a/.clangd b/.clangd new file mode 100644 index 000000000..bfb28d152 --- /dev/null +++ b/.clangd @@ -0,0 +1,7 @@ +CompileFlags: + Add: [] + Remove: [-mlongcalls, -fstrict-volatile-bitfields, -fno-shrink-wrap, -fno-tree-switch-conversion, -mno-direct-extern-access] +CompileFlags: + CompilationDatabase: build +Diagnostics: + Suppress: ['drv_unknown_argument', 'unused-includes', 'pp_file_not_found'] \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..8713c8d26 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,153 @@ +name: CI + +on: + push: + pull_request: + +jobs: + build-test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-2022] + env: + CMAKE_BUILD_TYPE: Release + RUN_OFX_ITEST: "0" + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + ninja-build pkg-config \ + qt6-base-dev qt6-base-dev-tools qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \ + libavcodec-dev libavformat-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev \ + libopencolorio-dev libopenimageio-dev libopenexr-dev libexpat1-dev \ + portaudio19-dev libgl1-mesa-dev libxkbcommon-dev + + - name: Install dependencies (macOS) + if: runner.os == 'macOS' + run: | + brew update + brew install ninja pkg-config qt@6 ffmpeg openimageio opencolorio openexr portaudio expat + echo "$(brew --prefix qt@6)/bin" >> "$GITHUB_PATH" + echo "CMAKE_PREFIX_PATH=$(brew --prefix qt@6)" >> "$GITHUB_ENV" + + - name: Build OpenTimelineIO (macOS) + if: runner.os == 'macOS' + run: | + git clone --depth 1 --branch v0.16.0 https://github.com/PixarAnimationStudios/OpenTimelineIO.git + cmake -S OpenTimelineIO -B OpenTimelineIO/build -G Ninja \ + -DOTIO_SHARED_LIBS=ON \ + -DOTIO_PYTHON_BINDINGS=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${PWD}/otio-install" + cmake --build OpenTimelineIO/build + cmake --install OpenTimelineIO/build + echo "OTIO_LOCATION=${PWD}/otio-install" >> "$GITHUB_ENV" + + - name: Install Qt (Windows) + if: runner.os == 'Windows' + uses: jurplel/install-qt-action@v4 + with: + version: 6.5.3 + cache: true + tools: 'tools_ninja' + + - name: Install dependencies (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + choco install -y ninja + $env:VCPKG_ROOT = "C:\vcpkg" + & "$env:VCPKG_ROOT\vcpkg.exe" install ffmpeg openimageio opencolorio openexr expat portaudio --triplet x64-windows + echo "VCPKG_ROOT=$env:VCPKG_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append + echo "CMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake" | Out-File -FilePath $env:GITHUB_ENV -Append + + - name: Setup MSVC (Windows) + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + + - name: Configure (Linux) + if: runner.os == 'Linux' + run: | + cmake -S . -B build -G Ninja \ + -DBUILD_TESTS=ON \ + -DBUILD_QT6=ON \ + -DOCIO_LOCATION=/usr \ + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + + - name: Configure (macOS) + if: runner.os == 'macOS' + run: | + cmake -S . -B build -G Ninja \ + -DBUILD_TESTS=ON \ + -DBUILD_QT6=ON \ + -DOCIO_LOCATION=$(brew --prefix opencolorio) \ + -DOTIO_LOCATION=${OTIO_LOCATION} \ + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + + - name: Configure (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $toolchain = "$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake" + $ninja = "$env:ChocolateyInstall\bin\ninja.exe" + cmake -S . -B build -G Ninja ` + -DBUILD_TESTS=ON ` + -DBUILD_QT6=ON ` + -DCMAKE_BUILD_TYPE=$env:CMAKE_BUILD_TYPE ` + -DCMAKE_TOOLCHAIN_FILE=$toolchain ` + -DCMAKE_MAKE_PROGRAM=$ninja ` + -DCMAKE_PREFIX_PATH=$env:Qt6_DIR + + - name: Build + run: cmake --build build --config ${{ env.CMAKE_BUILD_TYPE }} + + - name: Build OpenFX misc plugins (Linux, optional) + if: runner.os == 'Linux' && env.RUN_OFX_ITEST == '1' + run: | + git clone --depth 1 https://github.com/NatronGitHub/openfx-misc.git + cmake -S openfx-misc -B openfx-misc/build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release + cmake --build openfx-misc/build + echo "OAK_OFX_ITEST=1" >> "$GITHUB_ENV" + echo "OAK_OFX_PLUGIN_PATH=${PWD}/openfx-misc/build" >> "$GITHUB_ENV" + echo "OAK_OFX_PLUGIN_ID=net.sf.openfx.ChromaKeyerPlugin" >> "$GITHUB_ENV" + + - name: Build OpenFX misc plugins (macOS, optional) + if: runner.os == 'macOS' && env.RUN_OFX_ITEST == '1' + run: | + git clone --depth 1 https://github.com/NatronGitHub/openfx-misc.git + cmake -S openfx-misc -B openfx-misc/build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release + cmake --build openfx-misc/build + echo "OAK_OFX_ITEST=1" >> "$GITHUB_ENV" + echo "OAK_OFX_PLUGIN_PATH=${PWD}/openfx-misc/build" >> "$GITHUB_ENV" + echo "OAK_OFX_PLUGIN_ID=net.sf.openfx.ChromaKeyerPlugin" >> "$GITHUB_ENV" + + - name: Build OpenFX misc plugins (Windows, optional) + if: runner.os == 'Windows' && env.RUN_OFX_ITEST == '1' + shell: pwsh + run: | + git clone --depth 1 https://github.com/NatronGitHub/openfx-misc.git + cmake -S openfx-misc -B openfx-misc/build -G Ninja ` + -DCMAKE_BUILD_TYPE=Release + cmake --build openfx-misc/build + "OAK_OFX_ITEST=1" | Out-File -FilePath $env:GITHUB_ENV -Append + "OAK_OFX_PLUGIN_PATH=$env:GITHUB_WORKSPACE\\openfx-misc\\build" | Out-File -FilePath $env:GITHUB_ENV -Append + "OAK_OFX_PLUGIN_ID=net.sf.openfx.ChromaKeyerPlugin" | Out-File -FilePath $env:GITHUB_ENV -Append + + - name: Test (Linux) + if: runner.os == 'Linux' + env: + QT_QPA_PLATFORM: offscreen + run: ctest --test-dir build --output-on-failure -C ${{ env.CMAKE_BUILD_TYPE }} + + - name: Test (macOS/Windows) + if: runner.os != 'Linux' + run: ctest --test-dir build --output-on-failure -C ${{ env.CMAKE_BUILD_TYPE }} diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 000000000..984c8005c --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,47 @@ +name: Deploy Docs + +on: + push: + branches: [main, master] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - name: Install dependencies + run: npm install + - name: Build docs + run: npm run docs:build + env: + BASE: /${{ github.event.repository.name }}/ + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vuepress/dist + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index a21cddf06..ac79e8897 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ # CMake artifacts /build*/ - +build # Doxygen -/docs/ # Visual Studio (Code) .localhistory/ @@ -99,4 +98,9 @@ compile_flags.txt *_qmlcache.qrc .idea/ -.vimspector.json \ No newline at end of file +.vimspector.json + +AGENTS.md +.codex +operations-log.md +verification.md \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 46b51ee95..7e19cdfab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,8 @@ [submodule "ext/core"] path = ext/core - url = https://github.com/olive-editor/core + url = https://github.com/OliveCommunity/core.git + branch = dev [submodule "ext/KDDockWidgets"] path = ext/KDDockWidgets - url = https://github.com/olive-editor/KDDockWidgets.git + url = https://github.com/OliveCommunity/KDDockWidgets.git + branch = main diff --git a/0001-Fix-include-path-for-Window_p.h-in-qtcommon-director.patch b/0001-Fix-include-path-for-Window_p.h-in-qtcommon-director.patch new file mode 100644 index 000000000..e51c8ee8a --- /dev/null +++ b/0001-Fix-include-path-for-Window_p.h-in-qtcommon-director.patch @@ -0,0 +1,25 @@ +From 6b0ef44eb189411d36c739ccde8a081a3e62034a Mon Sep 17 00:00:00 2001 +From: Mike Solar +Date: Mon, 24 Nov 2025 20:57:12 +0800 +Subject: [PATCH] Fix include path for Window_p.h in qtcommon directory + +--- + src/qtcommon/Window_p.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/qtcommon/Window_p.h b/src/qtcommon/Window_p.h +index f29b209a5..d1d6b47ad 100644 +--- a/src/qtcommon/Window_p.h ++++ b/src/qtcommon/Window_p.h +@@ -11,7 +11,7 @@ + + #pragma once + +-#include "core/Window_p.h" ++#include "../core/Window_p.h" + #include "Screen_p.h" + + #include +-- +2.52.0 + diff --git a/CMakeLists.txt b/CMakeLists.txt index 303939381..5d2203616 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2023 Olive Studios LLC +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -17,7 +18,15 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(olive-editor VERSION 0.2.0 LANGUAGES CXX) +if(${CMAKE_BUILD_TYPE} EQUAL Debug) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -g") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -g") +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory) +endif () + +set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -DOFX_SUPPORTS_OPENGLRENDER) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOFX_SUPPORTS_OPENGLRENDER") option(BUILD_QT6 "Build with Qt 6 over 5 (experimental)" ON) option(BUILD_DOXYGEN "Build Doxygen documentation" OFF) option(BUILD_TESTS "Build unit tests" OFF) @@ -51,6 +60,7 @@ if(MSVC) /external:W0 "$<$:/O2>" "$<$:/MP>" + /DOFX_SUPPORTS_OPENGLRENDER ) if (USE_WERROR) list(APPEND OLIVE_COMPILE_OPTIONS "/WX") @@ -64,6 +74,8 @@ else() -Wextra -Wno-unused-parameter -Wshadow + -DOFX_SUPPORTS_OPENGLRENDER + ) if (USE_WERROR) list(APPEND OLIVE_COMPILE_OPTIONS "-Werror") @@ -77,6 +89,12 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +# OFX HostSupport requires expat::expat +find_package(EXPAT REQUIRED) +if (TARGET EXPAT::EXPAT AND NOT TARGET expat::expat) + add_library(expat::expat ALIAS EXPAT::EXPAT) +endif() + # Link OpenGL if(UNIX AND NOT APPLE AND NOT DEFINED OpenGL_GL_PREFERENCE) set(OpenGL_GL_PREFERENCE LEGACY) @@ -103,6 +121,7 @@ list(APPEND OLIVE_INCLUDE_DIRS ${OPENEXR_INCLUDES}) list(APPEND OLIVE_LIBRARIES olivecore) list(APPEND OLIVE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/core/include) + # Link Qt set(QT_LIBRARIES Core @@ -167,8 +186,11 @@ list(APPEND OLIVE_LIBRARIES KDAB::kddockwidgets ) +# Link OFX HostSupport wherever libolive-editor objects are used. +list(APPEND OLIVE_LIBRARIES OfxHost) + # Link FFmpeg -find_package(FFMPEG 3.0 REQUIRED +find_package(FFMPEG REQUIRED COMPONENTS avutil avcodec @@ -257,6 +279,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) list(APPEND OLIVE_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/ext) add_subdirectory(ext) +add_subdirectory(third_party/openfx/HostSupport) add_subdirectory(app) if (BUILD_TESTS) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af886102f..ba13dc1af 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,3 +16,21 @@ of code comments, including Javadoc in header files. Feel free to reach out via an issue or pull request if you have questions about the architecture or implementation details. +### Code Standards + +In order to keep the code as readable and maintainable as possible, code +submitted should abide by the following standards: + +* The code style generally follows the + [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) + including, but not limited to: + * Indentation is 4 spaces wide, spaces only (no tabs) + * `lowercase_underscored_variable_names` + * `lowercase_underscored_functions()` or `SentenceCaseFunctions()` + * `class SentenceCaseClassesAndStructs {}` + * `kSentenceCaseConstants` prepended with a lowercase `k` + * `UPPERCASE_UNDERSCORED_MACROS` for variables or same style as functions for macro functions + * `class_member_variables_` end with a `_` +* 100 column limit (where it doesn't impair readability) +* Unix line endings (only LF no CRLF) +* Javadoc documentation where appropriate diff --git a/README.md b/README.md index abe49928e..782fd683e 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,27 @@ -# Olive Video Editor Community Edition[![Build status](https://github.com/olive-editor/olive/workflows/CI/badge.svg?branch=master)](https://github.com/olive-editor/olive/actions?query=branch%3Amaster) +# Oak Video Editor[![Build status](https://github.com/olive-editor/olive/workflows/CI/badge.svg?branch=master)](https://github.com/olive-editor/olive/actions?query=branch%3Amaster) -Olive is a free non-linear video editor for Windows, macOS, and Linux. +Oak Video Editor is a free non-linear video editor for Windows, macOS, and Linux. Unfortunately, the original author has not submitted code updates for over 7 months, and no public contact information (email or otherwise) is available to reach them directly. -Now, we are maintaining a community edition for this project. +This project is a community-maintained fork of Olive Video Editor. ![screen](https://olivevideoeditor.org/img/020-2.png) -This project could now be successfully built with ffmpeg 7. I'm working for a plugin system for it. -**NOTE: Olive is alpha software and is considered highly unstable. While we highly appreciate users testing and providing usage information, please use at your own risk.** - -## Current Status - -I am working on the plugin branch to add OpenFX plugins support. After that I'll try to fix the issues which was submitted on the origin project. +**NOTE: Oak Video Editor is alpha software and is considered highly unstable. While we highly appreciate users testing and providing usage information, please use at your own risk.** ## Binaries The original author compiled following binaries: - [0.1.0 alpha](https://github.com/olive-editor/olive/releases/tag/0.1.0) -- [0.2.0 unstable development build](https://github.com/olive-editor/olive/releases/tag/0.2.0-nightly) \ No newline at end of file +- [0.2.0 unstable development build](https://github.com/olive-editor/olive/releases/tag/0.2.0-nightly) + +## OpenFX Support TODO +- Implement plugin discovery/loading from a given path and populate the cache (currently creates host/cache only). `app/pluginSupport/OliveHost.cpp` +- Wire output clip image storage: allocate a backing buffer, set `kOfxImagePropData`, and update bounds/rowBytes before render. `app/pluginSupport/OliveClip.cpp` +- Provide real input clip image fetches (currently returns an empty `Image` for inputs). `app/pluginSupport/OliveClip.cpp` +- Ensure render path sets per-frame output data and handles ROD/bounds correctly. `app/render/plugin/pluginrenderer.cpp` +- Add missing param instance types (String, Double3D/Integer3D, Group/Page, Custom/Bytes) and mapping to node inputs. `app/pluginSupport/OlivePluginInstance.cpp`, `app/node/plugins/Plugin.cpp` +- Implement `editBegin`/`editEnd`, progress, and timeline hooks instead of stubs. `app/pluginSupport/OlivePluginInstance.cpp`, `app/pluginSupport/OlivePluginInstance.h` +- Integrate persistent message handling with the app UI (currently TODO placeholders). `app/pluginSupport/OlivePluginInstance.cpp` +- Decide and enforce project extent/fielding behavior instead of the current placeholder comment. `app/pluginSupport/OlivePluginInstance.cpp` +- Add OpenGL texture render suite support or explicitly disable it (currently `loadTexture` returns null). `app/pluginSupport/OliveClip.h` diff --git a/TODO-zh.md b/TODO-zh.md new file mode 100644 index 000000000..a04b1a792 --- /dev/null +++ b/TODO-zh.md @@ -0,0 +1,90 @@ +# TODO + +## 目标 +- 实现 2–3 秒预渲染的 LRU 缓存和代理剪辑功能,并以“小步快跑”的方式在现有架构中逐步落地,确保每一步都可编译。 + +## 现有架构中的落点 +- 播放/渲染调度:`app/render/renderprocessor.cpp`, `app/render/plugin/pluginrenderer.cpp`, `app/node/traverser.cpp` +- 插件节点输入/默认值:`app/node/plugins/Plugin.cpp` +- Clip 图像/纹理获取:`app/pluginSupport/OliveClip.cpp`, `app/pluginSupport/OliveClip.h` +- 节点与值系统:`app/node/node.h`, `app/node/node.cpp`, `app/node/value.h` +- 工程序列化:`app/node/project/serializer/*` + +## LRU 缓存计划(代码改动 + 集成点) + +### 步骤 1(可编译):新增缓存类型但不接入逻辑 +- 新增缓存模块,例如 `app/render/cache/framecache.h/.cpp`。 +- 定义: + - `FrameCacheKey`(图哈希/版本、时间、参数、代理模式、渲染缩放)。 + - `FrameCacheEntry`(AVFrame 或 Texture + 元信息 + 字节数 + 最近访问时间)。 + - `FrameCache` API:`get(key)`、`put(key, entry)`、`invalidateByVersion(version)`。 +- 先只编译通过,不改变行为。 + +### 步骤 2(可编译):图版本号/失效机制 +- 在 `Node` 或渲染入口维护图版本号。 +- 当参数变化、连线变化时递增。 +- 渲染侧可读取版本号用于缓存失效。 + +### 步骤 3(小行为):仅缓存当前帧 +- 在 `renderprocessor.cpp` 播放路径上: + - 先查缓存,命中则直接显示。 + - 未命中则正常渲染,并写入缓存。 +- 缓存预算先设很小,风险低。 + +### 步骤 4(小行为):预渲染窗口 +- 增加队列,渲染 [now, now+N],N=2–3 秒。 +- 并发限制(例如 2–3 个任务),避免抢 UI。 +- 优先级:当前帧 > 近未来。 +- Seek 时取消/丢弃过期任务。 + +### 步骤 5(行为):LRU 淘汰 +- 按内存预算/帧数上限淘汰最久未使用。 + +### 步骤 6(行为):CPU/GPU 策略 +- 默认缓存 CPU 帧,播放时再上传 GPU。 +- GPU 缓存可作为后续优化开关。 + +### 步骤 7(可观测性) +- 统计命中率、平均渲染耗时、掉帧。 +- Debug 构建下输出日志。 + +## 代理剪辑计划(代码改动 + 集成点) + +### 步骤 1(可编译):数据模型与序列化 +- 在 clip 元数据里增加: + - `proxy_path`、`proxy_width`、`proxy_height`、`proxy_codec`、`proxy_fps`。 +- 在 `app/node/project/serializer/*` 写入/读取。 + +### 步骤 2(小行为):代理选择策略 +- 增加全局/每 clip 的代理模式: + - `Auto`、`ForceProxy`、`ForceOriginal`。 +- 在媒体解析层根据模式决定用原片还是代理。 + +### 步骤 3(行为):代理生成 +- 新增后台转码任务(复用现有渲染/导出流程)。 +- 生成完成后更新元数据。 + +### 步骤 4(行为):UI 接入 +- 增加“生成代理”“重链接代理”入口。 +- 在剪辑或预览上显示代理标识。 + +### 步骤 5(验证) +- 对比代理与原片的时间精度、音画同步。 +- 导出默认使用原片。 + +## 小步快跑执行顺序(每步可编译) +1) 新增缓存模块/类型(不接入)。 +2) 增加图版本号与失效接口。 +3) 播放路径只缓存当前帧。 +4) 预渲染 2–3 秒窗口 + 并发限制。 +5) LRU 淘汰策略。 +6) 图版本变更触发失效。 +7) 统计与日志。 +8) 代理元数据字段 + 序列化。 +9) 代理选择策略(Auto/Force)。 +10) 代理生成任务 + UI 入口。 + +## 待确认问题 +- 缓存预算默认值(按硬件分级)。 +- 代理文件默认存储路径。 +- 是否做 GPU 纹理缓存。 diff --git a/TODO.md b/TODO.md new file mode 100644 index 000000000..8700308b8 --- /dev/null +++ b/TODO.md @@ -0,0 +1,92 @@ +# TODO + +## Goal +- Add an LRU prerender cache (2–3 seconds ahead) and proxy clip support, implemented as incremental, compile-safe steps within the current architecture. + +## Where the Changes Live (Current Architecture) +- Playback/render scheduling: `app/render/renderprocessor.cpp`, `app/render/plugin/pluginrenderer.cpp`, `app/node/traverser.cpp` +- Plugin node inputs/defaults: `app/node/plugins/Plugin.cpp` +- Clip image/texture fetch: `app/pluginSupport/OliveClip.cpp`, `app/pluginSupport/OliveClip.h` +- Node graph and values: `app/node/node.h`, `app/node/node.cpp`, `app/node/value.h` +- Project/serialization: `app/node/project/serializer/*` + +## LRU Cache Plan (Code Changes + Integration Points) + +### Step 1 (compile-safe): Introduce cache data types (no behavior yet) +- Add a small cache module, e.g. `app/render/cache/framecache.h/.cpp`. +- Define: + - `FrameCacheKey` (graph version/hash, time, params, proxy mode, render scale). + - `FrameCacheEntry` (AVFrame or Texture + metadata + byte size + last-used). + - `FrameCache` API: `get(key)`, `put(key, entry)`, `invalidateByVersion(version)`. +- Wire in a compile-only stub with no runtime usage. + +### Step 2 (compile-safe): Define graph/version invalidation hook +- Add a lightweight “graph version” counter to `Node` or a render pipeline owner. +- Increment on param changes and graph edits. +- Expose a read-only version getter for the render pipeline. + +### Step 3 (small behavior): Cache current frame only +- In `renderprocessor.cpp` playback path, check cache before rendering: + - If hit, present cached frame. + - If miss, render normally and `put` into cache. +- Keep budget small (few frames) to minimize risk. + +### Step 4 (small behavior): Pre-render window scheduling +- Add a render queue for time range [now, now+N] (N = 2–3s). +- Limit worker count (e.g., 2–3 tasks) to avoid UI starvation. +- Prioritize current frame > near future. +- On seek, cancel or drop stale tasks. + +### Step 5 (behavior): LRU eviction policy +- Enforce memory budget and frame count cap. +- Evict least-recently-used entries. + +### Step 6 (behavior): GPU/CPU policy +- Cache CPU frames by default for safety. +- For GL outputs, upload from cached CPU frame when displayed. +- Optionally add GPU caching later behind a feature flag. + +### Step 7 (observability) +- Add counters for hit rate, average render time, and drops. +- Log only in debug builds. + +## Proxy Clip Plan (Code Changes + Integration Points) + +### Step 1 (compile-safe): Data model + serialization +- Extend clip metadata with: + - `proxy_path`, `proxy_width`, `proxy_height`, `proxy_codec`, `proxy_fps`. +- Add read/write in `app/node/project/serializer/*`. + +### Step 2 (small behavior): Proxy selection policy +- Add project-level and clip-level proxy mode: + - `Auto`, `ForceProxy`, `ForceOriginal`. +- Add a simple resolver in clip/media source code that picks proxy if enabled. + +### Step 3 (behavior): Proxy generation pipeline +- Add a background task to build proxies (using existing render/export tasks). +- Store output path and metadata on success. + +### Step 4 (behavior): UI wiring +- Add “Generate Proxy” action + proxy indicator. +- Add “Relink Proxy” dialog. + +### Step 5 (validation) +- Compare proxy vs original for timing and sync. +- Ensure proxies are ignored for export unless explicitly enabled. + +## Small-Step Implementation Plan (Each Step Builds) +1) Add cache module + types (no references). +2) Add graph version counter (increment on changes). +3) Wire cache lookup for current frame only. +4) Add prerender queue (2–3 seconds) with limited concurrency. +5) Add LRU eviction + memory budget. +6) Add cache invalidation on graph version change. +7) Add basic metrics/logging. +8) Add proxy metadata fields + serialization. +9) Add proxy selection policy (Auto/Force modes). +10) Add proxy generation task + UI entry points. + +## Open Questions +- Default cache size per hardware tier. +- Where to store proxy files on disk. +- Whether to cache GPU textures or CPU frames only. diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e8cf1ec2c..dfff99111 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -26,7 +27,6 @@ set(OLIVE_SOURCES add_subdirectory(audio) add_subdirectory(cli) add_subdirectory(codec) -add_subdirectory(common) add_subdirectory(config) add_subdirectory(dialog) add_subdirectory(node) @@ -56,6 +56,10 @@ configure_file(ts/translations.qrc.in ts/translations.qrc @ONLY) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ${CMAKE_CURRENT_BINARY_DIR}/ts/translations.qrc + render/job/pluginjob.cpp + render/job/pluginjob.h + widget/nodeparamview/nodeparambutton.cpp + widget/nodeparamview/nodeparambutton.h ) # Add version object @@ -73,7 +77,13 @@ add_library(libolive-editor ${OLIVE_SOURCES} ${OLIVE_RESOURCES} ) +add_subdirectory(common) +add_subdirectory(pluginSupport) + +target_compile_features(libolive-editor PUBLIC cxx_std_23) +include_directories(../third_party/openfx/include + ../third_party/openfx/HostSupport/include) # Remove prefix - prevents CMake calling it "liblibolive-editor" set_target_properties(libolive-editor PROPERTIES PREFIX "") @@ -83,10 +93,11 @@ add_executable(olive-editor $ $ ) - +target_include_directories(olive-editor PUBLIC pluginSupport) +target_link_libraries(olive-editor PUBLIC OfxHost) # Create docs if doxygen was found if(DOXYGEN_FOUND) - set(DOXYGEN_PROJECT_NAME "Olive") + set(DOXYGEN_PROJECT_NAME "Oak Video Editor") set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/docs") set(DOXYGEN_EXTRACT_ALL "YES") set(DOXYGEN_EXTRACT_PRIVATE "YES") @@ -110,13 +121,13 @@ elseif(APPLE) set_target_properties(olive-editor PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/packaging/macos/MacOSXBundleInfo.plist.in - MACOSX_BUNDLE_GUI_IDENTIFIER org.olivevideoeditor.Olive + MACOSX_BUNDLE_GUI_IDENTIFIER org.oakvideoeditor.Oak MACOSX_BUNDLE_ICON_FILE olive.icns MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION} - MACOSX_BUNDLE_BUNDLE_NAME "Olive" - MACOSX_BUNDLE_INFO_STRING "Olive ${PROJECT_LONG_VERSION}" - MACOSX_BUNDLE_COPYRIGHT "©2018-2021 Olive Studios LLC and others. Published under the GNU General Public License version 3.0." + MACOSX_BUNDLE_BUNDLE_NAME "Oak Video Editor" + MACOSX_BUNDLE_INFO_STRING "Oak Video Editor ${PROJECT_LONG_VERSION}" + MACOSX_BUNDLE_COPYRIGHT "©2018-2021 Olive Studios LLC and others. Fork maintained by Oak Video Editor Team." RESOURCE "${OLIVE_ICON}" OUTPUT_NAME "Olive" ) diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index e97107780..2f72ca2cf 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -318,7 +319,7 @@ AudioManager::AudioManager() #ifdef PA_HAS_JACK // PortAudio doesn't do a strcpy, so we need a const char that's readily accessible (i.e. not // a QString converted to UTF-8) - PaJack_SetClientName("Olive"); + PaJack_SetClientName("Oak Video Editor"); #endif Pa_Initialize(); diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h index b91fdcfa3..86ea5ed31 100644 --- a/app/audio/audiomanager.h +++ b/app/audio/audiomanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/audio/audioprocessor.cpp b/app/audio/audioprocessor.cpp index 7dee52dbe..586c725c5 100644 --- a/app/audio/audioprocessor.cpp +++ b/app/audio/audioprocessor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/audio/audioprocessor.h b/app/audio/audioprocessor.h index a5a9a34c7..9044c1657 100644 --- a/app/audio/audioprocessor.h +++ b/app/audio/audioprocessor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/audio/audiovisualwaveform.cpp b/app/audio/audiovisualwaveform.cpp index 8782766c2..efe1070df 100644 --- a/app/audio/audiovisualwaveform.cpp +++ b/app/audio/audiovisualwaveform.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/audio/audiovisualwaveform.h b/app/audio/audiovisualwaveform.h index ca5947f3d..860c0bdc8 100644 --- a/app/audio/audiovisualwaveform.h +++ b/app/audio/audiovisualwaveform.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/cli/cliexport/cliexportmanager.cpp b/app/cli/cliexport/cliexportmanager.cpp index 8fe2412d2..e9cdb2231 100644 --- a/app/cli/cliexport/cliexportmanager.cpp +++ b/app/cli/cliexport/cliexportmanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/cli/cliexport/cliexportmanager.h b/app/cli/cliexport/cliexportmanager.h index 952b6c791..ca5abb240 100644 --- a/app/cli/cliexport/cliexportmanager.h +++ b/app/cli/cliexport/cliexportmanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/cli/cliprogress/cliprogressdialog.cpp b/app/cli/cliprogress/cliprogressdialog.cpp index 3ac2a4346..694c605f8 100644 --- a/app/cli/cliprogress/cliprogressdialog.cpp +++ b/app/cli/cliprogress/cliprogressdialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/cli/cliprogress/cliprogressdialog.h b/app/cli/cliprogress/cliprogressdialog.h index 05ca655b4..53597607b 100644 --- a/app/cli/cliprogress/cliprogressdialog.h +++ b/app/cli/cliprogress/cliprogressdialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/cli/clitask/clitaskdialog.cpp b/app/cli/clitask/clitaskdialog.cpp index 81d6866f9..f1eccf94f 100644 --- a/app/cli/clitask/clitaskdialog.cpp +++ b/app/cli/clitask/clitaskdialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/cli/clitask/clitaskdialog.h b/app/cli/clitask/clitaskdialog.h index 219f1afca..29e33fc5f 100644 --- a/app/cli/clitask/clitaskdialog.h +++ b/app/cli/clitask/clitaskdialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/conformmanager.cpp b/app/codec/conformmanager.cpp index dd7ebe003..b9ca6b355 100644 --- a/app/codec/conformmanager.cpp +++ b/app/codec/conformmanager.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "conformmanager.h" #include diff --git a/app/codec/conformmanager.h b/app/codec/conformmanager.h index c888f3a85..c310a07ef 100644 --- a/app/codec/conformmanager.h +++ b/app/codec/conformmanager.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef CONFORMMANAGER_H #define CONFORMMANAGER_H diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index b91f102bd..88de05435 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -27,11 +28,7 @@ #include "codec/ffmpeg/ffmpegdecoder.h" #include "codec/planarfiledevice.h" #include "codec/oiio/oiiodecoder.h" -#include "common/ffmpegutils.h" -#include "common/filefunctions.h" #include "conformmanager.h" -#include "node/project.h" -#include "task/taskmanager.h" namespace olive { @@ -146,6 +143,11 @@ Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, return kInvalid; } + if (params.sample_rate() <= 0 || params.channel_count() <= 0) { + qWarning() << "Invalid audio parameters, skipping audio retrieve"; + return kInvalid; + } + // Get conform state from ConformManager ConformManager::Conform conform = ConformManager::instance()->GetConformState( diff --git a/app/codec/decoder.h b/app/codec/decoder.h index 84efe883f..0308edd80 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/encoder.cpp b/app/codec/encoder.cpp index 97b70730a..a27b3048d 100644 --- a/app/codec/encoder.cpp +++ b/app/codec/encoder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/encoder.h b/app/codec/encoder.h index 90e141d96..63f70996e 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/exportcodec.cpp b/app/codec/exportcodec.cpp index 69d6725e3..4dc676b50 100644 --- a/app/codec/exportcodec.cpp +++ b/app/codec/exportcodec.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -21,8 +22,6 @@ #include "exportcodec.h" extern "C" { -#include -#include } namespace olive diff --git a/app/codec/exportcodec.h b/app/codec/exportcodec.h index c51711647..7970475ad 100644 --- a/app/codec/exportcodec.h +++ b/app/codec/exportcodec.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/exportformat.cpp b/app/codec/exportformat.cpp index 5eb2b9b8a..a1bd3b18e 100644 --- a/app/codec/exportformat.cpp +++ b/app/codec/exportformat.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/exportformat.h b/app/codec/exportformat.h index d5af58777..d1e1bcb3a 100644 --- a/app/codec/exportformat.h +++ b/app/codec/exportformat.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index e963e8e64..bed947cbc 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -22,22 +23,17 @@ extern "C" { #include -#include -#include #include -#include -#include -#include +#include +#include } -#include #include #include #include #include #include #include -#include #include "codec/planarfiledevice.h" #include "common/ffmpegutils.h" @@ -51,6 +47,44 @@ namespace olive QVariant Yuv2RgbShader; QVariant DeinterlaceShader; +namespace { + +constexpr int64_t kAnalyzeDurationUs = 5000000; +constexpr int64_t kProbeSizeBytes = 20000000; + +void ApplyFormatOpenOptions(AVDictionary **opts) +{ + av_dict_set_int(opts, "analyzeduration", kAnalyzeDurationUs, 0); + av_dict_set_int(opts, "probesize", kProbeSizeBytes, 0); +} + +void TuneFormatContext(AVFormatContext *ctx) +{ + if (!ctx) { + return; + } + + ctx->probesize = kProbeSizeBytes; + ctx->max_analyze_duration = kAnalyzeDurationUs; +} + +void DiscardSubtitleStreams(AVFormatContext *ctx) +{ + if (!ctx) { + return; + } + + for (unsigned int i = 0; i < ctx->nb_streams; i++) { + AVStream *stream = ctx->streams[i]; + if (stream && stream->codecpar && + stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { + stream->discard = AVDISCARD_ALL; + } + } +} + +} // namespace + FFmpegDecoder::FFmpegDecoder() : sws_ctx_(nullptr) , working_packet_(nullptr) @@ -139,7 +173,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, break; } - AVFrame *hw_in = f.get(); + AVFramePtr hw_in = f; VideoParams plane_params = vp; plane_params.set_channel_count(1); @@ -147,7 +181,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, TexturePtr y_plane = p.renderer->CreateTexture( plane_params, hw_in->data[0], hw_in->linesize[0] / px_size); - + y_plane->handleFrame(hw_in); switch (f->format) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV422P: @@ -169,8 +203,11 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, TexturePtr u_plane = p.renderer->CreateTexture( plane_params, hw_in->data[1], hw_in->linesize[1] / px_size); + u_plane->handleFrame(hw_in); + TexturePtr v_plane = p.renderer->CreateTexture( plane_params, hw_in->data[2], hw_in->linesize[2] / px_size); + v_plane->handleFrame(hw_in); ShaderJob job; job.Insert(QStringLiteral("y_channel"), @@ -206,6 +243,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, case AV_PIX_FMT_RGBA: case AV_PIX_FMT_RGBA64LE: // RGBA can be uploaded directly to the texture + tex->handleFrame(f); tex->Upload(f->data[0], f->linesize[0] / vp.GetBytesPerPixel()); break; } @@ -281,14 +319,17 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(const RetrieveVideoParams &p) AVCOL_RANGE_MPEG; // Perform any CPU processing required - f = PreProcessFrame(f, p); + AVFramePtr ptr = PreProcessFrame(f, p); + f=std::move(ptr); if (!f) { // Error occurred while software scaling return nullptr; } // Finally, perform any GPU processing required - return ProcessFrameIntoTexture(f, p, original); + TexturePtr texture = ProcessFrameIntoTexture(f, p, original); + + return texture; } return nullptr; @@ -340,7 +381,12 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, // Open file in a format context AVFormatContext *fmt_ctx = nullptr; - error_code = avformat_open_input(&fmt_ctx, filename_c, nullptr, nullptr); + AVDictionary *format_opts = nullptr; + ApplyFormatOpenOptions(&format_opts); + error_code = avformat_open_input(&fmt_ctx, filename_c, nullptr, &format_opts); + av_dict_free(&format_opts); + TuneFormatContext(fmt_ctx); + DiscardSubtitleStreams(fmt_ctx); // Handle format context error if (error_code == 0) { @@ -382,116 +428,77 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, VideoParams::kInterlaceNone; { - // Read at least two frames to get more information about this video stream - AVPacket *pkt = av_packet_alloc(); - AVFrame *frame = av_frame_alloc(); + // Read at least two frames to get more information about this video stream + AVPacket *pkt = av_packet_alloc(); + AVFrame *frame = av_frame_alloc(); - { - Instance instance; - instance.Open(filename_c, avstream->index); + VideoParams::Interlacing interlacing = VideoParams::kInterlaceNone; + AVRational pixel_aspect_ratio = {1, 1}; + AVRational frame_rate = avstream->avg_frame_rate; + AVPixelFormat compatible_pix_fmt = + FFmpegUtils::GetCompatiblePixelFormat( + static_cast(avstream->codecpar->format)); + bool image_is_still = false; - // Read first frame and retrieve some metadata - if (instance.GetFrame(pkt, frame) >= 0) { - // Check if video is interlaced and what field dominance it has if so - if (frame->interlaced_frame) { - if (frame->top_field_first) { - interlacing = - VideoParams::kInterlacedTopFirst; - } else { - interlacing = - VideoParams::kInterlacedBottomFirst; - } - } + { + Instance instance; + if (instance.Open(filename_c, avstream->index) != 0) + goto cleanup; - pixel_aspect_ratio = - av_guess_sample_aspect_ratio( - instance.fmt_ctx(), instance.avstream(), - frame); + AVCodecContext *avctx = instance.codec_ctx(); + interlacing = FFmpegFieldOrderToOlive(avctx->field_order); - frame_rate = av_guess_frame_rate( - instance.fmt_ctx(), instance.avstream(), - frame); + if (instance.GetFrame(pkt, frame) >= 0) { + pixel_aspect_ratio = + av_guess_sample_aspect_ratio(instance.fmt_ctx(), + instance.avstream(), frame); + frame_rate = + av_guess_frame_rate(instance.fmt_ctx(), + instance.avstream(), frame); + } - compatible_pix_fmt = - FFmpegUtils::GetCompatiblePixelFormat( - static_cast( - avstream->codecpar->format)); - } + int ret = instance.GetFrame(pkt, frame); + if (ret == AVERROR_EOF) { + image_is_still = true; + } else if (avstream->duration == AV_NOPTS_VALUE || + duration_guessed_from_bitrate) { + int64_t last_ts = frame->best_effort_timestamp; + while (instance.GetFrame(pkt, frame) >= 0 && + (!cancelled || !cancelled->IsCancelled())) + last_ts = frame->best_effort_timestamp; + avstream->duration = last_ts; + } - // Read second frame - int ret = instance.GetFrame(pkt, frame); + instance.Close(); + } - if (ret >= 0) { - // Check if we need a manual duration - if (avstream->duration == AV_NOPTS_VALUE || - duration_guessed_from_bitrate) { - if (footage_duration == AV_NOPTS_VALUE || - duration_guessed_from_bitrate) { - // Manually read through file for duration - int64_t new_dur; + cleanup: + av_frame_free(&frame); + av_packet_free(&pkt); - do { - new_dur = - frame->best_effort_timestamp; - } while (instance.GetFrame( - pkt, frame) >= 0 && - (!cancelled || - !cancelled->IsCancelled())); + VideoParams stream; + stream.set_stream_index(i); + stream.set_width(avstream->codecpar->width); + stream.set_height(avstream->codecpar->height); + stream.set_video_type(image_is_still ? VideoParams::kVideoTypeStill + : VideoParams::kVideoTypeVideo); + stream.set_format(GetNativePixelFormat(compatible_pix_fmt)); + stream.set_channel_count(GetNativeChannelCount(compatible_pix_fmt)); + stream.set_interlacing(interlacing); // <-- 已正确填充 + stream.set_pixel_aspect_ratio(pixel_aspect_ratio); + stream.set_frame_rate(frame_rate); + stream.set_start_time(avstream->start_time); + stream.set_time_base(avstream->time_base); + stream.set_duration(avstream->duration); + stream.set_color_range(avstream->codecpar->color_range == AVCOL_RANGE_JPEG + ? VideoParams::kColorRangeFull + : VideoParams::kColorRangeLimited); + stream.set_premultiplied_alpha(false); - avstream->duration = new_dur; - - } else { - // Fallback to footage duration - avstream->duration = - Timecode::rescale_timestamp_ceil( - footage_duration, - rational(1, AV_TIME_BASE), - avstream->time_base); - } - } - } else if (ret == AVERROR_EOF) { - // Video has only one frame in it, treat it like a still image - image_is_still = true; - } - - instance.Close(); - } - - av_frame_free(&frame); - av_packet_free(&pkt); + desc.AddVideoStream(stream); + image_is_still ? still_streams++ : video_streams++; } - VideoParams stream; - stream.set_stream_index(i); - stream.set_width(avstream->codecpar->width); - stream.set_height(avstream->codecpar->height); - stream.set_video_type((image_is_still) ? - VideoParams::kVideoTypeStill : - VideoParams::kVideoTypeVideo); - stream.set_format(GetNativePixelFormat(compatible_pix_fmt)); - stream.set_channel_count( - GetNativeChannelCount(compatible_pix_fmt)); - stream.set_interlacing(interlacing); - stream.set_pixel_aspect_ratio(pixel_aspect_ratio); - stream.set_frame_rate(frame_rate); - stream.set_start_time(avstream->start_time); - stream.set_time_base(avstream->time_base); - stream.set_duration(avstream->duration); - stream.set_color_range(avstream->codecpar->color_range == - AVCOL_RANGE_JPEG ? - VideoParams::kColorRangeFull : - VideoParams::kColorRangeLimited); - - // Defaults to false, requires user intervention if incorrect - stream.set_premultiplied_alpha(false); - - desc.AddVideoStream(stream); - - if (image_is_still) { - still_streams++; - } else { - video_streams++; - } } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { @@ -629,7 +636,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector &filenames, } // Create resampling context AVChannelLayout layout = params.channel_layout(); - SwrContext *resampler; + SwrContext *resampler=NULL; swr_alloc_set_opts2( &resampler, &layout, FFmpegUtils::GetFFmpegSampleFormat(params.format()), @@ -837,7 +844,7 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, dest->format = f->format; dest->color_range = f->color_range; dest->colorspace = f->colorspace; - + dest->hw_frames_ctx = nullptr; if (p.divider > 1) { dest->width = VideoParams::GetScaledDimension(dest->width, p.divider); dest->height = VideoParams::GetScaledDimension(dest->height, p.divider); @@ -890,8 +897,8 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, dest->color_range == AVCOL_RANGE_JPEG ? 1 : 0, 0, 0x10000, 0x10000); } - r = sws_scale(sws_ctx_, f->data, f->linesize, 0, f->height, dest->data, - dest->linesize); + r = sws_scale_frame(sws_ctx_, dest.get(), f.get()); + if (r < 0) { FFmpegError(r); return nullptr; @@ -941,6 +948,7 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational &time, int ret; AVFramePtr return_frame = nullptr; AVFramePtr filtered = nullptr; + bool retried_after_eof = false; while (true) { // Break out of loop if we've cancelled @@ -988,6 +996,15 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational &time, cache_at_eof_ = true; if (cached_frames_.empty()) { + if (!retried_after_eof) { + retried_after_eof = true; + ClearFrameCache(); + instance_.Seek(min_seek); + cache_at_zero_ = true; + still_seeking = true; + continue; + } + qCritical() << "Unexpected codec EOF - unable to retrieve frame"; } else { @@ -1104,7 +1121,12 @@ FFmpegDecoder::Instance::Instance() bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index) { // Open file in a format context - int error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr); + AVDictionary *format_opts = nullptr; + ApplyFormatOpenOptions(&format_opts); + int error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, &format_opts); + av_dict_free(&format_opts); + TuneFormatContext(fmt_ctx_); + DiscardSubtitleStreams(fmt_ctx_); // Handle format context error if (error_code != 0) { diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index e904ef2f9..09201a2b5 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -42,6 +43,20 @@ extern "C" { namespace olive { +// 头文件里先备好枚举映射 +static VideoParams::Interlacing FFmpegFieldOrderToOlive(AVFieldOrder fo) +{ + switch (fo) { + case AV_FIELD_TT: // 隔行,顶场在前 + return VideoParams::kInterlacedTopFirst; + case AV_FIELD_BB: // 隔行,底场在前 + return VideoParams::kInterlacedBottomFirst; + case AV_FIELD_PROGRESSIVE: + default: + return VideoParams::kInterlaceNone; + } +} + /** * @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder */ @@ -124,6 +139,10 @@ private: { return avstream_; } + AVCodecContext *codec_ctx() + { + return codec_ctx_; + } private: AVFormatContext *fmt_ctx_; diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index 5f7ea1d87..39edb06ac 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -24,6 +25,7 @@ extern "C" { #include #include #include +#include } #include @@ -868,7 +870,7 @@ void FFmpegEncoder::FlushEncoders() } if (fmt_ctx_) { - if (fmt_ctx_->oformat->flags & AVFMT_ALLOW_FLUSH) { + if (fmt_ctx_->oformat->flags) { int r = av_interleaved_write_frame(fmt_ctx_, nullptr); if (r < 0) { FFmpegError(tr("Failed to write interleaved packet"), r); diff --git a/app/codec/ffmpeg/ffmpegencoder.h b/app/codec/ffmpeg/ffmpegencoder.h index 9474f527c..c5f3350e7 100644 --- a/app/codec/ffmpeg/ffmpegencoder.h +++ b/app/codec/ffmpeg/ffmpegencoder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/frame.cpp b/app/codec/frame.cpp index f2c087247..56fa0bbf3 100644 --- a/app/codec/frame.cpp +++ b/app/codec/frame.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/frame.h b/app/codec/frame.h index a87ac4080..a6e9d313b 100644 --- a/app/codec/frame.h +++ b/app/codec/frame.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index ebb8c1f04..94d3f3624 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -25,10 +26,7 @@ #include #include -#include "common/define.h" #include "common/oiioutils.h" -#include "config/config.h" -#include "core.h" #include "render/renderer.h" namespace olive diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index 9bb1197e8..e25172dfc 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/oiio/oiioencoder.cpp b/app/codec/oiio/oiioencoder.cpp index 585d69210..08c3e71ad 100644 --- a/app/codec/oiio/oiioencoder.cpp +++ b/app/codec/oiio/oiioencoder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/oiio/oiioencoder.h b/app/codec/oiio/oiioencoder.h index cb3971774..1200746d8 100644 --- a/app/codec/oiio/oiioencoder.h +++ b/app/codec/oiio/oiioencoder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/planarfiledevice.cpp b/app/codec/planarfiledevice.cpp index 4db824dac..6e516bc0c 100644 --- a/app/codec/planarfiledevice.cpp +++ b/app/codec/planarfiledevice.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/codec/planarfiledevice.h b/app/codec/planarfiledevice.h index 4f39a46cd..400518848 100644 --- a/app/codec/planarfiledevice.h +++ b/app/codec/planarfiledevice.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt index 68155d78a..e09f1fce6 100644 --- a/app/common/CMakeLists.txt +++ b/app/common/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -14,43 +15,43 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -set(OLIVE_SOURCES - ${OLIVE_SOURCES} - common/cancelableobject.h - common/channellayout.h - common/commandlineparser.cpp - common/commandlineparser.h - common/crashpadinterface.cpp - common/crashpadinterface.h - common/crashpadutils.h - common/debug.cpp - common/debug.h - common/decibel.h - common/define.h - common/ffmpegutils.cpp - common/ffmpegutils.h - common/filefunctions.cpp - common/filefunctions.h - common/html.cpp - common/html.h - common/jobtime.cpp - common/jobtime.h - common/lerp.h - common/memorypool.h - common/ocioutils.cpp - common/ocioutils.h - common/oiioutils.cpp - common/oiioutils.h - common/otioutils.h - common/qtutils.cpp - common/qtutils.h - common/range.h - common/ratiodialog.cpp - common/ratiodialog.h - common/threadsafemap.h - common/tohex.h - common/util.h - common/xmlutils.cpp - common/xmlutils.h - PARENT_SCOPE +target_sources(libolive-editor PRIVATE + cancelableobject.h + channellayout.h + commandlineparser.cpp + commandlineparser.h + crashpadinterface.cpp + crashpadinterface.h + crashpadutils.h + Current.cpp + Current.h + debug.cpp + debug.h + decibel.h + define.h + ffmpegutils.cpp + ffmpegutils.h + filefunctions.cpp + filefunctions.h + html.cpp + html.h + jobtime.cpp + jobtime.h + lerp.h + memorypool.h + ocioutils.cpp + ocioutils.h + oiioutils.cpp + oiioutils.h + otioutils.h + qtutils.cpp + qtutils.h + range.h + ratiodialog.cpp + ratiodialog.h + threadsafemap.h + tohex.h + util.h + xmlutils.cpp + xmlutils.h ) diff --git a/app/common/Current.cpp b/app/common/Current.cpp new file mode 100644 index 000000000..0c3fd1d98 --- /dev/null +++ b/app/common/Current.cpp @@ -0,0 +1,22 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "Current.h" + +Current Current::current; \ No newline at end of file diff --git a/app/common/Current.h b/app/common/Current.h new file mode 100644 index 000000000..8b6a50914 --- /dev/null +++ b/app/common/Current.h @@ -0,0 +1,90 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef CURRENT_H +#define CURRENT_H +#include "pluginSupport/OliveHost.h" +#include "render/videoparams.h" +#include "render/job/pluginjob.h" + +class Current { +public: + static Current& getInstance() + { + return current; + } + olive::VideoParams& currentVideoParams() + { + return currentVideoParams_; + } + olive::AudioParams& currentAudioParams() + { + return currentAudioParams_; + } + void setCurrentVideoParams(olive::VideoParams& params) + { + currentVideoParams_ = params; + } + void setCurrentAudioParams(olive::AudioParams& params) + { + currentAudioParams_ = params; + } + void setCurrentVideoParams(olive::VideoParams&& params) + { + currentVideoParams_ = params; + } + void setCurrentAudioParams(olive::AudioParams&& params) + { + currentAudioParams_ = params; + } + bool interactive() + { + return true; + } + + std::shared_ptr pluginHost() + { + return myHost; + } + + void setPluginHost(std::shared_ptr host) + { + myHost = host; + } + + std::shared_ptr pluginCache() + { + return plugin_cache_; + } + + void setPluginCache(std::shared_ptr cache) + { + plugin_cache_ = cache; + } +private: + static Current current; + olive::VideoParams currentVideoParams_; + olive::AudioParams currentAudioParams_; + std::shared_ptr myHost; + std::shared_ptr plugin_cache_; +}; + + + +#endif //CURRENT_H diff --git a/app/common/autoscroll.h b/app/common/autoscroll.h index 46c34e871..13a638a98 100644 --- a/app/common/autoscroll.h +++ b/app/common/autoscroll.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/cancelableobject.h b/app/common/cancelableobject.h index 3cd686ea2..35a68b40d 100644 --- a/app/common/cancelableobject.h +++ b/app/common/cancelableobject.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/commandlineparser.cpp b/app/common/commandlineparser.cpp index 46ce5a85f..6969480d5 100644 --- a/app/common/commandlineparser.cpp +++ b/app/common/commandlineparser.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -113,7 +114,7 @@ void CommandLineParser::PrintHelp(const char *filename) printf("%s %s\n", QCoreApplication::applicationName().toUtf8().constData(), QCoreApplication::applicationVersion().toUtf8().constData()); - printf("Copyright (C) 2018-2022 Olive Team\n"); + printf("Copyright (C) 2018-2022 Oak Video Editor Team\n"); QString positional_args; for (int i = 0; i < positional_args_.size(); i++) { diff --git a/app/common/commandlineparser.h b/app/common/commandlineparser.h index b7a060c38..e352e57f1 100644 --- a/app/common/commandlineparser.h +++ b/app/common/commandlineparser.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/crashpadinterface.cpp b/app/common/crashpadinterface.cpp index 8ae837efc..c7b43e0a2 100644 --- a/app/common/crashpadinterface.cpp +++ b/app/common/crashpadinterface.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/crashpadutils.h b/app/common/crashpadutils.h index b30eca5a1..290c10a6e 100644 --- a/app/common/crashpadutils.h +++ b/app/common/crashpadutils.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/debug.cpp b/app/common/debug.cpp index 734572976..9922bf1af 100644 --- a/app/common/debug.cpp +++ b/app/common/debug.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/debug.h b/app/common/debug.h index fd131dc1c..2ed0fdcc4 100644 --- a/app/common/debug.h +++ b/app/common/debug.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/decibel.h b/app/common/decibel.h index bdb56bd26..e5cc6be04 100644 --- a/app/common/decibel.h +++ b/app/common/decibel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/define.h b/app/common/define.h index 3782eeb6c..dbd26d09c 100644 --- a/app/common/define.h +++ b/app/common/define.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/digit.h b/app/common/digit.h index 4b4ef9d4a..6f4246a1c 100644 --- a/app/common/digit.h +++ b/app/common/digit.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/ffmpegutils.cpp b/app/common/ffmpegutils.cpp index 5e516998f..2096a347b 100644 --- a/app/common/ffmpegutils.cpp +++ b/app/common/ffmpegutils.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -164,7 +165,9 @@ AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const PixelFormat &pix_fmt, case PixelFormat::U16: return AV_PIX_FMT_RGB48; case PixelFormat::F16: + return AV_PIX_FMT_RGBF16; case PixelFormat::F32: + return AV_PIX_FMT_RGBF32; case PixelFormat::INVALID: case PixelFormat::COUNT: break; @@ -176,7 +179,9 @@ AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const PixelFormat &pix_fmt, case PixelFormat::U16: return AV_PIX_FMT_RGBA64; case PixelFormat::F16: + return AV_PIX_FMT_RGBAF16; case PixelFormat::F32: + return AV_PIX_FMT_RGBAF32; case PixelFormat::INVALID: case PixelFormat::COUNT: break; diff --git a/app/common/ffmpegutils.h b/app/common/ffmpegutils.h index 1d5e7da29..d2546591d 100644 --- a/app/common/ffmpegutils.h +++ b/app/common/ffmpegutils.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -87,7 +88,7 @@ public: using AVFramePtr = std::shared_ptr; inline AVFramePtr CreateAVFramePtr(AVFrame *f) { - return std::shared_ptr(f, [](AVFrame *g) { av_frame_free(&g); }); + return std::shared_ptr(f, [](AVFrame *g) { av_frame_free(&g); }); } inline AVFramePtr CreateAVFramePtr() { diff --git a/app/common/filefunctions.cpp b/app/common/filefunctions.cpp index ac7ccfc24..6f6fbc775 100644 --- a/app/common/filefunctions.cpp +++ b/app/common/filefunctions.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/filefunctions.h b/app/common/filefunctions.h index c38629a10..4d952b057 100644 --- a/app/common/filefunctions.h +++ b/app/common/filefunctions.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/html.cpp b/app/common/html.cpp index 8ebe4ea2e..d4b754304 100644 --- a/app/common/html.cpp +++ b/app/common/html.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "html.h" #include diff --git a/app/common/html.h b/app/common/html.h index bf1f5a488..387a1ae4c 100644 --- a/app/common/html.h +++ b/app/common/html.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef HTML_H #define HTML_H diff --git a/app/common/jobtime.cpp b/app/common/jobtime.cpp index 1ad873c0c..058b52a34 100644 --- a/app/common/jobtime.cpp +++ b/app/common/jobtime.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "jobtime.h" #include diff --git a/app/common/jobtime.h b/app/common/jobtime.h index e2334bf79..1a51871c8 100644 --- a/app/common/jobtime.h +++ b/app/common/jobtime.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef JOBTIME_H #define JOBTIME_H diff --git a/app/common/lerp.h b/app/common/lerp.h index 848bc8b48..d79ae75d5 100644 --- a/app/common/lerp.h +++ b/app/common/lerp.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/memorypool.h b/app/common/memorypool.h index dbcc3531c..272388707 100644 --- a/app/common/memorypool.h +++ b/app/common/memorypool.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/ocioutils.cpp b/app/common/ocioutils.cpp index d1f30081d..61b538528 100644 --- a/app/common/ocioutils.cpp +++ b/app/common/ocioutils.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/ocioutils.h b/app/common/ocioutils.h index 7a8f63378..bc317c2d9 100644 --- a/app/common/ocioutils.h +++ b/app/common/ocioutils.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/oiioutils.cpp b/app/common/oiioutils.cpp index 38e966f9d..a74d42306 100644 --- a/app/common/oiioutils.cpp +++ b/app/common/oiioutils.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/oiioutils.h b/app/common/oiioutils.h index 2c19c4b4b..b4ef2c010 100644 --- a/app/common/oiioutils.h +++ b/app/common/oiioutils.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/power.h b/app/common/power.h index bcb75e887..46f8e4b5a 100644 --- a/app/common/power.h +++ b/app/common/power.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/qtutils.cpp b/app/common/qtutils.cpp index 8b838da22..33c1c9f14 100644 --- a/app/common/qtutils.cpp +++ b/app/common/qtutils.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/qtutils.h b/app/common/qtutils.h index 5156c9cbd..34673e016 100644 --- a/app/common/qtutils.h +++ b/app/common/qtutils.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/range.h b/app/common/range.h index 9ae738a16..0dc48a0ec 100644 --- a/app/common/range.h +++ b/app/common/range.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/ratiodialog.cpp b/app/common/ratiodialog.cpp index 4586175c7..d6d5266f2 100644 --- a/app/common/ratiodialog.cpp +++ b/app/common/ratiodialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/ratiodialog.h b/app/common/ratiodialog.h index fca8d0194..7c1a80261 100644 --- a/app/common/ratiodialog.h +++ b/app/common/ratiodialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/threadsafemap.h b/app/common/threadsafemap.h index bcf4f15f8..de78078ac 100644 --- a/app/common/threadsafemap.h +++ b/app/common/threadsafemap.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef THREADSAFEMAP_H #define THREADSAFEMAP_H diff --git a/app/common/tohex.h b/app/common/tohex.h index fefc395e3..b0f04191f 100644 --- a/app/common/tohex.h +++ b/app/common/tohex.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef TOHEX_H #define TOHEX_H diff --git a/app/common/util.h b/app/common/util.h index 0438b4490..f5b9cb38d 100644 --- a/app/common/util.h +++ b/app/common/util.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/xmlutils.cpp b/app/common/xmlutils.cpp index 9cfa09fd7..20d0e9044 100644 --- a/app/common/xmlutils.cpp +++ b/app/common/xmlutils.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/common/xmlutils.h b/app/common/xmlutils.h index 08b48a125..79a653be0 100644 --- a/app/common/xmlutils.h +++ b/app/common/xmlutils.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/config/config.cpp b/app/config/config.cpp index 80f3c97cc..bbb9a6780 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -35,6 +36,7 @@ #include "timeline/timelinecommon.h" #include "ui/colorcoding.h" #include "ui/style/style.h" +#include "widget/timelinewidget/tool/import.h" #include "window/mainwindow/mainwindow.h" namespace olive diff --git a/app/config/config.h b/app/config/config.h index 68c7ab9d4..f3c8fb0bc 100644 --- a/app/config/config.h +++ b/app/config/config.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/core.cpp b/app/core.cpp index 412c9972e..fcc9f7811 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -28,6 +29,7 @@ #include #include #include +#include #include #include "window/mainwindow/mainwindowundo.h" #ifdef Q_OS_WINDOWS @@ -73,11 +75,74 @@ #include "ui/style/style.h" #include "undo/undostack.h" #include "widget/menu/menushared.h" -#include "widget/taskview/taskviewitem.h" -#include "widget/viewer/viewer.h" -#include "window/mainwindow/mainstatusbar.h" #include "window/mainwindow/mainwindow.h" +namespace { + +QStringList FootageVideoExtensions() +{ + return QStringList{ + QStringLiteral("mp4"), QStringLiteral("mov"), QStringLiteral("m4v"), + QStringLiteral("avi"), QStringLiteral("mpg"), QStringLiteral("mpeg"), + QStringLiteral("m2ts"), QStringLiteral("mts"), QStringLiteral("ts"), + QStringLiteral("webm"), QStringLiteral("wmv"), QStringLiteral("flv"), + QStringLiteral("3gp"), QStringLiteral("3g2"), QStringLiteral("mxf") + }; +} + +QStringList FootageAudioExtensions() +{ + return QStringList{ + QStringLiteral("wav"), QStringLiteral("mp3"), QStringLiteral("flac"), + QStringLiteral("aac"), QStringLiteral("ogg"), QStringLiteral("opus"), + QStringLiteral("m4a"), QStringLiteral("alac"), QStringLiteral("aif"), + QStringLiteral("aiff"), QStringLiteral("aifc"), QStringLiteral("wma") + }; +} + +QStringList FootageImageExtensions() +{ + return QStringList{ + QStringLiteral("png"), QStringLiteral("jpg"), QStringLiteral("jpeg"), + QStringLiteral("tif"), QStringLiteral("tiff"), QStringLiteral("bmp"), + QStringLiteral("gif"), QStringLiteral("exr"), QStringLiteral("dpx"), + QStringLiteral("webp") + }; +} + +QString BuildFootageFilterGroup(const QString &label, + const QStringList &extensions) +{ + QStringList patterns; + patterns.reserve(extensions.size()); + for (const QString &ext : extensions) { + patterns.append(QStringLiteral("*.%1").arg(ext)); + } + + return QStringLiteral("%1 (%2)") + .arg(label, patterns.join(QLatin1Char(' '))); +} + +QString BuildFootageFileDialogFilter() +{ + QStringList all = FootageVideoExtensions() + FootageAudioExtensions() + + FootageImageExtensions(); + all.removeDuplicates(); + + QStringList groups; + groups << BuildFootageFilterGroup(QObject::tr("Common Media Files"), all); + groups << BuildFootageFilterGroup(QObject::tr("Video Files"), + FootageVideoExtensions()); + groups << BuildFootageFilterGroup(QObject::tr("Audio Files"), + FootageAudioExtensions()); + groups << BuildFootageFilterGroup(QObject::tr("Image Files"), + FootageImageExtensions()); + + return groups.join(QStringLiteral(";;")); +} + +} // namespace + namespace olive { @@ -106,6 +171,29 @@ Core *Core::instance() return instance_; } +QString Core::FootageFileDialogFilter() +{ + return BuildFootageFileDialogFilter(); +} + +QStringList Core::AllowedFootageExtensions() +{ + QStringList all = FootageVideoExtensions() + FootageAudioExtensions() + + FootageImageExtensions(); + all.removeDuplicates(); + return all; +} + +bool Core::IsFootageExtensionAllowed(const QString &path) +{ + const QString ext = QFileInfo(path).suffix().toLower(); + if (ext.isEmpty()) { + return false; + } + + return AllowedFootageExtensions().contains(ext); +} + void Core::DeclareTypesForQt() { qRegisterMetaType(); @@ -244,7 +332,31 @@ void Core::ImportFiles(const QStringList &urls, Folder *parent) return; } - ProjectImportTask *pim = new ProjectImportTask(parent, urls); + QStringList filtered_urls; + QStringList rejected_urls; + filtered_urls.reserve(urls.size()); + + for (const QString &url : urls) { + if (IsFootageExtensionAllowed(url)) { + filtered_urls.append(url); + } else { + rejected_urls.append(url); + } + } + + if (!rejected_urls.isEmpty()) { + QMessageBox::warning( + main_window_, tr("Unsupported media"), + tr("Skipped %1 file(s) that are not allowed by the current media " + "type filter.") + .arg(rejected_urls.size())); + } + + if (filtered_urls.isEmpty()) { + return; + } + + ProjectImportTask *pim = new ProjectImportTask(parent, filtered_urls); if (!pim->GetFileCount()) { // No files to import @@ -337,8 +449,9 @@ void Core::DialogAboutShow() void Core::DialogImportShow() { // Open dialog for user to select files - QStringList files = - QFileDialog::getOpenFileNames(main_window_, tr("Import footage...")); + QStringList files = QFileDialog::getOpenFileNames( + main_window_, tr("Import footage..."), QString(), + FootageFileDialogFilter()); // Check if the user actually selected files to import if (!files.isEmpty()) { @@ -776,6 +889,7 @@ void Core::StartGUI(bool full_screen) connect(qApp, &QApplication::focusChanged, PanelManager::instance(), &PanelManager::FocusChanged); + KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtWidgets); // Set KDDockWidgets flags auto &config = KDDockWidgets::Config::self(); auto flags = config.flags(); @@ -1063,7 +1177,7 @@ void Core::SaveAutorecovery() QMessageBox::critical( main_window_, tr("Auto-Recovery Error"), tr("Failed to save auto-recovery to \"%1\". " - "Olive may not have permission to this directory.") + "Oak Video Editor may not have permission to this directory.") .arg(project_autorecovery_dir.absolutePath())); } } @@ -1136,11 +1250,11 @@ QString Core::PasteStringFromClipboard() QString Core::GetProjectFilter(bool include_any_filter) { static const QVector> FILTERS = { - // Standard compressed Olive project - { tr("Olive Project"), QStringLiteral("ove") }, + // Standard compressed Oak project + { tr("Oak Project"), QStringLiteral("ove") }, - // Uncompressed XML Olive project - { tr("Olive Project (Uncompressed XML)"), QStringLiteral("ovexml") }, + // Uncompressed XML Oak project + { tr("Oak Project (Uncompressed XML)"), QStringLiteral("ovexml") }, // OpenTimelineIO project, if available #ifdef USE_OTIO @@ -1251,7 +1365,7 @@ void Core::CheckForAutoRecoveries() QString::fromUtf8(autorecovery_index.readAll()).split('\n'); AutoRecoveryDialog ard( - tr("The following projects had unsaved changes when Olive " + tr("The following projects had unsaved changes when Oak Video Editor " "forcefully quit. Would you like to load them?"), recovery_filenames, true, main_window_); ard.exec(); @@ -1308,7 +1422,7 @@ void Core::WarnCacheFull() QMessageBox::warning( main_window_, tr("Disk Cache Full"), - tr("The disk cache is currently full and Olive is having to delete old " + tr("The disk cache is currently full and Oak Video Editor is having to delete old " "frames to keep it within the limits set in the Disk preferences. This " "will result in SIGNIFICANTLY reduced cache performance.\n\n" "To remedy this, please do one of the following:\n\n" diff --git a/app/core.h b/app/core.h index 55c77766b..846973786 100644 --- a/app/core.h +++ b/app/core.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -134,6 +135,10 @@ public: */ static Core *instance(); + static QString FootageFileDialogFilter(); + static QStringList AllowedFootageExtensions(); + static bool IsFootageExtensionAllowed(const QString &path); + const CoreParams &core_params() const { return core_params_; diff --git a/app/crashhandler/crashhandler.cpp b/app/crashhandler/crashhandler.cpp index b1b8a0971..86291cb4d 100644 --- a/app/crashhandler/crashhandler.cpp +++ b/app/crashhandler/crashhandler.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -45,7 +46,7 @@ namespace olive CrashHandlerDialog::CrashHandlerDialog(const QString &report_path) { - setWindowTitle(tr("Olive")); + setWindowTitle(tr("Oak Video Editor")); setWindowFlags(Qt::WindowStaysOnTopHint); report_filename_ = report_path; @@ -54,7 +55,7 @@ CrashHandlerDialog::CrashHandlerDialog(const QString &report_path) QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(new QLabel( - tr("We're sorry, Olive has crashed. Please help us fix it by " + tr("We're sorry, Oak Video Editor has crashed. Please help us fix it by " "sending an error report."))); QSplitter *splitter = new QSplitter(Qt::Vertical); diff --git a/app/crashhandler/crashhandler.h b/app/crashhandler/crashhandler.h index 1876ca3e9..b3753a070 100644 --- a/app/crashhandler/crashhandler.h +++ b/app/crashhandler/crashhandler.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/about/about.cpp b/app/dialog/about/about.cpp index d8fd4a652..8aa38b1de 100644 --- a/app/dialog/about/about.cpp +++ b/app/dialog/about/about.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -25,7 +26,6 @@ #include #include -#include "common/qtutils.h" #include "config/config.h" #include "patreon.h" #include "scrollinglabel.h" @@ -55,7 +55,7 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) horiz_layout->setSpacing(fm.height() * 2); QLabel *icon = new QLabel( - QStringLiteral("")); + QStringLiteral("")); icon->setAlignment(Qt::AlignCenter); horiz_layout->addWidget(icon); @@ -63,15 +63,15 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) QLabel *label = new QLabel( QStringLiteral("" "

%1 %2

" // AppName (version identifier) - "

" - "https://www.olivevideoeditor.org/" - "

" - "

%3

" // First statement + "

%3

" // Description + "

%4

" // Fork notice "") .arg(QApplication::applicationName(), QApplication::applicationVersion(), - tr("Olive is a free open source non-linear video editor. " - "This software is licensed under the GNU GPL Version 3."))); + tr("Oak Video Editor is a free open source non-linear video editor. " + "This software is licensed under the GNU GPL Version 3."), + tr("This project is a fork of " + "Olive Video Editor."))); // Set text formatting label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); @@ -92,18 +92,16 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) if (welcome_dialog || patrons.isEmpty()) { opening_statement = tr( - "Olive relies on support from the community to continue its development."); + "Oak Video Editor relies on support from the community to continue its development."); } else { opening_statement = tr( - "Olive wouldn't be possible without the support of gracious donations from the following people."); + "Oak Video Editor wouldn't be possible without the support of gracious donations from the following people."); } QLabel *support_lbl = new QLabel( tr("%1 " "If you like this project, please consider making a " - "one-time donation or " - "pledging monthly to " - "support its development.") + "one-time donation or pledging monthly to support its development.") .arg(opening_statement)); support_lbl->setWordWrap(true); support_lbl->setAlignment(Qt::AlignCenter); diff --git a/app/dialog/about/about.h b/app/dialog/about/about.h index ccea2bac6..804635097 100644 --- a/app/dialog/about/about.h +++ b/app/dialog/about/about.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/about/patreon.h b/app/dialog/about/patreon.h index 3cbc1495d..1ecac70d6 100644 --- a/app/dialog/about/patreon.h +++ b/app/dialog/about/patreon.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef PATREON_H #define PATREON_H diff --git a/app/dialog/about/patreon.py b/app/dialog/about/patreon.py index 411c8d215..5fc7a232f 100644 --- a/app/dialog/about/patreon.py +++ b/app/dialog/about/patreon.py @@ -1,3 +1,54 @@ +# Oak Video Editor - Non-Linear Video Editor +# Copyright (C) 2025 Olive CE Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# +# + +# /*** +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# ***/ +# + import json import requests import os diff --git a/app/dialog/about/scrollinglabel.cpp b/app/dialog/about/scrollinglabel.cpp index a426a30a5..681c10b33 100644 --- a/app/dialog/about/scrollinglabel.cpp +++ b/app/dialog/about/scrollinglabel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/about/scrollinglabel.h b/app/dialog/about/scrollinglabel.h index cf43e63ce..e8a1f7f49 100644 --- a/app/dialog/about/scrollinglabel.h +++ b/app/dialog/about/scrollinglabel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/actionsearch/actionsearch.cpp b/app/dialog/actionsearch/actionsearch.cpp index 7728f4575..fda36c79c 100644 --- a/app/dialog/actionsearch/actionsearch.cpp +++ b/app/dialog/actionsearch/actionsearch.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/actionsearch/actionsearch.h b/app/dialog/actionsearch/actionsearch.h index 70f31a8bc..0234dd638 100644 --- a/app/dialog/actionsearch/actionsearch.h +++ b/app/dialog/actionsearch/actionsearch.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/autorecovery/autorecoverydialog.cpp b/app/dialog/autorecovery/autorecoverydialog.cpp index 835365cd0..0fa7110bc 100644 --- a/app/dialog/autorecovery/autorecoverydialog.cpp +++ b/app/dialog/autorecovery/autorecoverydialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/autorecovery/autorecoverydialog.h b/app/dialog/autorecovery/autorecoverydialog.h index d7add3e45..fa09c5d89 100644 --- a/app/dialog/autorecovery/autorecoverydialog.h +++ b/app/dialog/autorecovery/autorecoverydialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/color/colordialog.cpp b/app/dialog/color/colordialog.cpp index b04717a07..c8f75643b 100644 --- a/app/dialog/color/colordialog.cpp +++ b/app/dialog/color/colordialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/color/colordialog.h b/app/dialog/color/colordialog.h index 109001841..86fc12c1d 100644 --- a/app/dialog/color/colordialog.h +++ b/app/dialog/color/colordialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/configbase/configdialogbase.cpp b/app/dialog/configbase/configdialogbase.cpp index cd237fa7e..ca64752b9 100644 --- a/app/dialog/configbase/configdialogbase.cpp +++ b/app/dialog/configbase/configdialogbase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/configbase/configdialogbase.h b/app/dialog/configbase/configdialogbase.h index 001abd5dc..9a27a84c4 100644 --- a/app/dialog/configbase/configdialogbase.h +++ b/app/dialog/configbase/configdialogbase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/configbase/configdialogbasetab.cpp b/app/dialog/configbase/configdialogbasetab.cpp index f616cb34d..c7b78975f 100644 --- a/app/dialog/configbase/configdialogbasetab.cpp +++ b/app/dialog/configbase/configdialogbasetab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/configbase/configdialogbasetab.h b/app/dialog/configbase/configdialogbasetab.h index 9301b11dd..4dabebd21 100644 --- a/app/dialog/configbase/configdialogbasetab.h +++ b/app/dialog/configbase/configdialogbasetab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/diskcache/diskcachedialog.cpp b/app/dialog/diskcache/diskcachedialog.cpp index 8c63e321b..172e26adc 100644 --- a/app/dialog/diskcache/diskcachedialog.cpp +++ b/app/dialog/diskcache/diskcachedialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -25,8 +26,6 @@ #include #include -#include "config/config.h" -#include "core.h" namespace olive { diff --git a/app/dialog/diskcache/diskcachedialog.h b/app/dialog/diskcache/diskcachedialog.h index 888f26b5e..fa56ae143 100644 --- a/app/dialog/diskcache/diskcachedialog.h +++ b/app/dialog/diskcache/diskcachedialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/av1section.cpp b/app/dialog/export/codec/av1section.cpp index 0a4136f5d..f30cc6806 100644 --- a/app/dialog/export/codec/av1section.cpp +++ b/app/dialog/export/codec/av1section.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/av1section.h b/app/dialog/export/codec/av1section.h index bbc8b0a7f..6e741799c 100644 --- a/app/dialog/export/codec/av1section.h +++ b/app/dialog/export/codec/av1section.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/cineformsection.cpp b/app/dialog/export/codec/cineformsection.cpp index f102a6501..ff3f5cc88 100644 --- a/app/dialog/export/codec/cineformsection.cpp +++ b/app/dialog/export/codec/cineformsection.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/cineformsection.h b/app/dialog/export/codec/cineformsection.h index f77822972..e76b148a9 100644 --- a/app/dialog/export/codec/cineformsection.h +++ b/app/dialog/export/codec/cineformsection.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/codecsection.cpp b/app/dialog/export/codec/codecsection.cpp index 497f4153a..686a0f7cc 100644 --- a/app/dialog/export/codec/codecsection.cpp +++ b/app/dialog/export/codec/codecsection.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/codecsection.h b/app/dialog/export/codec/codecsection.h index 5a43594e1..029cf53f1 100644 --- a/app/dialog/export/codec/codecsection.h +++ b/app/dialog/export/codec/codecsection.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/codecstack.cpp b/app/dialog/export/codec/codecstack.cpp index 1845f1121..0d5fdcbbe 100644 --- a/app/dialog/export/codec/codecstack.cpp +++ b/app/dialog/export/codec/codecstack.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/codecstack.h b/app/dialog/export/codec/codecstack.h index 352954d45..2b5dcf780 100644 --- a/app/dialog/export/codec/codecstack.h +++ b/app/dialog/export/codec/codecstack.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/h264section.cpp b/app/dialog/export/codec/h264section.cpp index 7a4cf520b..6d53de366 100644 --- a/app/dialog/export/codec/h264section.cpp +++ b/app/dialog/export/codec/h264section.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/h264section.h b/app/dialog/export/codec/h264section.h index d54e793c3..b6ef70514 100644 --- a/app/dialog/export/codec/h264section.h +++ b/app/dialog/export/codec/h264section.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/imagesection.cpp b/app/dialog/export/codec/imagesection.cpp index 8ceb307b4..3c53daf90 100644 --- a/app/dialog/export/codec/imagesection.cpp +++ b/app/dialog/export/codec/imagesection.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/codec/imagesection.h b/app/dialog/export/codec/imagesection.h index cfe76bbed..779f88eed 100644 --- a/app/dialog/export/codec/imagesection.h +++ b/app/dialog/export/codec/imagesection.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index 22f7b6598..eace5eeed 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -181,7 +182,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, bool stills_only_mode, export_bkg_box_ = new QCheckBox(tr("Run In Background")); export_bkg_box_->setToolTip(tr( - "Exporting in the background allows you to continue using Olive while " + "Exporting in the background allows you to continue using Oak Video Editor while " "exporting, but may result in slower export speeds, and may" "severely impact editing and playback performance.")); options_layout->addWidget(export_bkg_box_, opt_row, 0); @@ -343,7 +344,7 @@ void ExportDialog::StartExport() QtUtils::MsgBox( this, QMessageBox::Critical, tr("Failed to create output directory"), - tr("The intended output directory doesn't exist and Olive couldn't create it. " + tr("The intended output directory doesn't exist and Oak Video Editor couldn't create it. " "Please choose a different filename.")); return; } diff --git a/app/dialog/export/export.h b/app/dialog/export/export.h index 90b0f3478..8bb30ff3b 100644 --- a/app/dialog/export/export.h +++ b/app/dialog/export/export.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/exportadvancedvideodialog.cpp b/app/dialog/export/exportadvancedvideodialog.cpp index 4932778b9..c3b5f245a 100644 --- a/app/dialog/export/exportadvancedvideodialog.cpp +++ b/app/dialog/export/exportadvancedvideodialog.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "exportadvancedvideodialog.h" #include diff --git a/app/dialog/export/exportadvancedvideodialog.h b/app/dialog/export/exportadvancedvideodialog.h index 13a34d733..3f4e216d3 100644 --- a/app/dialog/export/exportadvancedvideodialog.h +++ b/app/dialog/export/exportadvancedvideodialog.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef EXPORTADVANCEDVIDEODIALOG_H #define EXPORTADVANCEDVIDEODIALOG_H diff --git a/app/dialog/export/exportaudiotab.cpp b/app/dialog/export/exportaudiotab.cpp index 2f0194a1e..9b1d5cb27 100644 --- a/app/dialog/export/exportaudiotab.cpp +++ b/app/dialog/export/exportaudiotab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -23,7 +24,6 @@ #include #include -#include "core.h" namespace olive { diff --git a/app/dialog/export/exportaudiotab.h b/app/dialog/export/exportaudiotab.h index f8325e3c0..56d10cb9e 100644 --- a/app/dialog/export/exportaudiotab.h +++ b/app/dialog/export/exportaudiotab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/exportformatcombobox.cpp b/app/dialog/export/exportformatcombobox.cpp index 658429783..3fd1d06c6 100644 --- a/app/dialog/export/exportformatcombobox.cpp +++ b/app/dialog/export/exportformatcombobox.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/exportformatcombobox.h b/app/dialog/export/exportformatcombobox.h index 32be322ec..82890ff85 100644 --- a/app/dialog/export/exportformatcombobox.h +++ b/app/dialog/export/exportformatcombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/exportsavepresetdialog.cpp b/app/dialog/export/exportsavepresetdialog.cpp index aadd2712a..f199ef926 100644 --- a/app/dialog/export/exportsavepresetdialog.cpp +++ b/app/dialog/export/exportsavepresetdialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/exportsavepresetdialog.h b/app/dialog/export/exportsavepresetdialog.h index 3791bea20..7206eac29 100644 --- a/app/dialog/export/exportsavepresetdialog.h +++ b/app/dialog/export/exportsavepresetdialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/exportsubtitlestab.cpp b/app/dialog/export/exportsubtitlestab.cpp index 6550d3408..237945d72 100644 --- a/app/dialog/export/exportsubtitlestab.cpp +++ b/app/dialog/export/exportsubtitlestab.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "exportsubtitlestab.h" #include diff --git a/app/dialog/export/exportsubtitlestab.h b/app/dialog/export/exportsubtitlestab.h index 3f440be6c..c54a4a006 100644 --- a/app/dialog/export/exportsubtitlestab.h +++ b/app/dialog/export/exportsubtitlestab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/export/exportvideotab.cpp b/app/dialog/export/exportvideotab.cpp index 271edf6e8..60474c2b3 100644 --- a/app/dialog/export/exportvideotab.cpp +++ b/app/dialog/export/exportvideotab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -26,7 +27,6 @@ #include #include -#include "core.h" #include "exportadvancedvideodialog.h" #include "node/color/colormanager/colormanager.h" diff --git a/app/dialog/export/exportvideotab.h b/app/dialog/export/exportvideotab.h index d283f8e83..024935047 100644 --- a/app/dialog/export/exportvideotab.h +++ b/app/dialog/export/exportvideotab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footageproperties/footageproperties.cpp b/app/dialog/footageproperties/footageproperties.cpp index 25cd73d56..113c64676 100644 --- a/app/dialog/footageproperties/footageproperties.cpp +++ b/app/dialog/footageproperties/footageproperties.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footageproperties/footageproperties.h b/app/dialog/footageproperties/footageproperties.h index 66a693d18..37987063c 100644 --- a/app/dialog/footageproperties/footageproperties.h +++ b/app/dialog/footageproperties/footageproperties.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp b/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp index 946f2f673..9d4713358 100644 --- a/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp +++ b/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footageproperties/streamproperties/audiostreamproperties.h b/app/dialog/footageproperties/streamproperties/audiostreamproperties.h index 8abf5f1bb..a95f25b64 100644 --- a/app/dialog/footageproperties/streamproperties/audiostreamproperties.h +++ b/app/dialog/footageproperties/streamproperties/audiostreamproperties.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footageproperties/streamproperties/streamproperties.cpp b/app/dialog/footageproperties/streamproperties/streamproperties.cpp index 6c7b2bc31..0ba9e2eb6 100644 --- a/app/dialog/footageproperties/streamproperties/streamproperties.cpp +++ b/app/dialog/footageproperties/streamproperties/streamproperties.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footageproperties/streamproperties/streamproperties.h b/app/dialog/footageproperties/streamproperties/streamproperties.h index 6bc350318..3eb6ff9cb 100644 --- a/app/dialog/footageproperties/streamproperties/streamproperties.h +++ b/app/dialog/footageproperties/streamproperties/streamproperties.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp b/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp index 785d5d30c..f67e3c38e 100644 --- a/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp +++ b/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -26,9 +27,7 @@ #include #include -#include "common/ocioutils.h" -#include "core.h" -#include "undo/undostack.h" +#include "node/project.h" namespace olive { diff --git a/app/dialog/footageproperties/streamproperties/videostreamproperties.h b/app/dialog/footageproperties/streamproperties/videostreamproperties.h index c8c153b08..a97ad98f8 100644 --- a/app/dialog/footageproperties/streamproperties/videostreamproperties.h +++ b/app/dialog/footageproperties/streamproperties/videostreamproperties.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/footagerelink/footagerelinkdialog.cpp b/app/dialog/footagerelink/footagerelinkdialog.cpp index e49365735..7235567a3 100644 --- a/app/dialog/footagerelink/footagerelinkdialog.cpp +++ b/app/dialog/footagerelink/footagerelinkdialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -20,11 +21,14 @@ #include "footagerelinkdialog.h" +#include "core.h" + #include #include #include #include #include +#include #include #include #include @@ -106,7 +110,8 @@ void FootageRelinkDialog::BrowseForFootage() QFileInfo info(f->filename()); QString new_fn = QFileDialog::getOpenFileName( - this, tr("Relink \"%1\"").arg(f->GetLabel()), info.absolutePath()); + this, tr("Relink \"%1\"").arg(f->GetLabel()), info.absolutePath(), + Core::FootageFileDialogFilter()); // Originally, this function would attempt to filter to the exact filename of the missing file. // However, this would break on Windows if the filename had any spaces in it. The reason is @@ -119,6 +124,13 @@ void FootageRelinkDialog::BrowseForFootage() // We received a new filename if (!new_fn.isEmpty()) { + if (!Core::IsFootageExtensionAllowed(new_fn)) { + QMessageBox::warning( + this, tr("Unsupported media"), + tr("This file type is not allowed by the current media type " + "filter.")); + return; + } // Store original dir since we might be able to use this to find other files QDir original_dir = info.dir(); QDir new_dir = QFileInfo(new_fn).dir(); diff --git a/app/dialog/footagerelink/footagerelinkdialog.h b/app/dialog/footagerelink/footagerelinkdialog.h index 1d96573c6..adb5881b6 100644 --- a/app/dialog/footagerelink/footagerelinkdialog.h +++ b/app/dialog/footagerelink/footagerelinkdialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/keyframeproperties/keyframeproperties.cpp b/app/dialog/keyframeproperties/keyframeproperties.cpp index 4bd79340b..1c760437d 100644 --- a/app/dialog/keyframeproperties/keyframeproperties.cpp +++ b/app/dialog/keyframeproperties/keyframeproperties.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/keyframeproperties/keyframeproperties.h b/app/dialog/keyframeproperties/keyframeproperties.h index d8fe48310..f0f8b7547 100644 --- a/app/dialog/keyframeproperties/keyframeproperties.h +++ b/app/dialog/keyframeproperties/keyframeproperties.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/markerproperties/markerpropertiesdialog.cpp b/app/dialog/markerproperties/markerpropertiesdialog.cpp index 43b83abd1..cf4e3468d 100644 --- a/app/dialog/markerproperties/markerpropertiesdialog.cpp +++ b/app/dialog/markerproperties/markerpropertiesdialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/markerproperties/markerpropertiesdialog.h b/app/dialog/markerproperties/markerpropertiesdialog.h index f8d407469..7d3108fbf 100644 --- a/app/dialog/markerproperties/markerpropertiesdialog.h +++ b/app/dialog/markerproperties/markerpropertiesdialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/otioproperties/otiopropertiesdialog.cpp b/app/dialog/otioproperties/otiopropertiesdialog.cpp index 2807880ee..e820d0fe5 100644 --- a/app/dialog/otioproperties/otiopropertiesdialog.cpp +++ b/app/dialog/otioproperties/otiopropertiesdialog.cpp @@ -1,6 +1,7 @@ /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/app/dialog/otioproperties/otiopropertiesdialog.h b/app/dialog/otioproperties/otiopropertiesdialog.h index 6ad06075d..22096b819 100644 --- a/app/dialog/otioproperties/otiopropertiesdialog.h +++ b/app/dialog/otioproperties/otiopropertiesdialog.h @@ -1,4 +1,22 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef OTIOPROPERTIESDIALOG_H #define OTIOPROPERTIESDIALOG_H diff --git a/app/dialog/preferences/keysequenceeditor.cpp b/app/dialog/preferences/keysequenceeditor.cpp index b98f3ba3b..6a4b276c8 100644 --- a/app/dialog/preferences/keysequenceeditor.cpp +++ b/app/dialog/preferences/keysequenceeditor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/keysequenceeditor.h b/app/dialog/preferences/keysequenceeditor.h index 3f68d8148..98b44575c 100644 --- a/app/dialog/preferences/keysequenceeditor.h +++ b/app/dialog/preferences/keysequenceeditor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/preferences.cpp b/app/dialog/preferences/preferences.cpp index 6ce8d44fe..922d5dfcf 100644 --- a/app/dialog/preferences/preferences.cpp +++ b/app/dialog/preferences/preferences.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/preferences.h b/app/dialog/preferences/preferences.h index faa619896..9718c3b2b 100644 --- a/app/dialog/preferences/preferences.h +++ b/app/dialog/preferences/preferences.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.cpp b/app/dialog/preferences/tabs/preferencesappearancetab.cpp index e292ab185..17206b90c 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.cpp +++ b/app/dialog/preferences/tabs/preferencesappearancetab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -27,9 +28,6 @@ #include #include "node/node.h" -#include "widget/colorbutton/colorbutton.h" -#include "widget/menu/menushared.h" -#include "ui/colorcoding.h" namespace olive { diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.h b/app/dialog/preferences/tabs/preferencesappearancetab.h index 6e06f0c39..6c06043c1 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.h +++ b/app/dialog/preferences/tabs/preferencesappearancetab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp index e412e6625..19cad4815 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h index 2d8cd3f6d..20b62d39d 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.h +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp index 7145de636..f691ba41c 100644 --- a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.h b/app/dialog/preferences/tabs/preferencesbehaviortab.h index a79c3c973..60f3b07c4 100644 --- a/app/dialog/preferences/tabs/preferencesbehaviortab.h +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesdisktab.cpp b/app/dialog/preferences/tabs/preferencesdisktab.cpp index cc04af3aa..1f800343b 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.cpp +++ b/app/dialog/preferences/tabs/preferencesdisktab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesdisktab.h b/app/dialog/preferences/tabs/preferencesdisktab.h index 7337fceac..59366d1b0 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.h +++ b/app/dialog/preferences/tabs/preferencesdisktab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp index 0468f5203..1a7f94dc7 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -27,8 +28,6 @@ #include "common/autoscroll.h" #include "core.h" -#include "dialog/sequence/sequence.h" -#include "node/project/sequence/sequence.h" namespace olive { diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.h b/app/dialog/preferences/tabs/preferencesgeneraltab.h index 60231bba7..841a36db0 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.h +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp b/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp index f6b9f0a0d..4f33a3019 100644 --- a/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp +++ b/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/preferences/tabs/preferenceskeyboardtab.h b/app/dialog/preferences/tabs/preferenceskeyboardtab.h index 9bc887c0f..bc84f4915 100644 --- a/app/dialog/preferences/tabs/preferenceskeyboardtab.h +++ b/app/dialog/preferences/tabs/preferenceskeyboardtab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/progress/progress.cpp b/app/dialog/progress/progress.cpp index 9a5e30be3..93a31452c 100644 --- a/app/dialog/progress/progress.cpp +++ b/app/dialog/progress/progress.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/progress/progress.h b/app/dialog/progress/progress.h index e1c31bfc0..1ebc92f81 100644 --- a/app/dialog/progress/progress.h +++ b/app/dialog/progress/progress.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index 49b4d90d7..f0a0a89f0 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/projectproperties/projectproperties.h b/app/dialog/projectproperties/projectproperties.h index 90f8909d4..8fda2e0d4 100644 --- a/app/dialog/projectproperties/projectproperties.h +++ b/app/dialog/projectproperties/projectproperties.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2020 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/rendercancel/rendercancel.cpp b/app/dialog/rendercancel/rendercancel.cpp index b1a2e14c9..71b1c2c5f 100644 --- a/app/dialog/rendercancel/rendercancel.cpp +++ b/app/dialog/rendercancel/rendercancel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/rendercancel/rendercancel.h b/app/dialog/rendercancel/rendercancel.h index 4e3dcac87..6a522aee8 100644 --- a/app/dialog/rendercancel/rendercancel.h +++ b/app/dialog/rendercancel/rendercancel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/sequence/presetmanager.h b/app/dialog/sequence/presetmanager.h index 0b7b3f28d..c19ee10b4 100644 --- a/app/dialog/sequence/presetmanager.h +++ b/app/dialog/sequence/presetmanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/sequence/sequence.cpp b/app/dialog/sequence/sequence.cpp index dee6df698..8d3711a14 100644 --- a/app/dialog/sequence/sequence.cpp +++ b/app/dialog/sequence/sequence.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -31,7 +32,6 @@ #include "config/config.h" #include "core.h" -#include "common/channellayout.h" #include "common/qtutils.h" #include "undo/undostack.h" diff --git a/app/dialog/sequence/sequence.h b/app/dialog/sequence/sequence.h index cfc4af3ef..bbf93d1b3 100644 --- a/app/dialog/sequence/sequence.h +++ b/app/dialog/sequence/sequence.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/sequence/sequencedialogparametertab.cpp b/app/dialog/sequence/sequencedialogparametertab.cpp index d615a77d4..2adf35b7c 100644 --- a/app/dialog/sequence/sequencedialogparametertab.cpp +++ b/app/dialog/sequence/sequencedialogparametertab.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "sequencedialogparametertab.h" #include @@ -5,7 +23,6 @@ #include #include -#include "core.h" namespace olive { diff --git a/app/dialog/sequence/sequencedialogparametertab.h b/app/dialog/sequence/sequencedialogparametertab.h index dd71fba9b..a11e1abbd 100644 --- a/app/dialog/sequence/sequencedialogparametertab.h +++ b/app/dialog/sequence/sequencedialogparametertab.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef SEQUENCEDIALOGPARAMETERTAB_H #define SEQUENCEDIALOGPARAMETERTAB_H diff --git a/app/dialog/sequence/sequencedialogpresettab.cpp b/app/dialog/sequence/sequencedialogpresettab.cpp index 2510b01c0..8400f0a16 100644 --- a/app/dialog/sequence/sequencedialogpresettab.cpp +++ b/app/dialog/sequence/sequencedialogpresettab.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -29,7 +30,6 @@ #include #include -#include "common/filefunctions.h" #include "config/config.h" #include "render/videoparams.h" #include "ui/icons/icons.h" diff --git a/app/dialog/sequence/sequencedialogpresettab.h b/app/dialog/sequence/sequencedialogpresettab.h index 2ca5a02f2..44d99b443 100644 --- a/app/dialog/sequence/sequencedialogpresettab.h +++ b/app/dialog/sequence/sequencedialogpresettab.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/sequence/sequencepreset.h b/app/dialog/sequence/sequencepreset.h index ab1f77860..f6c1b6352 100644 --- a/app/dialog/sequence/sequencepreset.h +++ b/app/dialog/sequence/sequencepreset.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/speedduration/speeddurationdialog.cpp b/app/dialog/speedduration/speeddurationdialog.cpp index 03cdb3a2b..7a0732f81 100644 --- a/app/dialog/speedduration/speeddurationdialog.cpp +++ b/app/dialog/speedduration/speeddurationdialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/speedduration/speeddurationdialog.h b/app/dialog/speedduration/speeddurationdialog.h index 8d4f90a03..445b905ba 100644 --- a/app/dialog/speedduration/speeddurationdialog.h +++ b/app/dialog/speedduration/speeddurationdialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/task/task.cpp b/app/dialog/task/task.cpp index dac71a87c..7aa1fdb44 100644 --- a/app/dialog/task/task.cpp +++ b/app/dialog/task/task.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -20,7 +21,8 @@ #include "task.h" -#include +#include +#include namespace olive { diff --git a/app/dialog/task/task.h b/app/dialog/task/task.h index 7375634ea..ded311dbf 100644 --- a/app/dialog/task/task.h +++ b/app/dialog/task/task.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/dialog/text/text.cpp b/app/dialog/text/text.cpp index 7f56d12fe..6130fe69f 100644 --- a/app/dialog/text/text.cpp +++ b/app/dialog/text/text.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -26,7 +27,6 @@ #include #include -#include "ui/icons/icons.h" namespace olive { diff --git a/app/dialog/text/text.h b/app/dialog/text/text.h index b14971324..77168a973 100644 --- a/app/dialog/text/text.h +++ b/app/dialog/text/text.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/icon.png b/app/icon.png new file mode 100644 index 000000000..393dea9fe Binary files /dev/null and b/app/icon.png differ diff --git a/app/main.cpp b/app/main.cpp index 6e351735c..364bcdec6 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -18,14 +19,15 @@ ***/ -/** \mainpage Olive Video Editor - Code Documentation +/** \mainpage Oak Video Editor - Code Documentation * - * This documentation is a primarily a developer resource. For information on using Olive, visit the website + * This documentation is a primarily a developer resource. For information on using Oak Video Editor, visit the website * https://www.olivevideoeditor.org/ * * Use the navigation above to find documentation on classes or source files. */ +#include "OliveHost.h" extern "C" { #include #include @@ -36,6 +38,7 @@ extern "C" { #include #include #include +#include #include #include "core.h" @@ -54,7 +57,6 @@ extern "C" { #ifdef USE_CRASHPAD #include "common/crashpadinterface.h" #endif // USE_CRASHPAD - int decompress_project(const QString &project) { if (project.isEmpty()) { @@ -145,14 +147,15 @@ int decompress_project(const QString &project) int main(int argc, char *argv[]) { + // Set up debug handler qInstallMessageHandler(olive::DebugHandler); // Set application metadata - QCoreApplication::setOrganizationName("olivevideoeditor.org"); - QCoreApplication::setOrganizationDomain("olivevideoeditor.org"); - QCoreApplication::setApplicationName("Olive"); - QGuiApplication::setDesktopFileName("org.olivevideoeditor.Olive"); + QCoreApplication::setOrganizationName("oakvideoeditor.org"); + QCoreApplication::setOrganizationDomain("oakvideoeditor.org"); + QCoreApplication::setApplicationName("Oak Video Editor"); + QGuiApplication::setDesktopFileName("org.oakvideoeditor.Oak"); QCoreApplication::setApplicationVersion(olive::kAppVersionLong); // @@ -216,6 +219,11 @@ int main(int argc, char *argv[]) QStringLiteral("project"), QCoreApplication::translate("main", "Project to open on startup")); + auto no_plugin = parser.AddOption( + { QStringLiteral("-no-plugin") }, + QCoreApplication::translate("main", "Don't load plugins") + ); + // Qt options re-implemented (add to this as necessary) // // Because we don't use QCommandLineParser, we must filter out Qt's arguments ourselves. Here, @@ -282,6 +290,8 @@ int main(int argc, char *argv[]) } } + const bool load_plugins = !no_plugin->IsSet(); + if (crash_option->IsSet()) { startup_params.set_crash_on_startup(true); } @@ -316,7 +326,7 @@ int main(int argc, char *argv[]) if (startup_params.run_mode() == olive::Core::CoreParams::kRunNormal) { #ifdef _WIN32 - // Since Olive is linked with the console subsystem (for better POSIX compatibility), a console + // Since Oak Video Editor is linked with the console subsystem (for better POSIX compatibility), a console // is created by default. If the user didn't request one, we free it here. if (!console_option->IsSet()) { FreeConsole(); @@ -328,6 +338,14 @@ int main(int argc, char *argv[]) a.reset(new QCoreApplication(argc, argv)); } + if (auto *gui_app = qobject_cast(a.get())) { + gui_app->setWindowIcon(QIcon(QStringLiteral(":/graphics/oak-logo.png"))); + } + + if (load_plugins) { + olive::plugin::loadPlugins("plugins"); + } + #ifdef _WIN32 // On Windows, users seem to frequently run into a crash caused by their graphics driver not // supporting framebuffers, which we require. I personally have only been able to recreate this @@ -354,7 +372,7 @@ int main(int argc, char *argv[]) QCoreApplication::translate( "main", "Your computer's graphics driver does not appear to support framebuffers. " - "This most likely means either your graphics driver is not up-to-date or your graphics card is too old to run Olive.\n\n" + "This most likely means either your graphics driver is not up-to-date or your graphics card is too old to run Oak Video Editor.\n\n" "Please update your graphics driver to the latest version and try again.\n\n" "Current driver information: %1 %2 %3") .arg(QString::fromStdString(gpu_vendor), diff --git a/app/node/CMakeLists.txt b/app/node/CMakeLists.txt index ef1978c21..b1472935c 100644 --- a/app/node/CMakeLists.txt +++ b/app/node/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -27,6 +28,7 @@ add_subdirectory(input) add_subdirectory(keying) add_subdirectory(math) add_subdirectory(output) +add_subdirectory(plugins) add_subdirectory(project) add_subdirectory(time) diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index 6c739ce2a..f80f88711 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/audio/pan/pan.h b/app/node/audio/pan/pan.h index 11c8f6010..c6f8627d1 100644 --- a/app/node/audio/pan/pan.h +++ b/app/node/audio/pan/pan.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index 8e9f86c6a..c8103a4f3 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/audio/volume/volume.h b/app/node/audio/volume/volume.h index f07e10017..31908c9f0 100644 --- a/app/node/audio/volume/volume.h +++ b/app/node/audio/volume/volume.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 84c85e79a..5fce241f1 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -23,8 +24,6 @@ #include #include "node/inputdragger.h" -#include "node/output/track/track.h" -#include "transition/transition.h" #include "widget/slider/rationalslider.h" namespace olive diff --git a/app/node/block/block.h b/app/node/block/block.h index 959c81029..5d913828a 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 00accb55c..46dab9efe 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -22,9 +23,9 @@ #include "config/config.h" #include "node/block/transition/transition.h" -#include "node/project/sequence/sequence.h" #include "node/output/track/track.h" #include "node/output/viewer/viewer.h" +#include "node/project/sequence/sequence.h" #include "widget/slider/floatslider.h" #include "widget/slider/rationalslider.h" diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 79e29dd20..f3f6f3d04 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/gap/gap.cpp b/app/node/block/gap/gap.cpp index 8ae68db9f..5a9f1880d 100644 --- a/app/node/block/gap/gap.cpp +++ b/app/node/block/gap/gap.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/gap/gap.h b/app/node/block/gap/gap.h index 1b93f4752..f1b37f3a2 100644 --- a/app/node/block/gap/gap.h +++ b/app/node/block/gap/gap.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/subtitle/subtitle.cpp b/app/node/block/subtitle/subtitle.cpp index b44f9bba6..75d5c50a0 100644 --- a/app/node/block/subtitle/subtitle.cpp +++ b/app/node/block/subtitle/subtitle.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/subtitle/subtitle.h b/app/node/block/subtitle/subtitle.h index 054815fc5..824c6f27c 100644 --- a/app/node/block/subtitle/subtitle.h +++ b/app/node/block/subtitle/subtitle.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp index d18c99048..cbc0f274f 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.h b/app/node/block/transition/crossdissolve/crossdissolvetransition.h index 3666f7d70..25b2065dd 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.h +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index 8a0461bad..866137366 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/transition/diptocolor/diptocolortransition.h b/app/node/block/transition/diptocolor/diptocolortransition.h index 24d439ae3..79ae9f949 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.h +++ b/app/node/block/transition/diptocolor/diptocolortransition.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index c847155df..2aa63a4c0 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index 7688dd471..854993b1a 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/colormanager/colormanager.cpp b/app/node/color/colormanager/colormanager.cpp index 891dbb577..010651374 100644 --- a/app/node/color/colormanager/colormanager.cpp +++ b/app/node/color/colormanager/colormanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/colormanager/colormanager.h b/app/node/color/colormanager/colormanager.h index 88e0ebf35..a270e61d5 100644 --- a/app/node/color/colormanager/colormanager.h +++ b/app/node/color/colormanager/colormanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp index 8c5d2711c..4b6055bc0 100644 --- a/app/node/color/displaytransform/displaytransform.cpp +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h index 89ea5b248..7958fd907 100644 --- a/app/node/color/displaytransform/displaytransform.h +++ b/app/node/color/displaytransform/displaytransform.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp index de4481104..1467667af 100644 --- a/app/node/color/ociobase/ociobase.cpp +++ b/app/node/color/ociobase/ociobase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/ociobase/ociobase.h b/app/node/color/ociobase/ociobase.h index 44fd0c59f..b95acdc80 100644 --- a/app/node/color/ociobase/ociobase.h +++ b/app/node/color/ociobase/ociobase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 9b56dc0f1..cdc1118ee 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h index 2509eabb8..85a2c9bf3 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/cornerpin/cornerpindistortnode.cpp b/app/node/distort/cornerpin/cornerpindistortnode.cpp index 44898b7af..d4d936e94 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.cpp +++ b/app/node/distort/cornerpin/cornerpindistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/cornerpin/cornerpindistortnode.h b/app/node/distort/cornerpin/cornerpindistortnode.h index 020a70357..cdb5debff 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.h +++ b/app/node/distort/cornerpin/cornerpindistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/crop/cropdistortnode.cpp b/app/node/distort/crop/cropdistortnode.cpp index a79da9b80..bf51b82b7 100644 --- a/app/node/distort/crop/cropdistortnode.cpp +++ b/app/node/distort/crop/cropdistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/crop/cropdistortnode.h b/app/node/distort/crop/cropdistortnode.h index d00bced55..427474f03 100644 --- a/app/node/distort/crop/cropdistortnode.h +++ b/app/node/distort/crop/cropdistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/flip/flipdistortnode.cpp b/app/node/distort/flip/flipdistortnode.cpp index 8851ee2b0..c666c63d8 100644 --- a/app/node/distort/flip/flipdistortnode.cpp +++ b/app/node/distort/flip/flipdistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/flip/flipdistortnode.h b/app/node/distort/flip/flipdistortnode.h index 7165671a9..91b3917be 100644 --- a/app/node/distort/flip/flipdistortnode.h +++ b/app/node/distort/flip/flipdistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/mask/mask.cpp b/app/node/distort/mask/mask.cpp index a21f51aeb..21bb8ebee 100644 --- a/app/node/distort/mask/mask.cpp +++ b/app/node/distort/mask/mask.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/mask/mask.h b/app/node/distort/mask/mask.h index 6dba92190..d9a4e8ef1 100644 --- a/app/node/distort/mask/mask.h +++ b/app/node/distort/mask/mask.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/ripple/rippledistortnode.cpp b/app/node/distort/ripple/rippledistortnode.cpp index 57643c455..4a0244037 100644 --- a/app/node/distort/ripple/rippledistortnode.cpp +++ b/app/node/distort/ripple/rippledistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/ripple/rippledistortnode.h b/app/node/distort/ripple/rippledistortnode.h index d731c7fba..d6bc6e13c 100644 --- a/app/node/distort/ripple/rippledistortnode.h +++ b/app/node/distort/ripple/rippledistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/swirl/swirldistortnode.cpp b/app/node/distort/swirl/swirldistortnode.cpp index 351152cd1..652526ffd 100644 --- a/app/node/distort/swirl/swirldistortnode.cpp +++ b/app/node/distort/swirl/swirldistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/swirl/swirldistortnode.h b/app/node/distort/swirl/swirldistortnode.h index 3b4cf0b54..1bba960e9 100644 --- a/app/node/distort/swirl/swirldistortnode.h +++ b/app/node/distort/swirl/swirldistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/tile/tiledistortnode.cpp b/app/node/distort/tile/tiledistortnode.cpp index 8a6a96c3a..880a88b28 100644 --- a/app/node/distort/tile/tiledistortnode.cpp +++ b/app/node/distort/tile/tiledistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/tile/tiledistortnode.h b/app/node/distort/tile/tiledistortnode.h index c83dcfc92..67f81684c 100644 --- a/app/node/distort/tile/tiledistortnode.h +++ b/app/node/distort/tile/tiledistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/transform/transformdistortnode.cpp b/app/node/distort/transform/transformdistortnode.cpp index baa102a66..59d427240 100644 --- a/app/node/distort/transform/transformdistortnode.cpp +++ b/app/node/distort/transform/transformdistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/transform/transformdistortnode.h b/app/node/distort/transform/transformdistortnode.h index 5aba90055..adf98b5d8 100644 --- a/app/node/distort/transform/transformdistortnode.h +++ b/app/node/distort/transform/transformdistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/wave/wavedistortnode.cpp b/app/node/distort/wave/wavedistortnode.cpp index 8751d9a40..f5e76dfdf 100644 --- a/app/node/distort/wave/wavedistortnode.cpp +++ b/app/node/distort/wave/wavedistortnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/distort/wave/wavedistortnode.h b/app/node/distort/wave/wavedistortnode.h index e1796fef2..f1b920be8 100644 --- a/app/node/distort/wave/wavedistortnode.h +++ b/app/node/distort/wave/wavedistortnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/effect/opacity/opacityeffect.cpp b/app/node/effect/opacity/opacityeffect.cpp index 1f3e69fc9..f0583587b 100644 --- a/app/node/effect/opacity/opacityeffect.cpp +++ b/app/node/effect/opacity/opacityeffect.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "opacityeffect.h" #include "node/math/math/math.h" diff --git a/app/node/effect/opacity/opacityeffect.h b/app/node/effect/opacity/opacityeffect.h index 31e29ca82..8224565bb 100644 --- a/app/node/effect/opacity/opacityeffect.h +++ b/app/node/effect/opacity/opacityeffect.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef OPACITYEFFECT_H #define OPACITYEFFECT_H diff --git a/app/node/factory.cpp b/app/node/factory.cpp index c1872561e..3ecc06226 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -31,6 +32,7 @@ #include "block/transition/diptocolor/diptocolortransition.h" #include "color/displaytransform/displaytransform.h" #include "color/ociogradingtransformlinear/ociogradingtransformlinear.h" +#include "common/Current.h" #include "distort/cornerpin/cornerpindistortnode.h" #include "distort/crop/cropdistortnode.h" #include "distort/flip/flipdistortnode.h" @@ -64,6 +66,8 @@ #include "math/trigonometry/trigonometry.h" #include "output/track/track.h" #include "output/viewer/viewer.h" +#include "pluginSupport/OliveHost.h" +#include "plugins/Plugin.h" #include "project/folder/folder.h" #include "project/footage/footage.h" #include "project/sequence/sequence.h" @@ -86,6 +90,9 @@ void NodeFactory::Initialize() library_.append(created_node); } + + RegisterPluginNodes(); + } void NodeFactory::Destroy() @@ -211,6 +218,48 @@ Node *NodeFactory::CreateFromID(const QString &id) return nullptr; } +void NodeFactory::RegisterPluginNodes() +{ + QSet existing_ids; + for (Node *node : library_) { + existing_ids.insert(node->id()); + } + + for (auto plugin : OFX::Host::PluginCache::getPluginCache()->getPlugins()) { + auto *image_effect = + dynamic_cast(plugin); + if (!image_effect) { + continue; + } + + const QString plugin_id = QString::fromStdString( + image_effect->getIdentifier()); + if (existing_ids.contains(plugin_id)) { + continue; + } + + const auto &contexts = image_effect->getContexts(); + if (contexts.empty()) { + qWarning() << "Skipping OFX plugin with no contexts:" + << plugin_id; + continue; + } + std::string context = kOfxImageEffectContextFilter; + if (contexts.find(kOfxImageEffectContextFilter) == contexts.end()) { + context = *contexts.begin(); + } + + auto *instance = image_effect->createInstance(context, nullptr); + if (!instance) { + continue; + } + + plugin::PluginNode *plugin_node = new plugin::PluginNode(instance); + library_.append(plugin_node); + existing_ids.insert(plugin_id); + } +} + Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) { switch (id) { diff --git a/app/node/factory.h b/app/node/factory.h index 762e7a83b..764386a5c 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -104,6 +105,7 @@ public: static QString GetNameFromID(const QString &id); static Node *CreateFromID(const QString &id); + static void RegisterPluginNodes(); static Node *CreateFromFactoryIndex(const InternalID &id); diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 46884a2e7..094544844 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/filter/blur/blur.h b/app/node/filter/blur/blur.h index ab76f23b1..35be91e5f 100644 --- a/app/node/filter/blur/blur.h +++ b/app/node/filter/blur/blur.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/filter/dropshadow/dropshadowfilter.cpp b/app/node/filter/dropshadow/dropshadowfilter.cpp index 93deeef5c..266ec71d4 100644 --- a/app/node/filter/dropshadow/dropshadowfilter.cpp +++ b/app/node/filter/dropshadow/dropshadowfilter.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/filter/dropshadow/dropshadowfilter.h b/app/node/filter/dropshadow/dropshadowfilter.h index ae89c6a6c..cbedf006f 100644 --- a/app/node/filter/dropshadow/dropshadowfilter.h +++ b/app/node/filter/dropshadow/dropshadowfilter.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/filter/mosaic/mosaicfilternode.cpp b/app/node/filter/mosaic/mosaicfilternode.cpp index b8409e6de..e48af28e7 100644 --- a/app/node/filter/mosaic/mosaicfilternode.cpp +++ b/app/node/filter/mosaic/mosaicfilternode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/filter/mosaic/mosaicfilternode.h b/app/node/filter/mosaic/mosaicfilternode.h index d7a6c0c5e..730017dc0 100644 --- a/app/node/filter/mosaic/mosaicfilternode.h +++ b/app/node/filter/mosaic/mosaicfilternode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index 36fd7adb8..bab59319a 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/filter/stroke/stroke.h b/app/node/filter/stroke/stroke.h index 0a18819f3..c2d0d829f 100644 --- a/app/node/filter/stroke/stroke.h +++ b/app/node/filter/stroke/stroke.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index 4536eeda1..8037fedac 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index f18aa1ca8..fc29a6464 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/noise/noise.cpp b/app/node/generator/noise/noise.cpp index ff739d9fe..aeb6294c5 100644 --- a/app/node/generator/noise/noise.cpp +++ b/app/node/generator/noise/noise.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/noise/noise.h b/app/node/generator/noise/noise.h index e398bc0bd..157d02a12 100644 --- a/app/node/generator/noise/noise.h +++ b/app/node/generator/noise/noise.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 27c007c43..f9e9d119a 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index 410a110f1..6c68d3fb7 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/shape/generatorwithmerge.cpp b/app/node/generator/shape/generatorwithmerge.cpp index 9932ea450..9367ef872 100644 --- a/app/node/generator/shape/generatorwithmerge.cpp +++ b/app/node/generator/shape/generatorwithmerge.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/shape/generatorwithmerge.h b/app/node/generator/shape/generatorwithmerge.h index 0183f26f3..56fce90da 100644 --- a/app/node/generator/shape/generatorwithmerge.h +++ b/app/node/generator/shape/generatorwithmerge.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/shape/shapenode.cpp b/app/node/generator/shape/shapenode.cpp index e9acca7c2..f76c72815 100644 --- a/app/node/generator/shape/shapenode.cpp +++ b/app/node/generator/shape/shapenode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/shape/shapenode.h b/app/node/generator/shape/shapenode.h index 45f8e7dec..1f079d8ca 100644 --- a/app/node/generator/shape/shapenode.h +++ b/app/node/generator/shape/shapenode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/shape/shapenodebase.cpp b/app/node/generator/shape/shapenodebase.cpp index 661e717b6..945c9ff88 100644 --- a/app/node/generator/shape/shapenodebase.cpp +++ b/app/node/generator/shape/shapenodebase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/shape/shapenodebase.h b/app/node/generator/shape/shapenodebase.h index 43ced165b..becdb29a1 100644 --- a/app/node/generator/shape/shapenodebase.h +++ b/app/node/generator/shape/shapenodebase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index dff474c7d..11e7e3137 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h index 2b97a56a8..b8fb0e27c 100644 --- a/app/node/generator/solid/solid.h +++ b/app/node/generator/solid/solid.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/text/textv1.cpp b/app/node/generator/text/textv1.cpp index 4f775c29d..0ac1211b5 100644 --- a/app/node/generator/text/textv1.cpp +++ b/app/node/generator/text/textv1.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/text/textv1.h b/app/node/generator/text/textv1.h index 63c00cb6a..793d89ae7 100644 --- a/app/node/generator/text/textv1.h +++ b/app/node/generator/text/textv1.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/text/textv2.cpp b/app/node/generator/text/textv2.cpp index ec241b447..a82967b24 100644 --- a/app/node/generator/text/textv2.cpp +++ b/app/node/generator/text/textv2.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/text/textv2.h b/app/node/generator/text/textv2.h index 693ea9765..df6ed4fe9 100644 --- a/app/node/generator/text/textv2.h +++ b/app/node/generator/text/textv2.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/text/textv3.cpp b/app/node/generator/text/textv3.cpp index 594172b4c..57b2eced0 100644 --- a/app/node/generator/text/textv3.cpp +++ b/app/node/generator/text/textv3.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/generator/text/textv3.h b/app/node/generator/text/textv3.h index 47ed92ea4..47a641c95 100644 --- a/app/node/generator/text/textv3.h +++ b/app/node/generator/text/textv3.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/draggable.cpp b/app/node/gizmo/draggable.cpp index 812bbb242..db2aa1ab4 100644 --- a/app/node/gizmo/draggable.cpp +++ b/app/node/gizmo/draggable.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/draggable.h b/app/node/gizmo/draggable.h index dee122b37..fdde2c94e 100644 --- a/app/node/gizmo/draggable.h +++ b/app/node/gizmo/draggable.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/gizmo.cpp b/app/node/gizmo/gizmo.cpp index 8c0008162..e5bfa6732 100644 --- a/app/node/gizmo/gizmo.cpp +++ b/app/node/gizmo/gizmo.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/gizmo.h b/app/node/gizmo/gizmo.h index 955f0c19e..db3a0d7da 100644 --- a/app/node/gizmo/gizmo.h +++ b/app/node/gizmo/gizmo.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/line.cpp b/app/node/gizmo/line.cpp index 5a01e16c5..7cf127127 100644 --- a/app/node/gizmo/line.cpp +++ b/app/node/gizmo/line.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/line.h b/app/node/gizmo/line.h index 8c8bf3d33..f60573199 100644 --- a/app/node/gizmo/line.h +++ b/app/node/gizmo/line.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/path.cpp b/app/node/gizmo/path.cpp index 6357d5d2c..4e7eb6e09 100644 --- a/app/node/gizmo/path.cpp +++ b/app/node/gizmo/path.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/path.h b/app/node/gizmo/path.h index dd245cc99..d0d1081ab 100644 --- a/app/node/gizmo/path.h +++ b/app/node/gizmo/path.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/point.cpp b/app/node/gizmo/point.cpp index 0d54fb4fc..957ccd866 100644 --- a/app/node/gizmo/point.cpp +++ b/app/node/gizmo/point.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/point.h b/app/node/gizmo/point.h index a61c37473..22d7d7b64 100644 --- a/app/node/gizmo/point.h +++ b/app/node/gizmo/point.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/polygon.cpp b/app/node/gizmo/polygon.cpp index 559b84351..68d73d4cf 100644 --- a/app/node/gizmo/polygon.cpp +++ b/app/node/gizmo/polygon.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/polygon.h b/app/node/gizmo/polygon.h index d3659dabd..fa4178d15 100644 --- a/app/node/gizmo/polygon.h +++ b/app/node/gizmo/polygon.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/screen.cpp b/app/node/gizmo/screen.cpp index ffcc43d82..87d3872b1 100644 --- a/app/node/gizmo/screen.cpp +++ b/app/node/gizmo/screen.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/screen.h b/app/node/gizmo/screen.h index 342048e51..1b0bfa224 100644 --- a/app/node/gizmo/screen.h +++ b/app/node/gizmo/screen.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/text.cpp b/app/node/gizmo/text.cpp index 7ff6a2b79..97ad2240c 100644 --- a/app/node/gizmo/text.cpp +++ b/app/node/gizmo/text.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/gizmo/text.h b/app/node/gizmo/text.h index a6846b561..ea5e49b3a 100644 --- a/app/node/gizmo/text.h +++ b/app/node/gizmo/text.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/globals.cpp b/app/node/globals.cpp index 5f6807b00..ed1da481b 100644 --- a/app/node/globals.cpp +++ b/app/node/globals.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/globals.h b/app/node/globals.h index 21a8a307c..14e8884bb 100644 --- a/app/node/globals.h +++ b/app/node/globals.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/group/group.cpp b/app/node/group/group.cpp index 1b3616bc8..7739d60e2 100644 --- a/app/node/group/group.cpp +++ b/app/node/group/group.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/group/group.h b/app/node/group/group.h index bb0f157f5..ff25faf09 100644 --- a/app/node/group/group.h +++ b/app/node/group/group.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/input/multicam/multicamnode.cpp b/app/node/input/multicam/multicamnode.cpp index e9acecd13..a192a01d5 100644 --- a/app/node/input/multicam/multicamnode.cpp +++ b/app/node/input/multicam/multicamnode.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "multicamnode.h" #include "node/project/sequence/sequence.h" diff --git a/app/node/input/multicam/multicamnode.h b/app/node/input/multicam/multicamnode.h index 8a462de40..ff9dcb555 100644 --- a/app/node/input/multicam/multicamnode.h +++ b/app/node/input/multicam/multicamnode.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef MULTICAMNODE_H #define MULTICAMNODE_H diff --git a/app/node/input/time/timeinput.cpp b/app/node/input/time/timeinput.cpp index e16d0e6b4..8acec004b 100644 --- a/app/node/input/time/timeinput.cpp +++ b/app/node/input/time/timeinput.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/input/time/timeinput.h b/app/node/input/time/timeinput.h index ce1098d52..9ba19483c 100644 --- a/app/node/input/time/timeinput.h +++ b/app/node/input/time/timeinput.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/input/value/valuenode.cpp b/app/node/input/value/valuenode.cpp index 5c0871e04..70fce2410 100644 --- a/app/node/input/value/valuenode.cpp +++ b/app/node/input/value/valuenode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/input/value/valuenode.h b/app/node/input/value/valuenode.h index 24e8a38a9..d4571bc9c 100644 --- a/app/node/input/value/valuenode.h +++ b/app/node/input/value/valuenode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/inputdragger.cpp b/app/node/inputdragger.cpp index 689f0c090..2a2c2d693 100644 --- a/app/node/inputdragger.cpp +++ b/app/node/inputdragger.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/inputdragger.h b/app/node/inputdragger.h index 2005606b1..48fac004f 100644 --- a/app/node/inputdragger.h +++ b/app/node/inputdragger.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/inputimmediate.cpp b/app/node/inputimmediate.cpp index 9d44d8f46..a68071ff7 100644 --- a/app/node/inputimmediate.cpp +++ b/app/node/inputimmediate.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/inputimmediate.h b/app/node/inputimmediate.h index 149dec5f9..5327416fe 100644 --- a/app/node/inputimmediate.h +++ b/app/node/inputimmediate.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/keyframe.cpp b/app/node/keyframe.cpp index 14c282b66..37f71cf51 100644 --- a/app/node/keyframe.cpp +++ b/app/node/keyframe.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -254,6 +255,10 @@ bool NodeKeyframe::load(QXmlStreamReader *reader, NodeValue::Type data_type) this->set_value( NodeValue::StringToValue(data_type, reader->readElementText(), true)); + if (!key_input.isEmpty()) { + this->set_input(key_input); + } + this->set_bezier_control_in(key_in_handle); this->set_bezier_control_out(key_out_handle); diff --git a/app/node/keyframe.h b/app/node/keyframe.h index 2a06e6390..1e5bb6bd4 100644 --- a/app/node/keyframe.h +++ b/app/node/keyframe.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 197a80261..eaf5bf9fd 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -1,6 +1,7 @@ /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index 2b049ffc0..3b163a55d 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -1,6 +1,7 @@ /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index ba0b0edd8..1b755882b 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -1,6 +1,7 @@ /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/app/node/keying/colordifferencekey/colordifferencekey.h b/app/node/keying/colordifferencekey/colordifferencekey.h index a350818fd..9ee4c7acd 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.h +++ b/app/node/keying/colordifferencekey/colordifferencekey.h @@ -1,6 +1,7 @@ /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/app/node/keying/despill/despill.cpp b/app/node/keying/despill/despill.cpp index 940c449d2..5a74a5fa9 100644 --- a/app/node/keying/despill/despill.cpp +++ b/app/node/keying/despill/despill.cpp @@ -1,6 +1,7 @@ /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/app/node/keying/despill/despill.h b/app/node/keying/despill/despill.h index b1b8fda46..40ed3b20e 100644 --- a/app/node/keying/despill/despill.h +++ b/app/node/keying/despill/despill.h @@ -1,6 +1,7 @@ /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team + Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index 8f07c0f53..14a2f1028 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index 5dcaa857f..759e9d540 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index 55a2e5bff..0ad7cacf9 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/math/math/mathbase.h b/app/node/math/math/mathbase.h index af784abb7..212aef0c5 100644 --- a/app/node/math/math/mathbase.h +++ b/app/node/math/math/mathbase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 0058cb92e..2d49b8057 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h index c10a94227..09f68a7cc 100644 --- a/app/node/math/merge/merge.h +++ b/app/node/math/merge/merge.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/math/trigonometry/trigonometry.cpp b/app/node/math/trigonometry/trigonometry.cpp index 768195710..90d5bab1e 100644 --- a/app/node/math/trigonometry/trigonometry.cpp +++ b/app/node/math/trigonometry/trigonometry.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/math/trigonometry/trigonometry.h b/app/node/math/trigonometry/trigonometry.h index 5bac78f99..6993f43fb 100644 --- a/app/node/math/trigonometry/trigonometry.h +++ b/app/node/math/trigonometry/trigonometry.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/node.cpp b/app/node/node.cpp index 99dff4674..ab3eb7aa8 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/node.h b/app/node/node.h index 11ace817b..4431fd2df 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -21,6 +22,8 @@ #ifndef NODE_H #define NODE_H +#include "ofxhImageEffectAPI.h" + #include #include #include @@ -1126,7 +1129,24 @@ public: static const QString kEnabledInput; + OFX::Host::ImageEffect::Instance* getPluginInstance() const + { + return plugin_instance_; + } + OFX::Host::ImageEffect::ImageEffectPlugin* getPlugin() const + { + return plugin_instance_ ? plugin_instance_->getPlugin() : nullptr; + } protected: + + // If set, this node owns a plugin instance. + OFX::Host::ImageEffect::Instance* plugin_instance_ = nullptr; + + void setPluginInstance(OFX::Host::ImageEffect::Instance* instance) + { + plugin_instance_ = instance; + } + void InsertInput(const QString &id, NodeValue::Type type, const QVariant &default_value, InputFlags flags, int index); @@ -1286,6 +1306,8 @@ signals: void KeyframeTimeChanged(NodeKeyframe *key); + void MessageCountChanged(); + void KeyframeTypeChanged(NodeKeyframe *key); void KeyframeValueChanged(NodeKeyframe *key); diff --git a/app/node/nodeundo.cpp b/app/node/nodeundo.cpp index 77fb01b55..786cf25cf 100644 --- a/app/node/nodeundo.cpp +++ b/app/node/nodeundo.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/nodeundo.h b/app/node/nodeundo.h index 323141d67..997fdad2b 100644 --- a/app/node/nodeundo.h +++ b/app/node/nodeundo.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 1f3132d32..0f494f72d 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 8b552902b..0b5ccbe2b 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/output/track/tracklist.cpp b/app/node/output/track/tracklist.cpp index 2ab6c2011..08d104e96 100644 --- a/app/node/output/track/tracklist.cpp +++ b/app/node/output/track/tracklist.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/output/track/tracklist.h b/app/node/output/track/tracklist.h index 32633c166..a02657d80 100644 --- a/app/node/output/track/tracklist.h +++ b/app/node/output/track/tracklist.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index ba5e749c8..84627570f 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index bb6d36e43..a97728e6f 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/param.cpp b/app/node/param.cpp index 98a7614c8..359f4e8ca 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/param.h b/app/node/param.h index 4fb673f5b..bcf6f5aa1 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/plugins/CMakeLists.txt b/app/node/plugins/CMakeLists.txt new file mode 100644 index 000000000..96a4e60f5 --- /dev/null +++ b/app/node/plugins/CMakeLists.txt @@ -0,0 +1,22 @@ +# Oak Video Editor - Non-Linear Video Editor +# Copyright (C) 2022 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/plugins/Plugin.h + node/plugins/Plugin.cpp + PARENT_SCOPE +) diff --git a/app/node/plugins/Plugin.cpp b/app/node/plugins/Plugin.cpp new file mode 100644 index 000000000..c089fffa9 --- /dev/null +++ b/app/node/plugins/Plugin.cpp @@ -0,0 +1,525 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Plugin.h" + +#include "render/rendermanager.h" +#include "render/job/pluginjob.h" +#include "pluginSupport/OlivePluginInstance.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +QHash> g_plugin_param_defaults; + +QVariant DefaultValueForParam(const OFX::Host::Param::Base *param) +{ + if (!param) { + return QVariant(); + } + const std::string &ofxType = param->getType(); + const auto &props = param->getProperties(); + + if (ofxType == kOfxParamTypeInteger || + ofxType == kOfxParamTypeChoice) { + return props.getIntProperty(kOfxParamPropDefault); + } + if (ofxType == kOfxParamTypeBoolean) { + return props.getIntProperty(kOfxParamPropDefault) != 0; + } + if (ofxType == kOfxParamTypeDouble) { + return props.getDoubleProperty(kOfxParamPropDefault); + } + if (ofxType == kOfxParamTypeString || + ofxType == kOfxParamTypeStrChoice || + ofxType == kOfxParamTypeCustom) { + return QString::fromStdString( + props.getStringProperty(kOfxParamPropDefault)); + } + if (ofxType == kOfxParamTypeRGB || + ofxType == kOfxParamTypeRGBA) { + const int count = (ofxType == kOfxParamTypeRGBA) ? 4 : 3; + double values[4] = {0.0, 0.0, 0.0, 1.0}; + props.getDoublePropertyN(kOfxParamPropDefault, values, count); + const double alpha = (count == 4) ? values[3] : 1.0; + return QVariant::fromValue( + olive::core::Color(values[0], values[1], values[2], alpha)); + } + if (ofxType == kOfxParamTypeDouble2D || + ofxType == kOfxParamTypeDouble3D || + ofxType == kOfxParamTypeInteger2D || + ofxType == kOfxParamTypeInteger3D) { + const bool is_double = + (ofxType == kOfxParamTypeDouble2D || + ofxType == kOfxParamTypeDouble3D); + const int count = (ofxType == kOfxParamTypeDouble2D || + ofxType == kOfxParamTypeInteger2D) + ? 2 + : 3; + if (is_double) { + double values[3] = {0.0, 0.0, 0.0}; + props.getDoublePropertyN(kOfxParamPropDefault, values, count); + if (count == 2) { + return QVector2D(values[0], values[1]); + } + return QVector3D(values[0], values[1], values[2]); + } + int values[3] = {0, 0, 0}; + props.getIntPropertyN(kOfxParamPropDefault, values, count); + if (count == 2) { + return QVector2D(values[0], values[1]); + } + return QVector3D(values[0], values[1], values[2]); + } + if (ofxType == kOfxParamTypeBytes) { + return QByteArray(); + } + + return QVariant(); +} + +QHash +BuildDefaultValues(const std::map ¶ms) +{ + QHash defaults; + for (const auto ¶m : params) { + const std::string &ofxType = param.second->getType(); + if (ofxType == kOfxParamTypeGroup || + ofxType == kOfxParamTypePage || + ofxType == kOfxParamTypePushButton) { + continue; + } + const auto &props = param.second->getProperties(); + if (props.getIntProperty(kOfxParamPropSecret) != 0) { + continue; + } + const QString input_id = + QString::fromStdString(param.second->getName()); + if (input_id.isEmpty()) { + continue; + } + QVariant default_value = DefaultValueForParam(param.second); + if (!default_value.isValid()) { + continue; + } + defaults.insert(input_id, default_value); + } + return defaults; +} +} +static QString ClipLabelForName(const std::string &name, + const OFX::Host::ImageEffect::ClipDescriptor *desc) +{ + if (name == kOfxImageEffectSimpleSourceClipName) { + return olive::plugin::PluginNode::tr("Source"); + } + if (name == kOfxImageEffectTransitionSourceFromClipName) { + return olive::plugin::PluginNode::tr("From"); + } + if (name == kOfxImageEffectTransitionSourceToClipName) { + return olive::plugin::PluginNode::tr("To"); + } + + if (desc) { + const std::string &label = + desc->getProps().getStringProperty(kOfxPropLabel); + if (!label.empty()) { + return QString::fromStdString(label); + } + } + + return QString::fromStdString(name); +} + +olive::plugin::PluginNode::PluginNode( + OFX::Host::ImageEffect::Instance *plugin) +{ + plugin_instance_=plugin; + bool has_texture_input = false; + QHash group_labels; + QHash page_labels; + QHash page_for_param; + + auto params=plugin_instance_->getParams(); + const QString plugin_id = QString::fromStdString( + plugin_instance_->getPlugin()->getIdentifier()); + auto defaults_iter = g_plugin_param_defaults.find(plugin_id); + if (defaults_iter == g_plugin_param_defaults.end()) { + g_plugin_param_defaults.insert(plugin_id, BuildDefaultValues(params)); + defaults_iter = g_plugin_param_defaults.find(plugin_id); + } + const QHash &defaults = defaults_iter.value(); + for (auto param: params) { + const std::string &ofxType = param.second->getType(); + if (ofxType == kOfxParamTypeGroup) { + const QString name = QString::fromStdString(param.first); + const QString label = + QString::fromStdString(param.second->getLabel()); + group_labels.insert(name, label.isEmpty() ? name : label); + } else if (ofxType == kOfxParamTypePage) { + const QString name = QString::fromStdString(param.first); + const QString label = + QString::fromStdString(param.second->getLabel()); + page_labels.insert(name, label.isEmpty() ? name : label); + + const auto &props = param.second->getProperties(); + int count = props.getDimension(kOfxParamPropPageChild); + for (int i = 0; i < count; ++i) { + const std::string &child = + props.getStringProperty(kOfxParamPropPageChild, i); + if (child == kOfxParamPageSkipRow || + child == kOfxParamPageSkipColumn) { + continue; + } + page_for_param.insert(QString::fromStdString(child), + page_labels.value(name)); + } + } + } + + for (auto param: params) { + + NodeValue::Type type = NodeValue::kNone; + + const std::string &ofxType = param.second->getType(); + if (ofxType == kOfxParamTypeInteger) { + type = NodeValue::kInt; + } else if (ofxType == kOfxParamTypeDouble) { + type = NodeValue::kFloat; + } else if (ofxType == kOfxParamTypeBoolean) { + type = NodeValue::kBoolean; + } else if (ofxType == kOfxParamTypeString) { + type = NodeValue::kText; + } else if (ofxType == kOfxParamTypeRGB || + ofxType == kOfxParamTypeRGBA) { + type = NodeValue::kColor; + } else if (ofxType == kOfxParamTypeChoice) { + type = NodeValue::kCombo; + } else if (ofxType == kOfxParamTypeDouble2D || + ofxType == kOfxParamTypeInteger2D){ + type = NodeValue::kVec2;} + else if (ofxType == kOfxParamTypeDouble3D || + ofxType == kOfxParamTypeInteger3D){ + type = NodeValue::kVec3; + } else if (ofxType == kOfxParamTypeStrChoice){ + type = NodeValue::kStrCombo; + }else if (ofxType == kOfxParamTypeBytes + || ofxType == kOfxParamTypeCustom) { + type = NodeValue::kBinary; + } else if (ofxType == kOfxParamTypePushButton) { + type = NodeValue::kPushButton; + } else if (ofxType == kOfxParamTypeGroup || + ofxType == kOfxParamTypePage) { + continue; + }else { + type = NodeValue::kNone; + } + + const QString input_id = QString::fromStdString(param.second->getName()); + if (input_id.isEmpty()) { + continue; + } + const auto &props = param.second->getProperties(); + if (props.getIntProperty(kOfxParamPropSecret) != 0) { + continue; + } + if (type == NodeValue::kNone) { + continue; + } + QVariant default_value = defaults.value(input_id, QVariant()); + if (default_value.isValid()) { + AddInput(input_id, type, default_value); + if (type != NodeValue::kPushButton) { + SetStandardValue(input_id, default_value); + } + } else { + AddInput(input_id, type); + } + const QString label = + QString::fromStdString(param.second->getLabel()); + if (!label.isEmpty()) { + SetInputName(input_id, label); + } else { + SetInputName(input_id, input_id); + } + const QString parent = + QString::fromStdString(param.second->getParentName()); + if (!parent.isEmpty()) { + SetInputProperty(input_id, QStringLiteral("ui_group"), + group_labels.value(parent, parent)); + } + if (page_for_param.contains(input_id)) { + SetInputProperty(input_id, QStringLiteral("ui_page"), + page_for_param.value(input_id)); + } + if (type == NodeValue::kCombo || type == NodeValue::kStrCombo) { + QStringList option_labels; + QStringList option_values; + const int label_count = + props.getDimension(kOfxParamPropChoiceOption); + const int value_count = + props.getDimension(kOfxParamPropChoiceEnum); + + for (int i = 0; i < label_count; ++i) { + const std::string &label = + props.getStringProperty(kOfxParamPropChoiceOption, i); + option_labels.append(QString::fromStdString(label)); + } + + for (int i = 0; i < value_count; ++i) { + const std::string &value = + props.getStringProperty(kOfxParamPropChoiceEnum, i); + option_values.append(QString::fromStdString(value)); + } + + if (option_labels.isEmpty() && !option_values.isEmpty()) { + option_labels = option_values; + } + if (option_values.isEmpty() && !option_labels.isEmpty()) { + option_values = option_labels; + } + + const int order_count = + props.getDimension(kOfxParamPropChoiceOrder); + if (order_count == option_labels.size() && + option_labels.size() == option_values.size()) { + QVector indices(option_labels.size()); + for (int i = 0; i < indices.size(); ++i) { + indices[i] = i; + } + + std::stable_sort(indices.begin(), indices.end(), + [&](int a, int b) { + return props.getIntProperty( + kOfxParamPropChoiceOrder, + a) < + props.getIntProperty( + kOfxParamPropChoiceOrder, + b); + }); + + QStringList ordered_labels; + QStringList ordered_values; + for (int index : indices) { + ordered_labels.append(option_labels.at(index)); + ordered_values.append(option_values.at(index)); + } + option_labels = ordered_labels; + option_values = ordered_values; + } + + if (!option_labels.isEmpty()) { + SetComboBoxStrings(input_id, option_labels); + if (type == NodeValue::kStrCombo) { + SetInputProperty(input_id, + QStringLiteral("combo_value_str"), + option_values); + } + } + } + } + + const auto &clips = plugin_instance_->getDescriptor().getClips(); + for (const auto &entry : clips) { + if (entry.first == kOfxImageEffectOutputClipName) { + continue; + } + QString input_id = QString::fromStdString(entry.first); + AddInput(input_id, NodeValue::kTexture); + SetInputName(input_id, ClipLabelForName(entry.first, entry.second)); + has_texture_input = true; + } + + + const QString source_id = + QString::fromUtf8(kOfxImageEffectSimpleSourceClipName); + if (HasInputWithID(source_id)) { + SetEffectInput(source_id); + } else if (HasInputWithID(kTextureInput)) { + SetEffectInput(kTextureInput); + } + else { + if (has_texture_input) { + AddInput(kTextureInput, NodeValue::kTexture); + SetInputName(kTextureInput, tr("Texture")); + SetEffectInput(kTextureInput); + } + } +} + +olive::plugin::PluginNode::~PluginNode() = default; +QString olive::plugin::PluginNode::Name() const +{ + const auto *plugin = plugin_instance_->getPlugin(); + return plugin->getDescriptor() + .getProps() + .getStringProperty(kOfxPropLabel) + .data(); + +} + +QVector olive::plugin::PluginNode::Category() const +{ + return { olive::Node::kCategoryUnknown }; +} + +QString olive::plugin::PluginNode::Description() const +{ + const auto *plugin = plugin_instance_->getPlugin(); + return plugin->getDescriptor() + .getProps() + .getStringProperty(kOfxPropPluginDescription) + .data(); + +} +void olive::plugin::PluginNode::ProcessSamples(const NodeValueRow &values, + const SampleBuffer &input, + SampleBuffer &output, + int index) const +{ + Q_UNUSED(values) + Q_UNUSED(index) + + if (!input.is_allocated() || input.channel_count() == 0 || + input.sample_count() == 0) { + if (output.is_allocated()) { + output.silence(); + } + return; + } + + if (!output.is_allocated() || + output.channel_count() != input.channel_count() || + output.sample_count() != input.sample_count()) { + output.set_audio_params(input.audio_params()); + output.set_sample_count(input.sample_count()); + output.allocate(); + } + + if (!output.is_allocated()) { + return; + } + + for (int channel = 0; channel < input.channel_count(); ++channel) { + output.fast_set(input, channel); + } +} + +void olive::plugin::PluginNode::GenerateFrame(FramePtr frame, + const GenerateJob &job) const +{ + Q_UNUSED(job) + + if (!frame) { + return; + } + + if (!frame->is_allocated()) { + frame->allocate(); + } + + if (!frame->is_allocated()) { + return; + } + + std::memset(frame->data(), 0, static_cast(frame->allocated_size())); +} +void olive::plugin::PluginNode::Value(const NodeValueRow &value, + const NodeGlobals &globals, + NodeValueTable *table) const +{ + for (auto it = value.cbegin(); it != value.cend(); ++it) { + const NodeValue &input_value = it.value(); + if (input_value.type() == NodeValue::kTexture || + input_value.type() == NodeValue::kNone) { + continue; + } + NodeValue tagged = input_value; + tagged.set_tag(it.key()); + table->Push(tagged); + } + + TexturePtr tex = nullptr; + const QString source_key = + QString::fromUtf8(kOfxImageEffectSimpleSourceClipName); + if (value.contains(source_key)) { + tex = value.value(source_key).toTexture(); + } + if (!tex) { + tex = value.value(kTextureInput).toTexture(); + } + if (!tex) { + for (auto it = value.cbegin(); it != value.cend(); ++it) { + if (it.value().type() == NodeValue::kTexture) { + tex = it.value().toTexture(); + if (tex) { + break; + } + } + } + } + if (tex && plugin_instance_) { + PluginJob job(plugin_instance_, this, value, globals.time().in()); + + table->Push(NodeValue::kTexture, tex->toJob(job), this); + } +} +void olive::plugin::PluginNode::pushButtonClicked(QString name) +{ +} + +QString olive::plugin::PluginNode::id() const +{ + const auto *plugin = plugin_instance_->getPlugin(); + return plugin->getIdentifier().data(); +} + + olive::Node *olive::plugin::PluginNode::copy() const + { + if (!plugin_instance_) { + return nullptr; + } + + const auto &contexts = plugin_instance_->getPlugin()->getContexts(); + std::string context = kOfxImageEffectContextFilter; + if (!contexts.empty() && + contexts.find(kOfxImageEffectContextFilter) == contexts.end()) { + context = *contexts.begin(); + } + + auto *instance = + plugin_instance_->getPlugin()->createInstance(context, nullptr); + if (!instance) { + return nullptr; + } + + auto *node = new PluginNode(instance); + if (auto *olive_instance = + dynamic_cast(instance)) { + olive_instance->setNode( + std::shared_ptr(node, [](PluginNode *) {})); + } + return node; + } diff --git a/app/node/plugins/Plugin.h b/app/node/plugins/Plugin.h new file mode 100644 index 000000000..e1e33aaa5 --- /dev/null +++ b/app/node/plugins/Plugin.h @@ -0,0 +1,88 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PLUGIN_NODES_H +#define PLUGIN_NODES_H +#include "ofxhImageEffectAPI.h" +#include "ofxhPluginCache.h" +#include "ofxImageEffect.h" +#include "node/node.h" + +namespace olive +{ +namespace plugin +{ +const QString kTextureInput = QStringLiteral("tex_in"); + +class PluginNode : public olive::Node{ +public: + PluginNode(OFX::Host::ImageEffect::Instance* plugin) ; + ~PluginNode() override; + + + QString Name() const override; + QString id() const override; + QVector Category() const override; + QString Description() const override; + + void AddPushButton(); + void AddPage(); + + Node *copy() const override; + /** + * @brief The main processing function + * + * The node's main purpose is to take values from inputs to set values in outputs. For whatever subclass node you + * create, this is where the code for that goes. + * + * Note that as a video editor, the node graph has to work across time. Depending on the purpose of your node, it may + * output different values depending on the time, and even if not, it will likely be receiving different input + * depending on the time. Most of the difficult work here is handled by NodeInput::get_value() which you should pass + * the `time` parameter to. It will return its value (at that time, if it's keyframed), or pass the time to a + * corresponding output if it's connected to one. If your node doesn't directly deal with time, the default behavior + * of the NodeParam objects will handle everything related to it automatically. + */ + void Value(const NodeValueRow &value, + const NodeGlobals &globals, NodeValueTable *table) const override; + + /** + * @brief If Value() pushes a ShaderJob, this is the function that will process them. + */ + virtual void ProcessSamples(const NodeValueRow &values, + const SampleBuffer &input, SampleBuffer &output, + int index) const; + + /** + * @brief If Value() pushes a GenerateJob, override this function for the image to create + * + * @param frame + * + * The destination buffer. It will already be allocated and ready for writing to. + */ + virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const; + +public slots: + void pushButtonClicked(QString name); + +}; + +} +} + + +#endif //PLUGIN_H diff --git a/app/node/project.cpp b/app/node/project.cpp index a1f988f56..4f22b535a 100644 --- a/app/node/project.cpp +++ b/app/node/project.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -23,6 +24,7 @@ #include #include +#include "common/Current.h" #include "common/qtutils.h" #include "common/xmlutils.h" #include "core.h" @@ -30,6 +32,8 @@ #include "node/color/ociobase/ociobase.h" #include "node/factory.h" #include "node/serializeddata.h" +#include "pluginSupport/OliveHost.h" +#include "ofxhPluginCache.h" #include "render/diskmanager.h" #include "window/mainwindow/mainwindow.h" @@ -97,11 +101,53 @@ void Project::Clear() SerializedData Project::Load(QXmlStreamReader *reader) { SerializedData data; + QSet plugin_paths; while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("uuid")) { this->SetUuid(QUuid::fromString(reader->readElementText())); + } else if (reader->name() == QStringLiteral("plugins")) { + while (XMLReadNextStartElement(reader)) { + if (reader->name() == QStringLiteral("plugin")) { + QString bundle_path; + QString file_path; + XMLAttributeLoop(reader, attr) + { + if (attr.name() == QStringLiteral("bundle")) { + bundle_path = attr.value().toString(); + } else if (attr.name() == QStringLiteral("file")) { + file_path = attr.value().toString(); + } + } + + const QString path = bundle_path.isEmpty() + ? file_path + : bundle_path; + if (!path.isEmpty()) { + plugin_paths.insert(path); + } + + reader->skipCurrentElement(); + } else { + reader->skipCurrentElement(); + } + } + + if (!plugin_paths.isEmpty()) { + if (!Current::getInstance().pluginHost() || + !Current::getInstance().pluginCache()) { + plugin::loadPlugins(QString()); + } + + auto *cache = OFX::Host::PluginCache::getPluginCache(); + for (const QString &path : plugin_paths) { + cache->addFileToPath(path.toStdString(), true); + } + cache->scanPluginFiles(); + NodeFactory::RegisterPluginNodes(); + } + } else if (reader->name() == QStringLiteral("nodes")) { while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("node")) { @@ -173,6 +219,65 @@ void Project::Save(QXmlStreamWriter *writer) const writer->writeTextElement(QStringLiteral("uuid"), this->GetUuid().toString()); + QVector>> plugins_to_save; + { + QSet seen; + for (Node *node : this->nodes()) { + auto *plugin = node->getPlugin(); + if (!plugin) { + continue; + } + + const std::string id = plugin->getIdentifier(); + const int major = plugin->getVersionMajor(); + const int minor = plugin->getVersionMinor(); + QString bundle_path; + QString file_path; + if (auto *binary = plugin->getBinary()) { + bundle_path = QString::fromStdString(binary->getBundlePath()); + file_path = QString::fromStdString(binary->getFilePath()); + } + + const QString key = QStringLiteral("%1|%2|%3|%4|%5") + .arg(QString::fromStdString(id)) + .arg(major) + .arg(minor) + .arg(bundle_path) + .arg(file_path); + if (seen.contains(key)) { + continue; + } + seen.insert(key); + + QMap attrs; + attrs.insert(QStringLiteral("id"), + QString::fromStdString(id)); + attrs.insert(QStringLiteral("major"), QString::number(major)); + attrs.insert(QStringLiteral("minor"), QString::number(minor)); + if (!bundle_path.isEmpty()) { + attrs.insert(QStringLiteral("bundle"), bundle_path); + } + if (!file_path.isEmpty()) { + attrs.insert(QStringLiteral("file"), file_path); + } + + plugins_to_save.append({ QString::fromStdString(id), attrs }); + } + } + + if (!plugins_to_save.isEmpty()) { + writer->writeStartElement(QStringLiteral("plugins")); + for (const auto &entry : plugins_to_save) { + writer->writeStartElement(QStringLiteral("plugin")); + for (auto it = entry.second.cbegin(); + it != entry.second.cend(); ++it) { + writer->writeAttribute(it.key(), it.value()); + } + writer->writeEndElement(); + } + writer->writeEndElement(); + } + if (!this->nodes().isEmpty()) { writer->writeStartElement(QStringLiteral("nodes")); diff --git a/app/node/project.h b/app/node/project.h index eef878e44..54b06ddb7 100644 --- a/app/node/project.h +++ b/app/node/project.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/folder/folder.cpp b/app/node/project/folder/folder.cpp index 2ce84c61b..7d0cd07c9 100644 --- a/app/node/project/folder/folder.cpp +++ b/app/node/project/folder/folder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/folder/folder.h b/app/node/project/folder/folder.h index 7ab602944..4317be764 100644 --- a/app/node/project/folder/folder.h +++ b/app/node/project/folder/folder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/footage/footage.cpp b/app/node/project/footage/footage.cpp index f1fcda32f..186e82014 100644 --- a/app/node/project/footage/footage.cpp +++ b/app/node/project/footage/footage.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/footage/footage.h b/app/node/project/footage/footage.h index ae374f998..c3332e22c 100644 --- a/app/node/project/footage/footage.h +++ b/app/node/project/footage/footage.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/footage/footagedescription.cpp b/app/node/project/footage/footagedescription.cpp index 094145e66..06e82c8b7 100644 --- a/app/node/project/footage/footagedescription.cpp +++ b/app/node/project/footage/footagedescription.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/footage/footagedescription.h b/app/node/project/footage/footagedescription.h index 431adb10f..83589b622 100644 --- a/app/node/project/footage/footagedescription.h +++ b/app/node/project/footage/footagedescription.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/sequence/sequence.cpp b/app/node/project/sequence/sequence.cpp index 895cc0e0b..60febfb0f 100644 --- a/app/node/project/sequence/sequence.cpp +++ b/app/node/project/sequence/sequence.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/sequence/sequence.h b/app/node/project/sequence/sequence.h index cdf9769c2..94c8c36ff 100644 --- a/app/node/project/sequence/sequence.h +++ b/app/node/project/sequence/sequence.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer.cpp b/app/node/project/serializer/serializer.cpp index 00f3f3ff9..f682997be 100644 --- a/app/node/project/serializer/serializer.cpp +++ b/app/node/project/serializer/serializer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer.h b/app/node/project/serializer/serializer.h index 5a122f144..b536027fe 100644 --- a/app/node/project/serializer/serializer.h +++ b/app/node/project/serializer/serializer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer190219.cpp b/app/node/project/serializer/serializer190219.cpp index bf67497ec..bae440d65 100644 --- a/app/node/project/serializer/serializer190219.cpp +++ b/app/node/project/serializer/serializer190219.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer190219.h b/app/node/project/serializer/serializer190219.h index a3d907c3f..eb2892622 100644 --- a/app/node/project/serializer/serializer190219.h +++ b/app/node/project/serializer/serializer190219.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer210528.cpp b/app/node/project/serializer/serializer210528.cpp index c9829eccc..4d4356a31 100644 --- a/app/node/project/serializer/serializer210528.cpp +++ b/app/node/project/serializer/serializer210528.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer210528.h b/app/node/project/serializer/serializer210528.h index 7bc5328ac..54617d93d 100644 --- a/app/node/project/serializer/serializer210528.h +++ b/app/node/project/serializer/serializer210528.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer210907.cpp b/app/node/project/serializer/serializer210907.cpp index 7d73df50b..79936384e 100644 --- a/app/node/project/serializer/serializer210907.cpp +++ b/app/node/project/serializer/serializer210907.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer210907.h b/app/node/project/serializer/serializer210907.h index e836b6e08..081d1d361 100644 --- a/app/node/project/serializer/serializer210907.h +++ b/app/node/project/serializer/serializer210907.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer211228.cpp b/app/node/project/serializer/serializer211228.cpp index 2029a4283..507ecd4b5 100644 --- a/app/node/project/serializer/serializer211228.cpp +++ b/app/node/project/serializer/serializer211228.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer211228.h b/app/node/project/serializer/serializer211228.h index 3082144ea..20c56437a 100644 --- a/app/node/project/serializer/serializer211228.h +++ b/app/node/project/serializer/serializer211228.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer220403.cpp b/app/node/project/serializer/serializer220403.cpp index 27ce55df6..70f71a94a 100644 --- a/app/node/project/serializer/serializer220403.cpp +++ b/app/node/project/serializer/serializer220403.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer220403.h b/app/node/project/serializer/serializer220403.h index 6a38773f4..813620692 100644 --- a/app/node/project/serializer/serializer220403.h +++ b/app/node/project/serializer/serializer220403.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/serializer230220.cpp b/app/node/project/serializer/serializer230220.cpp index df66372be..0794e3dae 100644 --- a/app/node/project/serializer/serializer230220.cpp +++ b/app/node/project/serializer/serializer230220.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 @@ -19,6 +20,8 @@ ***/ #include +#include + #include "serializer230220.h" #include "config/config.h" diff --git a/app/node/project/serializer/serializer230220.h b/app/node/project/serializer/serializer230220.h index c1216d05c..cb0923417 100644 --- a/app/node/project/serializer/serializer230220.h +++ b/app/node/project/serializer/serializer230220.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/typeserializer.cpp b/app/node/project/serializer/typeserializer.cpp index 4fa481ec4..c4d1e7a02 100644 --- a/app/node/project/serializer/typeserializer.cpp +++ b/app/node/project/serializer/typeserializer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/project/serializer/typeserializer.h b/app/node/project/serializer/typeserializer.h index 5a51c71c2..f061eb756 100644 --- a/app/node/project/serializer/typeserializer.h +++ b/app/node/project/serializer/typeserializer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/serializeddata.cpp b/app/node/serializeddata.cpp index dd23b3662..20ded8c3b 100644 --- a/app/node/serializeddata.cpp +++ b/app/node/serializeddata.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/serializeddata.h b/app/node/serializeddata.h index 3be500ed2..7f97c0ded 100644 --- a/app/node/serializeddata.h +++ b/app/node/serializeddata.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/splitvalue.h b/app/node/splitvalue.h index 472fa5ec4..31b837aa3 100644 --- a/app/node/splitvalue.h +++ b/app/node/splitvalue.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/time/timeformat/timeformat.cpp b/app/node/time/timeformat/timeformat.cpp index cced2beb5..f037c3086 100644 --- a/app/node/time/timeformat/timeformat.cpp +++ b/app/node/time/timeformat/timeformat.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/time/timeformat/timeformat.h b/app/node/time/timeformat/timeformat.h index 4f6e6d193..bcbdbb2d4 100644 --- a/app/node/time/timeformat/timeformat.h +++ b/app/node/time/timeformat/timeformat.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/time/timeoffset/timeoffsetnode.cpp b/app/node/time/timeoffset/timeoffsetnode.cpp index fde536d39..f0c1f8754 100644 --- a/app/node/time/timeoffset/timeoffsetnode.cpp +++ b/app/node/time/timeoffset/timeoffsetnode.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/time/timeoffset/timeoffsetnode.h b/app/node/time/timeoffset/timeoffsetnode.h index 072caefa2..5eba48e21 100644 --- a/app/node/time/timeoffset/timeoffsetnode.h +++ b/app/node/time/timeoffset/timeoffsetnode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/time/timeremap/timeremap.cpp b/app/node/time/timeremap/timeremap.cpp index 05e454bf6..20f2e026c 100644 --- a/app/node/time/timeremap/timeremap.cpp +++ b/app/node/time/timeremap/timeremap.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/time/timeremap/timeremap.h b/app/node/time/timeremap/timeremap.h index 69c693511..1035847cd 100644 --- a/app/node/time/timeremap/timeremap.h +++ b/app/node/time/timeremap/timeremap.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 2d4782c3a..63efb9c22 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -24,6 +25,7 @@ #include "node/block/clip/clip.h" #include "render/job/footagejob.h" #include "render/rendermanager.h" +#include "render/job/pluginjob.h" namespace olive { @@ -383,12 +385,23 @@ TexturePtr NodeTraverser::ProcessVideoCacheJob(const CacheJob *val) return nullptr; } +TexturePtr NodeTraverser::ProcessPluginJob(TexturePtr texture, + TexturePtr destination, + const Node *node) +{ + // TODO + return nullptr; +} QVector2D NodeTraverser::GenerateResolution() const { return QVector2D(video_params_.square_pixel_width(), video_params_.height()); } +/** + * Resolve Jobs. I need to add a PluginJob here and move the plugin code here. + * @param val + */ void NodeTraverser::ResolveJobs(NodeValue &val) { if (val.type() == NodeValue::kTexture) { @@ -488,6 +501,15 @@ void NodeTraverser::ResolveJobs(NodeValue &val) val.set_value(tex); } + else if (plugin::PluginJob* plugin_job=dynamic_cast(base_job)) { + VideoParams tex_params = job_tex->params(); + + TexturePtr tex = CreateTexture(tex_params); + + ProcessPluginJob(job_tex, tex, val.source()); + val.set_value(tex); + + } // Cache resolved value resolved_texture_cache_.insert(job_tex.get(), diff --git a/app/node/traverser.h b/app/node/traverser.h index af2ad75ba..18bf5a973 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -32,6 +33,7 @@ #include "render/job/colortransformjob.h" #include "render/job/footagejob.h" #include "value.h" +#include "render/job/pluginjob.h" namespace olive { @@ -145,6 +147,7 @@ protected: return SampleBuffer(); } + virtual TexturePtr ProcessPluginJob(TexturePtr texture, TexturePtr destination, const Node *node); SampleBuffer CreateSampleBuffer(const AudioParams ¶ms, const rational &length) { diff --git a/app/node/value.cpp b/app/node/value.cpp index 75fc91a04..aabcaa76d 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/value.h b/app/node/value.h index ae0d268ca..2df8f3e25 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -165,7 +166,13 @@ public: * Resolves to `int` - the index currently selected */ kCombo, - + /** + * ComboBox type + * + * Resolves to `QString` - the text of choice currently selected + * This is to support the OpenFX type kOfxParamTypeStrChoice + */ + kStrCombo, /** * Video Parameters type * @@ -193,6 +200,10 @@ public: kBinary, /** + *Push Button + */ + kPushButton, + /** * End of list */ kDataTypeCount diff --git a/app/node/valuedatabase.cpp b/app/node/valuedatabase.cpp index 0d0682a14..a43ad61a8 100644 --- a/app/node/valuedatabase.cpp +++ b/app/node/valuedatabase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/node/valuedatabase.h b/app/node/valuedatabase.h index 5db5ac872..189d741a9 100644 --- a/app/node/valuedatabase.h +++ b/app/node/valuedatabase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/packaging/linux/AppRun b/app/packaging/linux/AppRun index 6c2e0f4af..78498db05 100755 --- a/app/packaging/linux/AppRun +++ b/app/packaging/linux/AppRun @@ -1,5 +1,23 @@ #!/usr/bin/env bash +# +# Oak Video Editor - Non-Linear Video Editor +# Copyright (C) 2025 Olive CE Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + APPDIR=$(readlink -f $(dirname "$0")) # Custom AppRun that ensures the AppImage doesn't dismount before olive-crashhandler exits diff --git a/app/packaging/linux/CMakeLists.txt b/app/packaging/linux/CMakeLists.txt index 1696a9162..c45dae139 100644 --- a/app/packaging/linux/CMakeLists.txt +++ b/app/packaging/linux/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -27,17 +28,17 @@ else() endif() configure_file( - org.olivevideoeditor.Olive.appdata.xml.in - org.olivevideoeditor.Olive.appdata.xml + org.oakvideoeditor.Oak.appdata.xml.in + org.oakvideoeditor.Oak.appdata.xml ) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.olivevideoeditor.Olive.appdata.xml DESTINATION share/metainfo) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.oakvideoeditor.Oak.appdata.xml DESTINATION share/metainfo) -install(FILES org.olivevideoeditor.Olive.desktop DESTINATION share/applications) -install(FILES org.olivevideoeditor.Olive.xml DESTINATION share/mime/packages) +install(FILES org.oakvideoeditor.Oak.desktop DESTINATION share/applications) +install(FILES org.oakvideoeditor.Oak.xml DESTINATION share/mime/packages) foreach(size 16 32 48 64 128 256 512) install( - FILES icons/${size}x${size}/org.olivevideoeditor.Olive.png + FILES icons/${size}x${size}/org.oakvideoeditor.Oak.png DESTINATION share/icons/hicolor/${size}x${size}/apps ) install( diff --git a/app/packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/128x128/org.oakvideoeditor.Oak.png similarity index 100% rename from app/packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/128x128/org.oakvideoeditor.Oak.png diff --git a/app/packaging/linux/icons/16x16/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/16x16/org.oakvideoeditor.Oak.png similarity index 100% rename from app/packaging/linux/icons/16x16/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/16x16/org.oakvideoeditor.Oak.png diff --git a/app/packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/256x256/org.oakvideoeditor.Oak.png similarity index 100% rename from app/packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/256x256/org.oakvideoeditor.Oak.png diff --git a/app/packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/32x32/org.oakvideoeditor.Oak.png similarity index 100% rename from app/packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/32x32/org.oakvideoeditor.Oak.png diff --git a/app/packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/48x48/org.oakvideoeditor.Oak.png similarity index 100% rename from app/packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/48x48/org.oakvideoeditor.Oak.png diff --git a/app/packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/512x512/org.oakvideoeditor.Oak.png similarity index 100% rename from app/packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/512x512/org.oakvideoeditor.Oak.png diff --git a/app/packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/64x64/org.oakvideoeditor.Oak.png similarity index 100% rename from app/packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/64x64/org.oakvideoeditor.Oak.png diff --git a/app/packaging/linux/org.oakvideoeditor.Oak.appdata.xml.in b/app/packaging/linux/org.oakvideoeditor.Oak.appdata.xml.in new file mode 100644 index 000000000..ebef1bfb5 --- /dev/null +++ b/app/packaging/linux/org.oakvideoeditor.Oak.appdata.xml.in @@ -0,0 +1,37 @@ + + + org.oakvideoeditor.Oak + Oak Video Editor + CC0-1.0 + GPL-3.0 + Oak Video Editor Team + Non-linear video editor + Nicht-lineares Videoschnittprogramm + Editor de vídeo não-linear + Editor de video no lineal + Editor video non lineare + Нелинейный видеоредактор + Нелінійний відеоредактор + Нелінійний відеоредактор + Aplikasi edit video non-linier + Éditeur vidéo non-linéaire +

Oak Video Editor is a free non-linear video editor aiming to provide a fully-featured alternative to high-end professional video editing software. It is a community fork of Olive Video Editor.

+ Oak Video Editor ist ein freies nicht-lineares Videoschnittprogramm, welches eine vollwertige Alternative zu High-End Videoschnittprogrammen darstellen soll. Es ist ein Community-Fork von Olive Video Editor. +

Oak Video Editor é um editor de vídeo não-linear com o objetivo de fornecer uma alternativa completa para softwares profissionais de edição de vídeo. É um fork comunitário do Olive Video Editor.

+

Oak Video Editor es un editor de video no lineal libre que apunta a brindar una alternativa completa al software de edición de video profesional. Es un fork de la comunidad del Olive Video Editor.

+

Oak Video Editor è un programma di montaggio video che mira a fornire una alternativa di alta qualità ai software professionali. È un fork della comunità di Olive Video Editor.

+

Oak Video Editor — свободный нелинейный видеоредактор, задуманный как полноценная замена закрытым коммерческим продуктам. Это форк сообщества Olive Video Editor.

+

Oak Video Editor — вільний нелінійний відеоредактор, задуманий як повноцінна заміна закритим комерційним продуктам. Це форк спільноти Olive Video Editor.

+

Oak Video Editor — вільний нелінійний відеоредактор, задуманий як повноцінна заміна закритим комерційним продуктам. Це форк спільноти Olive Video Editor.

+

Oak Video Editor adalah aplikasi edit video bersifat non-linier yang bebas dan gratis, bertujuan untuk memberikan alternatif yang lengkap untuk aplikasi edit video profesional. Ini adalah fork komunitas dari Olive Video Editor.

+

Oak Video Editor est un éditeur vidéo non linéaire libre visant à fournir une alternative complète aux logiciels de montage vidéo professionnels haut de gamme. Il s'agit d'un fork communautaire d'Olive Video Editor.

+ https://github.com/olive-editor/olive + https://github.com/olive-editor/olive/issues + + https://olivevideoeditor.org/img/screenshot.1600.jpg + + + + + +
diff --git a/app/packaging/linux/org.olivevideoeditor.Olive.desktop b/app/packaging/linux/org.oakvideoeditor.Oak.desktop similarity index 89% rename from app/packaging/linux/org.olivevideoeditor.Olive.desktop rename to app/packaging/linux/org.oakvideoeditor.Oak.desktop index bad06f5c6..22d7fbff1 100644 --- a/app/packaging/linux/org.olivevideoeditor.Olive.desktop +++ b/app/packaging/linux/org.oakvideoeditor.Oak.desktop @@ -1,11 +1,11 @@ [Desktop Entry] -Name=Olive +Name=Oak Video Editor Comment=Professional open-source non-linear video editor Comment[fr]=Éditeur vidéo non-linéaire open-source professionnel Comment[it]=Programma di montaggio video professionale open-source Comment[id]=Aplikasi edit video yang non-linier, profesional serta sumbernya terbuka. Exec=olive-editor %f -Icon=org.olivevideoeditor.Olive +Icon=org.oakvideoeditor.Oak Terminal=false Type=Application Categories=AudioVideo;Recorder; diff --git a/app/packaging/linux/org.oakvideoeditor.Oak.xml b/app/packaging/linux/org.oakvideoeditor.Oak.xml new file mode 100644 index 000000000..a85eebc89 --- /dev/null +++ b/app/packaging/linux/org.oakvideoeditor.Oak.xml @@ -0,0 +1,25 @@ + + + + + + Oak project + + + diff --git a/app/packaging/linux/org.olivevideoeditor.Olive.appdata.xml.in b/app/packaging/linux/org.olivevideoeditor.Olive.appdata.xml.in deleted file mode 100644 index 0d7a2d8e8..000000000 --- a/app/packaging/linux/org.olivevideoeditor.Olive.appdata.xml.in +++ /dev/null @@ -1,38 +0,0 @@ - - - org.olivevideoeditor.Olive - Olive - CC0-1.0 - GPL-3.0 - Olive Team - Non-linear video editor - Nicht-lineares Videoschnittprogramm - Editor de vídeo não-linear - Editor de video no lineal - Editor video non lineare - Нелинейный видеоредактор - Нелінійний відеоредактор - Нелінійний відеоредактор - Aplikasi edit video non-linier - Éditeur vidéo non-linéaire -

Olive is a free non-linear video editor aiming to provide a fully-featured alternative to high-end professional video editing software.

- Olive ist ein freies nicht-lineares Videoschnittprogramm, welches eine vollwertige Alternative zu High-End Videoschnittprogrammen darstellen soll. -

Olive é um editor de vídeo não-linear com o objetivo de fornecer uma alternativa completa para softwares profissionais de edição de vídeo.

-

Olive es un editor de video no lineal libre que apunta a brindar una alternativa completa al software de edición de video profesional.

-

Olive è un programma di montaggio video che mira a fornire una alternativa di alta qualità ai software professionali

-

Olive — свободный нелинейный видеоредактор, задуманный как полноценная замена закрытым коммерческим продуктам.

-

Olive — вільний нелінійний відеоредактор, задуманий як повноцінна заміна закритим комерційним продуктам.

-

Olive — вільний нелінійний відеоредактор, задуманий як повноцінна заміна закритим комерційним продуктам.

-

Olive adalah aplikasi edit video bersifat non-linier yang bebas dan gratis, bertujuan untuk memberikan alternatif yang lengkap untuk aplikasi edit video profesional.

-

Olive est un éditeur vidéo non linéaire libre visant à fournir une alternative complète aux logiciels de montage vidéo professionnels haut de gamme.

- https://www.olivevideoeditor.org - https://www.patreon.com/olivevideoeditor - https://github.com/olive-editor/olive/issues - - https://olivevideoeditor.org/img/screenshot.1600.jpg - - - - - -
diff --git a/app/packaging/linux/org.olivevideoeditor.Olive.xml b/app/packaging/linux/org.olivevideoeditor.Olive.xml deleted file mode 100644 index df8e8e517..000000000 --- a/app/packaging/linux/org.olivevideoeditor.Olive.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Olive project - - - diff --git a/app/packaging/windows/nsis/olive.nsi b/app/packaging/windows/nsis/olive.nsi index 11e67f3c7..cd75b21bb 100644 --- a/app/packaging/windows/nsis/olive.nsi +++ b/app/packaging/windows/nsis/olive.nsi @@ -3,7 +3,7 @@ !define MUI_ICON "install icon.ico" !define MUI_UNICON "uninstall icon.ico" -!define APP_NAME "Olive" +!define APP_NAME "Oak Video Editor" !define APP_TARGET "olive-editor" !define MUI_FINISHPAGE_RUN "$INSTDIR\olive-editor.exe" @@ -29,12 +29,12 @@ InstallDir "$PROGRAMFILES32\${APP_NAME}" !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_RUN_TEXT "Run ${APP_NAME}" -!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchOlive" +!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchOak" !insertmacro MUI_PAGE_FINISH !insertmacro MUI_LANGUAGE "English" -Section "Olive" +Section "Oak Video Editor" SectionIn RO SetOutPath $INSTDIR File /r olive-editor\* @@ -56,12 +56,12 @@ Section "Create Start Menu shortcut" CreateShortCut "$SMPROGRAMS\${APP_NAME}\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe" SectionEnd -Section "Associate *.ove files with Olive" - WriteRegStr HKCR ".ove" "" "OliveEditor.OVEFile" +Section "Associate *.ove files with Oak Video Editor" + WriteRegStr HKCR ".ove" "" "OakEditor.OVEFile" WriteRegStr HKCR ".ove" "Content Type" "application/vnd.olive-project" - WriteRegStr HKCR "OliveEditor.OVEFile" "" "Olive project file" - WriteRegStr HKCR "OliveEditor.OVEFile\DefaultIcon" "" "$INSTDIR\olive-editor.exe,1" - WriteRegStr HKCR "OliveEditor.OVEFile\shell\open\command" "" "$\"$INSTDIR\olive-editor.exe$\" $\"%1$\"" + WriteRegStr HKCR "OakEditor.OVEFile" "" "Oak project file" + WriteRegStr HKCR "OakEditor.OVEFile\DefaultIcon" "" "$INSTDIR\olive-editor.exe,1" + WriteRegStr HKCR "OakEditor.OVEFile\shell\open\command" "" "$\"$INSTDIR\olive-editor.exe$\" $\"%1$\"" System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' SectionEnd @@ -76,12 +76,12 @@ Section "uninstall" rmdir /r "$SMPROGRAMS\${APP_NAME}" DeleteRegKey HKCR ".ove" - DeleteRegKey HKCR "OliveEditor.OVEFile" - DeleteRegKey HKCR "OliveEditor.OVEFile\DefaultIcon" "" - DeleteRegKey HKCR "OliveEditor.OVEFile\shell\open\command" "" + DeleteRegKey HKCR "OakEditor.OVEFile" + DeleteRegKey HKCR "OakEditor.OVEFile\DefaultIcon" "" + DeleteRegKey HKCR "OakEditor.OVEFile\shell\open\command" "" System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' SectionEnd -Function LaunchOlive +Function LaunchOak ShellExecAsUser::ShellExecAsUser "" "$INSTDIR\${APP_TARGET}.exe" FunctionEnd diff --git a/app/packaging/windows/version.h b/app/packaging/windows/version.h index 00f6a6c90..55206e9ed 100644 --- a/app/packaging/windows/version.h +++ b/app/packaging/windows/version.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef VERSION_H #define VERSION_H @@ -7,15 +25,15 @@ #define VER_PRODUCTVERSION 1, 0, 0, 0 #define VER_PRODUCTVERSION_STR "1.0\0" -#define VER_COMPANYNAME_STR "Olive Team" -#define VER_FILEDESCRIPTION_STR "Olive" -#define VER_INTERNALNAME_STR "Olive" -#define VER_LEGALCOPYRIGHT_STR "Copyright © 2018 Olive Team" +#define VER_COMPANYNAME_STR "Oak Video Editor Team" +#define VER_FILEDESCRIPTION_STR "Oak Video Editor" +#define VER_INTERNALNAME_STR "Oak Video Editor" +#define VER_LEGALCOPYRIGHT_STR "Copyright © 2018 Oak Video Editor Team" #define VER_LEGALTRADEMARKS1_STR "All Rights Reserved" #define VER_LEGALTRADEMARKS2_STR VER_LEGALTRADEMARKS1_STR -#define VER_ORIGINALFILENAME_STR "Olive.exe" -#define VER_PRODUCTNAME_STR "Olive" +#define VER_ORIGINALFILENAME_STR "OakVideoEditor.exe" +#define VER_PRODUCTNAME_STR "Oak Video Editor" -#define VER_COMPANYDOMAIN_STR "www.olivevideoeditor.org" +#define VER_COMPANYDOMAIN_STR "www.oakvideoeditor.org" #endif // VERSION_H diff --git a/app/panel/audiomonitor/audiomonitor.cpp b/app/panel/audiomonitor/audiomonitor.cpp index 0061a2fbe..e15e2d789 100644 --- a/app/panel/audiomonitor/audiomonitor.cpp +++ b/app/panel/audiomonitor/audiomonitor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/audiomonitor/audiomonitor.h b/app/panel/audiomonitor/audiomonitor.h index aa8f5ae0b..dad5dd03c 100644 --- a/app/panel/audiomonitor/audiomonitor.h +++ b/app/panel/audiomonitor/audiomonitor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/curve/curve.cpp b/app/panel/curve/curve.cpp index 6f8e072d9..29f9769ed 100644 --- a/app/panel/curve/curve.cpp +++ b/app/panel/curve/curve.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/curve/curve.h b/app/panel/curve/curve.h index 9d2049898..35b868845 100644 --- a/app/panel/curve/curve.h +++ b/app/panel/curve/curve.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/footageviewer/footageviewer.cpp b/app/panel/footageviewer/footageviewer.cpp index 52a932fea..70d7d709a 100644 --- a/app/panel/footageviewer/footageviewer.cpp +++ b/app/panel/footageviewer/footageviewer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/footageviewer/footageviewer.h b/app/panel/footageviewer/footageviewer.h index ab3b4394c..6a1cc5b87 100644 --- a/app/panel/footageviewer/footageviewer.h +++ b/app/panel/footageviewer/footageviewer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/history/historypanel.cpp b/app/panel/history/historypanel.cpp index bdeb981b3..0c9796832 100644 --- a/app/panel/history/historypanel.cpp +++ b/app/panel/history/historypanel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/history/historypanel.h b/app/panel/history/historypanel.h index a590afebc..2322cbf50 100644 --- a/app/panel/history/historypanel.h +++ b/app/panel/history/historypanel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/multicam/multicampanel.cpp b/app/panel/multicam/multicampanel.cpp index be4726956..b4ed442ea 100644 --- a/app/panel/multicam/multicampanel.cpp +++ b/app/panel/multicam/multicampanel.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "multicampanel.h" namespace olive diff --git a/app/panel/multicam/multicampanel.h b/app/panel/multicam/multicampanel.h index b1a952351..81f2e5608 100644 --- a/app/panel/multicam/multicampanel.h +++ b/app/panel/multicam/multicampanel.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef MULTICAMPANEL_H #define MULTICAMPANEL_H diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index 9eee8abb1..734a710b8 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/node/node.h b/app/panel/node/node.h index 32c143926..6f5d14477 100644 --- a/app/panel/node/node.h +++ b/app/panel/node/node.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/panel.cpp b/app/panel/panel.cpp index b1262624f..441b9a578 100644 --- a/app/panel/panel.cpp +++ b/app/panel/panel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -27,23 +28,24 @@ #include #include #include - #include "panel/panelmanager.h" +#include + namespace olive { -#define super KDDockWidgets::DockWidget +#define super KDDockWidgets::QtWidgets::DockWidget PanelWidget::PanelWidget(const QString &object_name) : super(object_name) , border_visible_(false) , signal_instead_of_close_(false) { - setFocusPolicy(Qt::ClickFocus); + View::setFocusPolicy(Qt::ClickFocus); connect(this, &PanelWidget::shown, this, - static_cast(&PanelWidget::setFocus)); + reinterpret_cast(&PanelWidget::setFocus)); PanelManager::instance()->RegisterPanel(this); } @@ -125,6 +127,15 @@ void PanelWidget::changeEvent(QEvent *e) if (e->type() == QEvent::LanguageChange) { Retranslate(); } + + if (e->type() == QEvent::WindowStateChange) { + if (isVisible() && !isMinimized()) { + emit shown(Qt::OtherFocusReason); + } + else { + emit hidden(); + } + } super::changeEvent(e); } diff --git a/app/panel/panel.h b/app/panel/panel.h index 56777fd11..9add206bd 100644 --- a/app/panel/panel.h +++ b/app/panel/panel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -21,18 +22,23 @@ #ifndef PANEL_WIDGET_H #define PANEL_WIDGET_H +#include "KDDockWidgets/src/core/Window_p.h" +#include "KDDockWidgets/src/qtwidgets/views/TabBar.h" + #include #include #include "common/define.h" +#include + namespace olive { /** * @brief A widget that is always dockable within the MainWindow. */ -class PanelWidget : public KDDockWidgets::DockWidget { +class PanelWidget : public KDDockWidgets::QtWidgets::DockWidget { Q_OBJECT public: /** @@ -279,7 +285,8 @@ public: signals: void CloseRequested(); - + void shown(Qt::FocusReason reason); + void hidden(); protected: /** * @brief paintEvent @@ -323,7 +330,7 @@ protected slots: * String to set the subtitle to */ void SetSubtitle(const QString &t); - +protected slots: private: /** * @brief Internal function that sets the QDockWidget's window title whenever the title/subtitle change. @@ -339,6 +346,10 @@ private: bool border_visible_; bool signal_instead_of_close_; + + QMetaObject::Connection m_tabBarConnection; + QMetaObject::Connection m_windowConnection; + bool m_lastVisibleState = false; }; } diff --git a/app/panel/panelmanager.cpp b/app/panel/panelmanager.cpp index e70ad05b2..23b88f0bb 100644 --- a/app/panel/panelmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/panelmanager.h b/app/panel/panelmanager.h index 39acb4cc3..a0bba59b6 100644 --- a/app/panel/panelmanager.h +++ b/app/panel/panelmanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index d19f185ae..107a8368f 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/param/param.h b/app/panel/param/param.h index 61a8f8551..1c2e900ea 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/pixelsampler/pixelsamplerpanel.cpp b/app/panel/pixelsampler/pixelsamplerpanel.cpp index 8cf4ed882..465a94ca6 100644 --- a/app/panel/pixelsampler/pixelsamplerpanel.cpp +++ b/app/panel/pixelsampler/pixelsamplerpanel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/pixelsampler/pixelsamplerpanel.h b/app/panel/pixelsampler/pixelsamplerpanel.h index 35de62478..6cf24fc16 100644 --- a/app/panel/pixelsampler/pixelsamplerpanel.h +++ b/app/panel/pixelsampler/pixelsamplerpanel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/project/footagemanagementpanel.h b/app/panel/project/footagemanagementpanel.h index 542eda339..510b82baa 100644 --- a/app/panel/project/footagemanagementpanel.h +++ b/app/panel/project/footagemanagementpanel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/project/project.cpp b/app/panel/project/project.cpp index f2f011e10..9886f8572 100644 --- a/app/panel/project/project.cpp +++ b/app/panel/project/project.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -180,7 +181,7 @@ void ProjectPanel::ItemDoubleClickSlot(Node *item) PanelManager::instance()->MostRecentlyFocused(); panel->ConnectViewerNode(static_cast(item)); panel->raise(); - panel->setFocus(); + panel->setFocus(Qt::FocusReason::MouseFocusReason); } else if (dynamic_cast(item)) { // Open this sequence in the Timeline Core::instance()->main_window()->OpenSequence( diff --git a/app/panel/project/project.h b/app/panel/project/project.h index 5600a166a..185185185 100644 --- a/app/panel/project/project.h +++ b/app/panel/project/project.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/scope/scope.cpp b/app/panel/scope/scope.cpp index 1e7357fa2..a45e1f8f0 100644 --- a/app/panel/scope/scope.cpp +++ b/app/panel/scope/scope.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/scope/scope.h b/app/panel/scope/scope.h index 6e7d6729a..edcd07d2a 100644 --- a/app/panel/scope/scope.h +++ b/app/panel/scope/scope.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/sequenceviewer/sequenceviewer.cpp b/app/panel/sequenceviewer/sequenceviewer.cpp index bc6f0a78b..372efbcbd 100644 --- a/app/panel/sequenceviewer/sequenceviewer.cpp +++ b/app/panel/sequenceviewer/sequenceviewer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/sequenceviewer/sequenceviewer.h b/app/panel/sequenceviewer/sequenceviewer.h index c622d0802..352a8c5c1 100644 --- a/app/panel/sequenceviewer/sequenceviewer.h +++ b/app/panel/sequenceviewer/sequenceviewer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/table/table.cpp b/app/panel/table/table.cpp index 97e2cdc0a..cfb072d03 100644 --- a/app/panel/table/table.cpp +++ b/app/panel/table/table.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/table/table.h b/app/panel/table/table.h index 81d1b732a..5d70bf8dd 100644 --- a/app/panel/table/table.h +++ b/app/panel/table/table.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/taskmanager/taskmanager.cpp b/app/panel/taskmanager/taskmanager.cpp index 07a64ca22..f81a17d01 100644 --- a/app/panel/taskmanager/taskmanager.cpp +++ b/app/panel/taskmanager/taskmanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/taskmanager/taskmanager.h b/app/panel/taskmanager/taskmanager.h index b27666ad0..3cc033850 100644 --- a/app/panel/taskmanager/taskmanager.h +++ b/app/panel/taskmanager/taskmanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/timebased/timebased.cpp b/app/panel/timebased/timebased.cpp index 6e62e1912..429f60c39 100644 --- a/app/panel/timebased/timebased.cpp +++ b/app/panel/timebased/timebased.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/timebased/timebased.h b/app/panel/timebased/timebased.h index 64f77ed4b..36871a22e 100644 --- a/app/panel/timebased/timebased.h +++ b/app/panel/timebased/timebased.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/timeline/timeline.cpp b/app/panel/timeline/timeline.cpp index 1931ec58a..8d4a72240 100644 --- a/app/panel/timeline/timeline.cpp +++ b/app/panel/timeline/timeline.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/timeline/timeline.h b/app/panel/timeline/timeline.h index a4ee3e086..75383a0fc 100644 --- a/app/panel/timeline/timeline.h +++ b/app/panel/timeline/timeline.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/tool/tool.cpp b/app/panel/tool/tool.cpp index 1998eb38c..d5592a898 100644 --- a/app/panel/tool/tool.cpp +++ b/app/panel/tool/tool.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/tool/tool.h b/app/panel/tool/tool.h index bf53458e8..d2c18c669 100644 --- a/app/panel/tool/tool.h +++ b/app/panel/tool/tool.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/viewer/viewer.cpp b/app/panel/viewer/viewer.cpp index 186bb5a3d..26654f921 100644 --- a/app/panel/viewer/viewer.cpp +++ b/app/panel/viewer/viewer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/viewer/viewer.h b/app/panel/viewer/viewer.h index 011c47e70..9a71f6a2a 100644 --- a/app/panel/viewer/viewer.h +++ b/app/panel/viewer/viewer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index 58651e68a..85c0e6973 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index 4e6780e7c..24d5ab4df 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/pluginSupport/CMakeLists.txt b/app/pluginSupport/CMakeLists.txt new file mode 100644 index 000000000..ce057b228 --- /dev/null +++ b/app/pluginSupport/CMakeLists.txt @@ -0,0 +1,12 @@ +target_sources(libolive-editor PRIVATE + OliveHost.h + OliveHost.cpp + OlivePluginInstance.h + OlivePluginInstance.cpp + OliveClip.cpp + OliveClip.h + paraminstance.cpp + paraminstance.h + image.cpp + image.h +) \ No newline at end of file diff --git a/app/pluginSupport/OliveClip.cpp b/app/pluginSupport/OliveClip.cpp new file mode 100644 index 000000000..a1a464d7b --- /dev/null +++ b/app/pluginSupport/OliveClip.cpp @@ -0,0 +1,654 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// +// Created by mikesolar on 25-10-1. +// + +#include "OliveClip.h" + +#include "common/Current.h" +#include "common/ffmpegutils.h" +#include "ofxCore.h" +#include "ofxhClip.h" +#include "pluginSupport/image.h" +#include +#include +#include +#include +#ifdef OFX_SUPPORTS_OPENGLRENDER +#include +#endif +#include "common/ffmpegutils.h" +#include "render/renderer.h" +extern "C" { +#include +#include +} +namespace { +const std::string kBitDepthNoneStr(kOfxBitDepthNone); +const std::string kBitDepthByteStr(kOfxBitDepthByte); +const std::string kBitDepthShortStr(kOfxBitDepthShort); +const std::string kBitDepthHalfStr(kOfxBitDepthHalf); +const std::string kBitDepthFloatStr(kOfxBitDepthFloat); +const std::string kImageComponentNoneStr(kOfxImageComponentNone); +const std::string kImageComponentAlphaStr(kOfxImageComponentAlpha); +const std::string kImageComponentRGBStr(kOfxImageComponentRGB); +const std::string kImageComponentRGBAStr(kOfxImageComponentRGBA); +const std::string kImagePremultStr(kOfxImagePreMultiplied); +const std::string kImageUnPremultStr(kOfxImageUnPreMultiplied); +const std::string kImageFieldNoneStr(kOfxImageFieldNone); +const std::string kImageFieldUpperStr(kOfxImageFieldUpper); +const std::string kImageFieldLowerStr(kOfxImageFieldLower); + +static int BytesToPixels(int byte_linesize, const olive::VideoParams ¶ms) +{ + const int bytes_per_pixel = + params.channel_count() * params.format().byte_count(); + if (bytes_per_pixel <= 0) { + return 0; + } + return byte_linesize / bytes_per_pixel; +} + +static int PackedFloatChannels(AVPixelFormat fmt) +{ + switch (fmt) { + case AV_PIX_FMT_GRAYF32LE: + case AV_PIX_FMT_GRAYF32BE: + return 1; + case AV_PIX_FMT_RGBF32LE: + case AV_PIX_FMT_RGBF32BE: + return 3; + case AV_PIX_FMT_RGBAF32LE: + case AV_PIX_FMT_RGBAF32BE: + return 4; + default: + return 0; + } +} + +static bool PackedDstInfo(AVPixelFormat fmt, int *channels, + int *bytes_per_component) +{ + switch (fmt) { + case AV_PIX_FMT_GRAY8: + *channels = 1; + *bytes_per_component = 1; + return true; + case AV_PIX_FMT_RGB24: + *channels = 3; + *bytes_per_component = 1; + return true; + case AV_PIX_FMT_RGBA: + *channels = 4; + *bytes_per_component = 1; + return true; + case AV_PIX_FMT_GRAY16LE: + *channels = 1; + *bytes_per_component = 2; + return true; + case AV_PIX_FMT_RGB48LE: + *channels = 3; + *bytes_per_component = 2; + return true; + case AV_PIX_FMT_RGBA64LE: + *channels = 4; + *bytes_per_component = 2; + return true; + default: + return false; + } +} + +static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture, + const olive::VideoParams ¶ms) +{ + if (!texture || texture->IsDummy() || !texture->renderer()) { + return nullptr; + } + + AVPixelFormat pix_fmt = + olive::FFmpegUtils::GetFFmpegPixelFormat(params.format(), + params.channel_count()); + if (pix_fmt == AV_PIX_FMT_NONE) { + return nullptr; + } + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) { + return nullptr; + } + + if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) { + olive::AVFramePtr frame = olive::CreateAVFramePtr(); + frame->format = pix_fmt; + frame->width = params.width(); + frame->height = params.height(); + if (av_frame_get_buffer(frame.get(), 0) < 0) { + return nullptr; + } + const int linesize_pixels = BytesToPixels(frame->linesize[0], params); + texture->renderer()->DownloadFromTexture(texture->id(), params, + frame->data[0], + linesize_pixels); + return frame; + } + + olive::VideoParams rgba_params( + params.width(), params.height(), olive::core::PixelFormat::U8, 4, + params.pixel_aspect_ratio(), params.interlacing(), params.divider()); + + olive::AVFramePtr rgba_frame = olive::CreateAVFramePtr(); + rgba_frame->format = AV_PIX_FMT_RGBA; + rgba_frame->width = params.width(); + rgba_frame->height = params.height(); + if (av_frame_get_buffer(rgba_frame.get(), 0) < 0) { + return nullptr; + } + + const int linesize_pixels = + BytesToPixels(rgba_frame->linesize[0], rgba_params); + texture->renderer()->DownloadFromTexture(texture->id(), rgba_params, + rgba_frame->data[0], + linesize_pixels); + + olive::AVFramePtr dst = olive::CreateAVFramePtr(); + dst->format = pix_fmt; + dst->width = params.width(); + dst->height = params.height(); + if (av_frame_get_buffer(dst.get(), 0) < 0) { + return rgba_frame; + } + + SwsContext *sws_ctx = sws_getContext( + rgba_frame->width, rgba_frame->height, + static_cast(rgba_frame->format), + dst->width, dst->height, pix_fmt, SWS_POINT, + nullptr, nullptr, nullptr); + if (!sws_ctx) { + return rgba_frame; + } + + sws_scale(sws_ctx, rgba_frame->data, rgba_frame->linesize, 0, + rgba_frame->height, dst->data, dst->linesize); + sws_freeContext(sws_ctx); + return dst; +} + +static olive::AVFramePtr ConvertPackedFloatFrame(olive::AVFramePtr src, + AVPixelFormat dst_fmt) +{ + if (!src || !src->data[0]) { + return nullptr; + } + const int src_channels = + PackedFloatChannels(static_cast(src->format)); + if (src_channels == 0) { + return nullptr; + } + + int dst_channels = 0; + int bytes_per_component = 0; + if (!PackedDstInfo(dst_fmt, &dst_channels, &bytes_per_component)) { + return nullptr; + } + + olive::AVFramePtr dst = olive::CreateAVFramePtr(); + dst->format = dst_fmt; + dst->width = src->width; + dst->height = src->height; + if (av_frame_get_buffer(dst.get(), 0) < 0) { + return nullptr; + } + + auto clamp01 = [](float v) -> float { + return std::clamp(v, 0.0f, 1.0f); + }; + + for (int y = 0; y < src->height; ++y) { + const float *src_row = reinterpret_cast( + src->data[0] + y * src->linesize[0]); + uint8_t *dst_row = dst->data[0] + y * dst->linesize[0]; + + if (bytes_per_component == 2) { + auto *dst_row_u16 = reinterpret_cast(dst_row); + for (int x = 0; x < src->width; ++x) { + const float *pix = src_row + x * src_channels; + float r = pix[0]; + float g = (src_channels > 1) ? pix[1] : r; + float b = (src_channels > 2) ? pix[2] : r; + float a = (src_channels > 3) ? pix[3] : 1.0f; + if (dst_channels == 1) { + float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b; + dst_row_u16[x] = static_cast( + std::lround(clamp01(luma) * 65535.0f)); + continue; + } + dst_row_u16[x * dst_channels + 0] = + static_cast( + std::lround(clamp01(r) * 65535.0f)); + dst_row_u16[x * dst_channels + 1] = + static_cast( + std::lround(clamp01(g) * 65535.0f)); + dst_row_u16[x * dst_channels + 2] = + static_cast( + std::lround(clamp01(b) * 65535.0f)); + if (dst_channels == 4) { + dst_row_u16[x * dst_channels + 3] = + static_cast( + std::lround(clamp01(a) * 65535.0f)); + } + } + } else { + for (int x = 0; x < src->width; ++x) { + const float *pix = src_row + x * src_channels; + float r = pix[0]; + float g = (src_channels > 1) ? pix[1] : r; + float b = (src_channels > 2) ? pix[2] : r; + float a = (src_channels > 3) ? pix[3] : 1.0f; + if (dst_channels == 1) { + float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b; + dst_row[x] = static_cast( + std::lround(clamp01(luma) * 255.0f)); + continue; + } + dst_row[x * dst_channels + 0] = + static_cast( + std::lround(clamp01(r) * 255.0f)); + dst_row[x * dst_channels + 1] = + static_cast( + std::lround(clamp01(g) * 255.0f)); + dst_row[x * dst_channels + 2] = + static_cast( + std::lround(clamp01(b) * 255.0f)); + if (dst_channels == 4) { + dst_row[x * dst_channels + 3] = + static_cast( + std::lround(clamp01(a) * 255.0f)); + } + } + } + } + + return dst; +} +} + +const std::string &olive::plugin::OliveClipInstance::getUnmappedBitDepth() const +{ + switch (params_.format()) { + case PixelFormat::INVALID: + return kBitDepthNoneStr; + case PixelFormat::U8: + return kBitDepthByteStr; + case PixelFormat::U16: + return kBitDepthShortStr; + case PixelFormat::F16: + return kBitDepthHalfStr; + case PixelFormat::F32: + return kBitDepthFloatStr; + default: + return kBitDepthNoneStr; + } +} +const std::string & +olive::plugin::OliveClipInstance::getUnmappedComponents() const +{ + switch (params_.channel_count()) { + case 1: + return kImageComponentAlphaStr; + case 3: + return kImageComponentRGBStr; + case 4: + return kImageComponentRGBAStr; + default: + return kImageComponentNoneStr; + } +} +const std::string &olive::plugin::OliveClipInstance::getPremult() const +{ + if (params_.premultiplied_alpha()) { + return kImagePremultStr; + } else { + return kImageUnPremultStr; + } +} +double olive::plugin::OliveClipInstance::getAspectRatio() const +{ + return params_.pixel_aspect_ratio().toDouble(); +} +double olive::plugin::OliveClipInstance::getFrameRate() const +{ + return params_.frame_rate().toDouble(); +} +void olive::plugin::OliveClipInstance::getFrameRange(double &startFrame, + double &endFrame) const +{ + startFrame = params_.frame_rate().toDouble() * params_.start_time(); + endFrame = + startFrame + params_.frame_rate().toDouble() * params_.duration(); +} +const std::string &olive::plugin::OliveClipInstance::getFieldOrder() const +{ + switch (params_.interlacing()) { + case VideoParams::kInterlaceNone: + return kImageFieldNoneStr; + case VideoParams::kInterlacedTopFirst: + return kImageFieldUpperStr; + case VideoParams::kInterlacedBottomFirst: + return kImageFieldLowerStr; + } + return kImageFieldNoneStr; +} +bool olive::plugin::OliveClipInstance::getConnected() const +{ + if (name_ == kOfxImageEffectOutputClipName) { +#ifdef OFX_SUPPORTS_OPENGLRENDER + if (!output_textures_.isEmpty()) { + return true; + } +#endif + if(images_.empty()) + return false; + return true; + } +#ifdef OFX_SUPPORTS_OPENGLRENDER + if (!input_textures_.isEmpty()) { + return true; + } +#endif + if(images_.empty()) + return false; + return true; +} +double olive::plugin::OliveClipInstance::getUnmappedFrameRate() const +{ + return getFrameRate(); +} +void olive::plugin::OliveClipInstance::getUnmappedFrameRange( + double &startFrame, double &endFrame) const +{ + getFrameRange(startFrame, endFrame); +} +bool olive::plugin::OliveClipInstance::getContinuousSamples() const +{ + return false; +} +OFX::Host::ImageEffect::Image * +olive::plugin::OliveClipInstance::getImage(OfxTime time, + const OfxRectD *optionalBounds) +{ + OfxRectD rod_d = getRegionOfDefinition(time); + OfxRectI rod = { static_cast(std::floor(rod_d.x1)), + static_cast(std::floor(rod_d.y1)), + static_cast(std::ceil(rod_d.x2)), + static_cast(std::ceil(rod_d.y2)) }; + (void)optionalBounds; + // Always return full-frame images to keep input data consistent. + OfxRectI bounds = rod; + + if (name_ == "Output") { + if (!images_.contains(time)) { + // make a new ref counted image + images_.insert(time, new Image(*const_cast(this), + params_, bounds, rod, true)); + } + + // add another reference to the member image for this fetch + // as we have a ref count of 1 due to construction, this will + // cause the output image never to delete by the plugin + // when it releases the image + images_[time]->addReference(); + + images_[time]->EnsureAllocatedFromParams(params_, bounds, rod, true); + + // return it + return images_[time]; + } else { + if (images_.contains(time)) { + Image* image = images_.value(time); + image->EnsureAllocatedFromParams(params_, bounds, rod, false); + image->addReference(); + return image; + } + + // Fetch on demand for the input clip. + // It does get deleted after the plugin is done with it as we + // have not incremented the auto ref + // + // You should do somewhat more sophisticated image management + // than this. + Image *image = new Image(*this, params_, bounds, rod, true); + return image; + } +} + +OFX::Host::ImageEffect::Image* +olive::plugin::OliveClipInstance::getOutputImage(OfxTime time) +{ + if (images_.contains(time)) { + return images_.value(time); + } + + OfxRectD rod_d = getRegionOfDefinition(time); + OfxRectI rod = { static_cast(std::floor(rod_d.x1)), + static_cast(std::floor(rod_d.y1)), + static_cast(std::ceil(rod_d.x2)), + static_cast(std::ceil(rod_d.y2)) }; + OfxRectI bounds = rod; + + auto image = new Image(*this, params_, bounds, rod, true); + images_.insert(time, image); + return image; +} +OfxRectD +olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const +{ + if (regionOfDefinitions_.contains(time)) { + return regionOfDefinitions_.value(time); + } + OfxRectD regionOfDefinition; + regionOfDefinition.x1 = regionOfDefinition.y1 = 0; + regionOfDefinition.x2 = params_.width(); + regionOfDefinition.y2 = params_.height(); + return regionOfDefinition; +} +void olive::plugin::OliveClipInstance::setRegionOfDefinition( + OfxRectD regionOfDefinition, OfxTime time) +{ + regionOfDefinitions_[time] = regionOfDefinition; +} + +void olive::plugin::OliveClipInstance::setDefaultRegionOfDefinition( + OfxRectD regionOfDefinition) +{ + defaultRegionOfDefinitions_ = regionOfDefinition; +} +void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTime time){ + if (!texture) { + return; + } + VideoParams incoming = texture->params(); + + this->params_ = incoming; +#ifdef OFX_SUPPORTS_OPENGLRENDER + input_textures_.insert(time, texture); +#endif + + AVFramePtr frame = texture->frame(); + if (!frame || !frame->data[0]) { + frame = ReadbackTextureToFrame(texture, params_); + } + AVPixelFormat expected_fmt = + FFmpegUtils::GetFFmpegPixelFormat(params_.format(), + params_.channel_count()); + if (expected_fmt == AV_PIX_FMT_NONE) { + return; + } + OfxRectI bounds = { 0, 0, params_.width(), params_.height() }; + OfxRectD rod_d = getRegionOfDefinition(time); + OfxRectI regionOfDefinition = { static_cast(std::floor(rod_d.x1)), + static_cast(std::floor(rod_d.y1)), + static_cast(std::ceil(rod_d.x2)), + static_cast(std::ceil(rod_d.y2)) }; + + Image* image; + if (images_.contains(time)) { + image = images_.value(time); + image->EnsureAllocatedFromParams(params_, bounds, regionOfDefinition, + false); + } else { + image = new Image(*this, params_, bounds, + regionOfDefinition, false); + images_.insert(time, image); + } + + uint8_t *dst = (uint8_t*)image->data(); + if (!dst) { + return; + } + + if (!frame || !frame->data[0]) { + std::memset(dst, 0, image->row_bytes() * image->height()); + return; + } + + AVFramePtr src_frame = frame; + if (frame->format != expected_fmt || + frame->width != params_.width() || + frame->height != params_.height()) { + if (PackedFloatChannels(static_cast(frame->format)) > 0) { + AVFramePtr converted = + ConvertPackedFloatFrame(frame, expected_fmt); + if (converted) { + src_frame = converted; + goto copy_pixels; + } + } + AVFramePtr converted = CreateAVFramePtr(); + converted->format = expected_fmt; + converted->width = params_.width(); + converted->height = params_.height(); + if (av_frame_get_buffer(converted.get(), 0) < 0) { + return; + } + + SwsContext *sws_ctx = sws_getContext( + frame->width, frame->height, + static_cast(frame->format), + converted->width, converted->height, + static_cast(converted->format), + SWS_POINT, nullptr, nullptr, nullptr); + if (!sws_ctx) { + return; + } + + sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, + converted->data, converted->linesize); + sws_freeContext(sws_ctx); + + src_frame = converted; + } + +copy_pixels: + int bytes_per_component = params_.format().byte_count(); + int bytes_per_row = params_.width() * params_.channel_count() * + bytes_per_component; + int src_row_bytes = src_frame->linesize[0]; + int dst_row_bytes = image->row_bytes(); + int copy_bytes = std::min(bytes_per_row, + std::min(src_row_bytes, dst_row_bytes)); + int copy_height = std::min(image->height(), src_frame->height); + + const uint8_t *src = src_frame->data[0]; + for (int y = 0; y < copy_height; ++y) { + std::memcpy(dst + y * dst_row_bytes, src + y * src_row_bytes, + copy_bytes); + } + + +} + +void olive::plugin::OliveClipInstance::setOutputTexture(TexturePtr texture, + OfxTime time) +{ +#ifdef OFX_SUPPORTS_OPENGLRENDER + if (!texture) { + return; + } + output_textures_.insert(time, texture); +#else + (void)texture; + (void)time; +#endif +} + +#ifdef OFX_SUPPORTS_OPENGLRENDER +OFX::Host::ImageEffect::Texture * +olive::plugin::OliveClipInstance::loadTexture(OfxTime time, const char *format, + const OfxRectD *optionalBounds) +{ + (void)format; + + TexturePtr gl_texture = nullptr; + if (isOutput()) { + gl_texture = output_textures_.value(time, nullptr); + } else { + TexturePtr input = input_textures_.value(time); + gl_texture = input ? input : nullptr; + } + + if (!gl_texture || gl_texture->IsDummy() || !gl_texture->id().isValid()) { + return nullptr; + } + + OfxRectD rod_d = getRegionOfDefinition(time); + OfxRectI rod = { static_cast(std::floor(rod_d.x1)), + static_cast(std::floor(rod_d.y1)), + static_cast(std::ceil(rod_d.x2)), + static_cast(std::ceil(rod_d.y2)) }; + OfxRectI bounds = rod; + if (optionalBounds) { + bounds.x1 = static_cast(std::floor(optionalBounds->x1)); + bounds.y1 = static_cast(std::floor(optionalBounds->y1)); + bounds.x2 = static_cast(std::ceil(optionalBounds->x2)); + bounds.y2 = static_cast(std::ceil(optionalBounds->y2)); + } + bounds.x1 = std::max(bounds.x1, rod.x1); + bounds.y1 = std::max(bounds.y1, rod.y1); + bounds.x2 = std::min(bounds.x2, rod.x2); + bounds.y2 = std::min(bounds.y2, rod.y2); + + const int bytes_per_row = + params_.width() * params_.channel_count() * params_.format().byte_count(); + const std::string &field = getFieldOrder(); + const std::string unique_id = std::to_string( + reinterpret_cast(gl_texture.get())) + "_" + + std::to_string(static_cast(time)); + + const int texture_id = gl_texture->id().value(); + OFX::Host::ImageEffect::Texture *texture = + new OFX::Host::ImageEffect::Texture( + *this, 1.0, 1.0, texture_id, GL_TEXTURE_2D, bounds, rod, + bytes_per_row, field, unique_id); + texture->addReference(); + return texture; +} +#endif diff --git a/app/pluginSupport/OliveClip.h b/app/pluginSupport/OliveClip.h new file mode 100644 index 000000000..85a4c9b13 --- /dev/null +++ b/app/pluginSupport/OliveClip.h @@ -0,0 +1,97 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// +// Created by mikesolar on 25-10-1. +// + +#ifndef OLIVECLIP_H +#define OLIVECLIP_H +#include "image.h" +#include "ofxCore.h" +#include "ofxhClip.h" +#include "render/texture.h" +#include "render/videoparams.h" + +#include +#include +namespace olive +{ +namespace plugin +{ +class OliveClipInstance: public OFX::Host::ImageEffect::ClipInstance { +public: + OliveClipInstance(OFX::Host::ImageEffect::Instance* effectInstance, + OFX::Host::ImageEffect::ClipDescriptor& desc,VideoParams ¶ms) + : ClipInstance(effectInstance, desc) + , name_(desc.getName()) + { + params_ = params; + } + OFX::Host::ImageEffect::Image* getOutputImage(OfxTime time); + + const std::string &getUnmappedBitDepth() const override; + const std::string &getUnmappedComponents() const override; + const std::string &getPremult() const override; + double getAspectRatio() const override; + double getFrameRate() const override; + void getFrameRange(double &startFrame, double &endFrame) const override; + const std::string &getFieldOrder() const override; + bool getConnected() const override; + double getUnmappedFrameRate() const override; + void getUnmappedFrameRange(double &startFrame, double &endFrame) const override; + bool getContinuousSamples() const override; + OFX::Host::ImageEffect::Image* getImage(OfxTime time, const OfxRectD *optionalBounds) override; + OfxRectD getRegionOfDefinition(OfxTime time) const override; + + void setRegionOfDefinition(OfxRectD regionOfDefinition, OfxTime time); + void setDefaultRegionOfDefinition(OfxRectD regionOfDefinition); + void setParams(const VideoParams ¶ms) + { + params_ = params; + } +# ifdef OFX_SUPPORTS_OPENGLRENDER + OFX::Host::ImageEffect::Texture* loadTexture(OfxTime time, + const char *format, + const OfxRectD *optionalBounds) override; +# endif + + void setInputTexture(TexturePtr texture, OfxTime time); + void setOutputTexture(TexturePtr texture, OfxTime time); + +private: + VideoParams params_; + + QMap regionOfDefinitions_; + + OfxRectD defaultRegionOfDefinitions_; + + std::string name_; + QMap images_; +#ifdef OFX_SUPPORTS_OPENGLRENDER + QMap input_textures_; + QMap output_textures_; +#endif +}; +} +} + + + +#endif //OLIVECLIP_H diff --git a/app/pluginSupport/OliveHost.cpp b/app/pluginSupport/OliveHost.cpp new file mode 100644 index 000000000..570e24448 --- /dev/null +++ b/app/pluginSupport/OliveHost.cpp @@ -0,0 +1,238 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "node/project.h" +#include "ofxhImageEffect.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "OliveHost.h" + +#include "OlivePluginInstance.h" +#include "common/Current.h" +#include "ofxMessage.h" +#include +using namespace OFX::Host; +using namespace olive::plugin; + +namespace olive { +namespace plugin { +class PluginNode; +} +} + +namespace { +void AddPluginPath(OFX::Host::PluginCache *cache, const QString &path, bool recurse = true) +{ + if (!cache || path.isEmpty()) { + return; + } + QDir dir(path); + if (!dir.exists()) { + return; + } + cache->addFileToPath(dir.canonicalPath().toStdString(), recurse); +} + +void AddPluginPathsFromEnv(OFX::Host::PluginCache *cache, const char *env_var) +{ + QString raw = qEnvironmentVariable(env_var); + if (raw.isEmpty()) { + return; + } + const QChar separator = QDir::listSeparator(); + const QStringList paths = raw.split(separator, Qt::SkipEmptyParts); + for (const QString &path : paths) { + AddPluginPath(cache, path); + } +} +} + +void olive::plugin::loadPlugins(QString path) +{ + std::shared_ptr host = Current::getInstance().pluginHost(); + std::shared_ptr imageEffectPluginCache = + Current::getInstance().pluginCache(); + + if (!host || !imageEffectPluginCache) { + host = std::make_shared(); + Current::getInstance().setPluginHost(host); + + imageEffectPluginCache = std::make_shared(*host); + Current::getInstance().setPluginCache(imageEffectPluginCache); + + imageEffectPluginCache->registerInCache( + *OFX::Host::PluginCache::getPluginCache()); + } + OFX::Host::PluginCache *cache = OFX::Host::PluginCache::getPluginCache(); + cache->setPluginHostPath("Olive"); + + const QString home_path = QDir::homePath(); + AddPluginPath(cache, QDir(home_path).filePath(".OFX/Plugins")); + AddPluginPath(cache, QDir(home_path).filePath(".local/share/OFX/Plugins")); + AddPluginPath(cache, QDir(home_path).filePath(".local/share/olive/ofx/Plugins")); + + const QString app_dir = QCoreApplication::applicationDirPath(); + AddPluginPath(cache, QDir(app_dir).filePath("../OFX/Plugins")); + AddPluginPath(cache, QDir(app_dir).filePath("../share/olive/ofx/Plugins")); + AddPluginPath(cache, QDir(app_dir).filePath("../lib/olive/ofx/Plugins")); + + AddPluginPathsFromEnv(cache, "OLIVE_OFX_PLUGIN_PATH"); + AddPluginPathsFromEnv(cache, "OLIVE_PLUGIN_PATH"); + + if (!path.isEmpty()) { + AddPluginPath(cache, path, true); + } + cache->scanPluginFiles(); +} +OliveHost::~OliveHost() +{ + +} + +void OliveHost::destroyInstance(OFX::Host::ImageEffect::Instance* instance) +{ + if (!instance) { + return; + } + for (auto it = instances_.begin(); it != instances_.end(); ++it) { + if (it->get() == instance) { + instances_.erase(it); + break; + } + } +} +std::shared_ptr +OliveHost::makeDescriptor(ImageEffect::ImageEffectPlugin *plugin) +{ + std::shared_ptr desc = + std::make_shared(plugin); + descriptors_.append(std::shared_ptr(desc)); + return desc; +} +std::shared_ptr +OliveHost::makeDescriptor(const ImageEffect::Descriptor &rootContext, + ImageEffect::ImageEffectPlugin *plugin) +{ + std::shared_ptr desc = + std::make_shared(rootContext, plugin); + descriptors_.append(std::shared_ptr(desc)); + return desc; +} +std::shared_ptr +OliveHost::makeDescriptor(const std::string &bundlePath, + ImageEffect::ImageEffectPlugin *plugin) +{ + std::shared_ptr desc = + std::make_shared(bundlePath, plugin); + descriptors_.append(std::shared_ptr(desc)); + return desc; +} + +ImageEffect::Instance* OliveHost::newInstance(void *clientData, + ImageEffect::ImageEffectPlugin* plugin, + ImageEffect::Descriptor& desc, + const std::string& context){ + auto* instance = new OlivePluginInstance( + plugin, desc, context, Current::getInstance().interactive()); + if (clientData) { + auto *node = static_cast(clientData); + instance->setNode( + std::shared_ptr(node, [](PluginNode *) {})); + } + instances_.append(std::shared_ptr(instance)); + return instance; +}; +OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, const char *format, + va_list args){ + if (!type || !format) { + return kOfxStatFailed; + } + + char buffer[1024]; + buffer[0] = '\0'; + vsnprintf(buffer, sizeof(buffer), format, args); + QString message(buffer); + + auto *app = qobject_cast(QCoreApplication::instance()); + if (!app) { + qWarning().noquote() + << "OFX message:" << type << message; + if (strcmp(type, kOfxMessageQuestion) == 0) { + return kOfxStatReplyNo; + } + return kOfxStatOK; + } + + if (strcmp(type, kOfxMessageQuestion) == 0) { + auto ret = QMessageBox::question(nullptr, "", message, + QMessageBox::Ok, QMessageBox::Cancel); + return (ret == QMessageBox::Ok) ? kOfxStatReplyYes : kOfxStatReplyNo; + } + + if (strcmp(type, kOfxMessageError) == 0) { + QMessageBox::critical(nullptr, "", message); + } else if (strcmp(type, kOfxMessageWarning) == 0) { + QMessageBox::warning(nullptr, "", message); + } else { + QMessageBox::information(nullptr, "", message); + } + + return kOfxStatOK; +} +// TODO: Persistent messages shouldn't use pop-up window. +OfxStatus olive::plugin::OliveHost::setPersistentMessage( + const char *type, const char *id, const char *format, va_list args) +{ + if (!type || !format) { + return kOfxStatFailed; + } + + char buffer[1024]; + buffer[0] = '\0'; + vsnprintf(buffer, sizeof(buffer), format, args); + QString message(buffer); + + if (strcmp(type, kOfxMessageError) == 0) { + persistent_messages_.append({HostMessageType::Error, message}); + QMessageBox::critical(nullptr, "", message); + } else if (strcmp(type, kOfxMessageWarning) == 0) { + persistent_messages_.append({HostMessageType::Warning, message}); + QMessageBox::warning(nullptr, "", message); + } else if (strcmp(type, kOfxMessageMessage) == 0) { + persistent_messages_.append({HostMessageType::Message, message}); + QMessageBox::information(nullptr, "", message); + } else { + return kOfxStatFailed; + } + + return kOfxStatOK; +} + +OfxStatus olive::plugin::OliveHost::clearPersistentMessage() +{ + persistent_messages_.clear(); + return kOfxStatOK; +} diff --git a/app/pluginSupport/OliveHost.h b/app/pluginSupport/OliveHost.h new file mode 100644 index 000000000..31adfe056 --- /dev/null +++ b/app/pluginSupport/OliveHost.h @@ -0,0 +1,108 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef OLIVE_HOST_H +#define OLIVE_HOST_H +#include "node/plugins/Plugin.h" +#include "ofxhHost.h" +#include "ofxhImageEffectAPI.h" +#include "ofxCore.h" +#include "ofxhImageEffect.h" + +#include +#include +#include +#include +#include +#include +#include +#include +namespace olive { +namespace plugin { +enum class HostMessageType{ + Error, + Warning, + Message +}; +struct HostPersistentMessage{ + HostMessageType type; + QString message; +}; + + +void loadPlugins(QString path); +class OliveHost: public OFX::Host::ImageEffect::Host{ +public: + OliveHost()=default; + ~OliveHost() override; + void destroyInstance(OFX::Host::ImageEffect::Instance *instance); + + bool pluginSupported(OFX::Host::ImageEffect::ImageEffectPlugin *plugin, + std::string &reason) const override + { + if (!plugin) { + reason = "null plugin"; + return false; + } + if (plugin->getContexts().empty()) { + reason = "no supported contexts (describe failed)"; + return false; + } + return true; + }; + + OFX::Host::ImageEffect::Instance* newInstance(void *clientData, + OFX::Host::ImageEffect::ImageEffectPlugin* plugin, + OFX::Host::ImageEffect::Descriptor& desc, + const std::string& context) override; + + + std::shared_ptr makeDescriptor( + OFX::Host::ImageEffect::ImageEffectPlugin* plugin) override; + + std::shared_ptr + makeDescriptor(const OFX::Host::ImageEffect::Descriptor &rootContext, + OFX::Host::ImageEffect::ImageEffectPlugin *plugin) override; + + std::shared_ptr + makeDescriptor(const std::string &bundlePath, + OFX::Host::ImageEffect::ImageEffectPlugin *plugin) override; + /// vmessage + virtual OfxStatus vmessage(const char *type, const char *id, + const char *format, va_list args); + + /// vmessage + virtual OfxStatus setPersistentMessage(const char *type, const char *id, + const char *format, va_list args); + /// vmessage + virtual OfxStatus clearPersistentMessage(); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /// @see OfxImageEffectOpenGLRenderSuiteV1.flushResources() + virtual OfxStatus flushOpenGLResources() const + { + return kOfxStatFailed; + }; +#endif +private: + QList> descriptors_; + QList> instances_; + QList persistent_messages_; +}; +} +} +#endif diff --git a/app/pluginSupport/OlivePluginInstance.cpp b/app/pluginSupport/OlivePluginInstance.cpp new file mode 100644 index 000000000..d998d029c --- /dev/null +++ b/app/pluginSupport/OlivePluginInstance.cpp @@ -0,0 +1,565 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "OlivePluginInstance.h" + +#include "OliveClip.h" +#include "ofxGPURender.h" +#include "ofxCore.h" +#include "ofxMessage.h" +#include "common/Current.h" +#include "core.h" +#include "dialog/progress/progress.h" +#include "node/output/viewer/viewer.h" +#include "panel/panelmanager.h" +#include "panel/timebased/timebased.h" +#include "panel/timeline/timeline.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "paraminstance.h" +namespace olive +{ +namespace plugin +{ +namespace { +const std::string kImageFieldNoneStr(kOfxImageFieldNone); +const std::string kImageFieldUpperStr(kOfxImageFieldUpper); +const std::string kImageFieldLowerStr(kOfxImageFieldLower); + +QString FormatOfxMessage(const char *format, va_list args) +{ + char buffer[1024]; + va_list args_copy; + va_copy(args_copy, args); + const int needed = vsnprintf(buffer, sizeof(buffer), format, args_copy); + va_end(args_copy); + if (needed < 0) { + return QString(); + } + if (needed < static_cast(sizeof(buffer))) { + return QString::fromUtf8(buffer); + } + QByteArray dynamic_buffer(needed + 1, 0); + const int written = vsnprintf(dynamic_buffer.data(), dynamic_buffer.size(), format, args); + if (written < 0) { + return QString(); + } + return QString::fromUtf8(dynamic_buffer.constData()); +} + +bool IsGuiThread() +{ + if (auto *app = QCoreApplication::instance()) { + return QThread::currentThread() == app->thread(); + } + return true; +} + +const std::string &FieldOrderForParams(const VideoParams ¶ms) +{ + switch (params.interlacing()) { + case VideoParams::kInterlaceNone: + return kImageFieldNoneStr; + case VideoParams::kInterlacedTopFirst: + return kImageFieldUpperStr; + case VideoParams::kInterlacedBottomFirst: + return kImageFieldLowerStr; + } + return kImageFieldNoneStr; +} + +class DeferredRedoCommand : public UndoCommand { +public: + explicit DeferredRedoCommand(UndoCommand *inner) + : inner_(inner) + { + } + + ~DeferredRedoCommand() override + { + delete inner_; + } + + Project *GetRelevantProject() const override + { + return inner_ ? inner_->GetRelevantProject() : nullptr; + } + +protected: + void redo() override + { + if (skip_first_redo_) { + skip_first_redo_ = false; + return; + } + if (inner_) { + inner_->redo_now(); + } + } + + void undo() override + { + if (inner_) { + inner_->undo_now(); + } + } + +private: + UndoCommand *inner_ = nullptr; + bool skip_first_redo_ = true; +}; + +ViewerOutput *GetActiveViewerOutput() +{ + PanelManager *manager = PanelManager::instance(); + if (!manager) { + return nullptr; + } + + if (auto *time_panel = manager->MostRecentlyFocused()) { + if (time_panel->GetConnectedViewer()) { + return time_panel->GetConnectedViewer(); + } + } + + QList timelines = manager->GetPanelsOfType(); + for (TimelinePanel *panel : timelines) { + if (panel && panel->GetConnectedViewer()) { + return panel->GetConnectedViewer(); + } + } + + return nullptr; +} +} // namespace + +const std::string &OlivePluginInstance::getDefaultOutputFielding() const +{ + return FieldOrderForParams(params_); +} + +void OlivePluginInstance::setNode(std::shared_ptr node) +{ + node_ = node; + for (const auto &entry : getParams()) { + if (!entry.second) { + continue; + } + if (auto *bound = dynamic_cast(entry.second)) { + bound->SetNode(node_); + } + } +} + +OfxStatus OlivePluginInstance::vmessage(const char *type, const char *id, + const char *format, va_list args) +{ + const QString message = FormatOfxMessage(format, args); + if (message.isEmpty()) { + return kOfxStatFailed; + } + + const bool is_question = + strncmp(type, kOfxMessageQuestion, strlen(kOfxMessageQuestion)) == 0; + OfxStatus result = kOfxStatOK; + auto show_message = [&]() { + if (is_question) { + const auto ret = QMessageBox::question( + nullptr, "", message, QMessageBox::Ok, QMessageBox::Cancel); + result = (ret == QMessageBox::Ok) ? kOfxStatReplyYes : kOfxStatReplyNo; + } else { + QMessageBox::information(nullptr, "", message); + result = kOfxStatOK; + } + }; + + if (IsGuiThread()) { + show_message(); + } else if (auto *app = QCoreApplication::instance()) { + if (is_question) { + QMetaObject::invokeMethod(app, show_message, Qt::BlockingQueuedConnection); + } else { + QMetaObject::invokeMethod(app, show_message, Qt::QueuedConnection); + } + } else if (is_question) { + result = kOfxStatReplyNo; + } + + return result; +} +OfxStatus OlivePluginInstance::setPersistentMessage(const char *type, const char *id, + const char *format, va_list args) +{ + const QString message = FormatOfxMessage(format, args); + if (message.isEmpty()) { + return kOfxStatFailed; + } + + ErrorType error_type; + // If This is a error message + if (strncmp(type, kOfxMessageError, strlen(kOfxMessageError)) == 0) { + error_type = ErrorType::Error; + } + // A warning + else if (strncmp(type, kOfxMessageWarning, strlen(kOfxMessageWarning)) == 0) { + error_type = ErrorType::Warning; + } + // A simple information + else if (strncmp(type, kOfxMessageMessage, strlen(kOfxMessageMessage)) == 0) { + error_type = ErrorType::Message; + } else { + return kOfxStatFailed; + } + + auto update_ui = [this, error_type, message]() { + persistentErrors_.append({ error_type, message }); + switch (error_type) { + case ErrorType::Error: + QMessageBox::critical(nullptr, "", message); + break; + case ErrorType::Warning: + QMessageBox::warning(nullptr, "", message); + break; + case ErrorType::Message: + QMessageBox::information(nullptr, "", message); + break; + } + if (node_) { + emit node_->MessageCountChanged(); + } + }; + + if (IsGuiThread()) { + update_ui(); + } else if (auto *app = QCoreApplication::instance()) { + QMetaObject::invokeMethod(app, update_ui, Qt::QueuedConnection); + } + return kOfxStatOK; +} +OfxStatus OlivePluginInstance::clearPersistentMessage() +{ + auto clear_ui = [this]() { + persistentErrors_.clear(); + // TODO: tell the shell to remove message. + if (node_) { + emit node_->MessageCountChanged(); + } + }; + if (IsGuiThread()) { + clear_ui(); + } else if (auto *app = QCoreApplication::instance()) { + QMetaObject::invokeMethod(app, clear_ui, Qt::QueuedConnection); + } + return kOfxStatOK; +} +void OlivePluginInstance::getProjectSize(double &xSize, double &ySize) const +{ + xSize =params_.width(); + ySize =params_.height(); +} +void OlivePluginInstance::getProjectOffset(double &xOffset, double &yOffset) const +{ + xOffset =params_.x(); + yOffset =params_.y(); +} +void OlivePluginInstance::getProjectExtent(double &xSize, double &ySize) const +{ + xSize =params_.width(); + ySize =params_.height(); +} +double OlivePluginInstance::getProjectPixelAspectRatio() const +{ + return Current::getInstance() + .currentVideoParams() + .pixel_aspect_ratio() + .toDouble(); +} +double OlivePluginInstance::getFrameRate() const +{ + return params_.frame_rate().toDouble(); +} + +double OlivePluginInstance::getEffectDuration() const +{ + // Return a default duration value + return 100.0; +} + +double OlivePluginInstance::getFrameRecursive() const +{ + // Return current frame (this would typically be set by the host during rendering) + return 0.0; +} + +void OlivePluginInstance::getRenderScaleRecursive(double &x, double &y) const +{ + // Return default render scale (1.0, 1.0) + x = 1.0; + y = 1.0; +} +OFX::Host::Param::Instance * +OlivePluginInstance::newParam(const std::string &name, + OFX::Host::Param::Descriptor &desc) +{ + const std::string &type = desc.getType(); + + if (type == kOfxParamTypeInteger) { + return new IntegerInstance(node_, desc); + } else if (type == kOfxParamTypeDouble) { + return new DoubleInstance(node_, name, desc); + } else if (type == kOfxParamTypeBoolean) { + return new BooleanInstance(node_, name, desc); + } else if (type == kOfxParamTypeChoice) { + return new ChoiceInstance(node_, name, desc); + } else if (type == kOfxParamTypeString) { + return new StringInstance(node_, name, desc); + } else if (type == kOfxParamTypeRGBA) { + return new RGBAInstance(node_, name, desc); + } else if (type == kOfxParamTypeRGB) { + return new RGBInstance(node_, name, desc); + } else if (type == kOfxParamTypeDouble2D) { + return new Double2DInstance(node_, name, desc); + } else if (type == kOfxParamTypeInteger2D) { + return new Integer2DInstance(node_, name, desc); + } else if (type == kOfxParamTypeDouble3D) { + return new Double3DInstance(node_, name, desc); + } else if (type == kOfxParamTypeInteger3D) { + return new Integer3DInstance(node_, name, desc); + } else if (type == kOfxParamTypeCustom || + type == kOfxParamTypeBytes) { + return new CustomInstance(node_, name, desc); + } else if (type == kOfxParamTypeGroup) { + return new GroupInstance(desc); + } else if (type == kOfxParamTypePage) { + return new PageInstance(desc); + } else if (type == kOfxParamTypePushButton) { + return new PushbuttonInstance(node_, name, desc); + } + + return nullptr; // 未实现的类型 +} +OfxStatus OlivePluginInstance::editBegin(const std::string &name) +{ + edit_depth_++; + if (edit_depth_ == 1) { + edit_command_ = nullptr; + edit_label_.clear(); + edit_first_label_.clear(); + edit_param_count_ = 0; + if (!name.empty()) { + edit_first_label_ = + QCoreApplication::translate( + "OlivePluginInstance", "Change %1") + .arg(QString::fromStdString(name)); + } + } + return kOfxStatOK; +} +OfxStatus OlivePluginInstance::editEnd() +{ + if (edit_depth_ > 0) { + edit_depth_--; + } + if (edit_depth_ == 0 && edit_command_) { + QString label = edit_label_; + if (label.isEmpty()) { + if (edit_param_count_ <= 1 && !edit_first_label_.isEmpty()) { + label = edit_first_label_; + } else if (edit_param_count_ > 1 && + !edit_first_label_.isEmpty()) { + label = QCoreApplication::translate( + "OlivePluginInstance", "%1 (+%2)") + .arg(edit_first_label_) + .arg(edit_param_count_ - 1); + } else { + label = QCoreApplication::translate( + "OlivePluginInstance", "Edit Parameters"); + } + } + Core::instance()->undo_stack()->push(edit_command_, label); + edit_command_ = nullptr; + edit_label_.clear(); + edit_first_label_.clear(); + edit_param_count_ = 0; + } + return kOfxStatOK; +} + +void OlivePluginInstance::SubmitUndoCommand(UndoCommand *command, + const QString &label) +{ + if (!command) { + return; + } + + if (edit_depth_ > 0) { + if (!edit_command_) { + edit_command_ = new MultiUndoCommand(); + } + edit_param_count_++; + if (!label.isEmpty() && edit_first_label_.isEmpty()) { + edit_first_label_ = label; + } + + command->redo_now(); + edit_command_->add_child(new DeferredRedoCommand(command)); + return; + } + + Core::instance()->undo_stack()->push(command, label); +} + +void OlivePluginInstance::progressStart(const std::string &message, + const std::string &messageid) +{ + (void)messageid; + progress_cancelled_ = false; + progress_active_ = true; + + auto *app = qobject_cast(QCoreApplication::instance()); + if (!app) { + return; + } + + if (progress_dialog_) { + progress_dialog_->close(); + progress_dialog_->deleteLater(); + } + + QString dialog_message = message.empty() + ? QStringLiteral("Processing...") + : QString::fromStdString(message); + + progress_dialog_ = new ::olive::ProgressDialog( + dialog_message, QStringLiteral("OpenFX"), nullptr); + progress_dialog_->setAttribute(Qt::WA_DeleteOnClose); + QObject::connect(progress_dialog_, &::olive::ProgressDialog::Cancelled, + progress_dialog_, + [this]() { progress_cancelled_ = true; }); + progress_dialog_->show(); +} + +void OlivePluginInstance::progressEnd() +{ + progress_active_ = false; + progress_cancelled_ = false; + + if (progress_dialog_) { + progress_dialog_->close(); + progress_dialog_->deleteLater(); + } +} + +bool OlivePluginInstance::progressUpdate(double t) +{ + if (!progress_active_) { + return true; + } + + if (progress_dialog_) { + double clamped = qBound(0.0, t, 1.0); + progress_dialog_->SetProgress(clamped); + } + + return !progress_cancelled_; +} + +#ifdef OFX_SUPPORTS_OPENGLRENDER +OfxStatus OlivePluginInstance::contextAttachedAction() +{ + if (!open_gl_enabled_) { + return kOfxStatReplyDefault; + } + return kOfxStatOK; +} + +OfxStatus OlivePluginInstance::contextDetachedAction() +{ + if (!open_gl_enabled_) { + return kOfxStatReplyDefault; + } + return kOfxStatOK; +} +#endif + +double OlivePluginInstance::timeLineGetTime() +{ + if (ViewerOutput *viewer = GetActiveViewerOutput()) { + return viewer->GetPlayhead().toDouble(); + } + + return 0.0; +} + +void OlivePluginInstance::timeLineGotoTime(double t) +{ + if (ViewerOutput *viewer = GetActiveViewerOutput()) { + viewer->SetPlayhead(olive::core::rational::fromDouble(t)); + } +} + +void OlivePluginInstance::timeLineGetBounds(double &t1, double &t2) +{ + if (ViewerOutput *viewer = GetActiveViewerOutput()) { + t1 = 0.0; + t2 = viewer->GetLength().toDouble(); + return; + } + + t1 = 0.0; + t2 = 0.0; +} + +void OlivePluginInstance::setCustomInArgs(const std::string &action, + OFX::Host::Property::Set &inArgs) +{ + if (action == kOfxImageEffectActionRender || + action == kOfxImageEffectActionBeginSequenceRender || + action == kOfxImageEffectActionEndSequenceRender) { + inArgs.setIntProperty(kOfxImageEffectPropOpenGLEnabled, + open_gl_enabled_ ? 1 : 0); + } +} + +OFX::Host::ImageEffect::ClipInstance *OlivePluginInstance::newClipInstance( + OFX::Host::ImageEffect::Instance *plugin, + OFX::Host::ImageEffect::ClipDescriptor *descriptor, + int index) +{ + // Create a new clip instance + OFX::Host::ImageEffect::ClipInstance* clipInstance = new OliveClipInstance(plugin, *descriptor, params_); + return clipInstance; +} + +OlivePluginInstance::~OlivePluginInstance() +{ + if (!QCoreApplication::instance() || + qEnvironmentVariableIsSet("OAK_OFX_ITEST")) { + _created = false; + } +} + +} +} diff --git a/app/pluginSupport/OlivePluginInstance.h b/app/pluginSupport/OlivePluginInstance.h new file mode 100644 index 000000000..e1908c94d --- /dev/null +++ b/app/pluginSupport/OlivePluginInstance.h @@ -0,0 +1,218 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef OLIVE_INSTANCE_H +#define OLIVE_INSTANCE_H +#include "ofxCore.h" +#include "ofxImageEffect.h" +#include +#include "ofxhImageEffect.h" +#include "node/plugins/Plugin.h" +#include "render/videoparams.h" +#include "undo/undocommand.h" + +#include +#include +#include +#include +namespace olive { +class ProgressDialog; +namespace plugin{ +class PluginNode; +enum class ErrorType{ + Error, + Warning, + Message +}; +struct PersistentErrors{ + ErrorType type; + QString message; +}; +class OlivePluginInstance : public OFX::Host::ImageEffect::Instance { +public: + OlivePluginInstance( + OFX::Host::ImageEffect::ImageEffectPlugin* plugin, + OFX::Host::ImageEffect::Descriptor& desc, + const std::string& context, + bool interactive) + : OFX::Host::ImageEffect::Instance(plugin, desc, context, interactive) + { + } + OlivePluginInstance(OlivePluginInstance& instance) + : Instance(instance._plugin, *instance._descriptor, instance._context, + instance._interactive) + { + _clips=instance._clips; + _created=instance._created; + _clipPrefsDirty=instance._clipPrefsDirty; + _continuousSamples=instance._continuousSamples; + _frameVarying=instance._frameVarying; + _outputPreMultiplication=instance._outputPreMultiplication; + _outputFielding=instance._outputFielding; + _outputFrameRate=instance._outputFrameRate; + + } + explicit OlivePluginInstance(Instance & instance):Instance(instance){}; + ~OlivePluginInstance() override; + const std::string &getDefaultOutputFielding() const override; + + void setVideoParam(VideoParams params) + { + this->params_=params; + } + void setNode(std::shared_ptr node); + std::shared_ptr node() const + { + return node_; + } + void setOpenGLEnabled(bool enabled) + { + open_gl_enabled_ = enabled; + } + bool isCreated() const + { + return _created; + } + OFX::Host::ImageEffect::ClipInstance *newClipInstance( + OFX::Host::ImageEffect::Instance *plugin, + OFX::Host::ImageEffect::ClipDescriptor *descriptor, + int index) override; + + OfxStatus vmessage(const char* type, + const char* id, + const char* format, + va_list args) override; + + OfxStatus setPersistentMessage(const char* type, + const char* id, + const char* format, + va_list args) override; + + OfxStatus clearPersistentMessage() override; + int persistentMessageCount() const + { + return persistentErrors_.size(); + } + const QList &persistentMessages() const + { + return persistentErrors_; + } + + void getProjectSize(double& xSize, double& ySize) const override; + void getProjectOffset(double& xOffset, double& yOffset) const override; + void getProjectExtent(double& xSize, double& ySize) const override; + // The pixel aspect ratio of the current project + double getProjectPixelAspectRatio() const override; + + // The duration of the effect + // This contains the duration of the plug-in effect, in frames. + double getEffectDuration() const override; + + // For an instance, this is the frame rate of the project the effect is in. + double getFrameRate() const override; + + /// This is called whenever a param is changed by the plugin so that + /// the recursive instanceChangedAction will be fed the correct frame + double getFrameRecursive() const override; + + /// This is called whenever a param is changed by the plugin so that + /// the recursive instanceChangedAction will be fed the correct + /// renderScale + void getRenderScaleRecursive(double &x, double &y) const override; + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for Param::SetInstance + + /// make a parameter instance + /// + /// Client host code needs to implement this + OFX::Host::Param::Instance* newParam(const std::string& name, OFX::Host::Param::Descriptor& Descriptor) override; + + void SubmitUndoCommand(UndoCommand *command, const QString &label); + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditBegin + /// + /// Client host code needs to implement this + virtual OfxStatus editBegin(const std::string& name) override; + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditEnd + /// + /// Client host code needs to implement this + virtual OfxStatus editEnd() override; + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for Progress::ProgressI + + /// Start doing progress. + virtual void progressStart(const std::string &message, + const std::string &messageid) override; + + /// finish yer progress + virtual void progressEnd() override; + + /// set the progress to some level of completion, returns + /// false if you should abandon processing, true to continue + virtual bool progressUpdate(double t) override; + +#ifdef OFX_SUPPORTS_OPENGLRENDER + virtual OfxStatus contextAttachedAction() override; + virtual OfxStatus contextDetachedAction() override; +#endif + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for TimeLine::TimeLineI + + /// get the current time on the timeline. This is not necessarily the same + /// time as being passed to an action (eg render) + virtual double timeLineGetTime(); + + /// set the timeline to a specific time + virtual void timeLineGotoTime(double t); + + /// get the first and last times available on the effect's timeline + virtual void timeLineGetBounds(double &t1, double &t2); + + void setCustomInArgs(const std::string &action, + OFX::Host::Property::Set &inArgs) override; + + +private: + QList persistentErrors_; + VideoParams params_; + std::shared_ptr node_ = nullptr; + int edit_depth_ = 0; + MultiUndoCommand *edit_command_ = nullptr; + QString edit_label_; + QString edit_first_label_; + int edit_param_count_ = 0; + QPointer progress_dialog_; + bool progress_cancelled_ = false; + bool progress_active_ = false; + bool open_gl_enabled_ = false; +}; +} +} +#endif diff --git a/app/pluginSupport/image.cpp b/app/pluginSupport/image.cpp new file mode 100644 index 000000000..5adad973a --- /dev/null +++ b/app/pluginSupport/image.cpp @@ -0,0 +1,245 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2026 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "image.h" + +#include "ofxImageEffect.h" + +#include + +namespace olive { +namespace plugin { + +static const char *PixelDepthToOfx(core::PixelFormat format) +{ + switch (format) { + case core::PixelFormat::U8: + return kOfxBitDepthByte; + case core::PixelFormat::U16: + return kOfxBitDepthShort; + case core::PixelFormat::F16: + return kOfxBitDepthHalf; + case core::PixelFormat::F32: + return kOfxBitDepthFloat; + case core::PixelFormat::INVALID: + case core::PixelFormat::COUNT: + break; + } + + return kOfxBitDepthNone; +} + +static const char *ComponentsToOfx(int channel_count) +{ + switch (channel_count) { + case 1: + return kOfxImageComponentAlpha; + case 3: + return kOfxImageComponentRGB; + case 4: + return kOfxImageComponentRGBA; + default: + break; + } + + return kOfxImageComponentNone; +} + +Image::Image(OFX::Host::ImageEffect::ClipInstance &clip_instance) + : OFX::Host::ImageEffect::Image(clip_instance) + , width_(0) + , height_(0) + , format_(core::PixelFormat::INVALID) + , premultiplied_alpha_(false) + , channel_count_(0) + , row_bytes_(0) + , bounds_{0, 0, 0, 0} + , rod_{0, 0, 0, 0} +{ +} + +Image::Image(OFX::Host::ImageEffect::ClipInstance &clip_instance, + const VideoParams ¶ms, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear) + : OFX::Host::ImageEffect::Image(clip_instance) + , width_(0) + , height_(0) + , format_(core::PixelFormat::INVALID) + , premultiplied_alpha_(false) + , channel_count_(0) + , row_bytes_(0) + , bounds_{0, 0, 0, 0} + , rod_{0, 0, 0, 0} +{ + AllocateFromParams(params, bounds, rod, clear); +} + +Image::~Image() +{ +} + +void Image::AllocateFromParams(const VideoParams ¶ms, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear) +{ + Allocate(bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1, + params.format(), + params.channel_count(), + params.premultiplied_alpha(), + bounds, + rod, + clear); +} + +void Image::EnsureAllocatedFromParams(const VideoParams ¶ms, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear) +{ + bool same = (width_ == bounds.x2 - bounds.x1) && + (height_ == bounds.y2 - bounds.y1) && + (format_ == params.format()) && + (channel_count_ == params.channel_count()) && + (premultiplied_alpha_ == params.premultiplied_alpha()) && + (bounds_.x1 == bounds.x1) && (bounds_.y1 == bounds.y1) && + (bounds_.x2 == bounds.x2) && (bounds_.y2 == bounds.y2) && + (rod_.x1 == rod.x1) && (rod_.y1 == rod.y1) && + (rod_.x2 == rod.x2) && (rod_.y2 == rod.y2); + + if (!same) { + AllocateFromParams(params, bounds, rod, clear); + } else if (clear && !image_.empty()) { + std::fill(image_.begin(), image_.end(), 0); + } +} + +void Image::Allocate(int width, + int height, + core::PixelFormat format, + int channel_count, + bool premultiplied_alpha, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear) +{ + width_ = width; + height_ = height; + format_ = format; + channel_count_ = channel_count; + premultiplied_alpha_ = premultiplied_alpha; + bounds_ = bounds; + rod_ = rod; + + int bytes_per_component = format_.byte_count(); + row_bytes_ = width_ * channel_count_ * bytes_per_component; + int buffer_size = row_bytes_ * height_; + if (buffer_size < 0) { + buffer_size = 0; + } + + image_.resize(static_cast(buffer_size)); + if (clear && !image_.empty()) { + std::fill(image_.begin(), image_.end(), 0); + } + + setPointerProperty(kOfxImagePropData, image_.data()); + setIntProperty(kOfxImagePropRowBytes, row_bytes_); + setIntProperty(kOfxImagePropBounds, bounds.x1, 0); + setIntProperty(kOfxImagePropBounds, bounds.y1, 1); + setIntProperty(kOfxImagePropBounds, bounds.x2, 2); + setIntProperty(kOfxImagePropBounds, bounds.y2, 3); + setIntProperty(kOfxImagePropRegionOfDefinition, rod.x1, 0); + setIntProperty(kOfxImagePropRegionOfDefinition, rod.y1, 1); + setIntProperty(kOfxImagePropRegionOfDefinition, rod.x2, 2); + setIntProperty(kOfxImagePropRegionOfDefinition, rod.y2, 3); + setStringProperty(kOfxImageEffectPropComponents, + ComponentsToOfx(channel_count_)); + setStringProperty(kOfxImageEffectPropPixelDepth, + PixelDepthToOfx(format_)); + setStringProperty(kOfxImageEffectPropPreMultiplication, + premultiplied_alpha_ ? kOfxImagePreMultiplied + : kOfxImageUnPreMultiplied); +} + +core::PixelFormat Image::pixel_format() +{ + if (format_ != core::PixelFormat::INVALID) { + return format_; + } + + std::string type = getStringProperty(kOfxImageEffectPropPixelDepth); + if (type == kOfxBitDepthByte) { + format_ = core::PixelFormat::U8; + } else if (type == kOfxBitDepthShort) { + format_ = core::PixelFormat::U16; + } else if (type == kOfxBitDepthHalf) { + format_ = core::PixelFormat::F16; + } else if (type == kOfxBitDepthFloat) { + format_ = core::PixelFormat::F32; + } else { + format_ = core::PixelFormat::INVALID; + } + return format_; +} + +bool Image::premultiplied_alpha() +{ + std::string premultiplied = + getStringProperty(kOfxImageEffectPropPreMultiplication); + premultiplied_alpha_ = (premultiplied == kOfxImagePreMultiplied); + return premultiplied_alpha_; +} + +int Image::width() +{ + int bounds[4] = {0}; + getIntPropertyN(kOfxImagePropBounds, bounds, 4); + width_ = bounds[2] - bounds[0]; + return width_; +} + +int Image::height() +{ + int bounds[4] = {0}; + getIntPropertyN(kOfxImagePropBounds, bounds, 4); + height_ = bounds[3] - bounds[1]; + return height_; +} + +int Image::channel_count() +{ + std::string type = getStringProperty(kOfxImageEffectPropComponents); + if (type == kOfxImageComponentAlpha) { + channel_count_ = 1; + } else if (type == kOfxImageComponentRGBA) { + channel_count_ = 4; + } else if (type == kOfxImageComponentRGB) { + channel_count_ = 3; + } else { + channel_count_ = 0; + } + return channel_count_; +} + +} // namespace plugin +} // namespace olive diff --git a/app/pluginSupport/image.h b/app/pluginSupport/image.h new file mode 100644 index 000000000..44f21e97b --- /dev/null +++ b/app/pluginSupport/image.h @@ -0,0 +1,89 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2026 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef OLIVE_EDITOR_PLUGIN_IMAGE_H +#define OLIVE_EDITOR_PLUGIN_IMAGE_H + +#include "ofxCore.h" +#include "ofxImageEffect.h" +#include "ofxhClip.h" +#include "olive/core/render/pixelformat.h" +#include "render/loopmode.h" +#include "render/videoparams.h" +#include +#include +#include +#include +namespace olive +{ +namespace plugin +{ +class Image : public OFX::Host::ImageEffect::Image { +public: + Image(OFX::Host::ImageEffect::ClipInstance &clip_instance); + Image(OFX::Host::ImageEffect::ClipInstance &clip_instance, + const VideoParams ¶ms, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear = true); + ~Image(); + uint8_t *data() { + return (uint8_t *)getPointerProperty(kOfxImagePropData); + } + int width(); + int height(); + core::PixelFormat pixel_format(); + bool premultiplied_alpha(); + int channel_count(); + + void AllocateFromParams(const VideoParams ¶ms, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear = true); + void EnsureAllocatedFromParams(const VideoParams ¶ms, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear = false); + void Allocate(int width, + int height, + core::PixelFormat format, + int channel_count, + bool premultiplied_alpha, + const OfxRectI &bounds, + const OfxRectI &rod, + bool clear = true); + int row_bytes() const + { + return row_bytes_; + } +protected: + std::vector image_; + int width_; + int height_; + core::PixelFormat format_; + bool premultiplied_alpha_; + int channel_count_; + int row_bytes_; + OfxRectI bounds_; + OfxRectI rod_; +}; +} +} + +#endif //OLIVE_EDITOR_PLUGIN_IMAGE_H diff --git a/app/pluginSupport/paraminstance.cpp b/app/pluginSupport/paraminstance.cpp new file mode 100644 index 000000000..70d53e087 --- /dev/null +++ b/app/pluginSupport/paraminstance.cpp @@ -0,0 +1,49 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#include "paraminstance.h" + +#include "OlivePluginInstance.h" + +namespace olive +{ +namespace plugin +{ +void SubmitUndoCommand(const std::shared_ptr &node, + UndoCommand *command, const QString &label) +{ + if (!command) { + return; + } + + if (node) { + auto *instance = node->getPluginInstance(); + auto *olive_instance = + dynamic_cast(instance); + if (olive_instance) { + olive_instance->SubmitUndoCommand(command, label); + return; + } + } + + Core::instance()->undo_stack()->push(command, label); +} +} +} diff --git a/app/pluginSupport/paraminstance.h b/app/pluginSupport/paraminstance.h new file mode 100644 index 000000000..e69aee287 --- /dev/null +++ b/app/pluginSupport/paraminstance.h @@ -0,0 +1,1197 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Copyright OpenFX and contributors to the OpenFX project. +#ifndef PARAM_INSTANCE_H +#define PARAM_INSTANCE_H + +#include "olive/core/util/rational.h" +#include "pluginSupport/OlivePluginInstance.h" +#include +#include +#include +#include +#include "ofxhParam.h" +#include "node/nodeundo.h" +#include "node/plugins/Plugin.h" +#include "core.h" +#include "undo/undocommand.h" +#include +#include +namespace olive +{ +namespace plugin +{ +inline QString ParamChangeLabel(const OFX::Host::Param::Descriptor &descriptor) +{ + return QStringLiteral("Change %1") + .arg(QString::fromStdString(descriptor.getName())); +} +void SubmitUndoCommand(const std::shared_ptr &node, + UndoCommand *command, const QString &label); + +class NodeBoundParam { +public: + virtual ~NodeBoundParam() = default; + virtual void SetNode(const std::shared_ptr &node) = 0; +}; + +class PushbuttonInstance : public OFX::Host::Param::PushbuttonInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor *_descriptor; +public: + PushbuttonInstance(std::shared_ptr effect, const std::string &name, + OFX::Host::Param::Descriptor &descriptor) + : OFX::Host::Param::PushbuttonInstance(descriptor) + , node(effect) + { + _descriptor = &descriptor; + }; + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } +}; + +class IntegerInstance : public OFX::Host::Param::IntegerInstance, + public NodeBoundParam { +protected: + std::shared_ptr _node; + OFX::Host::Param::Descriptor& _descriptor; + QString id; + bool has_value_ = false; + int value_ = 0; +public: + IntegerInstance(std::shared_ptrnode, OFX::Host::Param::Descriptor &descriptor) + : OFX::Host::Param::IntegerInstance(descriptor) + , _node(node) + , _descriptor(descriptor) + {} + void SetNode(const std::shared_ptr &new_node) override + { + _node = new_node; + } + OfxStatus get(int &a) + { + if (!_node) { + a = has_value_ ? value_ : 0; + return kOfxStatOK; + } + if (id.isEmpty()) { + return kOfxStatErrBadHandle; + } + QVariant variant=_node->GetStandardValue(id); + + if (variant.typeId()==QVariant::Int) { + a=variant.toInt(); + return kOfxStatOK; + } + a=0; + return kOfxStatErrValue; + } + OfxStatus get(OfxTime time, int &data) + { + if (!_node) { + data = has_value_ ? value_ : 0; + return kOfxStatOK; + } + if (id.isEmpty()) { + return kOfxStatErrBadHandle; + } + QVariant variant=_node->GetValueAtTime(id, rational::fromDouble(time)); + if (variant.typeId()==QVariant::Int) { + data=variant.toInt(); + return kOfxStatOK; + } + data=0; + return kOfxStatErrValue; + } + OfxStatus set(int data) + { + if (!_node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kInt, data); + + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(_node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(_node, command, ParamChangeLabel(_descriptor)); + id=_descriptor.getName().c_str(); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, int data) + { + if (!_node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + Node::SetValueAtTime( + NodeInput(_node.get(), _descriptor.getName().c_str()), + rational::fromDouble(time), data, 0, command, true); + SubmitUndoCommand(_node, command, ParamChangeLabel(_descriptor)); + id=_descriptor.getName().c_str(); + return kOfxStatOK; + } +}; + +class DoubleInstance : public OFX::Host::Param::DoubleInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + double value_ = 0.0; +public: + DoubleInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::DoubleInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(double& data) + { + if (!node) { + data = has_value_ ? value_ : 0.0; + return kOfxStatOK; + } + QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); + if (variant.canConvert()) { + data = variant.toDouble(); + return kOfxStatOK; + } + data = 0.0; + return kOfxStatErrValue; + } + OfxStatus get(OfxTime time, double& data) + { + if (!node) { + data = has_value_ ? value_ : 0.0; + return kOfxStatOK; + } + QVariant variant = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)); + if (variant.canConvert()) { + data = variant.toDouble(); + return kOfxStatOK; + } + data = 0.0; + return kOfxStatErrValue; + } + OfxStatus set(double data) + { + if (!node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kFloat, data); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, double data) + { + if (!node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + Node::SetValueAtTime( + NodeInput(node.get(), _descriptor.getName().c_str()), + rational::fromDouble(time), data, 0, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus derive(OfxTime, double&) + { + return kOfxStatErrUnsupported; + } + OfxStatus integrate(OfxTime, OfxTime, double&) + { + return kOfxStatErrUnsupported; + } +}; + +class BooleanInstance : public OFX::Host::Param::BooleanInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + bool value_ = false; + bool DefaultValue() const + { + return _descriptor.getProperties() + .getIntProperty(kOfxParamPropDefault) != 0; + } +public: + BooleanInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::BooleanInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(bool& data) + { + if (!node) { + data = has_value_ ? value_ : false; + return kOfxStatOK; + } + QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); + if (variant.canConvert()) { + data = variant.toBool(); + return kOfxStatOK; + } + data = DefaultValue(); + return kOfxStatOK; + } + OfxStatus get(OfxTime time, bool& data) + { + if (!node) { + data = has_value_ ? value_ : false; + return kOfxStatOK; + } + QVariant variant = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)); + if (variant.isNull()){ + qWarning().noquote()<<"Boolean get failed: Varient is null" << time << rational::fromDouble(time).toDouble(); + } + if (!variant.isValid()) { + qWarning().noquote() + << "Boolean get failed: Varient is invalid" << time + << rational::fromDouble(time).toDouble(); + } + if (variant.canConvert()) { + data = variant.toBool(); + return kOfxStatOK; + } + data = DefaultValue(); + return kOfxStatOK; + } + OfxStatus set(bool data) + { + if (!node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kBoolean, data); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, bool data) + { + if (!node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + Node::SetValueAtTime( + NodeInput(node.get(), _descriptor.getName().c_str()), + rational::fromDouble(time), data, 0, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class ChoiceInstance : public OFX::Host::Param::ChoiceInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + int value_ = 0; +public: + ChoiceInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::ChoiceInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(int& data) + { + if (!node) { + data = has_value_ ? value_ : 0; + return kOfxStatOK; + } + QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); + if (variant.canConvert()) { + data = variant.toInt(); + return kOfxStatOK; + } + data = 0; + return kOfxStatErrValue; + } + OfxStatus get(OfxTime time, int& data) + { + if (!node) { + data = has_value_ ? value_ : 0; + return kOfxStatOK; + } + QVariant variant = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)); + if (variant.canConvert()) { + data = variant.toInt(); + return kOfxStatOK; + } + data = 0; + return kOfxStatErrValue; + } + OfxStatus set(int data) + { + if (!node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kCombo, data); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, int data) + { + if (!node) { + value_ = data; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + Node::SetValueAtTime( + NodeInput(node.get(), _descriptor.getName().c_str()), + rational::fromDouble(time), data, 0, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class RGBAInstance : public OFX::Host::Param::RGBAInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + double value_[4] = {0.0, 0.0, 0.0, 0.0}; +public: + RGBAInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::RGBAInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(double& r,double& g,double& b,double& a) + { + if (!node) { + if (has_value_) { + r = value_[0]; + g = value_[1]; + b = value_[2]; + a = value_[3]; + } else { + r = g = b = a = 0.0; + } + return kOfxStatOK; + } + olive::core::Color c = + node->GetStandardValue(_descriptor.getName().c_str()) + .value(); + + r = static_cast(c.red()); + g = static_cast(c.green()); + b = static_cast(c.blue()); + a = static_cast(c.alpha()); + return kOfxStatOK; + } + OfxStatus get(OfxTime time, double& r,double& g,double& b,double& a) + { + if (!node) { + if (has_value_) { + r = value_[0]; + g = value_[1]; + b = value_[2]; + a = value_[3]; + } else { + r = g = b = a = 0.0; + } + return kOfxStatOK; + } + olive::core::Color c = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)) + .value(); + + r = static_cast(c.red()); + g = static_cast(c.green()); + b = static_cast(c.blue()); + a = static_cast(c.alpha()); + return kOfxStatOK; + } + OfxStatus set(double r,double g,double b,double a) + { + if (!node) { + value_[0] = r; + value_[1] = g; + value_[2] = b; + value_[3] = a; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kColor, + QVariant::fromValue(olive::core::Color(r, g, b, a))); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, double r,double g,double b,double a) + { + if (!node) { + value_[0] = r; + value_[1] = g; + value_[2] = b; + value_[3] = a; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + const QString name = _descriptor.getName().c_str(); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + r, 0, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + g, 1, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + b, 2, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + a, 3, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + + +class RGBInstance : public OFX::Host::Param::RGBInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + double value_[3] = {0.0, 0.0, 0.0}; +public: + RGBInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::RGBInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(double& r,double& g,double& b) + { + if (!node) { + if (has_value_) { + r = value_[0]; + g = value_[1]; + b = value_[2]; + } else { + r = g = b = 0.0; + } + return kOfxStatOK; + } + olive::core::Color c = + node->GetStandardValue(_descriptor.getName().c_str()) + .value(); + + r = static_cast(c.red()); + g = static_cast(c.green()); + b = static_cast(c.blue()); + return kOfxStatOK; + } + OfxStatus get(OfxTime time, double& r,double& g,double& b) + { + if (!node) { + if (has_value_) { + r = value_[0]; + g = value_[1]; + b = value_[2]; + } else { + r = g = b = 0.0; + } + return kOfxStatOK; + } + olive::core::Color c = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)) + .value(); + + r = static_cast(c.red()); + g = static_cast(c.green()); + b = static_cast(c.blue()); + return kOfxStatOK; + } + OfxStatus set(double r,double g,double b) + { + if (!node) { + value_[0] = r; + value_[1] = g; + value_[2] = b; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kColor, + QVariant::fromValue(olive::core::Color(r, g, b))); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, double r,double g,double b) + { + if (!node) { + value_[0] = r; + value_[1] = g; + value_[2] = b; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + const QString name = _descriptor.getName().c_str(); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + r, 0, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + g, 1, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + b, 2, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class Double2DInstance : public OFX::Host::Param::Double2DInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + double value_[2] = {0.0, 0.0}; +public: + Double2DInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::Double2DInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(double& x,double& y) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + } else { + x = y = 0.0; + } + return kOfxStatOK; + } + QVector2D vec = + node->GetStandardValue(_descriptor.getName().c_str()) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + return kOfxStatOK; + } + OfxStatus get(OfxTime time,double& x,double& y) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + } else { + x = y = 0.0; + } + return kOfxStatOK; + } + QVector2D vec = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + return kOfxStatOK; + } + OfxStatus set(double x,double y) + { + if (!node) { + value_[0] = x; + value_[1] = y; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kVec2, QVector2D(x, y)); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time,double x,double y) + { + if (!node) { + value_[0] = x; + value_[1] = y; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + const QString name = _descriptor.getName().c_str(); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + x, 0, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + y, 1, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class Integer2DInstance : public OFX::Host::Param::Integer2DInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + int value_[2] = {0, 0}; +public: + Integer2DInstance(std::shared_ptr effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::Integer2DInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(int& x,int& y) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + } else { + x = y = 0; + } + return kOfxStatOK; + } + QVector2D vec = + node->GetStandardValue(_descriptor.getName().c_str()) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + return kOfxStatOK; + } + OfxStatus get(OfxTime time,int& x,int& y) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + } else { + x = y = 0; + } + return kOfxStatOK; + } + QVector2D vec = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + return kOfxStatOK; + } + OfxStatus set(int x,int y) + { + if (!node) { + value_[0] = x; + value_[1] = y; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kVec2, QVector2D(x, y)); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time,int x,int y) + { + if (!node) { + value_[0] = x; + value_[1] = y; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + const QString name = _descriptor.getName().c_str(); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + x, 0, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time), + y, 1, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class Double3DInstance : public OFX::Host::Param::Double3DInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + double value_[3] = {0.0, 0.0, 0.0}; +public: + Double3DInstance(std::shared_ptr effect, const std::string& name, + OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::Double3DInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(double& x,double& y,double& z) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + z = value_[2]; + } else { + x = y = z = 0.0; + } + return kOfxStatOK; + } + QVector3D vec = + node->GetStandardValue(_descriptor.getName().c_str()) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + z = static_cast(vec.z()); + return kOfxStatOK; + } + OfxStatus get(OfxTime time,double& x,double& y,double& z) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + z = value_[2]; + } else { + x = y = z = 0.0; + } + return kOfxStatOK; + } + QVector3D vec = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + z = static_cast(vec.z()); + return kOfxStatOK; + } + OfxStatus set(double x,double y,double z) + { + if (!node) { + value_[0] = x; + value_[1] = y; + value_[2] = z; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kVec3, QVector3D(x, y, z)); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time,double x,double y,double z) + { + if (!node) { + value_[0] = x; + value_[1] = y; + value_[2] = z; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + const QString name = _descriptor.getName().c_str(); + Node::SetValueAtTime(NodeInput(node.get(), name), + rational::fromDouble(time), x, 0, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), + rational::fromDouble(time), y, 1, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), + rational::fromDouble(time), z, 2, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class Integer3DInstance : public OFX::Host::Param::Integer3DInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + int value_[3] = {0, 0, 0}; +public: + Integer3DInstance(std::shared_ptr effect, const std::string& name, + OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::Integer3DInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(int& x,int& y,int& z) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + z = value_[2]; + } else { + x = y = z = 0; + } + return kOfxStatOK; + } + QVector3D vec = + node->GetStandardValue(_descriptor.getName().c_str()) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + z = static_cast(vec.z()); + return kOfxStatOK; + } + OfxStatus get(OfxTime time,int& x,int& y,int& z) + { + if (!node) { + if (has_value_) { + x = value_[0]; + y = value_[1]; + z = value_[2]; + } else { + x = y = z = 0; + } + return kOfxStatOK; + } + QVector3D vec = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)) + .value(); + x = static_cast(vec.x()); + y = static_cast(vec.y()); + z = static_cast(vec.z()); + return kOfxStatOK; + } + OfxStatus set(int x,int y,int z) + { + if (!node) { + value_[0] = x; + value_[1] = y; + value_[2] = z; + has_value_ = true; + return kOfxStatOK; + } + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kVec3, QVector3D(x, y, z)); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time,int x,int y,int z) + { + if (!node) { + value_[0] = x; + value_[1] = y; + value_[2] = z; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + const QString name = _descriptor.getName().c_str(); + Node::SetValueAtTime(NodeInput(node.get(), name), + rational::fromDouble(time), x, 0, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), + rational::fromDouble(time), y, 1, command, true); + Node::SetValueAtTime(NodeInput(node.get(), name), + rational::fromDouble(time), z, 2, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class StringInstance : public OFX::Host::Param::StringInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + std::string value_; +public: + StringInstance(std::shared_ptr effect, const std::string& name, + OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::StringInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(std::string &data) + { + if (!node) { + data = has_value_ ? value_ : std::string(); + return kOfxStatOK; + } + QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); + if (variant.canConvert()) { + data = variant.toString().toStdString(); + return kOfxStatOK; + } + data.clear(); + return kOfxStatErrValue; + } + OfxStatus get(OfxTime time, std::string &data) + { + if (!node) { + data = has_value_ ? value_ : std::string(); + return kOfxStatOK; + } + QVariant variant = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)); + if (variant.canConvert()) { + data = variant.toString().toStdString(); + return kOfxStatOK; + } + data.clear(); + return kOfxStatErrValue; + } + OfxStatus set(const char *data) + { + if (!node) { + value_ = data ? data : ""; + has_value_ = true; + return kOfxStatOK; + } + QString v = QString::fromUtf8(data); + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kText, v); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, const char *data) + { + if (!node) { + value_ = data ? data : ""; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + Node::SetValueAtTime( + NodeInput(node.get(), _descriptor.getName().c_str()), + rational::fromDouble(time), QString::fromUtf8(data), 0, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class CustomInstance : public OFX::Host::Param::CustomInstance, + public NodeBoundParam { +protected: + std::shared_ptr node; + OFX::Host::Param::Descriptor& _descriptor; + bool has_value_ = false; + std::string value_; +public: + CustomInstance(std::shared_ptr effect, const std::string& name, + OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::CustomInstance(descriptor) + , node(effect) + , _descriptor(descriptor) + { + (void)name; + } + void SetNode(const std::shared_ptr &new_node) override + { + node = new_node; + } + OfxStatus get(std::string &data) + { + if (!node) { + data = has_value_ ? value_ : std::string(); + return kOfxStatOK; + } + QVariant variant = node->GetStandardValue(_descriptor.getName().c_str()); + if (variant.canConvert()) { + data = variant.toByteArray().toStdString(); + return kOfxStatOK; + } + if (variant.canConvert()) { + data = variant.toString().toStdString(); + return kOfxStatOK; + } + data.clear(); + return kOfxStatErrValue; + } + OfxStatus get(OfxTime time, std::string &data) + { + if (!node) { + data = has_value_ ? value_ : std::string(); + return kOfxStatOK; + } + QVariant variant = + node->GetValueAtTime(_descriptor.getName().c_str(), + rational::fromDouble(time)); + if (variant.canConvert()) { + data = variant.toByteArray().toStdString(); + return kOfxStatOK; + } + if (variant.canConvert()) { + data = variant.toString().toStdString(); + return kOfxStatOK; + } + data.clear(); + return kOfxStatErrValue; + } + OfxStatus set(const char *data) + { + if (!node) { + value_ = data ? data : ""; + has_value_ = true; + return kOfxStatOK; + } + QByteArray v = QByteArray(data); + SplitValue split = NodeValue::split_normal_value_into_track_values( + NodeValue::kBinary, v); + auto command = new NodeParamSetSplitStandardValueCommand( + NodeInput(node.get(), _descriptor.getName().c_str()), split); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } + OfxStatus set(OfxTime time, const char *data) + { + if (!node) { + value_ = data ? data : ""; + has_value_ = true; + return kOfxStatOK; + } + auto command = new MultiUndoCommand(); + Node::SetValueAtTime( + NodeInput(node.get(), _descriptor.getName().c_str()), + rational::fromDouble(time), QByteArray(data), 0, command, true); + SubmitUndoCommand(node, command, ParamChangeLabel(_descriptor)); + return kOfxStatOK; + } +}; + +class GroupInstance : public OFX::Host::Param::GroupInstance { +public: + GroupInstance(OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::GroupInstance(descriptor) + { + } +}; + +class PageInstance : public OFX::Host::Param::PageInstance { +public: + PageInstance(OFX::Host::Param::Descriptor& descriptor) + : OFX::Host::Param::PageInstance(descriptor) + { + } +}; +} +} + + + +#endif // HOST_DEMO_PARAM_INSTANCE_H diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt index 7b632d89f..bd54ff8b7 100644 --- a/app/render/CMakeLists.txt +++ b/app/render/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -17,7 +18,7 @@ add_subdirectory(job) add_subdirectory(ocioconf) add_subdirectory(opengl) - +add_subdirectory(plugin) set(OLIVE_SOURCES ${OLIVE_SOURCES} render/audioplaybackcache.cpp diff --git a/app/render/alphaassoc.h b/app/render/alphaassoc.h index c8b60d35a..977afe35b 100644 --- a/app/render/alphaassoc.h +++ b/app/render/alphaassoc.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index 430bbe619..a02c023ec 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index 5a458e96a..21776fc37 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/audiowaveformcache.cpp b/app/render/audiowaveformcache.cpp index 441d7b2d9..438177782 100644 --- a/app/render/audiowaveformcache.cpp +++ b/app/render/audiowaveformcache.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/audiowaveformcache.h b/app/render/audiowaveformcache.h index 7a224ddde..68b927e84 100644 --- a/app/render/audiowaveformcache.h +++ b/app/render/audiowaveformcache.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/cancelatom.h b/app/render/cancelatom.h index 544071302..caa2aadbe 100644 --- a/app/render/cancelatom.h +++ b/app/render/cancelatom.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef CANCELATOM_H #define CANCELATOM_H diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 59f987d46..36e23ba48 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h index 6588b5bcb..360262866 100644 --- a/app/render/colorprocessor.h +++ b/app/render/colorprocessor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/colorprocessorcache.h b/app/render/colorprocessorcache.h index 5289f7a86..12f8db82d 100644 --- a/app/render/colorprocessorcache.h +++ b/app/render/colorprocessorcache.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/colortransform.h b/app/render/colortransform.h index 676c05a1e..3598d3b5e 100644 --- a/app/render/colortransform.h +++ b/app/render/colortransform.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/diskmanager.cpp b/app/render/diskmanager.cpp index 59671f5c4..494fdf79a 100644 --- a/app/render/diskmanager.cpp +++ b/app/render/diskmanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/diskmanager.h b/app/render/diskmanager.h index 84fabca26..113730453 100644 --- a/app/render/diskmanager.h +++ b/app/render/diskmanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index 1f2e22f97..d8fa4642d 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/framehashcache.h b/app/render/framehashcache.h index 901b2da0f..100cd1d7a 100644 --- a/app/render/framehashcache.h +++ b/app/render/framehashcache.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/framemanager.cpp b/app/render/framemanager.cpp index 477233065..d700a6a1e 100644 --- a/app/render/framemanager.cpp +++ b/app/render/framemanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/framemanager.h b/app/render/framemanager.h index 626d9133c..14fd20616 100644 --- a/app/render/framemanager.h +++ b/app/render/framemanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/job/CMakeLists.txt b/app/render/job/CMakeLists.txt index 6ad233bbe..58d8a225d 100644 --- a/app/render/job/CMakeLists.txt +++ b/app/render/job/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -22,5 +23,7 @@ set(OLIVE_SOURCES render/job/generatejob.h render/job/samplejob.h render/job/shaderjob.h - PARENT_SCOPE + render/job/pluginjob.h + render/job/pluginjob.cpp + PARENT_SCOPE ) diff --git a/app/render/job/acceleratedjob.cpp b/app/render/job/acceleratedjob.cpp index 63cd8ea52..61f7eacc7 100644 --- a/app/render/job/acceleratedjob.cpp +++ b/app/render/job/acceleratedjob.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/job/acceleratedjob.h b/app/render/job/acceleratedjob.h index d7d194cc4..d2410595e 100644 --- a/app/render/job/acceleratedjob.h +++ b/app/render/job/acceleratedjob.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -35,22 +36,22 @@ public: { } - NodeValue Get(const QString &input) const + virtual NodeValue Get(const QString &input) const { return value_map_.value(input); } - void Insert(const QString &input, const NodeValueRow &row) + virtual void Insert(const QString &input, const NodeValueRow &row) { value_map_.insert(input, row.value(input)); } - void Insert(const QString &input, const NodeValue &value) + virtual void Insert(const QString &input, const NodeValue &value) { value_map_.insert(input, value); } - void Insert(const NodeValueRow &row) + virtual void Insert(const NodeValueRow &row) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) value_map_.insert(row); @@ -61,16 +62,16 @@ public: #endif } - const NodeValueRow &GetValues() const + virtual const NodeValueRow &GetValues() const { return value_map_; } - NodeValueRow &GetValues() + virtual NodeValueRow &GetValues() { return value_map_; } -private: +protected: NodeValueRow value_map_; }; diff --git a/app/render/job/cachejob.h b/app/render/job/cachejob.h index 37f60b227..cff208992 100644 --- a/app/render/job/cachejob.h +++ b/app/render/job/cachejob.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index ba9f7155e..f2ccead64 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/job/footagejob.h b/app/render/job/footagejob.h index bf156c888..f41acfec8 100644 --- a/app/render/job/footagejob.h +++ b/app/render/job/footagejob.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/job/generatejob.h b/app/render/job/generatejob.h index 3792aa0a8..934598efc 100644 --- a/app/render/job/generatejob.h +++ b/app/render/job/generatejob.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/job/pluginjob.cpp b/app/render/job/pluginjob.cpp new file mode 100644 index 000000000..20961d70d --- /dev/null +++ b/app/render/job/pluginjob.cpp @@ -0,0 +1,25 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "pluginjob.h" + +namespace olive { +namespace plugin { +} // plugin +} // olive \ No newline at end of file diff --git a/app/render/job/pluginjob.h b/app/render/job/pluginjob.h new file mode 100644 index 000000000..28831779b --- /dev/null +++ b/app/render/job/pluginjob.h @@ -0,0 +1,76 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef PLUGINJOB_H +#define PLUGINJOB_H +#include "acceleratedjob.h" +#include "pluginSupport/OlivePluginInstance.h" +#include "olive/core/util/rational.h" + +#include +#include + +namespace olive { +namespace plugin { + +class PluginJob :public AcceleratedJob{ +public: + explicit PluginJob(const OFX::Host::ImageEffect::Instance* pluginInstance, + const PluginNode* node, NodeValueRow row, + const olive::core::rational &time) + : AcceleratedJob() + , time_seconds_(time.toDouble()) + { + this->pluginInstance_ = pluginInstance; + this->node_=node; + Insert(row); + } + explicit PluginJob(const OFX::Host::ImageEffect::Instance* pluginInstance, + const PluginNode* node, NodeValueRow row) + : PluginJob(pluginInstance, node, row, olive::core::rational(0)) + { + } + + PluginNode *node() const { + return const_cast(node_); + } + + OFX::Host::ImageEffect::Instance* pluginInstance() { + return const_cast(pluginInstance_); + } + + double time_seconds() const { + return time_seconds_; + } + +private: + const OFX::Host::ImageEffect::Instance *pluginInstance_=nullptr; + + QHash> paramsOnTime; + + QHash params; + + const PluginNode *node_=nullptr; + double time_seconds_ = 0.0; +}; + +} // plugin +} // olive + +#endif //PLUGINJOB_H diff --git a/app/render/job/samplejob.h b/app/render/job/samplejob.h index c29a6972c..dbabc2079 100644 --- a/app/render/job/samplejob.h +++ b/app/render/job/samplejob.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/job/shaderjob.h b/app/render/job/shaderjob.h index e543c6261..d1ad16a4d 100644 --- a/app/render/job/shaderjob.h +++ b/app/render/job/shaderjob.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/loopmode.h b/app/render/loopmode.h index 307b3be5d..a33c89257 100644 --- a/app/render/loopmode.h +++ b/app/render/loopmode.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef LOOPMODE_H #define LOOPMODE_H diff --git a/app/render/managedcolor.cpp b/app/render/managedcolor.cpp index 996a76d91..cb1ebffdd 100644 --- a/app/render/managedcolor.cpp +++ b/app/render/managedcolor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/managedcolor.h b/app/render/managedcolor.h index 65de46ca1..70e4e3475 100644 --- a/app/render/managedcolor.h +++ b/app/render/managedcolor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index e3edc07bd..426237882 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -24,6 +25,7 @@ #include #include #include +#include #include "config/config.h" @@ -152,8 +154,9 @@ void OpenGLRenderer::DestroyInternal() if (context_) { GL_PREAMBLE; - // Delete framebuffer - functions_->glDeleteFramebuffers(1, &framebuffer_); + if (functions_ && framebuffer_) { + functions_->glDeleteFramebuffers(1, &framebuffer_); + } framebuffer_ = 0; // Delete context if it belongs to us @@ -161,6 +164,7 @@ void OpenGLRenderer::DestroyInternal() delete context_; } context_ = nullptr; + functions_ = nullptr; } } @@ -186,6 +190,9 @@ QVariant OpenGLRenderer::CreateNativeTexture(int width, int height, int depth, const void *data, int linesize) { GL_PREAMBLE; + if (!EnsureContextCurrent(__FUNCTION__)) { + return QVariant(); + } bool is_3d = depth > 1; @@ -236,7 +243,10 @@ void OpenGLRenderer::AttachTextureAsDestination(const QVariant &texture) void OpenGLRenderer::DetachTextureAsDestination() { - functions_->glBindFramebuffer(GL_FRAMEBUFFER, 0); + // QOpenGLWidget renders to a non-zero default FBO. + const GLuint default_fbo = + context_ ? context_->defaultFramebufferObject() : 0; + functions_->glBindFramebuffer(GL_FRAMEBUFFER, default_fbo); } void OpenGLRenderer::DestroyNativeTexture(QVariant texture) @@ -336,11 +346,28 @@ void OpenGLRenderer::DownloadFromTexture(const QVariant &id, { GL_PREAMBLE; + if (!EnsureContextCurrent(__FUNCTION__)) { + return; + } + + GLuint texture_id = id.value(); + if (!texture_id || !functions_->glIsTexture(texture_id)) { + qWarning() << "DownloadFromTexture called with invalid texture"; + return; + } + GLint current_tex; functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex); AttachTextureAsDestination(id); + GLenum status = functions_->glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + qWarning() << "DownloadFromTexture framebuffer incomplete" << status; + DetachTextureAsDestination(); + return; + } + functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize); { @@ -399,305 +426,317 @@ struct TextureToBind { Texture::Interpolation interpolation; }; -void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, +void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destination, VideoParams destination_params, bool clear_destination) { GL_PREAMBLE; - - // If this node is iterative, we'll pick up which input here - QMap texture_index_map; - QVector textures_to_bind; - - GLuint shader = s.value(); - - functions_->glUseProgram(shader); - - for (auto it = job.GetValues().constBegin(); - it != job.GetValues().constEnd(); it++) { - // See if the shader has takes this parameter as an input - GLint variable_location = functions_->glGetUniformLocation( - shader, it.key().toUtf8().constData()); - - if (variable_location == -1) { - continue; + try { + if (!destination) { + // Ensure we're drawing to the default framebuffer for this context. + GLuint fbo = context_ ? context_->defaultFramebufferObject() : 0; + functions_->glBindFramebuffer(GL_FRAMEBUFFER, fbo); } - // This variable is used in the shader, let's set it - const NodeValue &value = it.value(); + ShaderJob &s_job=dynamic_cast(a_job); + ShaderJob job(s_job); + // If this node is iterative, we'll pick up which input here + QMap texture_index_map; + QVector textures_to_bind; - // Arrays are not currently supported in this system - if (value.array()) { - continue; + GLuint shader = s.value(); + + functions_->glUseProgram(shader); + + for (auto it = job.GetValues().constBegin(); + it != job.GetValues().constEnd(); it++) { + // See if the shader has takes this parameter as an input + GLint variable_location = functions_->glGetUniformLocation( + shader, it.key().toUtf8().constData()); + + if (variable_location == -1) { + continue; + } + + // This variable is used in the shader, let's set it + const NodeValue &value = it.value(); + + // Arrays are not currently supported in this system + if (value.array()) { + continue; + } + + switch (value.type()) { + case NodeValue::kInt: + // kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to + // over/underflows if the number is large enough, but the likelihood of that is quite low. + functions_->glUniform1i(variable_location, value.toInt()); + break; + case NodeValue::kFloat: + // kFloat technically specifies a double but as above, OpenGL doesn't support those. + functions_->glUniform1f(variable_location, value.toDouble()); + break; + case NodeValue::kVec2: { + QVector2D v = value.toVec2(); + functions_->glUniform2fv(variable_location, 1, + reinterpret_cast(&v)); + break; + } + case NodeValue::kVec3: { + QVector3D v = value.toVec3(); + functions_->glUniform3fv(variable_location, 1, + reinterpret_cast(&v)); + break; + } + case NodeValue::kVec4: { + QVector4D v = value.toVec4(); + functions_->glUniform4fv(variable_location, 1, + reinterpret_cast(&v)); + break; + } + case NodeValue::kMatrix: + functions_->glUniformMatrix4fv(variable_location, 1, false, + value.toMatrix().constData()); + break; + case NodeValue::kCombo: + functions_->glUniform1i(variable_location, value.toInt()); + break; + case NodeValue::kColor: { + Color color = value.toColor(); + functions_->glUniform4f(variable_location, color.red(), + color.green(), color.blue(), color.alpha()); + break; + } + case NodeValue::kBoolean: + functions_->glUniform1i(variable_location, value.toBool()); + break; + case NodeValue::kTexture: { + TexturePtr texture = value.toTexture(); + + // Set value to bound texture + functions_->glUniform1i(variable_location, textures_to_bind.size()); + + texture_index_map.insert(it.key(), textures_to_bind.size()); + + textures_to_bind.append( + { texture, job.GetInterpolation(it.key()) }); + + // Set enable flag if shader wants it + GLuint tex_id = texture ? texture->id().value() : 0; + int enable_param_location = functions_->glGetUniformLocation( + shader, + QStringLiteral("%1_enabled").arg(it.key()).toUtf8().constData()); + if (enable_param_location > -1) { + functions_->glUniform1i(enable_param_location, tex_id > 0); + } + break; + } + case NodeValue::kSamples: + case NodeValue::kText: + case NodeValue::kRational: + case NodeValue::kFont: + case NodeValue::kFile: + case NodeValue::kVideoParams: + case NodeValue::kAudioParams: + case NodeValue::kSubtitleParams: + case NodeValue::kBezier: + case NodeValue::kBinary: + case NodeValue::kNone: + case NodeValue::kDataTypeCount: + break; + } } - switch (value.type()) { - case NodeValue::kInt: - // kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to - // over/underflows if the number is large enough, but the likelihood of that is quite low. - functions_->glUniform1i(variable_location, value.toInt()); - break; - case NodeValue::kFloat: - // kFloat technically specifies a double but as above, OpenGL doesn't support those. - functions_->glUniform1f(variable_location, value.toDouble()); - break; - case NodeValue::kVec2: { - QVector2D v = value.toVec2(); - functions_->glUniform2fv(variable_location, 1, - reinterpret_cast(&v)); - break; - } - case NodeValue::kVec3: { - QVector3D v = value.toVec3(); - functions_->glUniform3fv(variable_location, 1, - reinterpret_cast(&v)); - break; - } - case NodeValue::kVec4: { - QVector4D v = value.toVec4(); - functions_->glUniform4fv(variable_location, 1, - reinterpret_cast(&v)); - break; - } - case NodeValue::kMatrix: - functions_->glUniformMatrix4fv(variable_location, 1, false, - value.toMatrix().constData()); - break; - case NodeValue::kCombo: - functions_->glUniform1i(variable_location, value.toInt()); - break; - case NodeValue::kColor: { - Color color = value.toColor(); - functions_->glUniform4f(variable_location, color.red(), - color.green(), color.blue(), color.alpha()); - break; - } - case NodeValue::kBoolean: - functions_->glUniform1i(variable_location, value.toBool()); - break; - case NodeValue::kTexture: { - TexturePtr texture = value.toTexture(); + // Bind all textures + for (int i = 0; i < textures_to_bind.size(); i++) { + const TextureToBind &t = textures_to_bind.at(i); + TexturePtr texture = t.texture; - // Set value to bound texture - functions_->glUniform1i(variable_location, textures_to_bind.size()); - - texture_index_map.insert(it.key(), textures_to_bind.size()); - - textures_to_bind.append( - { texture, job.GetInterpolation(it.key()) }); - - // Set enable flag if shader wants it GLuint tex_id = texture ? texture->id().value() : 0; - int enable_param_location = functions_->glGetUniformLocation( - shader, - QStringLiteral("%1_enabled").arg(it.key()).toUtf8().constData()); - if (enable_param_location > -1) { - functions_->glUniform1i(enable_param_location, tex_id > 0); - } - break; - } - case NodeValue::kSamples: - case NodeValue::kText: - case NodeValue::kRational: - case NodeValue::kFont: - case NodeValue::kFile: - case NodeValue::kVideoParams: - case NodeValue::kAudioParams: - case NodeValue::kSubtitleParams: - case NodeValue::kBezier: - case NodeValue::kBinary: - case NodeValue::kNone: - case NodeValue::kDataTypeCount: - break; - } - } - // Bind all textures - for (int i = 0; i < textures_to_bind.size(); i++) { - const TextureToBind &t = textures_to_bind.at(i); - TexturePtr texture = t.texture; + functions_->glActiveTexture(GL_TEXTURE0 + i); - GLuint tex_id = texture ? texture->id().value() : 0; + GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D : + GL_TEXTURE_2D; + functions_->glBindTexture(target, tex_id); - functions_->glActiveTexture(GL_TEXTURE0 + i); + if (tex_id) { + PrepareInputTexture(target, t.interpolation); - GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D : - GL_TEXTURE_2D; - functions_->glBindTexture(target, tex_id); - - if (tex_id) { - PrepareInputTexture(target, t.interpolation); - - if (texture->channel_count() == 1 && - destination_params.channel_count() != 1) { - // Interpret this texture as a grayscale texture - functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, - GL_RED); - functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, - GL_RED); - functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, - GL_RED); + if (texture->channel_count() == 1 && + destination_params.channel_count() != 1) { + // Interpret this texture as a grayscale texture + functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, + GL_RED); + functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, + GL_RED); + functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, + GL_RED); + } } } - } - // Ensure matrix is set, at least to identity - GLint mvpmat_location = - functions_->glGetUniformLocation(shader, "ove_mvpmat"); - if (mvpmat_location > -1) { - functions_->glUniformMatrix4fv( - mvpmat_location, 1, false, - job.Get(QStringLiteral("ove_mvpmat")).toMatrix().constData()); - } + // Ensure matrix is set, at least to identity + GLint mvpmat_location = + functions_->glGetUniformLocation(shader, "ove_mvpmat"); + if (mvpmat_location > -1) { + functions_->glUniformMatrix4fv( + mvpmat_location, 1, false, + job.Get(QStringLiteral("ove_mvpmat")).toMatrix().constData()); + } - // Set the viewport to the "physical" resolution of the destination - functions_->glViewport(0, 0, destination_params.effective_width(), - destination_params.effective_height()); + // Set the viewport to the "physical" resolution of the destination + functions_->glViewport(0, 0, destination_params.effective_width(), + destination_params.effective_height()); - // Bind vertex array object - QOpenGLVertexArrayObject vao_; - vao_.create(); - vao_.bind(); + // Bind vertex array object + QOpenGLVertexArrayObject vao_; + vao_.create(); + vao_.bind(); - // Set buffers - QOpenGLBuffer vert_vbo_; - vert_vbo_.create(); - vert_vbo_.bind(); - // If the job has vertex coordinate overrides use them instead of the defaults. - if (!job.GetVertexCoordinates().isEmpty()) { - Q_ASSERT(job.GetVertexCoordinates().size() == 18); - vert_vbo_.allocate(job.GetVertexCoordinates().constData(), - job.GetVertexCoordinates().size() * sizeof(float)); - } else { - vert_vbo_.allocate(blit_vertices.constData(), - blit_vertices.size() * sizeof(GLfloat)); - } - vert_vbo_.release(); - - QOpenGLBuffer frag_vbo_; - frag_vbo_.create(); - frag_vbo_.bind(); - frag_vbo_.allocate(blit_texcoords.constData(), - blit_texcoords.size() * sizeof(GLfloat)); - frag_vbo_.release(); - - GLint vertex_location = - functions_->glGetAttribLocation(shader, "a_position"); - if (vertex_location != -1) { + // Set buffers + QOpenGLBuffer vert_vbo_; + vert_vbo_.create(); vert_vbo_.bind(); - functions_->glEnableVertexAttribArray(vertex_location); - functions_->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, - GL_FALSE, 0, nullptr); - vert_vbo_.release(); - } - - GLint tex_location = functions_->glGetAttribLocation(shader, "a_texcoord"); - if (tex_location != -1) { - frag_vbo_.bind(); - functions_->glEnableVertexAttribArray(tex_location); - functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, - 0, nullptr); - frag_vbo_.release(); - } - - // Some shaders optimize through multiple iterations which requires ping-ponging textures - // - If there are only two iterations, we can just create one backend texture and then the - // destination can be the second - // - If there are more than two iterations, we need to ping pong back and forth between two - // textures. We can still use the destination as the last iteration, but we'll need textures - // for the iterative process. - int real_iteration_count; - if (job.GetIterationCount() > 1 && !job.GetIterativeInput().isEmpty()) { - real_iteration_count = job.GetIterationCount(); - } else { - real_iteration_count = 1; - } - - TexturePtr output_tex, input_tex; - if (real_iteration_count > 1) { - // Create one texture to bounce off - output_tex = CreateTexture(destination_params); - - if (real_iteration_count > 2) { - // Create a second texture bounce off - input_tex = CreateTexture(destination_params); - } - } - - GLint iteration_location = - functions_->glGetUniformLocation(shader, "ove_iteration"); - for (int iteration = 0; iteration < real_iteration_count; iteration++) { - // Set iteration number - if (iteration_location > -1) { - functions_->glUniform1i(iteration_location, iteration); - } - - // Replace iterative input - if (iteration == real_iteration_count - 1) { - // This is the last iteration, draw to the destination - if (destination) { - // If we have a destination texture, draw to it - AttachTextureAsDestination(destination->id()); - } else if (iteration > 0) { - // Otherwise, if we were iterating before, detach texture now - DetachTextureAsDestination(); - } - - // Clear the destination if the caller requested it - if (clear_destination) { - ClearDestinationInternal(); - } + // If the job has vertex coordinate overrides use them instead of the defaults. + if (!job.GetVertexCoordinates().isEmpty()) { + Q_ASSERT(job.GetVertexCoordinates().size() == 18); + vert_vbo_.allocate(job.GetVertexCoordinates().constData(), + job.GetVertexCoordinates().size() * sizeof(float)); } else { - // Always draw to output_tex, which gets swapped with input_tex every iteration - AttachTextureAsDestination(output_tex->id()); + vert_vbo_.allocate(blit_vertices.constData(), + blit_vertices.size() * sizeof(GLfloat)); + } + vert_vbo_.release(); + + QOpenGLBuffer frag_vbo_; + frag_vbo_.create(); + frag_vbo_.bind(); + frag_vbo_.allocate(blit_texcoords.constData(), + blit_texcoords.size() * sizeof(GLfloat)); + frag_vbo_.release(); + + GLint vertex_location = + functions_->glGetAttribLocation(shader, "a_position"); + if (vertex_location != -1) { + vert_vbo_.bind(); + functions_->glEnableVertexAttribArray(vertex_location); + functions_->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, + GL_FALSE, 0, nullptr); + vert_vbo_.release(); } - if (iteration > 0) { - // If this is not the first iteration, replace the iterative texture with the one we - // last drew - const QString &iterative_input = job.GetIterativeInput(); - functions_->glActiveTexture( - GL_TEXTURE0 + texture_index_map.value(iterative_input)); - functions_->glBindTexture(GL_TEXTURE_2D, - input_tex->id().value()); - - // At this time, we only support iterating 2D textures - PrepareInputTexture(GL_TEXTURE_2D, - job.GetInterpolation(iterative_input)); + GLint tex_location = functions_->glGetAttribLocation(shader, "a_texcoord"); + if (tex_location != -1) { + frag_vbo_.bind(); + functions_->glEnableVertexAttribArray(tex_location); + functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, + 0, nullptr); + frag_vbo_.release(); } - // Swap so that the next iteration, the texture we draw now will be the input texture next - std::swap(output_tex, input_tex); - - // Blit this texture through this shader - { - PRINT_GL_ERRORS; - functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3); + // Some shaders optimize through multiple iterations which requires ping-ponging textures + // - If there are only two iterations, we can just create one backend texture and then the + // destination can be the second + // - If there are more than two iterations, we need to ping pong back and forth between two + // textures. We can still use the destination as the last iteration, but we'll need textures + // for the iterative process. + int real_iteration_count; + if (job.GetIterationCount() > 1 && !job.GetIterativeInput().isEmpty()) { + real_iteration_count = job.GetIterationCount(); + } else { + real_iteration_count = 1; } + + TexturePtr output_tex, input_tex; + if (real_iteration_count > 1) { + // Create one texture to bounce off + output_tex = CreateTexture(destination_params); + + if (real_iteration_count > 2) { + // Create a second texture bounce off + input_tex = CreateTexture(destination_params); + } + } + + GLint iteration_location = + functions_->glGetUniformLocation(shader, "ove_iteration"); + for (int iteration = 0; iteration < real_iteration_count; iteration++) { + // Set iteration number + if (iteration_location > -1) { + functions_->glUniform1i(iteration_location, iteration); + } + + // Replace iterative input + if (iteration == real_iteration_count - 1) { + // This is the last iteration, draw to the destination + if (destination) { + // If we have a destination texture, draw to it + AttachTextureAsDestination(destination->id()); + } else if (iteration > 0) { + // Otherwise, if we were iterating before, detach texture now + DetachTextureAsDestination(); + } + + // Clear the destination if the caller requested it + if (clear_destination) { + ClearDestinationInternal(); + } + } else { + // Always draw to output_tex, which gets swapped with input_tex every iteration + AttachTextureAsDestination(output_tex->id()); + } + + if (iteration > 0) { + // If this is not the first iteration, replace the iterative texture with the one we + // last drew + const QString &iterative_input = job.GetIterativeInput(); + functions_->glActiveTexture( + GL_TEXTURE0 + texture_index_map.value(iterative_input)); + functions_->glBindTexture(GL_TEXTURE_2D, + input_tex->id().value()); + + // At this time, we only support iterating 2D textures + PrepareInputTexture(GL_TEXTURE_2D, + job.GetInterpolation(iterative_input)); + } + + // Swap so that the next iteration, the texture we draw now will be the input texture next + std::swap(output_tex, input_tex); + + // Blit this texture through this shader + { + PRINT_GL_ERRORS; + functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3); + } + + } + + if (destination) { + // Reset framebuffer to default if we were drawing to a texture + DetachTextureAsDestination(); + } + + // Release any textures we bound before + for (int i = textures_to_bind.size() - 1; i >= 0; i--) { + TexturePtr texture = textures_to_bind.at(i).texture; + GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D : + GL_TEXTURE_2D; + functions_->glActiveTexture(GL_TEXTURE0 + i); + functions_->glBindTexture(target, 0); + } + + // Release shader + functions_->glUseProgram(0); + + // Release vertex array object + frag_vbo_.destroy(); + vert_vbo_.destroy(); + vao_.release(); + vao_.destroy(); } + catch (std::bad_cast e){} - if (destination) { - // Reset framebuffer to default if we were drawing to a texture - DetachTextureAsDestination(); - } - - // Release any textures we bound before - for (int i = textures_to_bind.size() - 1; i >= 0; i--) { - TexturePtr texture = textures_to_bind.at(i).texture; - GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D : - GL_TEXTURE_2D; - functions_->glActiveTexture(GL_TEXTURE0 + i); - functions_->glBindTexture(target, 0); - } - - // Release shader - functions_->glUseProgram(0); - - // Release vertex array object - frag_vbo_.destroy(); - vert_vbo_.destroy(); - vao_.release(); - vao_.destroy(); } GLint OpenGLRenderer::GetInternalFormat(PixelFormat format, int channel_layout) @@ -831,28 +870,65 @@ void OpenGLRenderer::ClearDestinationInternal(double r, double g, double b, GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code) { - static const QString shader_preamble = + const bool is_gles = context_ && context_->isOpenGLES(); + const int major = context_ ? context_->format().majorVersion() : 0; + const int minor = context_ ? context_->format().minorVersion() : 0; + const bool is_gles2 = is_gles && (major < 3); + const QString gles_preamble = is_gles2 + ? QStringLiteral("#version 100\n\n" + "precision highp float;\n\n" + "#define frag_color gl_FragColor\n") + : QStringLiteral("#version 300 es\n\n" + "precision highp float;\n\n"); + const QString desktop_preamble = // Use appropriate GL 3.2 shader header QStringLiteral("#version 150\n\n" "precision highp float;\n\n"); + const QString shader_preamble = is_gles ? gles_preamble : desktop_preamble; - QString complete_code; - - if (!code.startsWith(QStringLiteral("#version"))) { - complete_code = shader_preamble; - } - - if (code.isEmpty()) { + QString base_code = code; + if (base_code.isEmpty()) { // Use default code if (type == GL_FRAGMENT_SHADER) { - complete_code.append(FileFunctions::ReadFileAsString( - QStringLiteral(":/shaders/default.frag"))); + base_code = FileFunctions::ReadFileAsString( + QStringLiteral(":/shaders/default.frag")); } else if (type == GL_VERTEX_SHADER) { - complete_code.append(FileFunctions::ReadFileAsString( - QStringLiteral(":/shaders/default.vert"))); + base_code = FileFunctions::ReadFileAsString( + QStringLiteral(":/shaders/default.vert")); + } + } + + QString complete_code; + if (base_code.startsWith(QStringLiteral("#version"))) { + if (is_gles || !desktop_preamble.startsWith(QStringLiteral("#version"))) { + int newline = base_code.indexOf('\n'); + if (newline >= 0) { + complete_code = shader_preamble + base_code.mid(newline + 1); + } else { + complete_code = shader_preamble; + } + } else { + complete_code = base_code; } } else { - complete_code.append(code); + complete_code = shader_preamble + base_code; + } + + if (is_gles2) { + if (type == GL_VERTEX_SHADER) { + complete_code.replace(QRegularExpression(QStringLiteral("\\bin\\b")), + QStringLiteral("attribute")); + complete_code.replace(QRegularExpression(QStringLiteral("\\bout\\b")), + QStringLiteral("varying")); + } else if (type == GL_FRAGMENT_SHADER) { + complete_code.replace(QRegularExpression(QStringLiteral("\\bin\\b")), + QStringLiteral("varying")); + complete_code.replace(QRegularExpression( + QStringLiteral("\\bout\\s+vec4\\s+frag_color\\s*;")), + QStringLiteral("// frag_color output")); + complete_code.replace(QRegularExpression(QStringLiteral("\\btexture\\b")), + QStringLiteral("texture2D")); + } } QByteArray code_utf8 = complete_code.toUtf8(); @@ -880,4 +956,39 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code) return shader; } +bool OpenGLRenderer::EnsureContextCurrent(const char *caller) +{ + if (!context_) { + qWarning() << caller << "called without an OpenGL context"; + return false; + } + + if (QOpenGLContext::currentContext() != context_) { + if (context_->parent() == this && surface_.isValid()) { + if (!context_->makeCurrent(&surface_)) { + qWarning() << caller << "failed to make context current"; + return false; + } + } else { + qWarning() << caller << "OpenGL context not current"; + return false; + } + } + + if (!functions_) { + functions_ = context_->functions(); + } + + if (!functions_) { + qWarning() << caller << "OpenGL functions not available"; + return false; + } + + if (!framebuffer_) { + functions_->glGenFramebuffers(1, &framebuffer_); + } + + return true; +} + } diff --git a/app/render/opengl/openglrenderer.h b/app/render/opengl/openglrenderer.h index fce283bce..100a4307c 100644 --- a/app/render/opengl/openglrenderer.h +++ b/app/render/opengl/openglrenderer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -70,8 +71,15 @@ public: virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) override; + QOpenGLContext *context() const + { + return context_; + } + + bool EnsureContextCurrent(const char *caller); + protected: - virtual void Blit(QVariant shader, olive::ShaderJob job, + virtual void Blit(QVariant shader, olive::AcceleratedJob& job, olive::Texture *destination, olive::VideoParams destination_params, bool clear_destination) override; @@ -85,6 +93,10 @@ protected: virtual void DestroyInternal() override; + void AttachTextureAsDestination(const QVariant &texture); + + void DetachTextureAsDestination(); + private: static GLint GetInternalFormat(PixelFormat format, int channel_layout); @@ -92,10 +104,6 @@ private: static GLenum GetPixelFormat(int channel_count); - void AttachTextureAsDestination(const QVariant &texture); - - void DetachTextureAsDestination(); - void PrepareInputTexture(GLenum target, Texture::Interpolation interp); void ClearDestinationInternal(double r = 0.0, double g = 0.0, diff --git a/app/render/playbackcache.cpp b/app/render/playbackcache.cpp index 49385f01d..0a136984a 100644 --- a/app/render/playbackcache.cpp +++ b/app/render/playbackcache.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/playbackcache.h b/app/render/playbackcache.h index 4853aab75..c1747b874 100644 --- a/app/render/playbackcache.h +++ b/app/render/playbackcache.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/plugin/CMakeLists.txt b/app/render/plugin/CMakeLists.txt new file mode 100644 index 000000000..06ebc85d7 --- /dev/null +++ b/app/render/plugin/CMakeLists.txt @@ -0,0 +1,6 @@ +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + render/plugin/pluginrenderer.cpp + render/plugin/pluginrenderer.h + PARENT_SCOPE +) \ No newline at end of file diff --git a/app/render/plugin/pluginrenderer.cpp b/app/render/plugin/pluginrenderer.cpp new file mode 100644 index 000000000..f4a6bc471 --- /dev/null +++ b/app/render/plugin/pluginrenderer.cpp @@ -0,0 +1,1706 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// +// Created by mikesolar on 25-10-19. +// +#include "ofxCore.h" +#include "ofxhPropertySuite.h" +#include "olive/core/render/pixelformat.h" +#include "render/texture.h" +#include "render/opengl/openglrenderer.h" +#include "node/value.h" +#include "render/videoparams.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define GL_PREAMBLE //QMutexLocker __l(&global_opengl_mutex); +#include "pluginrenderer.h" +#include "pluginSupport/OliveClip.h" +#include "pluginSupport/OlivePluginInstance.h" +#include "common/ffmpegutils.h" +#include "ofxhParam.h" +#include "ofxImageEffect.h" +#include "ofxhUtilities.h" +#include "ofxGPURender.h" +#include "olive/core/util/color.h" +extern "C"{ +#include +#include +#include +} + + +// 作用:从 OFX Image 属性推导 FFmpeg 像素格式,并返回每像素字节数。 +// Purpose: Infer FFmpeg pixel format from OFX image properties and return bytes-per-pixel. +static AVPixelFormat GetOfxAVPixelFormat(const OFX::Host::ImageEffect::Image &image, + int *bytes_per_pixel) +{ + const std::string &depth = image.getStringProperty(kOfxImageEffectPropPixelDepth); + const std::string &components = image.getStringProperty(kOfxImageEffectPropComponents); + + olive::core::PixelFormat pixel_format = olive::core::PixelFormat::INVALID; + if (depth == kOfxBitDepthByte) { + pixel_format = olive::core::PixelFormat::U8; + } else if (depth == kOfxBitDepthShort) { + pixel_format = olive::core::PixelFormat::U16; + } else if (depth == kOfxBitDepthHalf) { + pixel_format = olive::core::PixelFormat::F16; + } else if (depth == kOfxBitDepthFloat) { + pixel_format = olive::core::PixelFormat::F32; + } + + int channel_count = 0; + if (components == kOfxImageComponentRGBA) { + channel_count = 4; + } else if (components == kOfxImageComponentRGB) { + channel_count = 3; + } else if (components == kOfxImageComponentAlpha) { + channel_count = 1; + } + + AVPixelFormat pix_fmt = olive::FFmpegUtils::GetFFmpegPixelFormat(pixel_format, channel_count); + if (pix_fmt == AV_PIX_FMT_NONE && channel_count == 1) { + if (pixel_format == olive::core::PixelFormat::U8) { + pix_fmt = AV_PIX_FMT_GRAY8; + } else if (pixel_format == olive::core::PixelFormat::U16) { + pix_fmt = AV_PIX_FMT_GRAY16LE; + } else if (pixel_format == olive::core::PixelFormat::F16) { + pix_fmt = AV_PIX_FMT_GRAYF16; + } else if (pixel_format == olive::core::PixelFormat::F32) { + pix_fmt = AV_PIX_FMT_GRAYF32; + } + } + + if (pix_fmt == AV_PIX_FMT_NONE) { + return AV_PIX_FMT_NONE; + } + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) { + return AV_PIX_FMT_NONE; + } + + int bits_per_pixel = av_get_bits_per_pixel(desc); + if (bits_per_pixel <= 0 || bits_per_pixel % 8 != 0) { + return AV_PIX_FMT_NONE; + } + + *bytes_per_pixel = bits_per_pixel / 8; + return pix_fmt; +} + +// 作用:为插件实例注入当前帧的参数值,避免依赖节点实时回读。 +static void ApplyParamOverrides(OFX::Host::ImageEffect::Instance &instance, + const olive::NodeValueRow &values, + OfxTime time) +{ + const auto ¶ms = instance.getParams(); + for (const auto &entry : params) { + if (!entry.second) { + continue; + } + const QString key = QString::fromStdString(entry.first); + if (!values.contains(key)) { + continue; + } + const olive::NodeValue &value = values.value(key); + if (value.type() == olive::NodeValue::kNone || + value.type() == olive::NodeValue::kTexture || + value.type() == olive::NodeValue::kSamples) { + continue; + } + const std::string &type = entry.second->getType(); + + if (type == kOfxParamTypeInteger) { + if (auto *param = + dynamic_cast( + entry.second)) { + param->set(time, value.data().toInt()); + } + continue; + } + if (type == kOfxParamTypeDouble) { + if (auto *param = + dynamic_cast( + entry.second)) { + param->set(time, value.data().toDouble()); + } + continue; + } + if (type == kOfxParamTypeBoolean) { + if (auto *param = + dynamic_cast( + entry.second)) { + param->set(time, value.data().toBool()); + } + continue; + } + if (type == kOfxParamTypeChoice) { + if (auto *param = + dynamic_cast( + entry.second)) { + param->set(time, value.data().toInt()); + } + continue; + } + if (type == kOfxParamTypeString || type == kOfxParamTypeCustom || + type == kOfxParamTypeBytes || type == kOfxParamTypeStrChoice) { + if (auto *param = + dynamic_cast( + entry.second)) { + const QByteArray utf8 = value.data().toString().toUtf8(); + param->set(time, utf8.constData()); + } + continue; + } + if (type == kOfxParamTypeRGBA) { + if (auto *param = + dynamic_cast( + entry.second)) { + if (value.data().canConvert()) { + const auto c = value.data().value(); + param->set(time, c.red(), c.green(), c.blue(), c.alpha()); + } else if (value.data().canConvert()) { + const QVector4D v = value.data().value(); + param->set(time, v.x(), v.y(), v.z(), v.w()); + } else if (value.data().canConvert()) { + const QVector3D v = value.data().value(); + param->set(time, v.x(), v.y(), v.z(), 1.0); + } + } + continue; + } + if (type == kOfxParamTypeRGB) { + if (auto *param = + dynamic_cast( + entry.second)) { + if (value.data().canConvert()) { + const auto c = value.data().value(); + param->set(time, c.red(), c.green(), c.blue()); + } else if (value.data().canConvert()) { + const QVector4D v = value.data().value(); + param->set(time, v.x(), v.y(), v.z()); + } else if (value.data().canConvert()) { + const QVector3D v = value.data().value(); + param->set(time, v.x(), v.y(), v.z()); + } + } + continue; + } + if (type == kOfxParamTypeDouble2D) { + if (auto *param = + dynamic_cast( + entry.second)) { + if (value.data().canConvert()) { + const QVector2D v = value.data().value(); + param->set(time, v.x(), v.y()); + } + } + continue; + } + if (type == kOfxParamTypeInteger2D) { + if (auto *param = + dynamic_cast( + entry.second)) { + if (value.data().canConvert()) { + const QVector2D v = value.data().value(); + param->set(time, static_cast(v.x()), + static_cast(v.y())); + } + } + continue; + } + if (type == kOfxParamTypeDouble3D) { + if (auto *param = + dynamic_cast( + entry.second)) { + if (value.data().canConvert()) { + const QVector3D v = value.data().value(); + param->set(time, v.x(), v.y(), v.z()); + } + } + continue; + } + if (type == kOfxParamTypeInteger3D) { + if (auto *param = + dynamic_cast( + entry.second)) { + if (value.data().canConvert()) { + const QVector3D v = value.data().value(); + param->set(time, static_cast(v.x()), + static_cast(v.y()), + static_cast(v.z())); + } + } + continue; + } + } +} + +static AVPixelFormat GetDestinationAVPixelFormat(const olive::VideoParams ¶ms); + +// 作用:读取 clip 偏好(像素深度与分量)并更新 VideoParams。 +// Purpose: Apply clip preferences (depth/components) into VideoParams. +static bool ApplyClipPreferencesToParams( + const OFX::Host::ImageEffect::ClipInstance &clip, + olive::VideoParams *params) +{ + if (!params) { + return false; + } + + olive::core::PixelFormat format = olive::core::PixelFormat::INVALID; + const std::string &depth = clip.getPixelDepth(); + if (depth == kOfxBitDepthByte) { + format = olive::core::PixelFormat::U8; + } else if (depth == kOfxBitDepthShort) { + format = olive::core::PixelFormat::U16; + } else if (depth == kOfxBitDepthHalf) { + format = olive::core::PixelFormat::F16; + } else if (depth == kOfxBitDepthFloat) { + format = olive::core::PixelFormat::F32; + } + + int channels = 0; + const std::string &components = clip.getComponents(); + if (components == kOfxImageComponentRGBA) { + channels = 4; + } else if (components == kOfxImageComponentRGB) { + channels = 3; + } else if (components == kOfxImageComponentAlpha) { + channels = 1; + } + + if (format == olive::core::PixelFormat::INVALID || channels == 0) { + return false; + } + + params->set_format(format); + params->set_channel_count(channels); + return true; +} + +// 作用:将 OFX bit depth 字符串映射为内部 PixelFormat。 +// Purpose: Map OFX bit depth string to internal PixelFormat. +static olive::core::PixelFormat PixelFormatFromOfxDepth( + const std::string &depth) +{ + if (depth == kOfxBitDepthByte) { + return olive::core::PixelFormat::U8; + } + if (depth == kOfxBitDepthShort) { + return olive::core::PixelFormat::U16; + } + if (depth == kOfxBitDepthHalf) { + return olive::core::PixelFormat::F16; + } + if (depth == kOfxBitDepthFloat) { + return olive::core::PixelFormat::F32; + } + return olive::core::PixelFormat::INVALID; +} + +// 作用:将内部 PixelFormat 转为 OFX bit depth 字符串。 +// Purpose: Map internal PixelFormat to OFX bit depth string. +static const char *OfxDepthFromPixelFormat(olive::core::PixelFormat format) +{ + switch (format) { + case olive::core::PixelFormat::U8: + return kOfxBitDepthByte; + case olive::core::PixelFormat::U16: + return kOfxBitDepthShort; + case olive::core::PixelFormat::F16: + return kOfxBitDepthHalf; + case olive::core::PixelFormat::F32: + return kOfxBitDepthFloat; + case olive::core::PixelFormat::INVALID: + case olive::core::PixelFormat::COUNT: + break; + } + return kOfxBitDepthNone; +} + +// 作用:将 OFX components 字符串映射为通道数。 +// Purpose: Map OFX components string to channel count. +static int ChannelCountFromOfxComponent(const std::string &components) +{ + if (components == kOfxImageComponentRGBA) { + return 4; + } + if (components == kOfxImageComponentRGB) { + return 3; + } + if (components == kOfxImageComponentAlpha) { + return 1; + } + return 0; +} + +// 作用:将通道数映射为 OFX components 字符串。 +// Purpose: Map channel count to OFX components string. +static const char *OfxComponentsFromChannels(int channel_count) +{ + switch (channel_count) { + case 1: + return kOfxImageComponentAlpha; + case 3: + return kOfxImageComponentRGB; + case 4: + return kOfxImageComponentRGBA; + default: + break; + } + return kOfxImageComponentNone; +} + +// 作用:判断插件是否支持指定像素深度。 +// Purpose: Check whether effect supports a given pixel depth. +static bool EffectSupportsPixelDepth( + const OFX::Host::ImageEffect::Instance &instance, + const std::string &depth) +{ + const auto &effect_props = instance.getDescriptor().getProps(); + const int depth_count = + effect_props.getDimension(kOfxImageEffectPropSupportedPixelDepths); + for (int i = 0; i < depth_count; ++i) { + if (effect_props.getStringProperty( + kOfxImageEffectPropSupportedPixelDepths, i) == depth) { + return true; + } + } + return false; +} + +// 作用:判断 clip 是否支持指定组件格式。 +// Purpose: Check whether clip supports a given components string. +static bool ClipSupportsComponents( + const OFX::Host::ImageEffect::ClipInstance &clip, + const std::string &components) +{ + const auto &supported_components = clip.getSupportedComponents(); + for (const auto &comp : supported_components) { + if (comp == components) { + return true; + } + } + return false; +} + +// 作用:估算从源参数到目标参数的转换代价,用于排序选择。 +// Purpose: Estimate conversion cost from source to target params for ranking. +static int ConversionCost(const olive::VideoParams &src, + const olive::VideoParams &dst) +{ + const int src_bpp = src.channel_count() * src.format().byte_count(); + const int dst_bpp = dst.channel_count() * dst.format().byte_count(); + int cost = std::abs(dst_bpp - src_bpp); + if (src.format() != dst.format()) { + cost += 4; + } + if (src.channel_count() != dst.channel_count()) { + cost += 2; + } + return cost; +} + +// 作用:判断目标参数能否转换为可用的 AVPixelFormat。 +// Purpose: Check if params map to a valid AVPixelFormat. +static bool ParamsConvertible(const olive::VideoParams ¶ms) +{ + return GetDestinationAVPixelFormat(params) != AV_PIX_FMT_NONE; +} + +// 作用:在 clip 偏好无效时,选择一个插件支持的输出格式。 +// Purpose: Pick a supported output format when clip preferences are invalid. +static void ChooseSupportedOutputParams( + const OFX::Host::ImageEffect::Instance &instance, + const OFX::Host::ImageEffect::ClipInstance &clip, + const olive::VideoParams &preferred, + olive::VideoParams *out) +{ + if (!out) { + return; + } + + *out = preferred; + + const char *preferred_components = + OfxComponentsFromChannels(preferred.channel_count()); + if (std::strcmp(preferred_components, kOfxImageComponentNone) != 0 && + ClipSupportsComponents(clip, preferred_components)) { + out->set_channel_count(preferred.channel_count()); + } else if (ClipSupportsComponents(clip, kOfxImageComponentRGBA)) { + out->set_channel_count(4); + } else if (ClipSupportsComponents(clip, kOfxImageComponentRGB)) { + out->set_channel_count(3); + } else if (ClipSupportsComponents(clip, kOfxImageComponentAlpha)) { + out->set_channel_count(1); + } + + const olive::core::PixelFormat preferred_format = preferred.format(); + const std::array candidates = { + preferred_format, + olive::core::PixelFormat::F16, + olive::core::PixelFormat::F32, + olive::core::PixelFormat::U16, + olive::core::PixelFormat::U8, + }; + for (const auto &candidate : candidates) { + if (candidate == olive::core::PixelFormat::INVALID) { + continue; + } + if (!EffectSupportsPixelDepth( + instance, OfxDepthFromPixelFormat(candidate))) { + continue; + } + olive::VideoParams test_params = *out; + test_params.set_format(candidate); + if (!ParamsConvertible(test_params)) { + continue; + } + out->set_format(candidate); + return; + } +} + +static olive::TexturePtr ConvertTextureForParams( + olive::TexturePtr src, + const olive::VideoParams &dst_params); + +// 作用:根据插件能力与偏好选择输入格式并执行转换。 +// Purpose: Select a supported input format and convert texture for the clip. +static olive::TexturePtr ConvertTextureForClip( + const OFX::Host::ImageEffect::Instance &instance, + const OFX::Host::ImageEffect::ClipInstance &clip, + olive::TexturePtr src, + const olive::VideoParams &preferred_params, + bool force_preferred, + olive::VideoParams *out_params) +{ + if (!src || !out_params) { + return nullptr; + } + + const olive::VideoParams &src_params = src->params(); + auto add_candidate = [](std::vector &list, + const olive::VideoParams ¶ms) { + for (const auto &existing : list) { + if (existing.format() == params.format() && + existing.channel_count() == params.channel_count()) { + return; + } + } + list.push_back(params); + }; + + std::vector channel_candidates; + const auto &supported_components = clip.getSupportedComponents(); + for (const auto &comp : supported_components) { + int channels = ChannelCountFromOfxComponent(comp); + if (channels > 0 && + std::find(channel_candidates.begin(), + channel_candidates.end(), + channels) == channel_candidates.end()) { + channel_candidates.push_back(channels); + } + } + if (channel_candidates.empty() && preferred_params.channel_count() > 0) { + channel_candidates.push_back(preferred_params.channel_count()); + } + + std::vector format_candidates; + const auto &effect_props = instance.getDescriptor().getProps(); + const int depth_count = + effect_props.getDimension(kOfxImageEffectPropSupportedPixelDepths); + for (int i = 0; i < depth_count; ++i) { + olive::core::PixelFormat fmt = + PixelFormatFromOfxDepth(effect_props.getStringProperty( + kOfxImageEffectPropSupportedPixelDepths, i)); + if (fmt != olive::core::PixelFormat::INVALID && + std::find(format_candidates.begin(), + format_candidates.end(), + fmt) == format_candidates.end()) { + format_candidates.push_back(fmt); + } + } + if (format_candidates.empty() && + preferred_params.format() != olive::core::PixelFormat::INVALID) { + format_candidates.push_back(preferred_params.format()); + } + + std::vector candidates; + add_candidate(candidates, preferred_params); + + const bool prefer_rgba8 = + (preferred_params.format() == olive::core::PixelFormat::U8 || + preferred_params.format() == olive::core::PixelFormat::INVALID) && + ClipSupportsComponents(clip, kOfxImageComponentRGBA) && + EffectSupportsPixelDepth(instance, kOfxBitDepthByte); + if (prefer_rgba8) { + olive::VideoParams rgba_candidate = src_params; + rgba_candidate.set_format(olive::core::PixelFormat::U8); + rgba_candidate.set_channel_count(4); + if (ParamsConvertible(rgba_candidate)) { + add_candidate(candidates, rgba_candidate); + } + } + + for (olive::core::PixelFormat fmt : format_candidates) { + for (int channels : channel_candidates) { + if (fmt == olive::core::PixelFormat::INVALID || channels <= 0) { + continue; + } + olive::VideoParams candidate = src_params; + candidate.set_format(fmt); + candidate.set_channel_count(channels); + if (!ParamsConvertible(candidate)) { + continue; + } + add_candidate(candidates, candidate); + } + } + + if (candidates.empty()) { + return nullptr; + } + + std::stable_sort(candidates.begin(), candidates.end(), + [&src_params, &preferred_params, prefer_rgba8, force_preferred](const auto &a, + const auto &b) { + if (force_preferred) { + const bool a_pref = (a.format() == preferred_params.format() && + a.channel_count() == preferred_params.channel_count()); + const bool b_pref = (b.format() == preferred_params.format() && + b.channel_count() == preferred_params.channel_count()); + if (a_pref != b_pref) { + return a_pref; + } + } + if (prefer_rgba8) { + const bool a_rgba8 = + a.format() == olive::core::PixelFormat::U8 && + a.channel_count() == 4; + const bool b_rgba8 = + b.format() == olive::core::PixelFormat::U8 && + b.channel_count() == 4; + if (a_rgba8 != b_rgba8) { + return a_rgba8; + } + } + const int cost_a = ConversionCost(src_params, a); + const int cost_b = ConversionCost(src_params, b); + if (cost_a != cost_b) { + return cost_a < cost_b; + } + if (a.format() == preferred_params.format() && + a.channel_count() == preferred_params.channel_count()) { + return true; + } + return false; + }); + + for (const auto &candidate : candidates) { + if (candidate.format() == src_params.format() && + candidate.channel_count() == src_params.channel_count()) { + *out_params = src_params; + return src; + } + olive::TexturePtr converted = + ConvertTextureForParams(src, candidate); + if (converted) { + *out_params = candidate; + return converted; + } + } + + return nullptr; +} + +// 作用:从 OFX Image 复制数据到 AVFrame(按图像属性推导格式)。 +// Purpose: Copy OFX Image data into an AVFrame with inferred format. +static olive::AVFramePtr create_avframe_from_ofx_image(OFX::Host::ImageEffect::Image &image) +{ + void *data_ptr = image.getPointerProperty(kOfxImagePropData); + if (!data_ptr) { + qWarning().noquote() << "OFX output image missing data pointer"; + return nullptr; + } + + int bounds[4] = {0, 0, 0, 0}; + image.getIntPropertyN(kOfxImagePropBounds, bounds, 4); + int width = bounds[2] - bounds[0]; + int height = bounds[3] - bounds[1]; + if (width <= 0 || height <= 0) { + qWarning().noquote() + << "OFX output image has invalid bounds" + << bounds[0] << bounds[1] << bounds[2] << bounds[3]; + return nullptr; + } + + int bytes_per_pixel = 0; + AVPixelFormat pix_fmt = GetOfxAVPixelFormat(image, &bytes_per_pixel); + if (pix_fmt == AV_PIX_FMT_NONE || bytes_per_pixel <= 0) { + qWarning().noquote() + << "OFX output image has unsupported pixel format depth=" + << QString::fromStdString(image.getStringProperty( + kOfxImageEffectPropPixelDepth)) + << "components=" + << QString::fromStdString( + image.getStringProperty(kOfxImageEffectPropComponents)); + return nullptr; + } + + int row_bytes = image.getIntProperty(kOfxImagePropRowBytes); + if (row_bytes <= 0) { + row_bytes = width * bytes_per_pixel; + } + + uint8_t *src = static_cast(data_ptr); + src += bounds[1] * row_bytes + bounds[0] * bytes_per_pixel; + + olive::AVFramePtr frame = olive::CreateAVFramePtr(); + frame->width = width; + frame->height = height; + frame->format = pix_fmt; + + if (av_frame_get_buffer(frame.get(), 0) < 0) { + return nullptr; + } + + const int copy_bytes = width * bytes_per_pixel; + for (int y = 0; y < height; ++y) { + std::memcpy(frame->data[0] + y * frame->linesize[0], + src + y * row_bytes, + copy_bytes); + } + + return frame; +} + +// 作用:按指定 VideoParams 复制 OFX Image 到 AVFrame。 +// Purpose: Copy OFX Image data into an AVFrame using target VideoParams. +static olive::AVFramePtr create_avframe_from_ofx_image_with_params( + OFX::Host::ImageEffect::Image &image, + const olive::VideoParams ¶ms) +{ + void *data_ptr = image.getPointerProperty(kOfxImagePropData); + if (!data_ptr) { + return nullptr; + } + + int bounds[4] = {0, 0, 0, 0}; + image.getIntPropertyN(kOfxImagePropBounds, bounds, 4); + int width = bounds[2] - bounds[0]; + int height = bounds[3] - bounds[1]; + if (width <= 0 || height <= 0) { + return nullptr; + } + + AVPixelFormat pix_fmt = GetDestinationAVPixelFormat(params); + if (pix_fmt == AV_PIX_FMT_NONE) { + return nullptr; + } + + const int bytes_per_pixel = + params.channel_count() * params.format().byte_count(); + if (bytes_per_pixel <= 0) { + return nullptr; + } + + int row_bytes = image.getIntProperty(kOfxImagePropRowBytes); + if (row_bytes <= 0) { + row_bytes = width * bytes_per_pixel; + } + + uint8_t *src = static_cast(data_ptr); + src += bounds[1] * row_bytes + bounds[0] * bytes_per_pixel; + + olive::AVFramePtr frame = olive::CreateAVFramePtr(); + frame->width = width; + frame->height = height; + frame->format = pix_fmt; + + if (av_frame_get_buffer(frame.get(), 0) < 0) { + return nullptr; + } + + const int copy_bytes = width * bytes_per_pixel; + for (int y = 0; y < height; ++y) { + std::memcpy(frame->data[0] + y * frame->linesize[0], + src + y * row_bytes, + copy_bytes); + } + + return frame; +} + +// 作用:将 VideoParams 映射为最终输出的 AVPixelFormat。 +// Purpose: Map VideoParams to the final AVPixelFormat. +static AVPixelFormat GetDestinationAVPixelFormat(const olive::VideoParams ¶ms) +{ + AVPixelFormat pix_fmt = + olive::FFmpegUtils::GetFFmpegPixelFormat(params.format(), + params.channel_count()); + if (pix_fmt == AV_PIX_FMT_NONE && params.channel_count() == 1) { + if (params.format() == olive::core::PixelFormat::U8) { + pix_fmt = AV_PIX_FMT_GRAY8; + } else if (params.format() == olive::core::PixelFormat::U16) { + pix_fmt = AV_PIX_FMT_GRAY16LE; + } else if (params.format() == olive::core::PixelFormat::F16) { + pix_fmt = AV_PIX_FMT_GRAYF16; + } else if (params.format() == olive::core::PixelFormat::F32) { + pix_fmt = AV_PIX_FMT_GRAYF32; + } + } + return pix_fmt; +} + +// 作用:根据交错设置返回 OFX render field 字符串。 +// Purpose: Return OFX render field string based on interlacing. +static const char *GetRenderFieldForParams(const olive::VideoParams ¶ms) +{ + switch (params.interlacing()) { + case olive::VideoParams::kInterlaceNone: + return kOfxImageFieldNone; + case olive::VideoParams::kInterlacedTopFirst: + case olive::VideoParams::kInterlacedBottomFirst: + return kOfxImageFieldBoth; + } + return kOfxImageFieldNone; +} + +// 作用:从 GPU 纹理回读到 AVFrame(必要时做格式转换)。 +// Purpose: Read back GPU texture into AVFrame with format conversion if needed. +static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture, + const olive::VideoParams ¶ms) +{ + if (!texture || texture->IsDummy()) { + return nullptr; + } + + AVPixelFormat pix_fmt = GetDestinationAVPixelFormat(params); + if (pix_fmt == AV_PIX_FMT_NONE) { + return nullptr; + } + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) { + return nullptr; + } + + if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) { + olive::AVFramePtr frame = olive::CreateAVFramePtr(); + frame->format = pix_fmt; + frame->width = params.width(); + frame->height = params.height(); + if (av_frame_get_buffer(frame.get(), 0) < 0) { + return nullptr; + } + + if (texture->renderer()) { + const int linesize_pixels = + olive::plugin::detail::BytesToPixels(frame->linesize[0], + params); + texture->renderer()->DownloadFromTexture( + texture->id(), params, frame->data[0], linesize_pixels); + } + return frame; + } + + // Planar formats: read back as RGBA and convert. + olive::VideoParams rgba_params( + params.width(), params.height(), olive::core::PixelFormat::U8, 4, + params.pixel_aspect_ratio(), params.interlacing(), params.divider()); + + olive::AVFramePtr rgba_frame = olive::CreateAVFramePtr(); + rgba_frame->format = AV_PIX_FMT_RGBA; + rgba_frame->width = params.width(); + rgba_frame->height = params.height(); + if (av_frame_get_buffer(rgba_frame.get(), 0) < 0) { + return nullptr; + } + + if (texture->renderer()) { + const int linesize_pixels = + olive::plugin::detail::BytesToPixels(rgba_frame->linesize[0], + rgba_params); + texture->renderer()->DownloadFromTexture( + texture->id(), rgba_params, rgba_frame->data[0], linesize_pixels); + } + + olive::AVFramePtr dst = olive::CreateAVFramePtr(); + dst->format = pix_fmt; + dst->width = params.width(); + dst->height = params.height(); + if (av_frame_get_buffer(dst.get(), 0) < 0) { + return rgba_frame; + } + + SwsContext *sws_ctx = sws_getContext( + rgba_frame->width, rgba_frame->height, + static_cast(rgba_frame->format), + dst->width, dst->height, pix_fmt, SWS_POINT, + nullptr, nullptr, nullptr); + if (!sws_ctx) { + return rgba_frame; + } + + sws_scale(sws_ctx, rgba_frame->data, rgba_frame->linesize, 0, + rgba_frame->height, dst->data, dst->linesize); + sws_freeContext(sws_ctx); + + return dst; +} + +// 作用:将字节行跨度转换为像素行跨度。 +// Purpose: Convert byte stride to pixel stride. +int olive::plugin::detail::BytesToPixels(int byte_linesize, + const olive::VideoParams ¶ms) +{ + const int bytes_per_pixel = + olive::VideoParams::GetBytesPerPixel(params.format(), + params.channel_count()); + if (byte_linesize <= 0 || bytes_per_pixel <= 0) { + return 0; + } + return byte_linesize / bytes_per_pixel; +} + +// 作用:必要时将 AVFrame 转换为目标 VideoParams 对应格式。 +// Purpose: Convert AVFrame to match destination VideoParams when needed. +static olive::AVFramePtr ConvertFrameIfNeeded(olive::AVFramePtr src, + const olive::VideoParams &dst_params) +{ + if (!src) { + return nullptr; + } + + AVPixelFormat dst_fmt = GetDestinationAVPixelFormat(dst_params); + if (dst_fmt == AV_PIX_FMT_NONE) { + return src; + } + + if (src->format == dst_fmt && + src->width == dst_params.width() && + src->height == dst_params.height()) { + return src; + } + + olive::AVFramePtr dst = olive::CreateAVFramePtr(); + dst->format = dst_fmt; + dst->width = dst_params.width(); + dst->height = dst_params.height(); + if (av_frame_get_buffer(dst.get(), 0) < 0) { + return src; + } + + auto float_channels = [](AVPixelFormat fmt) -> int { + switch (fmt) { + case AV_PIX_FMT_GRAYF32LE: + case AV_PIX_FMT_GRAYF32BE: + return 1; + case AV_PIX_FMT_RGBF32LE: + case AV_PIX_FMT_RGBF32BE: + return 3; + case AV_PIX_FMT_RGBAF32LE: + case AV_PIX_FMT_RGBAF32BE: + return 4; + default: + return 0; + } + }; + + auto dst_packed_info = [](AVPixelFormat fmt, int *channels, + int *bytes_per_component) -> bool { + switch (fmt) { + case AV_PIX_FMT_GRAY8: + *channels = 1; + *bytes_per_component = 1; + return true; + case AV_PIX_FMT_RGB24: + *channels = 3; + *bytes_per_component = 1; + return true; + case AV_PIX_FMT_RGBA: + *channels = 4; + *bytes_per_component = 1; + return true; + case AV_PIX_FMT_GRAY16LE: + *channels = 1; + *bytes_per_component = 2; + return true; + case AV_PIX_FMT_RGB48LE: + *channels = 3; + *bytes_per_component = 2; + return true; + case AV_PIX_FMT_RGBA64LE: + *channels = 4; + *bytes_per_component = 2; + return true; + default: + return false; + } + }; + + auto float_dst_from_packed = [&](const olive::AVFramePtr &packed_src, + AVPixelFormat float_fmt, + const olive::AVFramePtr &float_dst) -> bool { + if (!packed_src || !float_dst || !packed_src->data[0] || + !float_dst->data[0]) { + return false; + } + const int dst_channels = float_channels(float_fmt); + if (dst_channels == 0) { + return false; + } + int src_channels = 0; + int bytes_per_component = 0; + if (!dst_packed_info(static_cast(packed_src->format), + &src_channels, &bytes_per_component)) { + return false; + } + const float inv_scale = + (bytes_per_component == 2) ? (1.0f / 65535.0f) + : (1.0f / 255.0f); + for (int y = 0; y < packed_src->height; ++y) { + const uint8_t *src_row = + packed_src->data[0] + y * packed_src->linesize[0]; + float *dst_row = reinterpret_cast( + float_dst->data[0] + y * float_dst->linesize[0]); + if (bytes_per_component == 2) { + const uint16_t *src_u16 = + reinterpret_cast(src_row); + for (int x = 0; x < packed_src->width; ++x) { + const uint16_t *pix = src_u16 + x * src_channels; + float r = pix[0] * inv_scale; + float g = (src_channels > 1) ? pix[1] * inv_scale : r; + float b = (src_channels > 2) ? pix[2] * inv_scale : r; + float a = (src_channels > 3) ? pix[3] * inv_scale : 1.0f; + dst_row[x * dst_channels + 0] = r; + if (dst_channels > 1) { + dst_row[x * dst_channels + 1] = g; + } + if (dst_channels > 2) { + dst_row[x * dst_channels + 2] = b; + } + if (dst_channels > 3) { + dst_row[x * dst_channels + 3] = a; + } + } + } else { + for (int x = 0; x < packed_src->width; ++x) { + const uint8_t *pix = src_row + x * src_channels; + float r = pix[0] * inv_scale; + float g = (src_channels > 1) ? pix[1] * inv_scale : r; + float b = (src_channels > 2) ? pix[2] * inv_scale : r; + float a = (src_channels > 3) ? pix[3] * inv_scale : 1.0f; + dst_row[x * dst_channels + 0] = r; + if (dst_channels > 1) { + dst_row[x * dst_channels + 1] = g; + } + if (dst_channels > 2) { + dst_row[x * dst_channels + 2] = b; + } + if (dst_channels > 3) { + dst_row[x * dst_channels + 3] = a; + } + } + } + } + return true; + }; + + const int dst_float_channels = float_channels(dst_fmt); + if (dst_float_channels > 0) { + int src_channels = 0; + int bytes_per_component = 0; + if (dst_packed_info(static_cast(src->format), + &src_channels, &bytes_per_component)) { + if (float_dst_from_packed(src, dst_fmt, dst)) { + return dst; + } + } else { + olive::AVFramePtr packed = olive::CreateAVFramePtr(); + AVPixelFormat packed_fmt = (dst_float_channels == 4) + ? AV_PIX_FMT_RGBA + : (dst_float_channels == 3) + ? AV_PIX_FMT_RGB24 + : AV_PIX_FMT_GRAY8; + packed->format = packed_fmt; + packed->width = dst->width; + packed->height = dst->height; + if (av_frame_get_buffer(packed.get(), 0) >= 0) { + SwsContext *pre_ctx = sws_getContext( + src->width, src->height, + static_cast(src->format), + packed->width, packed->height, packed_fmt, SWS_POINT, + nullptr, nullptr, nullptr); + if (pre_ctx) { + sws_scale(pre_ctx, src->data, src->linesize, 0, src->height, + packed->data, packed->linesize); + sws_freeContext(pre_ctx); + if (float_dst_from_packed(packed, dst_fmt, dst)) { + return dst; + } + } + } + } + } + + auto clamp01 = [](float v) -> float { + return std::clamp(v, 0.0f, 1.0f); + }; + + const int src_float_channels = float_channels( + static_cast(src->format)); + if (src_float_channels > 0) { + int dst_channels = 0; + int bytes_per_component = 0; + if (dst_packed_info(dst_fmt, &dst_channels, &bytes_per_component) && + src->data[0] && dst->data[0]) { + for (int y = 0; y < src->height; ++y) { + const float *src_row = reinterpret_cast( + src->data[0] + y * src->linesize[0]); + uint8_t *dst_row = dst->data[0] + y * dst->linesize[0]; + if (bytes_per_component == 2) { + auto *dst_row_u16 = + reinterpret_cast(dst_row); + for (int x = 0; x < src->width; ++x) { + const float *pix = + src_row + x * src_float_channels; + float r = pix[0]; + float g = (src_float_channels > 1) ? pix[1] : r; + float b = (src_float_channels > 2) ? pix[2] : r; + float a = (src_float_channels > 3) ? pix[3] : 1.0f; + if (dst_channels == 1) { + float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b; + dst_row_u16[x] = static_cast( + std::lround(clamp01(luma) * 65535.0f)); + continue; + } + dst_row_u16[x * dst_channels + 0] = + static_cast( + std::lround(clamp01(r) * 65535.0f)); + dst_row_u16[x * dst_channels + 1] = + static_cast( + std::lround(clamp01(g) * 65535.0f)); + dst_row_u16[x * dst_channels + 2] = + static_cast( + std::lround(clamp01(b) * 65535.0f)); + if (dst_channels == 4) { + dst_row_u16[x * dst_channels + 3] = + static_cast( + std::lround(clamp01(a) * 65535.0f)); + } + } + } else { + for (int x = 0; x < src->width; ++x) { + const float *pix = + src_row + x * src_float_channels; + float r = pix[0]; + float g = (src_float_channels > 1) ? pix[1] : r; + float b = (src_float_channels > 2) ? pix[2] : r; + float a = (src_float_channels > 3) ? pix[3] : 1.0f; + if (dst_channels == 1) { + float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b; + dst_row[x] = static_cast( + std::lround(clamp01(luma) * 255.0f)); + continue; + } + dst_row[x * dst_channels + 0] = + static_cast( + std::lround(clamp01(r) * 255.0f)); + dst_row[x * dst_channels + 1] = + static_cast( + std::lround(clamp01(g) * 255.0f)); + dst_row[x * dst_channels + 2] = + static_cast( + std::lround(clamp01(b) * 255.0f)); + if (dst_channels == 4) { + dst_row[x * dst_channels + 3] = + static_cast( + std::lround(clamp01(a) * 255.0f)); + } + } + } + } + return dst; + } + } + + SwsContext *sws_ctx = sws_getContext( + src->width, src->height, static_cast(src->format), + dst->width, dst->height, dst_fmt, SWS_POINT, + nullptr, nullptr, nullptr); + if (!sws_ctx) { + return src; + } + + sws_scale(sws_ctx, src->data, src->linesize, 0, src->height, + dst->data, dst->linesize); + sws_freeContext(sws_ctx); + + return dst; +} + +// 作用:从字节行跨度换算像素行跨度。 +// Purpose: Convert byte line size to pixel line size. +static int LinesizeToPixels(const olive::VideoParams ¶ms, int linesize_bytes) +{ + const int bytes_per_pixel = + params.channel_count() * params.format().byte_count(); + if (bytes_per_pixel <= 0) { + return 0; + } + return linesize_bytes / bytes_per_pixel; +} + +// 作用:将纹理转换为指定 VideoParams(CPU 路径,必要时回读)。 +// Purpose: Convert texture to target VideoParams (CPU path with readback). +static olive::TexturePtr ConvertTextureForParams(olive::TexturePtr src, + const olive::VideoParams &dst_params) +{ + if (!src) { + return nullptr; + } + const olive::VideoParams &src_params = src->params(); + if (src_params.format() == dst_params.format() && + src_params.channel_count() == dst_params.channel_count() && + src_params.width() == dst_params.width() && + src_params.height() == dst_params.height()) { + return src; + } + + olive::AVFramePtr frame = src->frame(); + if (!frame || !frame->data[0]) { + frame = ReadbackTextureToFrame(src, src_params); + } + if (!frame || !frame->data[0]) { + return nullptr; + } + + olive::AVFramePtr converted = ConvertFrameIfNeeded(frame, dst_params); + if (!converted || !converted->data[0]) { + return nullptr; + } + if (converted->linesize[0] <= 0) { + return nullptr; + } + + olive::TexturePtr dst; + if (auto *renderer = src->renderer()) { + int linesize_pixels = + LinesizeToPixels(dst_params, converted->linesize[0]); + if (linesize_pixels <= 0) { + linesize_pixels = dst_params.effective_width(); + } + dst = renderer->CreateTexture(dst_params, converted->data[0], + linesize_pixels); + } else { + dst = std::make_shared(dst_params); + int linesize_pixels = + LinesizeToPixels(dst_params, converted->linesize[0]); + if (linesize_pixels <= 0) { + linesize_pixels = dst_params.effective_width(); + } + dst->Upload(converted->data[0], linesize_pixels); + } + if (dst) { + dst->handleFrame(converted); + } + return dst; +} + +// 作用:安全获取插件标识符,便于日志输出。 +// Purpose: Safely fetch plugin identifier for logging. +static QString PluginIdForInstance(const OFX::Host::ImageEffect::Instance *instance) +{ + if (!instance) { + return QStringLiteral(""); + } + auto *plugin = instance->getPlugin(); + if (!plugin) { + return QStringLiteral(""); + } + return QString::fromStdString(plugin->getIdentifier()); +} + +// 作用:统一 OFX 调用失败日志输出。 +// Purpose: Centralized logging for OFX action failures. +static void LogOfxFailure(const char *action, OfxStatus stat, + const OFX::Host::ImageEffect::Instance *instance) +{ + if (stat == kOfxStatOK || stat == kOfxStatReplyDefault) { + return; + } + qWarning().noquote() + << "OFX action failed:" << action + << "plugin=" << PluginIdForInstance(instance) + << "status=" << OFX::StatStr(stat) + << "(" << stat << ")"; +} + +// 作用:输出 clip 的声明属性与关联 VideoParams,辅助定位格式不一致。 +// Purpose: Log clip declared properties and VideoParams for debugging. +static void LogClipState(const char *label, + const OFX::Host::ImageEffect::ClipInstance *clip, + const olive::VideoParams *params) +{ + if (!clip) { + qWarning().noquote() << "OFX clip state" << label << ""; + return; + } + qWarning().noquote() + << "OFX clip state" << label + << "name=" << QString::fromStdString(clip->getName()) + << "pixelDepth=" << QString::fromStdString(clip->getPixelDepth()) + << "components=" << QString::fromStdString(clip->getComponents()); + if (params) { + qWarning().noquote() + << "OFX clip params" << label + << "width=" << params->width() + << "height=" << params->height() + << "format=" << static_cast(params->format()) + << "channels=" << params->channel_count(); + } +} + +// 作用:输出 OFX Image 的属性(深度/组件/行跨度/边界)。 +// Purpose: Log OFX image properties (depth/components/stride/bounds). +static void LogImageProps(const char *label, + OFX::Host::ImageEffect::Image *image) +{ + if (!image) { + qWarning().noquote() << "OFX image props" << label << ""; + return; + } + int bounds[4] = {0, 0, 0, 0}; + int rod[4] = {0, 0, 0, 0}; + image->getIntPropertyN(kOfxImagePropBounds, bounds, 4); + image->getIntPropertyN(kOfxImagePropRegionOfDefinition, rod, 4); + const int row_bytes = image->getIntProperty(kOfxImagePropRowBytes); + const std::string &depth = + image->getStringProperty(kOfxImageEffectPropPixelDepth); + const std::string &components = + image->getStringProperty(kOfxImageEffectPropComponents); + qWarning().noquote() + << "OFX image props" << label + << "pixelDepth=" << QString::fromStdString(depth) + << "components=" << QString::fromStdString(components) + << "rowBytes=" << row_bytes + << "bounds=" << bounds[0] << bounds[1] << bounds[2] << bounds[3] + << "rod=" << rod[0] << rod[1] << rod[2] << rod[3]; +} + +// 作用:渲染失败时标记目标画面(紫色)提示错误。 +// Purpose: Mark render failure on destination (magenta). +static void MarkRenderFailure(olive::TexturePtr destination) +{ + if (destination && destination->renderer()) { + destination->renderer()->ClearDestination(destination.get(), 1.0, 0.0, 1.0, 1.0); + } +} +static olive::AVFramePtr DownloadTextureToFrame(const olive::TexturePtr &tex) +{ + if (!tex || tex->IsDummy() || !tex->renderer()) { + return nullptr; + } + const olive::VideoParams ¶ms = tex->params(); + return ReadbackTextureToFrame(tex, params); +} + +// 作用:执行 OFX 插件渲染全流程(准备输入、调用动作、处理输出)。 +// Purpose: Run full OFX plugin render flow (inputs, actions, outputs). +void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job, + olive::TexturePtr destination, + olive::VideoParams destination_params, + bool clear_destination, bool interactive) +{ + auto instance=job.pluginInstance(); + if (!instance) { + return; + } + bool supports_opengl = false; +#ifdef OFX_SUPPORTS_OPENGLRENDER + const std::string &gl_supported = + instance->getDescriptor().getProps().getStringProperty( + kOfxImageEffectPropOpenGLRenderSupported); + supports_opengl = (gl_supported == "true" || gl_supported == "1"); +#endif + auto *olive_instance = + dynamic_cast(instance); + const bool use_opengl = + supports_opengl && destination && destination->renderer() && + destination->id().isValid(); + if (olive_instance) { + olive_instance->setVideoParam(destination_params); + } + + // current render scale of 1 + OfxPointD renderScale; + renderScale.x = renderScale.y = 1.0; + + + int numFramesToRender=1; + + // Output Clip + OliveClipInstance *output_clip=dynamic_cast(instance->getClip("Output")); + if (!output_clip) { + return; + } + + // ensure the instance was created + OfxStatus stat = kOfxStatOK; + if (olive_instance && !olive_instance->isCreated()) { + stat = instance->createInstanceAction(); + if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + LogOfxFailure("createInstance", stat, instance); + MarkRenderFailure(destination); + return; + } + } + + + OfxTime frame = job.time_seconds(); + + const auto &clips = olive_instance->getDescriptor().getClips(); + QString effect_input_id; + if (const auto *node = job.node()) { + effect_input_id = node->GetEffectInputID(); + } + auto is_usable_input = [](const TexturePtr &tex) { + if (!tex) { + return false; + } + if (!tex->IsDummy() && tex->renderer()) { + return true; + } + AVFramePtr frame = tex->frame(); + return frame && frame->data[0]; + }; + std::map input_textures; + std::map input_clips; + std::map input_params; + auto values = job.GetValues(); + for (const auto &entry : clips) { + if (entry.first == kOfxImageEffectOutputClipName) { + continue; + } + OliveClipInstance *input_clip = + dynamic_cast(instance->getClip(entry.first)); + if (!input_clip) { + continue; + } + const QString clip_key = QString::fromStdString(entry.first); + TexturePtr input_tex = nullptr; + if (!effect_input_id.isEmpty() && clip_key == effect_input_id && + is_usable_input(src)) { + input_tex = src; + } else { + input_tex = values.value(clip_key).toTexture(); + if (!input_tex && + entry.first == kOfxImageEffectSimpleSourceClipName) { + input_tex = values.value(kTextureInput).toTexture(); + } + } + if (!is_usable_input(input_tex) && + entry.first == kOfxImageEffectSimpleSourceClipName && + is_usable_input(src)) { + input_tex = src; + } + if (is_usable_input(input_tex)) { + input_textures[entry.first] = input_tex; + olive::VideoParams params = input_tex->params(); + input_clip->setInputTexture(input_tex, frame); + input_clips[entry.first] = input_clip; + } + } + + // call getClipPreferences to know which format plugin requires + OFX::Host::Property::Set args; + args.setDoubleProperty(kOfxPropTime, frame); + double render_scale_array[] = { + renderScale.x, renderScale.y + }; + args.setDoublePropertyN(kOfxImageEffectPropRenderScale, render_scale_array, 2); + instance->setupClipPreferencesArgs(args); + // now we need to call getClipPreferences on the instance so that it does + // the clip component/depth logic and caches away the components and depth. + bool ok = instance->getClipPreferences(); + if (!ok) { + qWarning().noquote() << "OFX getClipPreferences failed for plugin=" + << PluginIdForInstance(instance); + MarkRenderFailure(destination); + return; + } + /// RoI is in canonical coords. + OfxRectD regionOfInterest; + regionOfInterest.x1 = 0.0; + regionOfInterest.y1 = 0.0; + regionOfInterest.x2 = destination_params.width() * destination_params.pixel_aspect_ratio().toDouble(); + regionOfInterest.y2 = destination_params.height(); + + OfxRectD regionOfDefinition = regionOfInterest; + + output_clip->setRegionOfDefinition(regionOfDefinition, frame); + output_clip->setOutputTexture(destination, frame); + + // get the RoI for each input clip + // the regions of interest for each input clip are returned in a std::map + // on a real host, these will be the regions of each input clip that the + // effect needs to render a given frame (clipped to the RoD). + // + // In our example we are doing full frame fetches regardless. + + + // set correct format for input + for (const auto &entry : input_clips) { + if (entry.first == kOfxImageEffectOutputClipName) { + continue; + } + OliveClipInstance *input_clip = entry.second; + if (!input_clip) { + continue; + } + const QString clip_key = QString::fromStdString(entry.first); + TexturePtr input_tex = input_textures[entry.first]; + if (!use_opengl) { + AVFramePtr ptr = + ReadbackTextureToFrame(input_tex, input_tex->params()); + input_tex->handleFrame(ptr); + } + if (is_usable_input(input_tex)) { + input_textures[entry.first] = input_tex; + std::string bitdepth = input_clip->getProps() + .getStringProperty(kOfxImageEffectPropPixelDepth); + std::string component = input_clip->getProps() + .getStringProperty(kOfxImageEffectPropComponents); + VideoParams params = input_tex->params(); + params.set_format(PixelFormat::from_ofx(bitdepth)); + params.set_channel_count(component); + ConvertTextureForParams(input_tex, params); + OfxRectD rod; + rod.x1 = 0; + rod.y1 = 0; + rod.x2 = params.width() * params.pixel_aspect_ratio().toDouble(); + rod.y2 = params.height(); + input_clip->setRegionOfDefinition(rod, frame); + input_clip->setInputTexture(input_tex,frame); + input_clips[entry.first] = input_clip; + } + } + std::map rois; + stat = instance->getRegionOfInterestAction(frame, renderScale, + regionOfInterest, rois); + if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + LogOfxFailure("getRegionOfInterest", stat, instance); + MarkRenderFailure(destination); + return; + } + // set correct format for output + VideoParams output_params = destination_params; // params for plugin + std::string bitdepth = + output_clip->getProps().getStringProperty(kOfxImageEffectPropPixelDepth); + std::string component = + output_clip->getProps().getStringProperty(kOfxImageEffectPropComponents); + output_params.set_format(PixelFormat::from_ofx(bitdepth)); + output_params.set_channel_count(component); + output_clip->setParams(output_params); + + // The render window is in pixel coordinates + // ie: render scale and a PAR of not 1 + OfxRectI renderWindow; + renderWindow.x1 = renderWindow.y1 = 0; + renderWindow.x2 = destination_params.width(); + renderWindow.y2 = destination_params.height(); + + + stat = instance->beginRenderAction(frame, numFramesToRender, + 1.0, false, renderScale, true, + interactive); + if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + LogOfxFailure("beginRender", stat, instance); + MarkRenderFailure(destination); + return; + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + if (use_opengl) { + instance->contextAttachedAction(); + AttachOutputTexture(destination); + } +#endif + + + if (!output_params.is_valid()) { + qWarning().noquote() + << "OFX render skipped due to invalid output params for plugin=" + << PluginIdForInstance(instance); + MarkRenderFailure(destination); + instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, + renderScale, true, interactive); + return; + } + + // render a frame + const char *render_field = GetRenderFieldForParams(output_params); + stat = instance->renderAction(frame, render_field, renderWindow, renderScale, + true, interactive, interactive); + if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + LogOfxFailure("render", stat, instance); + LogClipState("output", output_clip, &output_params); + for (const auto &entry : input_clips) { + const auto params_it = input_params.find(entry.first); + const olive::VideoParams *params = + (params_it != input_params.end()) ? ¶ms_it->second + : nullptr; + LogClipState("input", entry.second, params); + OFX::Host::ImageEffect::Image *image = + entry.second->getImage(frame, nullptr); + LogImageProps("input", image); + //if (image) { + //image->releaseReference(); + //} + } + OFX::Host::ImageEffect::Image* output_image = + output_clip->getOutputImage(frame); + LogImageProps("output", output_image); + MarkRenderFailure(destination); + instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, + renderScale, true, interactive); + return; + } + + // get the output image buffer (CPU path only) + OFX::Host::ImageEffect::Image* output_image; + if (!use_opengl) { + output_image = output_clip->getOutputImage(frame); + if (!output_image) { + qWarning().noquote() + << "OFX getOutputImage returned null for plugin=" + << PluginIdForInstance(instance); + MarkRenderFailure(destination); + instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, + renderScale, true, interactive); + return; + } + } else { + if (!destination || !destination->id().isValid()) { +#ifdef OFX_SUPPORTS_OPENGLRENDER + DetachOutputTexture(); + instance->contextDetachedAction(); +#endif + instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, + renderScale, true, interactive); + return; + } + } + + if (!use_opengl) { + AVFramePtr frame_ptr = + create_avframe_from_ofx_image_with_params(*output_image, + output_params); + if (!frame_ptr) { + qWarning().noquote() + << "OFX output image conversion failed for plugin=" + << PluginIdForInstance(instance); + instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, + renderScale, true, interactive); + return; + } + AVFramePtr converted = ConvertFrameIfNeeded(frame_ptr, destination_params); + const AVPixelFormat expected_fmt = + GetDestinationAVPixelFormat(destination_params); + destination->handleFrame(converted); + if (destination->renderer() && converted && converted->data[0] && + (expected_fmt == AV_PIX_FMT_NONE || + converted->format == expected_fmt)) { + int linesize_pixels = + LinesizeToPixels(destination_params, converted->linesize[0]); + if (linesize_pixels <= 0) { + linesize_pixels = destination_params.effective_width(); + } + destination->Upload(converted->data[0], linesize_pixels); + } else if (destination->renderer() && converted && converted->data[0]) { + qWarning().noquote() + << "OFX output pixel format mismatch for plugin=" + << PluginIdForInstance(instance); + } + } else { + AVFramePtr frame_ptr = + ReadbackTextureToFrame(destination, destination_params); +#ifdef OFX_SUPPORTS_OPENGLRENDER + DetachOutputTexture(); + instance->contextDetachedAction(); +#endif + if (frame_ptr && destination) { + AVFramePtr converted = + ConvertFrameIfNeeded(frame_ptr, destination_params); + const AVPixelFormat expected_fmt = + GetDestinationAVPixelFormat(destination_params); + destination->handleFrame(converted); + if (destination->renderer() && converted && converted->data[0] && + (expected_fmt == AV_PIX_FMT_NONE || + converted->format == expected_fmt)) { + int linesize_pixels = LinesizeToPixels(destination_params, + converted->linesize[0]); + if (linesize_pixels <= 0) { + linesize_pixels = destination_params.effective_width(); + } + destination->Upload(converted->data[0], linesize_pixels); + } else if (destination->renderer() && converted && + converted->data[0]) { + qWarning().noquote() + << "OFX output pixel format mismatch for plugin=" + << PluginIdForInstance(instance); + } + } + } + + instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, renderScale, true,interactive + ); + +} + +// 作用:绑定输出纹理到 OFX 的 GL 输出路径。 +// Purpose: Attach output texture for OFX GL rendering. +void olive::plugin::PluginRenderer::AttachOutputTexture(olive::TexturePtr texture) +{ + if (!texture) { + return; + } + AttachTextureAsDestination(texture->id()); +} + +// 作用:解除 OFX 的 GL 输出绑定。 +// Purpose: Detach OFX GL output binding. +void olive::plugin::PluginRenderer::DetachOutputTexture() +{ + DetachTextureAsDestination(); +} diff --git a/app/render/plugin/pluginrenderer.h b/app/render/plugin/pluginrenderer.h new file mode 100644 index 000000000..689848613 --- /dev/null +++ b/app/render/plugin/pluginrenderer.h @@ -0,0 +1,71 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// +// Created by mikesolar on 25-10-19. +// + +#ifndef PLUGINRENDERER_H +#define PLUGINRENDERER_H +#include +#include +#include +#include +#include +#include +#include + +#include "render/renderer.h" +#include "render/job/pluginjob.h" +#include "render/opengl/openglrenderer.h" +namespace olive +{ +namespace plugin{ +namespace detail { +// 作用:将字节行跨度转换为像素跨度,便于纹理读写。 +// Purpose: Convert byte stride to pixel stride for texture I/O. +int BytesToPixels(int byte_linesize, const olive::VideoParams ¶ms); +} +// 作用:OFX 插件渲染器,负责 CPU/GL 路径下的插件调用和纹理桥接。 +// Purpose: OFX plugin renderer that drives CPU/GL render paths and texture bridging. +class PluginRenderer : public olive::OpenGLRenderer{ + Q_OBJECT +public: + PluginRenderer(QObject *parent=nullptr):OpenGLRenderer(parent){}; + virtual ~PluginRenderer() override{}; + // 作用:将目标纹理绑定为插件输出。 + // Purpose: Attach destination texture as OFX output. + void AttachOutputTexture(olive::TexturePtr texture); + // 作用:解除目标纹理绑定。 + // Purpose: Detach destination texture binding. + void DetachOutputTexture(); + // 作用:执行插件渲染流程(参数配置、输入/输出、调用渲染动作)。 + // Purpose: Execute plugin render flow (params, inputs/outputs, render actions). + void RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job, + olive::TexturePtr destination, + olive::VideoParams destination_params, + bool clear_destination, bool interactive); + +}; +} +} + + + +#endif //PLUGINRENDERER_H diff --git a/app/render/previewaudiodevice.cpp b/app/render/previewaudiodevice.cpp index b7fa3aeb1..1f6a8c748 100644 --- a/app/render/previewaudiodevice.cpp +++ b/app/render/previewaudiodevice.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/previewaudiodevice.h b/app/render/previewaudiodevice.h index 5502c3aed..8a24c1962 100644 --- a/app/render/previewaudiodevice.h +++ b/app/render/previewaudiodevice.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index c78df9581..eb490ac75 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -395,8 +396,9 @@ void PreviewAutoCacher::StartCachingAudioRange(ViewerOutput *context, cache->ClearRequestRange(range); pending_audio_jobs_.push_back({ node, context, cache, range }); - audio_cache_data_[cache].job_tracker.insert(range, - copier_->GetGraphChangeTime()); + AudioCacheData &data = audio_cache_data_[cache]; + data.context = context; + data.job_tracker.insert(range, copier_->GetGraphChangeTime()); TryRender(); } @@ -531,8 +533,11 @@ void PreviewAutoCacher::TryRender() t->property("dry").toBool()); video_immediate_passthroughs_[watcher].append(t); } else { - qWarning() << "Failed to find copied node for SFR ticket"; - t->Finish(); + qWarning() << "Failed to find copied node for SFR ticket, requeueing"; + single_frame_render_ = t; + if (!delayed_requeue_timer_.isActive()) { + delayed_requeue_timer_.start(); + } } } @@ -561,7 +566,11 @@ void PreviewAutoCacher::TryRender() } } } else { - qCritical() << "Failed to find node copy for video job"; + qWarning() << "Failed to find node copy for video job, retrying"; + if (!delayed_requeue_timer_.isActive()) { + delayed_requeue_timer_.start(); + } + break; } if (d.iterator.HasNext()) { @@ -599,7 +608,12 @@ void PreviewAutoCacher::TryRender() RenderAudio(copy, d.context, use_range, d.cache); } else { - qCritical() << "Failed to find node copy for audio job"; + qWarning() << "Failed to find node copy for audio job, retrying"; + pop = false; + if (!delayed_requeue_timer_.isActive()) { + delayed_requeue_timer_.start(); + } + break; } if (pop) { @@ -677,6 +691,15 @@ RenderTicketPtr PreviewAutoCacher::RenderAudio(Node *node, running_audio_tasks_.append(watcher); AudioParams p = context->GetAudioParams(); + const bool invalid_params = + (p.sample_rate() <= 0 || p.channel_count() <= 0); + if (invalid_params) { + AudioParams fallback( + OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(), + OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(), + ViewerOutput::kDefaultSampleFormat); + p = fallback; + } p.set_format(ViewerOutput::kDefaultSampleFormat); RenderManager::RenderAudioParams rap(node, r, p, RenderMode::kOffline); @@ -694,13 +717,17 @@ void PreviewAutoCacher::ConformFinished() // Got an audio conform, requeue all the audio currently needing a conform last_conform_task_.Acquire(); - qDebug() << "CONFORM RESPONSE TEMPORARILY DISABLED"; - /*for (auto it=audio_cache_data_.begin(); it!=audio_cache_data_.end(); it++) { - foreach (const TimeRange &range, it.value().needs_conform) { - it.key()->Request(range); - } - it.value().needs_conform.clear(); - }*/ + for (auto it = audio_cache_data_.begin(); it != audio_cache_data_.end(); + it++) { + if (!it.key() || !it.value().context) { + continue; + } + + for (const TimeRange &range : it.value().needs_conform) { + it.key()->Request(it.value().context, range); + } + it.value().needs_conform.clear(); + } } void PreviewAutoCacher::CacheProxyTaskCancelled() diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h index 699c6bff3..b3ebad1be 100644 --- a/app/render/previewautocacher.h +++ b/app/render/previewautocacher.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -188,6 +189,7 @@ private: struct AudioCacheData { RenderJobTracker job_tracker; TimeRangeList needs_conform; + ViewerOutput *context = nullptr; }; std::list pending_video_jobs_; diff --git a/app/render/projectcopier.cpp b/app/render/projectcopier.cpp index 2cdd4a831..4416c2693 100644 --- a/app/render/projectcopier.cpp +++ b/app/render/projectcopier.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/projectcopier.h b/app/render/projectcopier.h index c087e6c3c..a7397c4f7 100644 --- a/app/render/projectcopier.h +++ b/app/render/projectcopier.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/rendercache.h b/app/render/rendercache.h index a3b51c81e..8dec354ec 100644 --- a/app/render/rendercache.h +++ b/app/render/rendercache.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index c95ce5469..02001526a 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -30,9 +31,18 @@ namespace olive Renderer::Renderer(QObject *parent) : QObject(parent) + , lifetime_(std::make_shared()) { } +Renderer::~Renderer() +{ + destroyed_ = true; + if (lifetime_) { + lifetime_->alive = false; + } +} + TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data, int linesize) { @@ -70,6 +80,9 @@ TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data, void Renderer::DestroyTexture(Texture *texture) { + if (destroyed_) { + return; + } if (USE_TEXTURE_CACHE) { // HACK: Dirty, dirty hack. OpenGL uses "contexts" to store all of its data, and each context // can only be used by the thread that created it. However there are also "shared contexts" @@ -144,6 +157,10 @@ QVariant Renderer::GetDefaultShader() void Renderer::Destroy() { + destroyed_ = true; + if (lifetime_) { + lifetime_->alive = false; + } if (!default_shader_.isNull()) { DestroyNativeShader(default_shader_); default_shader_.clear(); @@ -171,7 +188,7 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, return nullptr; } - return std::make_shared(this, v, params); + return std::make_shared(this, v, params, lifetime_); } bool Renderer::GetColorContext(const ColorTransformJob &color_job, @@ -325,6 +342,20 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job, { ColorContext color_ctx; if (!GetColorContext(color_job, &color_ctx)) { + ShaderJob fallback_job; + fallback_job.Insert(QStringLiteral("ove_maintex"), + color_job.GetInputTexture()); + fallback_job.Insert( + QStringLiteral("ove_mvpmat"), + NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix())); + + if (destination) { + BlitToTexture(GetDefaultShader(), fallback_job, destination, + color_job.IsClearDestinationEnabled()); + } else { + Blit(GetDefaultShader(), fallback_job, params, + color_job.IsClearDestinationEnabled()); + } return; } diff --git a/app/render/renderer.h b/app/render/renderer.h index 468c50aa6..85463c24c 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -24,6 +25,8 @@ #include #include #include +#include +#include #include "common/define.h" #include "node/node.h" @@ -31,6 +34,7 @@ #include "render/job/colortransformjob.h" #include "render/videoparams.h" #include "texture.h" +#include "job/pluginjob.h" namespace olive { @@ -41,6 +45,7 @@ class Renderer : public QObject { Q_OBJECT public: Renderer(QObject *parent = nullptr); + virtual ~Renderer() override; virtual bool Init() = 0; @@ -49,15 +54,16 @@ public: void DestroyTexture(Texture *texture); - void BlitToTexture(QVariant shader, olive::ShaderJob job, + virtual void BlitToTexture(QVariant shader, olive::AcceleratedJob& job, olive::Texture *destination, bool clear_destination = true) { Blit(shader, job, destination, destination->params(), clear_destination); + } - void Blit(QVariant shader, olive::ShaderJob job, olive::VideoParams params, + void Blit(QVariant shader, olive::AcceleratedJob& job, olive::VideoParams params, bool clear_destination = true) { Blit(shader, job, nullptr, params, clear_destination); @@ -106,13 +112,16 @@ public: virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) = 0; + std::shared_ptr GetLifetime() const + { + return lifetime_; + } protected: - virtual void Blit(QVariant shader, olive::ShaderJob job, + virtual void Blit(QVariant shader, olive::AcceleratedJob& job, olive::Texture *destination, olive::VideoParams destination_params, bool clear_destination) = 0; - virtual QVariant CreateNativeTexture(int width, int height, int depth, PixelFormat format, int channel_count, const void *data = nullptr, @@ -123,6 +132,8 @@ protected: virtual void DestroyInternal() = 0; private: + std::atomic destroyed_{false}; + std::shared_ptr lifetime_; struct ColorContext { struct LUT { TexturePtr texture; diff --git a/app/render/renderjobtracker.cpp b/app/render/renderjobtracker.cpp index 8cffc43ab..36c762cb3 100644 --- a/app/render/renderjobtracker.cpp +++ b/app/render/renderjobtracker.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/renderjobtracker.h b/app/render/renderjobtracker.h index d4ec580a2..b909e3352 100644 --- a/app/render/renderjobtracker.h +++ b/app/render/renderjobtracker.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/rendermanager.cpp b/app/render/rendermanager.cpp index 820a01546..9affa3f35 100644 --- a/app/render/rendermanager.cpp +++ b/app/render/rendermanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -92,7 +93,7 @@ RenderThread *RenderManager::CreateThread(Renderer *renderer) { auto t = new RenderThread(renderer, decoder_cache_, shader_cache_, this); render_threads_.push_back(t); - t->start(QThread::IdlePriority); + t->start(QThread::NormalPriority); return t; } diff --git a/app/render/rendermanager.h b/app/render/rendermanager.h index 26cf7d739..7b8997008 100644 --- a/app/render/rendermanager.h +++ b/app/render/rendermanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/rendermodes.h b/app/render/rendermodes.h index e68ea6c12..9ccbdfa9e 100644 --- a/app/render/rendermodes.h +++ b/app/render/rendermodes.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 36d99a797..ac122d8d9 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -30,6 +31,10 @@ #include "node/block/transition/transition.h" #include "node/project.h" #include "rendermanager.h" +#include "render/opengl/openglrenderer.h" +#include "render/plugin/pluginrenderer.h" +#include "pluginSupport/OliveClip.h" +#include "pluginSupport/OliveHost.h" namespace olive { @@ -159,6 +164,7 @@ void RenderProcessor::Run() SetCancelPointer(ticket_->GetCancelAtom()); + VideoParams params=ticket_->property("vparam").value(); SetCacheVideoParams(ticket_->property("vparam").value()); SetCacheAudioParams(ticket_->property("aparam").value()); @@ -167,6 +173,17 @@ void RenderProcessor::Run() return; } + // if is a plugin + /*Node *node=ticket_->property("node").value(); + if (node && node->getPlugin()) { + std::shared_ptr plugin + = node->getPlugin(); + std::unique_ptr instance(plugin->createInstance(kOfxImageEffectContextFilter, NULL)); + + + } + */ + switch (type) { case RenderManager::kTypeVideo: { rational time = ticket_->property("time").value(); @@ -527,7 +544,7 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, locker.unlock(); // Run shader - render_ctx_->BlitToTexture(shader, *job, destination.get()); + render_ctx_->BlitToTexture(shader, const_cast(*job), destination.get()); } void RenderProcessor::ProcessSamples(SampleBuffer &destination, @@ -594,6 +611,92 @@ void RenderProcessor::ProcessFrameGeneration(TexturePtr destination, destination->Upload(frame->data(), frame->linesize_pixels()); } +TexturePtr RenderProcessor::ProcessPluginJob(TexturePtr texture, + TexturePtr destination, + const Node *node) +{ + (void)node; + + if (!render_ctx_ || !texture || !destination) { + return destination; + } + + auto *plugin_job = + dynamic_cast(texture->job()); + if (!plugin_job) { + return destination; + } + + if (!plugin_renderer_) { + auto *gl = dynamic_cast(render_ctx_); + if (!gl || !gl->context()) { + return destination; + } + + plugin_renderer_ = std::make_unique(); + plugin_renderer_->Init(gl->context()); + plugin_renderer_->PostInit(); + } + + NodeValueRow &values = plugin_job->GetValues(); + + auto is_usable_texture = [](const TexturePtr &tex) { + if (!tex) { + return false; + } + if (!tex->IsDummy() && tex->renderer()) { + return true; + } + AVFramePtr frame = tex->frame(); + return frame && frame->data[0]; + }; + + TexturePtr src = nullptr; + QString effect_input_id; + if (plugin_job->node()) { + effect_input_id = plugin_job->node()->GetEffectInputID(); + } + if (!effect_input_id.isEmpty()) { + if (TexturePtr effect_tex = values.value(effect_input_id).toTexture(); + is_usable_texture(effect_tex)) { + src = effect_tex; + } + } + if (!src) { + const QString source_key = + QString::fromUtf8(kOfxImageEffectSimpleSourceClipName); + if (TexturePtr source_tex = values.value(source_key).toTexture(); + is_usable_texture(source_tex)) { + src = source_tex; + } else if (TexturePtr effect_tex = + values.value(plugin::kTextureInput).toTexture(); + is_usable_texture(effect_tex)) { + src = effect_tex; + } + } + if (!src) { + for (auto it = values.cbegin(); it != values.cend(); ++it) { + if (it.value().type() == NodeValue::kTexture) { + if (TexturePtr any_tex = it.value().toTexture(); + is_usable_texture(any_tex)) { + src = any_tex; + break; + } + } + } + } + + plugin_renderer_->RenderPlugin( + src, + *plugin_job, + destination, + destination->params(), + true, + false); + + return destination; +} + TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob *val) { FramePtr frame = FrameHashCache::LoadCacheFrame(val->GetFilename()); diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 0478ff838..d72d8b0af 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -22,6 +23,7 @@ #define RENDERPROCESSOR_H #include "node/block/clip/clip.h" +#include #include "node/traverser.h" #include "render/renderer.h" #include "rendercache.h" @@ -30,6 +32,10 @@ namespace olive { +namespace plugin { +class PluginRenderer; +} + class RenderProcessor : public NodeTraverser { public: virtual NodeValueDatabase GenerateDatabase(const Node *node, @@ -68,6 +74,10 @@ protected: const Node *node, const GenerateJob *job) override; + virtual TexturePtr ProcessPluginJob(TexturePtr texture, + TexturePtr destination, + const Node *node) override; + virtual TexturePtr ProcessVideoCacheJob(const CacheJob *val) override; virtual TexturePtr CreateTexture(const VideoParams &p) override; @@ -102,6 +112,8 @@ private: Renderer *render_ctx_; + std::unique_ptr plugin_renderer_; + DecoderCache *decoder_cache_; ShaderCache *shader_cache_; diff --git a/app/render/renderticket.cpp b/app/render/renderticket.cpp index 17dde9770..63faf4040 100644 --- a/app/render/renderticket.cpp +++ b/app/render/renderticket.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/renderticket.h b/app/render/renderticket.h index b5b4c061d..be1af260d 100644 --- a/app/render/renderticket.h +++ b/app/render/renderticket.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/shadercode.h b/app/render/shadercode.h index 2901d31c2..9feab9f47 100644 --- a/app/render/shadercode.h +++ b/app/render/shadercode.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/subtitleparams.cpp b/app/render/subtitleparams.cpp index 92f4dad16..70ef9e096 100644 --- a/app/render/subtitleparams.cpp +++ b/app/render/subtitleparams.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/subtitleparams.h b/app/render/subtitleparams.h index 86b81fb58..4d9c4dbad 100644 --- a/app/render/subtitleparams.h +++ b/app/render/subtitleparams.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/render/texture.cpp b/app/render/texture.cpp index 8822c6c7e..cdd6a3b01 100644 --- a/app/render/texture.cpp +++ b/app/render/texture.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -30,7 +31,7 @@ const Texture::Interpolation Texture::kDefaultInterpolation = Texture::~Texture() { - if (renderer_) { + if (IsRendererAlive()) { renderer_->DestroyTexture(this); } @@ -41,14 +42,14 @@ Texture::~Texture() void Texture::Upload(void *data, int linesize) { - if (renderer_) { + if (IsRendererAlive()) { renderer_->UploadToTexture(this->id(), this->params(), data, linesize); } } void Texture::Download(void *data, int linesize) { - if (renderer_) { + if (IsRendererAlive()) { renderer_->DownloadFromTexture(this->id(), this->params(), data, linesize); } diff --git a/app/render/texture.h b/app/render/texture.h index 350ffe9e3..5b1c55a67 100644 --- a/app/render/texture.h +++ b/app/render/texture.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -21,6 +22,9 @@ #ifndef RENDERTEXTURE_H #define RENDERTEXTURE_H +#include "common/ffmpegutils.h" + +#include #include #include @@ -31,6 +35,9 @@ namespace olive class AcceleratedJob; class Renderer; +struct RendererLifetime { + std::atomic alive{true}; +}; class Texture; using TexturePtr = std::shared_ptr; @@ -46,6 +53,7 @@ public: */ Texture(const VideoParams ¶m) : renderer_(nullptr) + , renderer_lifetime_(nullptr) , params_(param) , job_(nullptr) { @@ -62,8 +70,10 @@ public: * @brief Construct a real texture linked to a renderer backend */ Texture(Renderer *renderer, const QVariant &native, - const VideoParams ¶m) + const VideoParams ¶m, + std::shared_ptr lifetime = nullptr) : renderer_(renderer) + , renderer_lifetime_(lifetime) , params_(param) , id_(native) , job_(nullptr) @@ -150,15 +160,30 @@ public: { return job_; } - + void handleFrame(AVFramePtr ptr) + { + frame_=ptr; + } + AVFramePtr frame(){ + return frame_; + } private: + bool IsRendererAlive() const + { + return renderer_ && + (!renderer_lifetime_ || renderer_lifetime_->alive.load()); + } + Renderer *renderer_; + std::shared_ptr renderer_lifetime_; VideoParams params_; QVariant id_; AcceleratedJob *job_; + + AVFramePtr frame_; }; } diff --git a/app/render/videoparams.cpp b/app/render/videoparams.cpp index 1a1dd6fb2..26c1178c5 100644 --- a/app/render/videoparams.cpp +++ b/app/render/videoparams.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -73,11 +74,15 @@ VideoParams::VideoParams() : width_(0) , height_(0) , depth_(0) + , time_base_(0) , format_(PixelFormat::INVALID) , channel_count_(0) + , pixel_aspect_ratio_(1) , interlacing_(Interlacing::kInterlaceNone) , divider_(1) { + calculate_effective_size(); + validate_pixel_aspect_ratio(); set_defaults_for_footage(); } @@ -234,8 +239,8 @@ QString VideoParams::GetFormatName(PixelFormat format) break; } - return QCoreApplication::translate("VideoParams", "Unknown (0x%1)") - .arg(format, 0, 16); + return QCoreApplication::translate("VideoParams", "Unknown (0x%1)") + .arg(static_cast(format), 0, 16); } int VideoParams::GetDividerForTargetResolution(int src_width, int src_height, diff --git a/app/render/videoparams.h b/app/render/videoparams.h index f15d7b218..cac603c18 100644 --- a/app/render/videoparams.h +++ b/app/render/videoparams.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -21,10 +22,12 @@ #ifndef VIDEOPARAMS_H #define VIDEOPARAMS_H +#include "ofxImageEffect.h" #include #include #include #include +#include namespace olive { @@ -175,7 +178,18 @@ public: { channel_count_ = c; } - + void set_channel_count(std::string ofxComponent) + { + if (ofxComponent == kOfxImageComponentAlpha){ + channel_count_ = 1; + } + else if (ofxComponent == kOfxImageComponentRGB){ + channel_count_ = kRGBChannelCount; + } + else if(ofxComponent == kOfxImageComponentRGBA){ + channel_count_ = kRGBAChannelCount; + } + } const rational &pixel_aspect_ratio() const { return pixel_aspect_ratio_; diff --git a/app/task/conform/conform.cpp b/app/task/conform/conform.cpp index 7b5d6d0c1..8b035a7c3 100644 --- a/app/task/conform/conform.cpp +++ b/app/task/conform/conform.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/conform/conform.h b/app/task/conform/conform.h index 5ce798c69..3ca179049 100644 --- a/app/task/conform/conform.h +++ b/app/task/conform/conform.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/customcache/customcachetask.cpp b/app/task/customcache/customcachetask.cpp index 1c4b4a8e8..28e04f4f7 100644 --- a/app/task/customcache/customcachetask.cpp +++ b/app/task/customcache/customcachetask.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/customcache/customcachetask.h b/app/task/customcache/customcachetask.h index f4caeccb0..8675d3dcb 100644 --- a/app/task/customcache/customcachetask.h +++ b/app/task/customcache/customcachetask.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index e59e08df1..42c054204 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/export/export.h b/app/task/export/export.h index ffafb5176..e860bbabf 100644 --- a/app/task/export/export.h +++ b/app/task/export/export.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/precache/precachetask.cpp b/app/task/precache/precachetask.cpp index f1443ac3a..27dc1c55e 100644 --- a/app/task/precache/precachetask.cpp +++ b/app/task/precache/precachetask.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/precache/precachetask.h b/app/task/precache/precachetask.h index 48ddf98da..da31b9fe1 100644 --- a/app/task/precache/precachetask.h +++ b/app/task/precache/precachetask.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index efe7b6197..6189dec97 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/import/import.h b/app/task/project/import/import.h index d7b81ed7d..9a51fc336 100644 --- a/app/task/project/import/import.h +++ b/app/task/project/import/import.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/import/importerrordialog.cpp b/app/task/project/import/importerrordialog.cpp index f3db5bae3..1501d4ab8 100644 --- a/app/task/project/import/importerrordialog.cpp +++ b/app/task/project/import/importerrordialog.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -37,7 +38,7 @@ ProjectImportErrorDialog::ProjectImportErrorDialog(const QStringList &filenames, setWindowTitle(tr("Import Error")); layout->addWidget(new QLabel( - tr("The following files failed to import. Olive likely does not " + tr("The following files failed to import. Oak Video Editor likely does not " "support their formats."))); QListWidget *list_widget = new QListWidget(); diff --git a/app/task/project/import/importerrordialog.h b/app/task/project/import/importerrordialog.h index ea12fc81a..04f7c702f 100644 --- a/app/task/project/import/importerrordialog.h +++ b/app/task/project/import/importerrordialog.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/load/load.cpp b/app/task/project/load/load.cpp index c87167fc2..9bda7edad 100644 --- a/app/task/project/load/load.cpp +++ b/app/task/project/load/load.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -48,11 +49,11 @@ bool ProjectLoadTask::Run() break; case ProjectSerializer::kProjectTooOld: SetError(tr( - "This project is from a version of Olive that is no longer supported in this version.")); + "This project is from a version of Oak Video Editor that is no longer supported in this version.")); break; case ProjectSerializer::kProjectTooNew: SetError(tr( - "This project is from a newer version of Olive and cannot be opened in this version.")); + "This project is from a newer version of Oak Video Editor and cannot be opened in this version.")); break; case ProjectSerializer::kUnknownVersion: SetError(tr("Failed to determine project version.")); diff --git a/app/task/project/load/load.h b/app/task/project/load/load.h index fda53d467..11c9a1c54 100644 --- a/app/task/project/load/load.h +++ b/app/task/project/load/load.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/load/loadbasetask.cpp b/app/task/project/load/loadbasetask.cpp index 756de064c..d61d2e4b4 100644 --- a/app/task/project/load/loadbasetask.cpp +++ b/app/task/project/load/loadbasetask.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/load/loadbasetask.h b/app/task/project/load/loadbasetask.h index 3163339b2..653562d80 100644 --- a/app/task/project/load/loadbasetask.h +++ b/app/task/project/load/loadbasetask.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/loadotio/loadotio.cpp b/app/task/project/loadotio/loadotio.cpp index 10146fc35..4b8eab907 100644 --- a/app/task/project/loadotio/loadotio.cpp +++ b/app/task/project/loadotio/loadotio.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/loadotio/loadotio.h b/app/task/project/loadotio/loadotio.h index 78e3066d0..58d5a3497 100644 --- a/app/task/project/loadotio/loadotio.h +++ b/app/task/project/loadotio/loadotio.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/save/save.cpp b/app/task/project/save/save.cpp index f80619795..c1a757d4a 100644 --- a/app/task/project/save/save.cpp +++ b/app/task/project/save/save.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/save/save.h b/app/task/project/save/save.h index 1d655d275..2b4d7479f 100644 --- a/app/task/project/save/save.h +++ b/app/task/project/save/save.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index e90e1c20f..b411d6e83 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/project/saveotio/saveotio.h b/app/task/project/saveotio/saveotio.h index 80ab40bf8..1d0a26953 100644 --- a/app/task/project/saveotio/saveotio.h +++ b/app/task/project/saveotio/saveotio.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index a73b1417b..1ebcf6fe4 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/render/render.h b/app/task/render/render.h index 462710aef..51a589661 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/task.h b/app/task/task.h index aeb4c3ebc..47c5ec70b 100644 --- a/app/task/task.h +++ b/app/task/task.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/taskmanager.cpp b/app/task/taskmanager.cpp index c71fee046..0417c3f24 100644 --- a/app/task/taskmanager.cpp +++ b/app/task/taskmanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/task/taskmanager.h b/app/task/taskmanager.h index a559740a2..aaae46be8 100644 --- a/app/task/taskmanager.h +++ b/app/task/taskmanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelinecommon.h b/app/timeline/timelinecommon.h index 33dce0aa6..bfebf66e4 100644 --- a/app/timeline/timelinecommon.h +++ b/app/timeline/timelinecommon.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelinecoordinate.cpp b/app/timeline/timelinecoordinate.cpp index 882fa67fe..f7059c4ab 100644 --- a/app/timeline/timelinecoordinate.cpp +++ b/app/timeline/timelinecoordinate.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelinecoordinate.h b/app/timeline/timelinecoordinate.h index e1e976157..d6bbe3a2e 100644 --- a/app/timeline/timelinecoordinate.h +++ b/app/timeline/timelinecoordinate.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelinemarker.cpp b/app/timeline/timelinemarker.cpp index 35b7d97c3..50411135b 100644 --- a/app/timeline/timelinemarker.cpp +++ b/app/timeline/timelinemarker.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -308,9 +309,11 @@ void TimelineMarkerList::HandleMarkerTimeChange() MarkerAddCommand::MarkerAddCommand(TimelineMarkerList *marker_list, const TimeRange &range, const QString &name, int color) - : MarkerAddCommand(marker_list, - new TimelineMarker(color, range, name, &memory_manager_)) + : marker_list_(marker_list) + , added_marker_(nullptr) { + added_marker_ = new TimelineMarker(color, range, name, &memory_manager_); + added_marker_->setParent(&memory_manager_); } MarkerAddCommand::MarkerAddCommand(TimelineMarkerList *marker_list, diff --git a/app/timeline/timelinemarker.h b/app/timeline/timelinemarker.h index 6d38f56b6..0709947f1 100644 --- a/app/timeline/timelinemarker.h +++ b/app/timeline/timelinemarker.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundocommon.h b/app/timeline/timelineundocommon.h index 51bfaea80..bae3136e1 100644 --- a/app/timeline/timelineundocommon.h +++ b/app/timeline/timelineundocommon.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundogeneral.cpp b/app/timeline/timelineundogeneral.cpp index 00daf34e5..0032cac0e 100644 --- a/app/timeline/timelineundogeneral.cpp +++ b/app/timeline/timelineundogeneral.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundogeneral.h b/app/timeline/timelineundogeneral.h index bd19c223d..7196aed8f 100644 --- a/app/timeline/timelineundogeneral.h +++ b/app/timeline/timelineundogeneral.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundopointer.cpp b/app/timeline/timelineundopointer.cpp index dab1fee02..9d2ba467a 100644 --- a/app/timeline/timelineundopointer.cpp +++ b/app/timeline/timelineundopointer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundopointer.h b/app/timeline/timelineundopointer.h index b591505a7..d2057d609 100644 --- a/app/timeline/timelineundopointer.h +++ b/app/timeline/timelineundopointer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundoripple.cpp b/app/timeline/timelineundoripple.cpp index 38461109d..f0fe73077 100644 --- a/app/timeline/timelineundoripple.cpp +++ b/app/timeline/timelineundoripple.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundoripple.h b/app/timeline/timelineundoripple.h index c6ad30f93..5e3d720d5 100644 --- a/app/timeline/timelineundoripple.h +++ b/app/timeline/timelineundoripple.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundosplit.cpp b/app/timeline/timelineundosplit.cpp index e4400a289..3309f5a77 100644 --- a/app/timeline/timelineundosplit.cpp +++ b/app/timeline/timelineundosplit.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundosplit.h b/app/timeline/timelineundosplit.h index b07671720..3b1687f23 100644 --- a/app/timeline/timelineundosplit.h +++ b/app/timeline/timelineundosplit.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundotrack.cpp b/app/timeline/timelineundotrack.cpp index 7f80dad52..568be8e50 100644 --- a/app/timeline/timelineundotrack.cpp +++ b/app/timeline/timelineundotrack.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundotrack.h b/app/timeline/timelineundotrack.h index 53af0381c..2488a4b89 100644 --- a/app/timeline/timelineundotrack.h +++ b/app/timeline/timelineundotrack.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundoworkarea.cpp b/app/timeline/timelineundoworkarea.cpp index d45a1b21e..098bf01cb 100644 --- a/app/timeline/timelineundoworkarea.cpp +++ b/app/timeline/timelineundoworkarea.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineundoworkarea.h b/app/timeline/timelineundoworkarea.h index 37756f87e..69f0319f4 100644 --- a/app/timeline/timelineundoworkarea.h +++ b/app/timeline/timelineundoworkarea.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineworkarea.cpp b/app/timeline/timelineworkarea.cpp index da4052929..c185391a5 100644 --- a/app/timeline/timelineworkarea.cpp +++ b/app/timeline/timelineworkarea.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/timeline/timelineworkarea.h b/app/timeline/timelineworkarea.h index 1d4d3479b..cce9492a6 100644 --- a/app/timeline/timelineworkarea.h +++ b/app/timeline/timelineworkarea.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/tool/tool.h b/app/tool/tool.h index 6f2bf4c6e..28375d4bb 100644 --- a/app/tool/tool.h +++ b/app/tool/tool.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/ts/ar_AR.ts b/app/ts/ar_AR.ts index 42663dcfa..d878b0198 100644 --- a/app/ts/ar_AR.ts +++ b/app/ts/ar_AR.ts @@ -4764,4 +4764,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + تغيير %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + تحرير المعلمات + + diff --git a/app/ts/bs_BA.ts b/app/ts/bs_BA.ts index cb5cba83d..915375581 100644 --- a/app/ts/bs_BA.ts +++ b/app/ts/bs_BA.ts @@ -4770,4 +4770,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + Promijeni %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Uredi parametre + + diff --git a/app/ts/cs_CZ.ts b/app/ts/cs_CZ.ts index 94cd192d2..dbc0a7307 100644 --- a/app/ts/cs_CZ.ts +++ b/app/ts/cs_CZ.ts @@ -4684,4 +4684,19 @@ Opravdu chcete tento záznam smazat? Vzorky + + OlivePluginInstance + + Change %1 + Změnit %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Upravit parametry + + diff --git a/app/ts/de_DE.ts b/app/ts/de_DE.ts index 37ae0eabd..69e98407a 100644 --- a/app/ts/de_DE.ts +++ b/app/ts/de_DE.ts @@ -5716,4 +5716,19 @@ Soll es wirklich gelöscht werden? Samples + + OlivePluginInstance + + Change %1 + %1 ändern + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Parameter bearbeiten + + diff --git a/app/ts/en_US.ts b/app/ts/en_US.ts index 645d9a47f..2b3b09659 100644 --- a/app/ts/en_US.ts +++ b/app/ts/en_US.ts @@ -51,4 +51,19 @@ + + OlivePluginInstance + + Change %1 + Change %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Edit Parameters + + diff --git a/app/ts/es_ES.ts b/app/ts/es_ES.ts index db8fb45c5..3d8bd9eb6 100644 --- a/app/ts/es_ES.ts +++ b/app/ts/es_ES.ts @@ -4915,4 +4915,19 @@ y salida. Muestras + + OlivePluginInstance + + Change %1 + Cambiar %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Editar parámetros + + diff --git a/app/ts/fr_FR.ts b/app/ts/fr_FR.ts index d5b77bfee..d98998396 100644 --- a/app/ts/fr_FR.ts +++ b/app/ts/fr_FR.ts @@ -4900,4 +4900,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + Modifier %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Modifier les paramètres + + diff --git a/app/ts/hr_HR.ts b/app/ts/hr_HR.ts index 304f3515d..e5eaa9465 100644 --- a/app/ts/hr_HR.ts +++ b/app/ts/hr_HR.ts @@ -4770,4 +4770,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + Promijeni %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Uredi parametre + + diff --git a/app/ts/id_ID.ts b/app/ts/id_ID.ts index 6c9bc644e..d66727c9e 100644 --- a/app/ts/id_ID.ts +++ b/app/ts/id_ID.ts @@ -4764,4 +4764,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + Ubah %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Edit parameter + + diff --git a/app/ts/it_IT.ts b/app/ts/it_IT.ts index a9967c499..abb1deeab 100644 --- a/app/ts/it_IT.ts +++ b/app/ts/it_IT.ts @@ -5476,4 +5476,19 @@ Equivale a moltiplicare per una matrice ortografica. Esempi + + OlivePluginInstance + + Change %1 + Modifica %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Modifica parametri + + diff --git a/app/ts/ja_JP.ts b/app/ts/ja_JP.ts index 457ac9eef..400e9595e 100644 --- a/app/ts/ja_JP.ts +++ b/app/ts/ja_JP.ts @@ -5462,4 +5462,19 @@ Are you sure you wish to delete this footage? サンプル + + OlivePluginInstance + + Change %1 + %1 を変更 + + + %1 (+%2) + %1(+%2) + + + Edit Parameters + パラメーターを編集 + + diff --git a/app/ts/pt_BR.ts b/app/ts/pt_BR.ts index 9c3ab35cd..ad15eb9fc 100644 --- a/app/ts/pt_BR.ts +++ b/app/ts/pt_BR.ts @@ -4764,4 +4764,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + Alterar %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Editar parâmetros + + diff --git a/app/ts/ru_RU.ts b/app/ts/ru_RU.ts index 15ca0fcd0..f7c92a873 100644 --- a/app/ts/ru_RU.ts +++ b/app/ts/ru_RU.ts @@ -6075,4 +6075,19 @@ Duration: %3 Сэмплы + + OlivePluginInstance + + Change %1 + Изменить %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Изменить параметры + + diff --git a/app/ts/sr_RS.ts b/app/ts/sr_RS.ts index 7aa0e4601..a6e88b13a 100644 --- a/app/ts/sr_RS.ts +++ b/app/ts/sr_RS.ts @@ -4770,4 +4770,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + Promeni %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Izmeni parametre + + diff --git a/app/ts/tr_TR.ts b/app/ts/tr_TR.ts index 6d2be9f9d..af5dc00e9 100644 --- a/app/ts/tr_TR.ts +++ b/app/ts/tr_TR.ts @@ -4764,4 +4764,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + %1 değiştir + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Parametreleri düzenle + + diff --git a/app/ts/uk_UK.ts b/app/ts/uk_UK.ts index 4123719ad..994e86b2c 100644 --- a/app/ts/uk_UK.ts +++ b/app/ts/uk_UK.ts @@ -4764,4 +4764,19 @@ What would you like to do with these clips? + + OlivePluginInstance + + Change %1 + Змінити %1 + + + %1 (+%2) + %1 (+%2) + + + Edit Parameters + Редагувати параметри + + diff --git a/app/ts/zh_CN.ts b/app/ts/zh_CN.ts index aad7ff71d..8c2cbf567 100644 --- a/app/ts/zh_CN.ts +++ b/app/ts/zh_CN.ts @@ -7400,4 +7400,19 @@ Please check your audio preferences and try again. 垂直 + + OlivePluginInstance + + Change %1 + 更改 %1 + + + %1 (+%2) + %1(+%2) + + + Edit Parameters + 编辑参数 + + diff --git a/app/ts/zh_TW.ts b/app/ts/zh_TW.ts index 82a89bb7d..303a9dfcb 100644 --- a/app/ts/zh_TW.ts +++ b/app/ts/zh_TW.ts @@ -4777,4 +4777,19 @@ What would you like to do with these clips? 取樣 + + OlivePluginInstance + + Change %1 + 變更 %1 + + + %1 (+%2) + %1(+%2) + + + Edit Parameters + 編輯參數 + + diff --git a/app/ui/colorcoding.cpp b/app/ui/colorcoding.cpp index 58ab473a5..da7af49bf 100644 --- a/app/ui/colorcoding.cpp +++ b/app/ui/colorcoding.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -49,7 +50,7 @@ QString ColorCoding::GetColorName(int c) case kYellow: return tr("Yellow"); case kOlive: - return tr("Olive"); + return tr("Oak"); case kLime: return tr("Lime"); case kGreen: diff --git a/app/ui/colorcoding.h b/app/ui/colorcoding.h index 8986d8b76..3e876622f 100644 --- a/app/ui/colorcoding.h +++ b/app/ui/colorcoding.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/ui/cursors/cursors.qrc b/app/ui/cursors/cursors.qrc index 491a89677..83346a0c0 100644 --- a/app/ui/cursors/cursors.qrc +++ b/app/ui/cursors/cursors.qrc @@ -1,3 +1,21 @@ + + diff --git a/app/ui/cursors/razor-a.svg b/app/ui/cursors/razor-a.svg index 9f8780356..17bb4935a 100644 --- a/app/ui/cursors/razor-a.svg +++ b/app/ui/cursors/razor-a.svg @@ -1,4 +1,22 @@ + + + + + + + + + + + + + + + + + + . + --> + throbber.png + ../../icon.png olive-splash.png diff --git a/app/ui/humanstrings.cpp b/app/ui/humanstrings.cpp index e1c926bb3..6b8a19609 100644 --- a/app/ui/humanstrings.cpp +++ b/app/ui/humanstrings.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "humanstrings.h" #include @@ -74,8 +92,8 @@ QString HumanStrings::FormatToString(const SampleFormat &f) break; } - return QCoreApplication::translate("AudioParams", "Unknown (0x%1)") - .arg(f, 1, 16); + return QCoreApplication::translate("AudioParams", "Unknown (0x%1)") + .arg(static_cast(f), 1, 16); } } diff --git a/app/ui/humanstrings.h b/app/ui/humanstrings.h index 7b4d64708..d9b7d45f1 100644 --- a/app/ui/humanstrings.h +++ b/app/ui/humanstrings.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef HUMANSTRINGS_H #define HUMANSTRINGS_H diff --git a/app/ui/icons/icons.cpp b/app/ui/icons/icons.cpp index 32242a247..45bfb6447 100644 --- a/app/ui/icons/icons.cpp +++ b/app/ui/icons/icons.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/ui/icons/icons.h b/app/ui/icons/icons.h index b9f32701a..9bdfd485e 100644 --- a/app/ui/icons/icons.h +++ b/app/ui/icons/icons.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/ui/style/HOWTO.md b/app/ui/style/HOWTO.md index be26fa5d2..e92b62d95 100644 --- a/app/ui/style/HOWTO.md +++ b/app/ui/style/HOWTO.md @@ -1,13 +1,13 @@ -# How to create an Olive style +# How to create an Oak Video Editor style -Olive supports customization of its interface through CSS (Qt CSS) and icon replacements. +Oak Video Editor supports customization of its interface through CSS (Qt CSS) and icon replacements. To create a style, you'll need to create a CSS file called `style.css` and SVG icons. Feel free to duplicate an existing theme for reference. -To save performance, Olive doesn't actually use the SVGs directly and will need them to be converted to multiple-size +To save performance, Oak Video Editor doesn't actually use the SVGs directly and will need them to be converted to multiple-size PNGs. You don't need to worry about this step though, `generate-style.sh` will do this for you automatically. You'll need to re-run this script any time you change an SVG to update the PNG. -For internal use, `generate-style.sh` will also create a QRC so the style can be compiled into Olive. You'll need to -manually add the QRC to `ui/style/CMakeLists.txt` though. \ No newline at end of file +For internal use, `generate-style.sh` will also create a QRC so the style can be compiled into Oak Video Editor. You'll need to +manually add the QRC to `ui/style/CMakeLists.txt` though. diff --git a/app/ui/style/generate-style.sh b/app/ui/style/generate-style.sh index 03a0af8a5..7f986a764 100755 --- a/app/ui/style/generate-style.sh +++ b/app/ui/style/generate-style.sh @@ -2,6 +2,7 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -16,6 +17,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . + + + + # genicons.sh # # A simple script that uses Inkscape to generate multiple PNG sizes from SVGs. diff --git a/app/ui/style/olive-dark/svg/add-button.svg b/app/ui/style/olive-dark/svg/add-button.svg index 94dc6e4be..9d282cbc2 100644 --- a/app/ui/style/olive-dark/svg/add-button.svg +++ b/app/ui/style/olive-dark/svg/add-button.svg @@ -1,4 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + + + # convert-to-dark.sh # # A simple script that uses sed/regex to convert any use of white to dark grey. diff --git a/app/ui/style/olive-light/svg/copy.svg b/app/ui/style/olive-light/svg/copy.svg index 841bd52b8..908770e3c 100644 --- a/app/ui/style/olive-light/svg/copy.svg +++ b/app/ui/style/olive-light/svg/copy.svg @@ -1,4 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + setStyle(QStyleFactory::create("Fusion")); available_themes_.insert(QStringLiteral("olive-dark"), - QStringLiteral("Olive Dark")); + QStringLiteral("Oak Dark")); available_themes_.insert(QStringLiteral("olive-light"), - QStringLiteral("Olive Light")); + QStringLiteral("Oak Light")); QString config_style = OLIVE_CONFIG("Style").toString(); diff --git a/app/ui/style/style.h b/app/ui/style/style.h index 1818a3f8e..4ff645040 100644 --- a/app/ui/style/style.h +++ b/app/ui/style/style.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/undo/undocommand.cpp b/app/undo/undocommand.cpp index 8357c3125..d5bacd660 100644 --- a/app/undo/undocommand.cpp +++ b/app/undo/undocommand.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/undo/undocommand.h b/app/undo/undocommand.h index 4a8116f7e..66733f183 100644 --- a/app/undo/undocommand.h +++ b/app/undo/undocommand.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/undo/undostack.cpp b/app/undo/undostack.cpp index 870c80c67..fc0c4374c 100644 --- a/app/undo/undostack.cpp +++ b/app/undo/undostack.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/undo/undostack.h b/app/undo/undostack.h index af18e2f27..b51aaa4f1 100644 --- a/app/undo/undostack.h +++ b/app/undo/undostack.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/version.cpp b/app/version.cpp index 62d8dd6bb..e8b0626c8 100644 --- a/app/version.cpp +++ b/app/version.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/version.h b/app/version.h index 609a752ed..176feec09 100644 --- a/app/version.h +++ b/app/version.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/audiomonitor/audiomonitor.cpp b/app/widget/audiomonitor/audiomonitor.cpp index 7921860ca..1df3c306d 100644 --- a/app/widget/audiomonitor/audiomonitor.cpp +++ b/app/widget/audiomonitor/audiomonitor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/audiomonitor/audiomonitor.h b/app/widget/audiomonitor/audiomonitor.h index 3427dd926..c1888ab08 100644 --- a/app/widget/audiomonitor/audiomonitor.h +++ b/app/widget/audiomonitor/audiomonitor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/bezier/bezierwidget.cpp b/app/widget/bezier/bezierwidget.cpp index ac8f6c0e2..8a4ef0b8d 100644 --- a/app/widget/bezier/bezierwidget.cpp +++ b/app/widget/bezier/bezierwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/bezier/bezierwidget.h b/app/widget/bezier/bezierwidget.h index 26633f4f2..1a13da1f5 100644 --- a/app/widget/bezier/bezierwidget.h +++ b/app/widget/bezier/bezierwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/clickablelabel/clickablelabel.cpp b/app/widget/clickablelabel/clickablelabel.cpp index 2708c56af..c97880f63 100644 --- a/app/widget/clickablelabel/clickablelabel.cpp +++ b/app/widget/clickablelabel/clickablelabel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/clickablelabel/clickablelabel.h b/app/widget/clickablelabel/clickablelabel.h index da1fd0f0c..3c54bc938 100644 --- a/app/widget/clickablelabel/clickablelabel.h +++ b/app/widget/clickablelabel/clickablelabel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/collapsebutton/collapsebutton.cpp b/app/widget/collapsebutton/collapsebutton.cpp index f222d1dd7..4e39f58eb 100644 --- a/app/widget/collapsebutton/collapsebutton.cpp +++ b/app/widget/collapsebutton/collapsebutton.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/collapsebutton/collapsebutton.h b/app/widget/collapsebutton/collapsebutton.h index effe7c120..62e052184 100644 --- a/app/widget/collapsebutton/collapsebutton.h +++ b/app/widget/collapsebutton/collapsebutton.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorbutton/colorbutton.cpp b/app/widget/colorbutton/colorbutton.cpp index 40a37cac6..9e86c9aef 100644 --- a/app/widget/colorbutton/colorbutton.cpp +++ b/app/widget/colorbutton/colorbutton.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorbutton/colorbutton.h b/app/widget/colorbutton/colorbutton.h index e9651478c..4ce4aa385 100644 --- a/app/widget/colorbutton/colorbutton.h +++ b/app/widget/colorbutton/colorbutton.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorlabelmenu/colorcodingcombobox.cpp b/app/widget/colorlabelmenu/colorcodingcombobox.cpp index 78730f3f8..f5ef88af9 100644 --- a/app/widget/colorlabelmenu/colorcodingcombobox.cpp +++ b/app/widget/colorlabelmenu/colorcodingcombobox.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorlabelmenu/colorcodingcombobox.h b/app/widget/colorlabelmenu/colorcodingcombobox.h index da2db5373..7fad58698 100644 --- a/app/widget/colorlabelmenu/colorcodingcombobox.h +++ b/app/widget/colorlabelmenu/colorcodingcombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorlabelmenu/colorlabelmenu.cpp b/app/widget/colorlabelmenu/colorlabelmenu.cpp index 6d18ab3b5..2034b3188 100644 --- a/app/widget/colorlabelmenu/colorlabelmenu.cpp +++ b/app/widget/colorlabelmenu/colorlabelmenu.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorlabelmenu/colorlabelmenu.h b/app/widget/colorlabelmenu/colorlabelmenu.h index 4aabb5ba1..328e9dc7a 100644 --- a/app/widget/colorlabelmenu/colorlabelmenu.h +++ b/app/widget/colorlabelmenu/colorlabelmenu.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorgradientwidget.cpp b/app/widget/colorwheel/colorgradientwidget.cpp index 2d65af3d5..34cdf0aae 100644 --- a/app/widget/colorwheel/colorgradientwidget.cpp +++ b/app/widget/colorwheel/colorgradientwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorgradientwidget.h b/app/widget/colorwheel/colorgradientwidget.h index 71f69e181..c1ff1dd63 100644 --- a/app/widget/colorwheel/colorgradientwidget.h +++ b/app/widget/colorwheel/colorgradientwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorpreviewbox.cpp b/app/widget/colorwheel/colorpreviewbox.cpp index a6775b81f..fbf5e3a00 100644 --- a/app/widget/colorwheel/colorpreviewbox.cpp +++ b/app/widget/colorwheel/colorpreviewbox.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorpreviewbox.h b/app/widget/colorwheel/colorpreviewbox.h index 70692d2e4..ce57d12d3 100644 --- a/app/widget/colorwheel/colorpreviewbox.h +++ b/app/widget/colorwheel/colorpreviewbox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorspacechooser.cpp b/app/widget/colorwheel/colorspacechooser.cpp index 25654420f..ac0ec14ee 100644 --- a/app/widget/colorwheel/colorspacechooser.cpp +++ b/app/widget/colorwheel/colorspacechooser.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorspacechooser.h b/app/widget/colorwheel/colorspacechooser.h index ac1913425..f8034bc05 100644 --- a/app/widget/colorwheel/colorspacechooser.h +++ b/app/widget/colorwheel/colorspacechooser.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorswatchchooser.cpp b/app/widget/colorwheel/colorswatchchooser.cpp index 07ccfdab1..02cfac961 100644 --- a/app/widget/colorwheel/colorswatchchooser.cpp +++ b/app/widget/colorwheel/colorswatchchooser.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorswatchchooser.h b/app/widget/colorwheel/colorswatchchooser.h index e2ecba4f9..a9e05fd6b 100644 --- a/app/widget/colorwheel/colorswatchchooser.h +++ b/app/widget/colorwheel/colorswatchchooser.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorswatchwidget.cpp b/app/widget/colorwheel/colorswatchwidget.cpp index 1d3253a20..fd8802858 100644 --- a/app/widget/colorwheel/colorswatchwidget.cpp +++ b/app/widget/colorwheel/colorswatchwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorswatchwidget.h b/app/widget/colorwheel/colorswatchwidget.h index 93996815a..0f4cccf67 100644 --- a/app/widget/colorwheel/colorswatchwidget.h +++ b/app/widget/colorwheel/colorswatchwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorvalueswidget.cpp b/app/widget/colorwheel/colorvalueswidget.cpp index c53bcc547..a2229ff34 100644 --- a/app/widget/colorwheel/colorvalueswidget.cpp +++ b/app/widget/colorwheel/colorvalueswidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorvalueswidget.h b/app/widget/colorwheel/colorvalueswidget.h index 8d270342f..924492834 100644 --- a/app/widget/colorwheel/colorvalueswidget.h +++ b/app/widget/colorwheel/colorvalueswidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorwheelwidget.cpp b/app/widget/colorwheel/colorwheelwidget.cpp index cb6992650..6ae16f8d2 100644 --- a/app/widget/colorwheel/colorwheelwidget.cpp +++ b/app/widget/colorwheel/colorwheelwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/colorwheel/colorwheelwidget.h b/app/widget/colorwheel/colorwheelwidget.h index fe217aece..c5966dce8 100644 --- a/app/widget/colorwheel/colorwheelwidget.h +++ b/app/widget/colorwheel/colorwheelwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/columnedgridlayout/columnedgridlayout.cpp b/app/widget/columnedgridlayout/columnedgridlayout.cpp index f4ce3b358..d14671c85 100644 --- a/app/widget/columnedgridlayout/columnedgridlayout.cpp +++ b/app/widget/columnedgridlayout/columnedgridlayout.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/columnedgridlayout/columnedgridlayout.h b/app/widget/columnedgridlayout/columnedgridlayout.h index a38a2899a..d13945cf0 100644 --- a/app/widget/columnedgridlayout/columnedgridlayout.h +++ b/app/widget/columnedgridlayout/columnedgridlayout.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/curvewidget/curveview.cpp b/app/widget/curvewidget/curveview.cpp index 34fac9c6b..25e608bf6 100644 --- a/app/widget/curvewidget/curveview.cpp +++ b/app/widget/curvewidget/curveview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/curvewidget/curveview.h b/app/widget/curvewidget/curveview.h index 36ecc591c..e1e4f6b09 100644 --- a/app/widget/curvewidget/curveview.h +++ b/app/widget/curvewidget/curveview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index 2234207e9..e576f8314 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/curvewidget/curvewidget.h b/app/widget/curvewidget/curvewidget.h index 9143bbba8..54c512fe6 100644 --- a/app/widget/curvewidget/curvewidget.h +++ b/app/widget/curvewidget/curvewidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/filefield/filefield.cpp b/app/widget/filefield/filefield.cpp index 2d9086766..70e2ae697 100644 --- a/app/widget/filefield/filefield.cpp +++ b/app/widget/filefield/filefield.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/filefield/filefield.h b/app/widget/filefield/filefield.h index a32f72294..7bb4915b4 100644 --- a/app/widget/filefield/filefield.h +++ b/app/widget/filefield/filefield.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/flowlayout/flowlayout.cpp b/app/widget/flowlayout/flowlayout.cpp index 63af95dd9..cffa9ad34 100644 --- a/app/widget/flowlayout/flowlayout.cpp +++ b/app/widget/flowlayout/flowlayout.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Modifications Copyright (C) 2025 mikesolar ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. diff --git a/app/widget/flowlayout/flowlayout.h b/app/widget/flowlayout/flowlayout.h index c70b84071..a6846623b 100644 --- a/app/widget/flowlayout/flowlayout.h +++ b/app/widget/flowlayout/flowlayout.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Modifications Copyright (C) 2025 mikesolar ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. diff --git a/app/widget/focusablelineedit/focusablelineedit.cpp b/app/widget/focusablelineedit/focusablelineedit.cpp index 572d5e02e..348b86bf9 100644 --- a/app/widget/focusablelineedit/focusablelineedit.cpp +++ b/app/widget/focusablelineedit/focusablelineedit.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/focusablelineedit/focusablelineedit.h b/app/widget/focusablelineedit/focusablelineedit.h index 920ea374f..b748171a1 100644 --- a/app/widget/focusablelineedit/focusablelineedit.h +++ b/app/widget/focusablelineedit/focusablelineedit.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/handmovableview/handmovableview.cpp b/app/widget/handmovableview/handmovableview.cpp index 300c50d82..87ccd2cc7 100644 --- a/app/widget/handmovableview/handmovableview.cpp +++ b/app/widget/handmovableview/handmovableview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/handmovableview/handmovableview.h b/app/widget/handmovableview/handmovableview.h index f5785ccaa..97ee32e5f 100644 --- a/app/widget/handmovableview/handmovableview.h +++ b/app/widget/handmovableview/handmovableview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/history/historywidget.cpp b/app/widget/history/historywidget.cpp index b57e21071..0e7d54520 100644 --- a/app/widget/history/historywidget.cpp +++ b/app/widget/history/historywidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/history/historywidget.h b/app/widget/history/historywidget.h index dbe2c2006..105dd6cea 100644 --- a/app/widget/history/historywidget.h +++ b/app/widget/history/historywidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/keyframeview/keyframeview.cpp b/app/widget/keyframeview/keyframeview.cpp index 35a60e061..35403eabd 100644 --- a/app/widget/keyframeview/keyframeview.cpp +++ b/app/widget/keyframeview/keyframeview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/keyframeview/keyframeview.h b/app/widget/keyframeview/keyframeview.h index 9347f2bd2..2eb150725 100644 --- a/app/widget/keyframeview/keyframeview.h +++ b/app/widget/keyframeview/keyframeview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/keyframeview/keyframeviewinputconnection.cpp b/app/widget/keyframeview/keyframeviewinputconnection.cpp index 830fb8163..7a0d0086a 100644 --- a/app/widget/keyframeview/keyframeviewinputconnection.cpp +++ b/app/widget/keyframeview/keyframeviewinputconnection.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/keyframeview/keyframeviewinputconnection.h b/app/widget/keyframeview/keyframeviewinputconnection.h index 14b1c3d5c..1724a323a 100644 --- a/app/widget/keyframeview/keyframeviewinputconnection.h +++ b/app/widget/keyframeview/keyframeviewinputconnection.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/keyframeview/keyframeviewundo.cpp b/app/widget/keyframeview/keyframeviewundo.cpp index b76eaa654..fe24c9f34 100644 --- a/app/widget/keyframeview/keyframeviewundo.cpp +++ b/app/widget/keyframeview/keyframeviewundo.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/keyframeview/keyframeviewundo.h b/app/widget/keyframeview/keyframeviewundo.h index a716fcd09..eca6c8f3e 100644 --- a/app/widget/keyframeview/keyframeviewundo.h +++ b/app/widget/keyframeview/keyframeviewundo.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/manageddisplay/manageddisplay.cpp b/app/widget/manageddisplay/manageddisplay.cpp index af7e6c072..e25f16e0d 100644 --- a/app/widget/manageddisplay/manageddisplay.cpp +++ b/app/widget/manageddisplay/manageddisplay.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/manageddisplay/manageddisplay.h b/app/widget/manageddisplay/manageddisplay.h index 95a47ca49..817cbf703 100644 --- a/app/widget/manageddisplay/manageddisplay.h +++ b/app/widget/manageddisplay/manageddisplay.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/menu/menu.cpp b/app/widget/menu/menu.cpp index 84380f87d..3013d29d6 100644 --- a/app/widget/menu/menu.cpp +++ b/app/widget/menu/menu.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/menu/menu.h b/app/widget/menu/menu.h index 99216a3d8..d4e1b8f53 100644 --- a/app/widget/menu/menu.h +++ b/app/widget/menu/menu.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/menu/menushared.cpp b/app/widget/menu/menushared.cpp index 03ceb03cd..957285903 100644 --- a/app/widget/menu/menushared.cpp +++ b/app/widget/menu/menushared.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/menu/menushared.h b/app/widget/menu/menushared.h index f9d50bcc1..8a6612a0b 100644 --- a/app/widget/menu/menushared.h +++ b/app/widget/menu/menushared.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/multicam/multicamdisplay.cpp b/app/widget/multicam/multicamdisplay.cpp index 54d0aa9e4..2f11f1c15 100644 --- a/app/widget/multicam/multicamdisplay.cpp +++ b/app/widget/multicam/multicamdisplay.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/multicam/multicamdisplay.h b/app/widget/multicam/multicamdisplay.h index a701b6d3b..505150c08 100644 --- a/app/widget/multicam/multicamdisplay.h +++ b/app/widget/multicam/multicamdisplay.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/multicam/multicamwidget.cpp b/app/widget/multicam/multicamwidget.cpp index 743173143..4a092b933 100644 --- a/app/widget/multicam/multicamwidget.cpp +++ b/app/widget/multicam/multicamwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/multicam/multicamwidget.h b/app/widget/multicam/multicamwidget.h index 30a8b7b07..d789e908f 100644 --- a/app/widget/multicam/multicamwidget.h +++ b/app/widget/multicam/multicamwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodecombobox/nodecombobox.cpp b/app/widget/nodecombobox/nodecombobox.cpp index 7eb1fad3e..be1d14d81 100644 --- a/app/widget/nodecombobox/nodecombobox.cpp +++ b/app/widget/nodecombobox/nodecombobox.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodecombobox/nodecombobox.h b/app/widget/nodecombobox/nodecombobox.h index b0f76aec4..fb9c95414 100644 --- a/app/widget/nodecombobox/nodecombobox.h +++ b/app/widget/nodecombobox/nodecombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/CMakeLists.txt b/app/widget/nodeparamview/CMakeLists.txt index 1b80edebc..64a8377f4 100644 --- a/app/widget/nodeparamview/CMakeLists.txt +++ b/app/widget/nodeparamview/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -15,28 +16,30 @@ # along with this program. If not, see . set(OLIVE_SOURCES - ${OLIVE_SOURCES} - widget/nodeparamview/nodeparamview.cpp - widget/nodeparamview/nodeparamview.h - widget/nodeparamview/nodeparamviewarraywidget.cpp - widget/nodeparamview/nodeparamviewarraywidget.h - widget/nodeparamview/nodeparamviewconnectedlabel.cpp - widget/nodeparamview/nodeparamviewconnectedlabel.h - widget/nodeparamview/nodeparamviewcontext.cpp - widget/nodeparamview/nodeparamviewcontext.h - widget/nodeparamview/nodeparamviewdockarea.cpp - widget/nodeparamview/nodeparamviewdockarea.h - widget/nodeparamview/nodeparamviewitem.cpp - widget/nodeparamview/nodeparamviewitem.h - widget/nodeparamview/nodeparamviewitembase.cpp - widget/nodeparamview/nodeparamviewitembase.h - widget/nodeparamview/nodeparamviewitemtitlebar.cpp - widget/nodeparamview/nodeparamviewitemtitlebar.h - widget/nodeparamview/nodeparamviewkeyframecontrol.cpp - widget/nodeparamview/nodeparamviewkeyframecontrol.h - widget/nodeparamview/nodeparamviewtextedit.cpp - widget/nodeparamview/nodeparamviewtextedit.h - widget/nodeparamview/nodeparamviewwidgetbridge.cpp - widget/nodeparamview/nodeparamviewwidgetbridge.h - PARENT_SCOPE + ${OLIVE_SOURCES} + widget/nodeparamview/nodeparamview.cpp + widget/nodeparamview/nodeparamview.h + widget/nodeparamview/nodeparamviewarraywidget.cpp + widget/nodeparamview/nodeparamviewarraywidget.h + widget/nodeparamview/nodeparamviewconnectedlabel.cpp + widget/nodeparamview/nodeparamviewconnectedlabel.h + widget/nodeparamview/nodeparamviewcontext.cpp + widget/nodeparamview/nodeparamviewcontext.h + widget/nodeparamview/nodeparamviewdockarea.cpp + widget/nodeparamview/nodeparamviewdockarea.h + widget/nodeparamview/nodeparamviewitem.cpp + widget/nodeparamview/nodeparamviewitem.h + widget/nodeparamview/nodeparamviewitembase.cpp + widget/nodeparamview/nodeparamviewitembase.h + widget/nodeparamview/nodeparamviewitemtitlebar.cpp + widget/nodeparamview/nodeparamviewitemtitlebar.h + widget/nodeparamview/nodeparamviewkeyframecontrol.cpp + widget/nodeparamview/nodeparamviewkeyframecontrol.h + widget/nodeparamview/nodeparamviewtextedit.cpp + widget/nodeparamview/nodeparamviewtextedit.h + widget/nodeparamview/nodeparamviewwidgetbridge.cpp + widget/nodeparamview/nodeparamviewwidgetbridge.h + widget/nodeparamview/nodeparambutton.h + widget/nodeparamview/nodeparambutton.cpp + PARENT_SCOPE ) diff --git a/app/widget/nodeparamview/nodeparambutton.cpp b/app/widget/nodeparamview/nodeparambutton.cpp new file mode 100644 index 000000000..775838c46 --- /dev/null +++ b/app/widget/nodeparamview/nodeparambutton.cpp @@ -0,0 +1,20 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "nodeparambutton.h" diff --git a/app/widget/nodeparamview/nodeparambutton.h b/app/widget/nodeparamview/nodeparambutton.h new file mode 100644 index 000000000..1c427b835 --- /dev/null +++ b/app/widget/nodeparamview/nodeparambutton.h @@ -0,0 +1,47 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef NODEPARAMBUTTON_H +#define NODEPARAMBUTTON_H +#include "node/plugins/Plugin.h" + +#include + +class NodeParamButton : public QPushButton{ +Q_OBJECT +public: + NodeParamButton(QString name, QWidget *parent = nullptr):QPushButton(parent) + { + this->name_=name; + connect(this, &QPushButton::clicked, this, &NodeParamButton::pressed); + } +signals: + void onPressed(QString name); +private slots: + void pressed(){ + emit onPressed(name_); + } +private: + QString name_; + +}; + + + +#endif //NODEPARAMBUTTON_H diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index 973d7225e..fa0697ba9 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 1f0cecc94..e6ae460ef 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewarraywidget.cpp b/app/widget/nodeparamview/nodeparamviewarraywidget.cpp index b39336f1d..d7dbfd27c 100644 --- a/app/widget/nodeparamview/nodeparamviewarraywidget.cpp +++ b/app/widget/nodeparamview/nodeparamviewarraywidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewarraywidget.h b/app/widget/nodeparamview/nodeparamviewarraywidget.h index 4810fae76..27aee635d 100644 --- a/app/widget/nodeparamview/nodeparamviewarraywidget.h +++ b/app/widget/nodeparamview/nodeparamviewarraywidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp index ab9cc2638..3f9c03d59 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h index c26244249..ecfedf98d 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewcontext.cpp b/app/widget/nodeparamview/nodeparamviewcontext.cpp index ccbe1b043..22b82a584 100644 --- a/app/widget/nodeparamview/nodeparamviewcontext.cpp +++ b/app/widget/nodeparamview/nodeparamviewcontext.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -76,7 +77,7 @@ void NodeParamViewContext::RemoveNode(Node *node, Node *ctx) if (item->GetNode() == node && item->GetContext() == ctx) { emit AboutToDeleteItem(item); - delete item; + dock_area_->RemoveItem(item); it = items_.erase(it); } else { it++; @@ -91,7 +92,7 @@ void NodeParamViewContext::RemoveNodesWithContext(Node *ctx) if (item->GetContext() == ctx) { emit AboutToDeleteItem(item); - delete item; + dock_area_->RemoveItem(item); it = items_.erase(it); } else { it++; diff --git a/app/widget/nodeparamview/nodeparamviewcontext.h b/app/widget/nodeparamview/nodeparamviewcontext.h index a9bec5f2e..3f99b9c0e 100644 --- a/app/widget/nodeparamview/nodeparamviewcontext.h +++ b/app/widget/nodeparamview/nodeparamviewcontext.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewdockarea.cpp b/app/widget/nodeparamview/nodeparamviewdockarea.cpp index 3843f6069..af91aa80f 100644 --- a/app/widget/nodeparamview/nodeparamviewdockarea.cpp +++ b/app/widget/nodeparamview/nodeparamviewdockarea.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -49,4 +50,14 @@ void NodeParamViewDockArea::AddItem(QDockWidget *item) addDockWidget(Qt::LeftDockWidgetArea, item); } +void NodeParamViewDockArea::RemoveItem(QDockWidget *item) +{ + if (!item) { + return; + } + removeDockWidget(item); + item->setParent(nullptr); + item->deleteLater(); +} + } diff --git a/app/widget/nodeparamview/nodeparamviewdockarea.h b/app/widget/nodeparamview/nodeparamviewdockarea.h index 8ea7d6167..44826876f 100644 --- a/app/widget/nodeparamview/nodeparamviewdockarea.h +++ b/app/widget/nodeparamview/nodeparamviewdockarea.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -36,6 +37,7 @@ public: virtual QMenu *createPopupMenu() override; void AddItem(QDockWidget *item); + void RemoveItem(QDockWidget *item); }; } diff --git a/app/widget/nodeparamview/nodeparamviewitem.cpp b/app/widget/nodeparamview/nodeparamviewitem.cpp index 431030622..2a32ee845 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.cpp +++ b/app/widget/nodeparamview/nodeparamviewitem.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -29,6 +30,7 @@ #include "node/group/group.h" #include "node/nodeundo.h" #include "node/project/sequence/sequence.h" +#include "pluginSupport/OlivePluginInstance.h" namespace olive { @@ -51,6 +53,9 @@ NodeParamViewItem::NodeParamViewItem( QWidget *parent) : super(parent) , body_(nullptr) + , message_label_(nullptr) + , message_clear_button_(nullptr) + , message_container_(nullptr) , node_(node) , create_checkboxes_(create_checkboxes) , ctx_(nullptr) @@ -64,6 +69,8 @@ NodeParamViewItem::NodeParamViewItem( connect(node_, &Node::LabelChanged, this, &NodeParamViewItem::Retranslate); connect(node_, &Node::InputArraySizeChanged, this, &NodeParamViewItem::InputArraySizeChanged); + connect(node_, &Node::MessageCountChanged, this, + &NodeParamViewItem::UpdateMessagePanel); // FIXME: Implemented to pick up when an input is set to hidden or not - DEFINITELY not a fast // way of doing this, but "fine" for now. @@ -95,6 +102,13 @@ void NodeParamViewItem::RecreateBody() body_->setParent(nullptr); body_->deleteLater(); } + if (message_container_) { + message_container_->setParent(nullptr); + message_container_->deleteLater(); + message_container_ = nullptr; + message_label_ = nullptr; + message_clear_button_ = nullptr; + } body_ = new NodeParamViewItemBody(node_, create_checkboxes_, this); connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, @@ -108,7 +122,73 @@ void NodeParamViewItem::RecreateBody() body_->Retranslate(); body_->SetTimebase(timebase_); body_->SetTimeTarget(time_target_); - SetBody(body_); + + message_container_ = new QWidget(this); + QVBoxLayout *message_layout = new QVBoxLayout(message_container_); + message_layout->setContentsMargins(0, 0, 0, 0); + message_layout->setSpacing(4); + + QHBoxLayout *message_header = new QHBoxLayout(); + message_header->setContentsMargins(0, 0, 0, 0); + message_header->addStretch(); + message_clear_button_ = new QPushButton(tr("Clear"), message_container_); + message_clear_button_->setVisible(false); + connect(message_clear_button_, &QPushButton::clicked, this, + &NodeParamViewItem::ClearMessages); + message_header->addWidget(message_clear_button_); + message_layout->addLayout(message_header); + + message_label_ = new QLabel(message_container_); + message_label_->setWordWrap(true); + message_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); + message_label_->setStyleSheet( + QStringLiteral("background: rgba(0, 0, 0, 0.06); padding: 6px;")); + message_layout->addWidget(message_label_); + message_layout->addWidget(body_); + + SetBody(message_container_); + UpdateMessagePanel(); +} + +void NodeParamViewItem::UpdateMessagePanel() +{ + if (!message_label_) { + return; + } + + auto *instance = node_->getPluginInstance(); + auto *olive_instance = + dynamic_cast(instance); + if (!olive_instance || olive_instance->persistentMessageCount() == 0) { + message_label_->setVisible(false); + if (message_clear_button_) { + message_clear_button_->setVisible(false); + } + return; + } + + QStringList lines; + for (const auto &msg : olive_instance->persistentMessages()) { + QString prefix; + switch (msg.type) { + case plugin::ErrorType::Error: + prefix = QStringLiteral("Error"); + break; + case plugin::ErrorType::Warning: + prefix = QStringLiteral("Warning"); + break; + case plugin::ErrorType::Message: + prefix = QStringLiteral("Message"); + break; + } + lines.append(QStringLiteral("%1: %2").arg(prefix, msg.message)); + } + + message_label_->setText(lines.join('\n')); + message_label_->setVisible(true); + if (message_clear_button_) { + message_clear_button_->setVisible(true); + } } int NodeParamViewItem::GetElementY(const NodeInput &c) const @@ -126,6 +206,18 @@ void NodeParamViewItem::SetInputChecked(const NodeInput &input, bool e) body_->SetInputChecked(input, e); } +void NodeParamViewItem::ClearMessages() +{ + auto *instance = node_->getPluginInstance(); + auto *olive_instance = + dynamic_cast(instance); + if (!olive_instance) { + return; + } + + olive_instance->clearPersistentMessage(); +} + NodeParamViewItemBody::NodeParamViewItemBody( Node *node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget *parent) @@ -137,6 +229,8 @@ NodeParamViewItemBody::NodeParamViewItemBody( QGridLayout *root_layout = new QGridLayout(this); int insert_row = 0; + QString current_page; + QString current_group; QVector connected_signals; @@ -160,6 +254,27 @@ NodeParamViewItemBody::NodeParamViewItemBody( { n, input }); if (!(n->GetInputFlags(input) & kInputFlagHidden)) { + QString page_label = n->GetInputProperty(input, QStringLiteral("ui_page")).toString(); + QString group_label = n->GetInputProperty(input, QStringLiteral("ui_group")).toString(); + if (!page_label.isEmpty() && page_label != current_page) { + QLabel *page_title = new QLabel(page_label, this); + QFont f = page_title->font(); + f.setBold(true); + page_title->setFont(f); + root_layout->addWidget(page_title, insert_row, 0, 1, 10); + insert_row++; + current_page = page_label; + current_group.clear(); + } + if (!group_label.isEmpty() && group_label != current_group) { + QLabel *group_title = new QLabel(group_label, this); + QFont f = group_title->font(); + f.setBold(true); + group_title->setFont(f); + root_layout->addWidget(group_title, insert_row, 0, 1, 10); + insert_row++; + current_group = group_label; + } CreateWidgets(root_layout, n, input, -1, insert_row); insert_row++; diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index cd7ba3204..8e2beabba 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -234,6 +235,9 @@ protected slots: private: NodeParamViewItemBody *body_; + QLabel *message_label_; + QPushButton *message_clear_button_; + QWidget *message_container_; Node *node_; @@ -249,6 +253,8 @@ private: private slots: void RecreateBody(); + void UpdateMessagePanel(); + void ClearMessages(); }; } diff --git a/app/widget/nodeparamview/nodeparamviewitembase.cpp b/app/widget/nodeparamview/nodeparamviewitembase.cpp index e94907feb..b3ed57434 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.cpp +++ b/app/widget/nodeparamview/nodeparamviewitembase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewitembase.h b/app/widget/nodeparamview/nodeparamviewitembase.h index 674c7991c..fd137b7e1 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.h +++ b/app/widget/nodeparamview/nodeparamviewitembase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp index 5ea956680..03ce287df 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h index 501cd9ba4..11334d369 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp index 86c508159..f66ae4a8b 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h index bdcc10e60..1fb2a2ea8 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewtextedit.cpp b/app/widget/nodeparamview/nodeparamviewtextedit.cpp index ff9f57d2a..9da0ff5fd 100644 --- a/app/widget/nodeparamview/nodeparamviewtextedit.cpp +++ b/app/widget/nodeparamview/nodeparamviewtextedit.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewtextedit.h b/app/widget/nodeparamview/nodeparamviewtextedit.h index b2b37ce80..427942972 100644 --- a/app/widget/nodeparamview/nodeparamviewtextedit.h +++ b/app/widget/nodeparamview/nodeparamviewtextedit.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index eee8df177..09ecc1245 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -28,6 +29,7 @@ #include "common/qtutils.h" #include "core.h" +#include "nodeparambutton.h" #include "node/group/group.h" #include "node/node.h" #include "node/nodeundo.h" @@ -42,6 +44,8 @@ #include "widget/slider/integerslider.h" #include "widget/slider/rationalslider.h" +#include + namespace olive { @@ -109,12 +113,22 @@ void NodeParamViewWidgetBridge::CreateWidgets() CreateSliders(GetSliderCount(t), parent); break; } - case NodeValue::kCombo: { + case NodeValue::kCombo: + case NodeValue::kStrCombo: { QComboBox *combobox = new QComboBox(parent); QStringList items = GetInnerInput().GetComboBoxStrings(); - foreach (const QString &s, items) { - combobox->addItem(s); + QStringList values = + GetInnerInput().GetProperty("combo_value_str").toStringList(); + const bool use_value_data = + (t == NodeValue::kStrCombo) && !values.isEmpty(); + for (int i = 0; i < items.size(); ++i) { + const QString &label = items.at(i); + if (use_value_data && i < values.size()) { + combobox->addItem(label, values.at(i)); + } else { + combobox->addItem(label); + } } widgets_.append(combobox); @@ -181,6 +195,13 @@ void NodeParamViewWidgetBridge::CreateWidgets() &NodeParamViewWidgetBridge::WidgetCallback); break; } + case NodeValue::kPushButton: { + NodeInput input=GetInnerInput(); + NodeParamButton *button=new NodeParamButton(input.name(),parent); + widgets_.append(button); + plugin::PluginNode* plugin_node=dynamic_cast(input.node()); + connect(button, &NodeParamButton::onPressed, plugin_node, &plugin::PluginNode::pushButtonClicked); + } } // Check all properties @@ -253,7 +274,6 @@ void NodeParamViewWidgetBridge::WidgetCallback() case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kSubtitleParams: - case NodeValue::kBinary: case NodeValue::kDataTypeCount: break; case NodeValue::kInt: { @@ -334,6 +354,16 @@ void NodeParamViewWidgetBridge::WidgetCallback() 0); break; } + case NodeValue::kBinary: { + QString text = static_cast(sender())->text(); + QByteArray raw = text.toUtf8(); + QByteArray decoded = QByteArray::fromBase64(raw); + if (decoded.isEmpty() && !raw.isEmpty()) { + decoded = raw; + } + SetInputValue(decoded, 0); + break; + } case NodeValue::kBoolean: { // Widget is a QCheckBox SetInputValue(static_cast(sender())->isChecked(), 0); @@ -361,6 +391,16 @@ void NodeParamViewWidgetBridge::WidgetCallback() SetInputValue(index, 0); break; } + case NodeValue::kStrCombo: { + QComboBox *cb = static_cast(widgets_.first()); + const QVariant data = cb->currentData(); + if (data.isValid()) { + SetInputValue(data.toString(), 0); + } else { + SetInputValue(cb->currentText(), 0); + } + break; + } case NodeValue::kBezier: { // Widget is a FloatSlider (child of BezierWidget) BezierWidget *bw = static_cast(widgets_.first()); @@ -432,9 +472,15 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kSubtitleParams: - case NodeValue::kBinary: case NodeValue::kDataTypeCount: break; + case NodeValue::kBinary: { + NodeParamViewTextEdit *e = + static_cast(widgets_.first()); + QByteArray bytes = GetInnerInput().GetValueAtTime(node_time).toByteArray(); + e->setTextPreservingCursor(QString::fromUtf8(bytes.toBase64())); + break; + } case NodeValue::kInt: { static_cast(widgets_.first()) ->SetValue(GetInnerInput().GetValueAtTime(node_time).toLongLong()); @@ -538,6 +584,22 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() cb->blockSignals(false); break; } + case NodeValue::kStrCombo: { + QComboBox *cb = static_cast(widgets_.first()); + cb->blockSignals(true); + const QString current = + GetInnerInput().GetValueAtTime(node_time).toString(); + for (int i = 0; i < cb->count(); ++i) { + const QVariant data = cb->itemData(i); + if ((data.isValid() && data.toString() == current) || + (!data.isValid() && cb->itemText(i) == current)) { + cb->setCurrentIndex(i); + break; + } + } + cb->blockSignals(false); + break; + } case NodeValue::kBezier: { BezierWidget *bw = static_cast(widgets_.first()); bw->SetValue(GetInnerInput().GetValueAtTime(node_time).value()); @@ -749,7 +811,7 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, } // ComboBox strings changing - if (data_type == NodeValue::kCombo) { + if (data_type == NodeValue::kCombo || data_type == NodeValue::kStrCombo) { if (key == QStringLiteral("combo_str")) { QComboBox *cb = static_cast(widgets_.first()); @@ -761,14 +823,23 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, cb->clear(); QStringList items = value.toStringList(); + QStringList values = + GetInnerInput().GetProperty("combo_value_str").toStringList(); + const bool use_value_data = + (data_type == NodeValue::kStrCombo) && !values.isEmpty(); int index = 0; - foreach (const QString &s, items) { + for (int i = 0; i < items.size(); ++i) { + const QString &s = items.at(i); if (s.isEmpty()) { cb->insertSeparator(cb->count()); cb->setItemData(cb->count() - 1, -1); } else { - cb->addItem(s, index); - index++; + if (use_value_data && i < values.size()) { + cb->addItem(s, values.at(i)); + } else { + cb->addItem(s, index); + index++; + } } } diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index 1cd182623..9780b381d 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodetableview/nodetableview.cpp b/app/widget/nodetableview/nodetableview.cpp index 3687ebfe4..810ffadef 100644 --- a/app/widget/nodetableview/nodetableview.cpp +++ b/app/widget/nodetableview/nodetableview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodetableview/nodetableview.h b/app/widget/nodetableview/nodetableview.h index d908e5ec2..f89c50a64 100644 --- a/app/widget/nodetableview/nodetableview.h +++ b/app/widget/nodetableview/nodetableview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodetableview/nodetablewidget.cpp b/app/widget/nodetableview/nodetablewidget.cpp index 9e83d5ba1..213bf7998 100644 --- a/app/widget/nodetableview/nodetablewidget.cpp +++ b/app/widget/nodetableview/nodetablewidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodetableview/nodetablewidget.h b/app/widget/nodetableview/nodetablewidget.h index a872ba824..5384af5c0 100644 --- a/app/widget/nodetableview/nodetablewidget.h +++ b/app/widget/nodetableview/nodetablewidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodetreeview/nodetreeview.cpp b/app/widget/nodetreeview/nodetreeview.cpp index 01d00d655..6e8a57e80 100644 --- a/app/widget/nodetreeview/nodetreeview.cpp +++ b/app/widget/nodetreeview/nodetreeview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodetreeview/nodetreeview.h b/app/widget/nodetreeview/nodetreeview.h index 74d224135..577d66671 100644 --- a/app/widget/nodetreeview/nodetreeview.h +++ b/app/widget/nodetreeview/nodetreeview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodevaluetree/nodevaluetree.cpp b/app/widget/nodevaluetree/nodevaluetree.cpp index bca520c0a..5a408ca0f 100644 --- a/app/widget/nodevaluetree/nodevaluetree.cpp +++ b/app/widget/nodevaluetree/nodevaluetree.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "nodevaluetree.h" #include diff --git a/app/widget/nodevaluetree/nodevaluetree.h b/app/widget/nodevaluetree/nodevaluetree.h index ed3475364..075f79472 100644 --- a/app/widget/nodevaluetree/nodevaluetree.h +++ b/app/widget/nodevaluetree/nodevaluetree.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef NODEVALUETREE_H #define NODEVALUETREE_H diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 090e2456c..e2aeacfc1 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -34,6 +35,7 @@ #include "node/group/group.h" #include "node/nodeundo.h" #include "node/project/serializer/serializer.h" +#include "panel/panelmanager.h" #include "node/traverser.h" #include "ui/icons/icons.h" #include "widget/menu/menushared.h" @@ -641,6 +643,15 @@ void NodeView::mouseDoubleClickEvent(QMouseEvent *event) dynamic_cast(itemAt(event->pos())); if (item_at_cursor) { item_at_cursor->ToggleExpanded(); + if (PanelManager::instance()) { + if (PanelWidget *panel = PanelManager::instance() + ->GetPanelWithName( + QStringLiteral("ParamPanel"))) { + panel->show(); + panel->raise(); + panel->setFocus(Qt::OtherFocusReason); + } + } } } } diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index 925d54593..b28e60326 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewcommon.h b/app/widget/nodeview/nodeviewcommon.h index 8f70f5b6d..bc0384338 100644 --- a/app/widget/nodeview/nodeviewcommon.h +++ b/app/widget/nodeview/nodeviewcommon.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewcontext.cpp b/app/widget/nodeview/nodeviewcontext.cpp index 3acedd743..8faa79e33 100644 --- a/app/widget/nodeview/nodeviewcontext.cpp +++ b/app/widget/nodeview/nodeviewcontext.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "nodeviewcontext.h" #include diff --git a/app/widget/nodeview/nodeviewcontext.h b/app/widget/nodeview/nodeviewcontext.h index bdabeb189..9f9e57b10 100644 --- a/app/widget/nodeview/nodeviewcontext.h +++ b/app/widget/nodeview/nodeviewcontext.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef NODEVIEWCONTEXT_H #define NODEVIEWCONTEXT_H diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp index b413988e1..883893336 100644 --- a/app/widget/nodeview/nodeviewedge.cpp +++ b/app/widget/nodeview/nodeviewedge.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewedge.h b/app/widget/nodeview/nodeviewedge.h index 67d793ea2..863050729 100644 --- a/app/widget/nodeview/nodeviewedge.h +++ b/app/widget/nodeview/nodeviewedge.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index 642e55be3..c086c40b2 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -30,6 +31,7 @@ #include "config/config.h" #include "core.h" #include "node/nodeundo.h" +#include "pluginSupport/OlivePluginInstance.h" #include "nodeview.h" #include "nodeviewscene.h" #include "ui/colorcoding.h" @@ -70,6 +72,8 @@ NodeViewItem::NodeViewItem(Node *node, const QString &input, int element, &NodeViewItem::NodeAppearanceChanged); connect(node_, &Node::ColorChanged, this, &NodeViewItem::NodeAppearanceChanged); + connect(node_, &Node::MessageCountChanged, this, + &NodeViewItem::NodeAppearanceChanged); if (IsOutputItem()) { connect(node_, &Node::InputAdded, this, @@ -430,6 +434,41 @@ void NodeViewItem::paint(QPainter *painter, arrow_size); } + if (IsOutputItem()) { + auto *instance = node_->getPluginInstance(); + auto *olive_instance = + dynamic_cast(instance); + int message_count = + olive_instance ? olive_instance->persistentMessageCount() : 0; + + if (message_count > 0) { + QString badge_text = QString::number(message_count); + QFont badge_font = painter->font(); + badge_font.setPointSizeF(badge_font.pointSizeF() * 0.7); + painter->setFont(badge_font); + + QFontMetrics badge_metrics(badge_font); + int text_width = badge_metrics.horizontalAdvance(badge_text); + int text_height = badge_metrics.height(); + int pad = text_height / 3; + int badge_width = qMax(text_width + pad * 2, text_height + pad); + int badge_height = text_height + pad; + + QRectF badge_rect( + single_unit_rect.right() - badge_width - 4, + single_unit_rect.top() + 4, + badge_width, badge_height); + + painter->setPen(Qt::NoPen); + painter->setBrush(QColor(220, 50, 47)); + painter->drawRoundedRect(badge_rect, badge_height / 2, + badge_height / 2); + + painter->setPen(Qt::white); + painter->drawText(badge_rect, Qt::AlignCenter, badge_text); + } + } + // Draw final border (output only) if (IsOutputItem()) { QPen border_pen; diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index d61dc5756..f8c04588f 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewitemconnector.cpp b/app/widget/nodeview/nodeviewitemconnector.cpp index 73f06e957..ebf5b3285 100644 --- a/app/widget/nodeview/nodeviewitemconnector.cpp +++ b/app/widget/nodeview/nodeviewitemconnector.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewitemconnector.h b/app/widget/nodeview/nodeviewitemconnector.h index 59fef354b..a7dffe5ad 100644 --- a/app/widget/nodeview/nodeviewitemconnector.h +++ b/app/widget/nodeview/nodeviewitemconnector.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewminimap.cpp b/app/widget/nodeview/nodeviewminimap.cpp index d541423a4..37fe868f5 100644 --- a/app/widget/nodeview/nodeviewminimap.cpp +++ b/app/widget/nodeview/nodeviewminimap.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewminimap.h b/app/widget/nodeview/nodeviewminimap.h index 543289d08..6ab88abe2 100644 --- a/app/widget/nodeview/nodeviewminimap.h +++ b/app/widget/nodeview/nodeviewminimap.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp index 8e5ec2c19..5df079778 100644 --- a/app/widget/nodeview/nodeviewscene.cpp +++ b/app/widget/nodeview/nodeviewscene.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h index 1b02d3483..d5b05c654 100644 --- a/app/widget/nodeview/nodeviewscene.h +++ b/app/widget/nodeview/nodeviewscene.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodeviewtoolbar.cpp b/app/widget/nodeview/nodeviewtoolbar.cpp index 8c41a1926..b2f789280 100644 --- a/app/widget/nodeview/nodeviewtoolbar.cpp +++ b/app/widget/nodeview/nodeviewtoolbar.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "nodeviewtoolbar.h" #include diff --git a/app/widget/nodeview/nodeviewtoolbar.h b/app/widget/nodeview/nodeviewtoolbar.h index ac798ac71..519f1850f 100644 --- a/app/widget/nodeview/nodeviewtoolbar.h +++ b/app/widget/nodeview/nodeviewtoolbar.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef NODEVIEWTOOLBAR_H #define NODEVIEWTOOLBAR_H diff --git a/app/widget/nodeview/nodewidget.cpp b/app/widget/nodeview/nodewidget.cpp index 974a5a191..d7fd7762d 100644 --- a/app/widget/nodeview/nodewidget.cpp +++ b/app/widget/nodeview/nodewidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/nodeview/nodewidget.h b/app/widget/nodeview/nodewidget.h index 2766d1f56..7909cc88c 100644 --- a/app/widget/nodeview/nodewidget.h +++ b/app/widget/nodeview/nodewidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/path/pathwidget.cpp b/app/widget/path/pathwidget.cpp index b36eeb60d..30074a66d 100644 --- a/app/widget/path/pathwidget.cpp +++ b/app/widget/path/pathwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/path/pathwidget.h b/app/widget/path/pathwidget.h index d19a1b7a4..f57a2ad2e 100644 --- a/app/widget/path/pathwidget.h +++ b/app/widget/path/pathwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/pixelsampler/pixelsampler.cpp b/app/widget/pixelsampler/pixelsampler.cpp index 08e2e27dd..241472e51 100644 --- a/app/widget/pixelsampler/pixelsampler.cpp +++ b/app/widget/pixelsampler/pixelsampler.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/pixelsampler/pixelsampler.h b/app/widget/pixelsampler/pixelsampler.h index 238585f57..8956fa8dc 100644 --- a/app/widget/pixelsampler/pixelsampler.h +++ b/app/widget/pixelsampler/pixelsampler.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/playbackcontrols/dragbutton.cpp b/app/widget/playbackcontrols/dragbutton.cpp index c0eb95f14..716c6bf4d 100644 --- a/app/widget/playbackcontrols/dragbutton.cpp +++ b/app/widget/playbackcontrols/dragbutton.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/playbackcontrols/dragbutton.h b/app/widget/playbackcontrols/dragbutton.h index 2ffeb5b2a..d4e6a68ca 100644 --- a/app/widget/playbackcontrols/dragbutton.h +++ b/app/widget/playbackcontrols/dragbutton.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2023 Olive Studios LLC + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/playbackcontrols/playbackcontrols.cpp b/app/widget/playbackcontrols/playbackcontrols.cpp index 46096cbd1..9fcf1a442 100644 --- a/app/widget/playbackcontrols/playbackcontrols.cpp +++ b/app/widget/playbackcontrols/playbackcontrols.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/playbackcontrols/playbackcontrols.h b/app/widget/playbackcontrols/playbackcontrols.h index 8621d9162..0b56054bc 100644 --- a/app/widget/playbackcontrols/playbackcontrols.h +++ b/app/widget/playbackcontrols/playbackcontrols.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index 6cb642fd1..143e9d9a3 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -508,8 +509,18 @@ void ProjectExplorer::ReplaceSelectedFootage() { Footage *footage = static_cast(context_menu_items_.first()); - QString file = QFileDialog::getOpenFileName(this, tr("Replace Footage")); + QString file = QFileDialog::getOpenFileName( + this, tr("Replace Footage"), QString(), + Core::FootageFileDialogFilter()); if (!file.isEmpty()) { + if (!Core::IsFootageExtensionAllowed(file)) { + QMessageBox::warning( + this, tr("Unsupported media"), + tr("This file type is not allowed by the current media type " + "filter.")); + return; + } + auto p = new MultiUndoCommand(); // Change filename parameter diff --git a/app/widget/projectexplorer/projectexplorer.h b/app/widget/projectexplorer/projectexplorer.h index ea070d320..074c467cc 100644 --- a/app/widget/projectexplorer/projectexplorer.h +++ b/app/widget/projectexplorer/projectexplorer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorericonview.cpp b/app/widget/projectexplorer/projectexplorericonview.cpp index fd109f25a..8bf040870 100644 --- a/app/widget/projectexplorer/projectexplorericonview.cpp +++ b/app/widget/projectexplorer/projectexplorericonview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorericonview.h b/app/widget/projectexplorer/projectexplorericonview.h index 1cd3f08bb..b4d417caf 100644 --- a/app/widget/projectexplorer/projectexplorericonview.h +++ b/app/widget/projectexplorer/projectexplorericonview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp index 5cd87d666..3f06c8b50 100644 --- a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp +++ b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h index 7fcb524e6..ac5a136ee 100644 --- a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h +++ b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorerlistview.cpp b/app/widget/projectexplorer/projectexplorerlistview.cpp index e9dcd03fc..b8574a1e5 100644 --- a/app/widget/projectexplorer/projectexplorerlistview.cpp +++ b/app/widget/projectexplorer/projectexplorerlistview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorerlistview.h b/app/widget/projectexplorer/projectexplorerlistview.h index 4e480ddb4..2f7d823fe 100644 --- a/app/widget/projectexplorer/projectexplorerlistview.h +++ b/app/widget/projectexplorer/projectexplorerlistview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorerlistviewbase.cpp b/app/widget/projectexplorer/projectexplorerlistviewbase.cpp index 6f4fb3e9a..c98799c84 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewbase.cpp +++ b/app/widget/projectexplorer/projectexplorerlistviewbase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorerlistviewbase.h b/app/widget/projectexplorer/projectexplorerlistviewbase.h index 0062ba992..8f3adebcf 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewbase.h +++ b/app/widget/projectexplorer/projectexplorerlistviewbase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp index 92f776278..fa2d243a0 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp +++ b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h index 56dc5b732..0211401c9 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h +++ b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorernavigation.cpp b/app/widget/projectexplorer/projectexplorernavigation.cpp index fa3823aa7..22ba6dc54 100644 --- a/app/widget/projectexplorer/projectexplorernavigation.cpp +++ b/app/widget/projectexplorer/projectexplorernavigation.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorernavigation.h b/app/widget/projectexplorer/projectexplorernavigation.h index 63b9d933d..101fb187f 100644 --- a/app/widget/projectexplorer/projectexplorernavigation.h +++ b/app/widget/projectexplorer/projectexplorernavigation.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorertreeview.cpp b/app/widget/projectexplorer/projectexplorertreeview.cpp index f0a2c19d6..d874b03a4 100644 --- a/app/widget/projectexplorer/projectexplorertreeview.cpp +++ b/app/widget/projectexplorer/projectexplorertreeview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorertreeview.h b/app/widget/projectexplorer/projectexplorertreeview.h index b680e6456..a6ba237ba 100644 --- a/app/widget/projectexplorer/projectexplorertreeview.h +++ b/app/widget/projectexplorer/projectexplorertreeview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectexplorerundo.h b/app/widget/projectexplorer/projectexplorerundo.h index 0e43c76a7..aeb2bbdc7 100644 --- a/app/widget/projectexplorer/projectexplorerundo.h +++ b/app/widget/projectexplorer/projectexplorerundo.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectviewmodel.cpp b/app/widget/projectexplorer/projectviewmodel.cpp index 1b9490bc2..9df75d2c3 100644 --- a/app/widget/projectexplorer/projectviewmodel.cpp +++ b/app/widget/projectexplorer/projectviewmodel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projectexplorer/projectviewmodel.h b/app/widget/projectexplorer/projectviewmodel.h index 7f760963a..8f0e4d9a9 100644 --- a/app/widget/projectexplorer/projectviewmodel.h +++ b/app/widget/projectexplorer/projectviewmodel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projecttoolbar/projecttoolbar.cpp b/app/widget/projecttoolbar/projecttoolbar.cpp index 11e46dcbe..692bbcecc 100644 --- a/app/widget/projecttoolbar/projecttoolbar.cpp +++ b/app/widget/projecttoolbar/projecttoolbar.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/projecttoolbar/projecttoolbar.h b/app/widget/projecttoolbar/projecttoolbar.h index 1d2ec4cce..96205d6d1 100644 --- a/app/widget/projecttoolbar/projecttoolbar.h +++ b/app/widget/projecttoolbar/projecttoolbar.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/resizablescrollbar/resizablescrollbar.cpp b/app/widget/resizablescrollbar/resizablescrollbar.cpp index 32a130fb3..f6786b6ce 100644 --- a/app/widget/resizablescrollbar/resizablescrollbar.cpp +++ b/app/widget/resizablescrollbar/resizablescrollbar.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/resizablescrollbar/resizablescrollbar.h b/app/widget/resizablescrollbar/resizablescrollbar.h index 94e8d6618..3f75507b6 100644 --- a/app/widget/resizablescrollbar/resizablescrollbar.h +++ b/app/widget/resizablescrollbar/resizablescrollbar.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp b/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp index ae6d71ab5..cfd4bf1ce 100644 --- a/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp +++ b/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/resizablescrollbar/resizabletimelinescrollbar.h b/app/widget/resizablescrollbar/resizabletimelinescrollbar.h index 865fb0e97..f6633171c 100644 --- a/app/widget/resizablescrollbar/resizabletimelinescrollbar.h +++ b/app/widget/resizablescrollbar/resizabletimelinescrollbar.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index 807be492f..05c7a82ce 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/scope/histogram/histogram.h b/app/widget/scope/histogram/histogram.h index 521ea1019..dd33591d9 100644 --- a/app/widget/scope/histogram/histogram.h +++ b/app/widget/scope/histogram/histogram.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index 12392bc87..83c17457f 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/scope/scopebase/scopebase.h b/app/widget/scope/scopebase/scopebase.h index aeeb7218a..6f493d197 100644 --- a/app/widget/scope/scopebase/scopebase.h +++ b/app/widget/scope/scopebase/scopebase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 2551d8f1f..a34827687 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -3,6 +3,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/scope/waveform/waveform.h b/app/widget/scope/waveform/waveform.h index 36472c0f9..4cfc847ab 100644 --- a/app/widget/scope/waveform/waveform.h +++ b/app/widget/scope/waveform/waveform.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/decimalsliderbase.cpp b/app/widget/slider/base/decimalsliderbase.cpp index 18c806359..66ae792f4 100644 --- a/app/widget/slider/base/decimalsliderbase.cpp +++ b/app/widget/slider/base/decimalsliderbase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/decimalsliderbase.h b/app/widget/slider/base/decimalsliderbase.h index b25df4558..3ab4a78c8 100644 --- a/app/widget/slider/base/decimalsliderbase.h +++ b/app/widget/slider/base/decimalsliderbase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/numericsliderbase.cpp b/app/widget/slider/base/numericsliderbase.cpp index 06af4cb3d..933c5399b 100644 --- a/app/widget/slider/base/numericsliderbase.cpp +++ b/app/widget/slider/base/numericsliderbase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/numericsliderbase.h b/app/widget/slider/base/numericsliderbase.h index ed189b8bf..38848b158 100644 --- a/app/widget/slider/base/numericsliderbase.h +++ b/app/widget/slider/base/numericsliderbase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/sliderbase.cpp b/app/widget/slider/base/sliderbase.cpp index 1b6ebdb32..54aeeb23b 100644 --- a/app/widget/slider/base/sliderbase.cpp +++ b/app/widget/slider/base/sliderbase.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/sliderbase.h b/app/widget/slider/base/sliderbase.h index 06b71b2ad..7e5bd33a1 100644 --- a/app/widget/slider/base/sliderbase.h +++ b/app/widget/slider/base/sliderbase.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/sliderlabel.cpp b/app/widget/slider/base/sliderlabel.cpp index df1161847..d261af337 100644 --- a/app/widget/slider/base/sliderlabel.cpp +++ b/app/widget/slider/base/sliderlabel.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/sliderlabel.h b/app/widget/slider/base/sliderlabel.h index 9f9c3fdbf..6ea2f5615 100644 --- a/app/widget/slider/base/sliderlabel.h +++ b/app/widget/slider/base/sliderlabel.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/sliderladder.cpp b/app/widget/slider/base/sliderladder.cpp index 104499a95..8b393a8c1 100644 --- a/app/widget/slider/base/sliderladder.cpp +++ b/app/widget/slider/base/sliderladder.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/base/sliderladder.h b/app/widget/slider/base/sliderladder.h index a27564b54..df7e201df 100644 --- a/app/widget/slider/base/sliderladder.h +++ b/app/widget/slider/base/sliderladder.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/floatslider.cpp b/app/widget/slider/floatslider.cpp index da3cf6343..f219ea959 100644 --- a/app/widget/slider/floatslider.cpp +++ b/app/widget/slider/floatslider.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/floatslider.h b/app/widget/slider/floatslider.h index 2c8671a09..cc00f633a 100644 --- a/app/widget/slider/floatslider.h +++ b/app/widget/slider/floatslider.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/integerslider.cpp b/app/widget/slider/integerslider.cpp index 85154fb16..6f8e3ea6f 100644 --- a/app/widget/slider/integerslider.cpp +++ b/app/widget/slider/integerslider.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/integerslider.h b/app/widget/slider/integerslider.h index 295530e73..fe18ff924 100644 --- a/app/widget/slider/integerslider.h +++ b/app/widget/slider/integerslider.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/rationalslider.cpp b/app/widget/slider/rationalslider.cpp index 6346ee732..6aaa2289d 100644 --- a/app/widget/slider/rationalslider.cpp +++ b/app/widget/slider/rationalslider.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/rationalslider.h b/app/widget/slider/rationalslider.h index e95af20e8..a42a1ea71 100644 --- a/app/widget/slider/rationalslider.h +++ b/app/widget/slider/rationalslider.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/stringslider.cpp b/app/widget/slider/stringslider.cpp index be1086c9a..8771a7bf7 100644 --- a/app/widget/slider/stringslider.cpp +++ b/app/widget/slider/stringslider.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/slider/stringslider.h b/app/widget/slider/stringslider.h index 6a9b837c4..0a481680d 100644 --- a/app/widget/slider/stringslider.h +++ b/app/widget/slider/stringslider.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/standardcombos/channellayoutcombobox.h b/app/widget/standardcombos/channellayoutcombobox.h index 7890f69da..f5ddefefd 100644 --- a/app/widget/standardcombos/channellayoutcombobox.h +++ b/app/widget/standardcombos/channellayoutcombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -61,16 +62,7 @@ public: } } } - void SetChannelLayout(AVChannelLayout &ch) - { - for (int i = 0; i < this->count(); i++) { - if (this->itemData(i).toULongLong() == ch.u.mask) { - this->setCurrentIndex(i); - break; - } - } - } - void SetChannelLayout(AVChannelLayout &&ch) + void SetChannelLayout(const AVChannelLayout &ch) { for (int i = 0; i < this->count(); i++) { if (this->itemData(i).toULongLong() == ch.u.mask) { diff --git a/app/widget/standardcombos/frameratecombobox.h b/app/widget/standardcombos/frameratecombobox.h index 27d6181a5..ac8ecbb47 100644 --- a/app/widget/standardcombos/frameratecombobox.h +++ b/app/widget/standardcombos/frameratecombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/standardcombos/interlacedcombobox.h b/app/widget/standardcombos/interlacedcombobox.h index 0f5b966c3..e6c057a05 100644 --- a/app/widget/standardcombos/interlacedcombobox.h +++ b/app/widget/standardcombos/interlacedcombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/standardcombos/pixelaspectratiocombobox.h b/app/widget/standardcombos/pixelaspectratiocombobox.h index bf03b7c8a..8ee4f4854 100644 --- a/app/widget/standardcombos/pixelaspectratiocombobox.h +++ b/app/widget/standardcombos/pixelaspectratiocombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/standardcombos/pixelformatcombobox.h b/app/widget/standardcombos/pixelformatcombobox.h index 210ad7943..76fe9594a 100644 --- a/app/widget/standardcombos/pixelformatcombobox.h +++ b/app/widget/standardcombos/pixelformatcombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/standardcombos/sampleformatcombobox.h b/app/widget/standardcombos/sampleformatcombobox.h index 159f3b7c4..9995abf31 100644 --- a/app/widget/standardcombos/sampleformatcombobox.h +++ b/app/widget/standardcombos/sampleformatcombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/standardcombos/sampleratecombobox.h b/app/widget/standardcombos/sampleratecombobox.h index 8976b571e..df3cc5103 100644 --- a/app/widget/standardcombos/sampleratecombobox.h +++ b/app/widget/standardcombos/sampleratecombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/standardcombos/videodividercombobox.h b/app/widget/standardcombos/videodividercombobox.h index 27eb0e979..5c718ff5c 100644 --- a/app/widget/standardcombos/videodividercombobox.h +++ b/app/widget/standardcombos/videodividercombobox.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/taskview/elapsedcounterwidget.cpp b/app/widget/taskview/elapsedcounterwidget.cpp index 739f1b7f1..fdb6e5046 100644 --- a/app/widget/taskview/elapsedcounterwidget.cpp +++ b/app/widget/taskview/elapsedcounterwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/taskview/elapsedcounterwidget.h b/app/widget/taskview/elapsedcounterwidget.h index 9e2865d30..3e687c153 100644 --- a/app/widget/taskview/elapsedcounterwidget.h +++ b/app/widget/taskview/elapsedcounterwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/taskview/taskview.cpp b/app/widget/taskview/taskview.cpp index ed314383e..1a48cd224 100644 --- a/app/widget/taskview/taskview.cpp +++ b/app/widget/taskview/taskview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/taskview/taskview.h b/app/widget/taskview/taskview.h index 36161d437..fc208413a 100644 --- a/app/widget/taskview/taskview.h +++ b/app/widget/taskview/taskview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/taskview/taskviewitem.cpp b/app/widget/taskview/taskviewitem.cpp index a97e3a875..6c46d15a5 100644 --- a/app/widget/taskview/taskviewitem.cpp +++ b/app/widget/taskview/taskviewitem.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/taskview/taskviewitem.h b/app/widget/taskview/taskviewitem.h index 6e42e490e..756a7969c 100644 --- a/app/widget/taskview/taskviewitem.h +++ b/app/widget/taskview/taskviewitem.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timebased/timebasedview.cpp b/app/widget/timebased/timebasedview.cpp index c429e12ff..bcd992311 100644 --- a/app/widget/timebased/timebasedview.cpp +++ b/app/widget/timebased/timebasedview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timebased/timebasedview.h b/app/widget/timebased/timebasedview.h index 09ca00f8c..5108b78b4 100644 --- a/app/widget/timebased/timebasedview.h +++ b/app/widget/timebased/timebasedview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timebased/timebasedviewselectionmanager.cpp b/app/widget/timebased/timebasedviewselectionmanager.cpp index 84ee06974..ea434a3d0 100644 --- a/app/widget/timebased/timebasedviewselectionmanager.cpp +++ b/app/widget/timebased/timebasedviewselectionmanager.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timebased/timebasedviewselectionmanager.h b/app/widget/timebased/timebasedviewselectionmanager.h index e86c08eb9..a6b15659d 100644 --- a/app/widget/timebased/timebasedviewselectionmanager.h +++ b/app/widget/timebased/timebasedviewselectionmanager.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index 6ee45bbef..09b4a1ae1 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -26,6 +27,7 @@ #include "common/range.h" #include "config/config.h" #include "core.h" +#include "common/Current.h" #include "dialog/markerproperties/markerpropertiesdialog.h" #include "node/project/sequence/sequence.h" #include "timeline/timelineundoworkarea.h" @@ -79,7 +81,7 @@ void TimeBasedWidget::SetScaleAndCenterOnPlayhead(const double &scale) ViewerOutput *TimeBasedWidget::GetConnectedNode() const { - return viewer_node_; + return viewer_node_.data(); } void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) @@ -90,9 +92,17 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) } // Set viewer node - ViewerOutput *old = viewer_node_; + ViewerOutput *old = viewer_node_.data(); viewer_node_ = node; - + if (viewer_node_) { + Current::getInstance().setCurrentVideoParams( + viewer_node_->GetVideoParams()); + Current::getInstance().setCurrentAudioParams( + viewer_node_->GetAudioParams()); + } else { + Current::getInstance().setCurrentVideoParams(VideoParams()); + Current::getInstance().setCurrentAudioParams(AudioParams()); + } if (old) { // Call potential derivative functions for disconnecting the viewer node DisconnectNodeEvent(old); @@ -121,17 +131,17 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) // Call derivatives for (TimeBasedView *view : timeline_views_) { - view->SetViewerNode(viewer_node_); + view->SetViewerNode(viewer_node_.data()); } - ConnectedNodeChangeEvent(viewer_node_); + ConnectedNodeChangeEvent(viewer_node_.data()); if (viewer_node_) { // Connect length changed signal - connect(viewer_node_, &ViewerOutput::LengthChanged, this, + connect(viewer_node_.data(), &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll); - connect(viewer_node_, &ViewerOutput::RemovedFromGraph, this, + connect(viewer_node_.data(), &ViewerOutput::RemovedFromGraph, this, &TimeBasedWidget::ConnectedNodeRemovedFromGraph); - connect(viewer_node_, &ViewerOutput::PlayheadChanged, this, + connect(viewer_node_.data(), &ViewerOutput::PlayheadChanged, this, &TimeBasedWidget::PlayheadTimeChanged); // Connect ruler and scrollbar to timeline points @@ -141,14 +151,14 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) // If we're setting the timebase, set it automatically based on the video and audio parameters if (auto_set_timebase_) { AutoUpdateTimebase(); - connect(viewer_node_, &ViewerOutput::FrameRateChanged, this, + connect(viewer_node_.data(), &ViewerOutput::FrameRateChanged, this, &TimeBasedWidget::AutoUpdateTimebase); - connect(viewer_node_, &ViewerOutput::SampleRateChanged, this, + connect(viewer_node_.data(), &ViewerOutput::SampleRateChanged, this, &TimeBasedWidget::AutoUpdateTimebase); } // Call derivatives - ConnectNodeEvent(viewer_node_); + ConnectNodeEvent(viewer_node_.data()); } UpdateMaximumScroll(); @@ -271,6 +281,10 @@ void TimeBasedWidget::SendCatchUpScrollEvent() void TimeBasedWidget::AutoUpdateTimebase() { + if (!viewer_node_) { + SetTimebase(rational()); + return; + } rational video_tb = viewer_node_->GetVideoParams().frame_rate_as_time_base(); @@ -448,7 +462,7 @@ void TimeBasedWidget::ZoomOut() void TimeBasedWidget::GoToPrevCut() { // Cuts are only possible in sequences - Sequence *sequence = dynamic_cast(viewer_node_); + Sequence *sequence = dynamic_cast(viewer_node_.data()); if (!sequence) { return; @@ -480,7 +494,7 @@ void TimeBasedWidget::GoToPrevCut() void TimeBasedWidget::GoToNextCut() { // Cuts are only possible in sequences - Sequence *sequence = dynamic_cast(viewer_node_); + Sequence *sequence = dynamic_cast(viewer_node_.data()); if (!sequence) { return; diff --git a/app/widget/timebased/timebasedwidget.h b/app/widget/timebased/timebasedwidget.h index ebb064464..212406656 100644 --- a/app/widget/timebased/timebasedwidget.h +++ b/app/widget/timebased/timebasedwidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -21,6 +22,7 @@ #ifndef TIMEBASEDWIDGET_H #define TIMEBASEDWIDGET_H +#include #include #include "node/output/viewer/viewer.h" @@ -241,7 +243,7 @@ private: bool UserIsDraggingPlayhead() const; - ViewerOutput *viewer_node_; + QPointer viewer_node_; TimeRuler *ruler_; diff --git a/app/widget/timebased/timescaledobject.cpp b/app/widget/timebased/timescaledobject.cpp index c28d2bc29..3703d9b70 100644 --- a/app/widget/timebased/timescaledobject.cpp +++ b/app/widget/timebased/timescaledobject.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -58,6 +59,9 @@ const double &TimeScaledObject::timebase_dbl() const rational TimeScaledObject::SceneToTime(const double &x, const double &x_scale, const rational &timebase, bool round) { + if (timebase.isNull()) { + return rational(); + } double unscaled_time = x / x_scale / timebase.toDouble(); // Adjust screen point by scale and timebase @@ -87,16 +91,25 @@ rational TimeScaledObject::SceneToTimeNoGrid(const double &x, double TimeScaledObject::TimeToScene(const rational &time) const { + if (timebase_.isNull()) { + return 0.0; + } return time.toDouble() * scale_; } rational TimeScaledObject::SceneToTime(const double &x, bool round) const { + if (timebase_.isNull()) { + return rational(); + } return SceneToTime(x, scale_, timebase_, round); } rational TimeScaledObject::SceneToTimeNoGrid(const double &x) const { + if (timebase_.isNull()) { + return rational::fromDouble(x / scale_); + } return SceneToTimeNoGrid(x, scale_); } diff --git a/app/widget/timebased/timescaledobject.h b/app/widget/timebased/timescaledobject.h index 407b271af..f0adb1afc 100644 --- a/app/widget/timebased/timescaledobject.h +++ b/app/widget/timebased/timescaledobject.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/timelineandtrackview.cpp b/app/widget/timelinewidget/timelineandtrackview.cpp index 4a4d0e81e..558c9bbf5 100644 --- a/app/widget/timelinewidget/timelineandtrackview.cpp +++ b/app/widget/timelinewidget/timelineandtrackview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/timelineandtrackview.h b/app/widget/timelinewidget/timelineandtrackview.h index a2a97026b..77a84a03c 100644 --- a/app/widget/timelinewidget/timelineandtrackview.h +++ b/app/widget/timelinewidget/timelineandtrackview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index c39e2943f..d71e13c6c 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index 34d035795..2f3f27df6 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/timelinewidgetselections.cpp b/app/widget/timelinewidget/timelinewidgetselections.cpp index 3fc575dcf..ca24c9a1c 100644 --- a/app/widget/timelinewidget/timelinewidgetselections.cpp +++ b/app/widget/timelinewidget/timelinewidgetselections.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/timelinewidgetselections.h b/app/widget/timelinewidget/timelinewidgetselections.h index ad45c31ca..c0c60755f 100644 --- a/app/widget/timelinewidget/timelinewidgetselections.h +++ b/app/widget/timelinewidget/timelinewidgetselections.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp index 9ba6cd83c..a6721471a 100644 --- a/app/widget/timelinewidget/tool/add.cpp +++ b/app/widget/timelinewidget/tool/add.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/add.h b/app/widget/timelinewidget/tool/add.h index 14d7cd316..8e71ffda7 100644 --- a/app/widget/timelinewidget/tool/add.h +++ b/app/widget/timelinewidget/tool/add.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/beam.cpp b/app/widget/timelinewidget/tool/beam.cpp index 80dc933ea..23bbaae6e 100644 --- a/app/widget/timelinewidget/tool/beam.cpp +++ b/app/widget/timelinewidget/tool/beam.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/beam.h b/app/widget/timelinewidget/tool/beam.h index 0a9a1bf27..0e8923a79 100644 --- a/app/widget/timelinewidget/tool/beam.h +++ b/app/widget/timelinewidget/tool/beam.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/edit.cpp b/app/widget/timelinewidget/tool/edit.cpp index df76c8434..42f94705d 100644 --- a/app/widget/timelinewidget/tool/edit.cpp +++ b/app/widget/timelinewidget/tool/edit.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/edit.h b/app/widget/timelinewidget/tool/edit.h index 870a543bd..e347085cb 100644 --- a/app/widget/timelinewidget/tool/edit.h +++ b/app/widget/timelinewidget/tool/edit.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index 7e97aef7a..de1000bb9 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/import.h b/app/widget/timelinewidget/tool/import.h index 99b988e8f..d0c5d272a 100644 --- a/app/widget/timelinewidget/tool/import.h +++ b/app/widget/timelinewidget/tool/import.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/pointer.cpp b/app/widget/timelinewidget/tool/pointer.cpp index 5de4b37f4..7c38eae57 100644 --- a/app/widget/timelinewidget/tool/pointer.cpp +++ b/app/widget/timelinewidget/tool/pointer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/pointer.h b/app/widget/timelinewidget/tool/pointer.h index e074b63b8..17f05eac7 100644 --- a/app/widget/timelinewidget/tool/pointer.h +++ b/app/widget/timelinewidget/tool/pointer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/razor.cpp b/app/widget/timelinewidget/tool/razor.cpp index 5baae3dc8..0b3152c90 100644 --- a/app/widget/timelinewidget/tool/razor.cpp +++ b/app/widget/timelinewidget/tool/razor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/razor.h b/app/widget/timelinewidget/tool/razor.h index 64e49ed39..66b993d33 100644 --- a/app/widget/timelinewidget/tool/razor.h +++ b/app/widget/timelinewidget/tool/razor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/record.cpp b/app/widget/timelinewidget/tool/record.cpp index e6eaf1e0c..f194d60b7 100644 --- a/app/widget/timelinewidget/tool/record.cpp +++ b/app/widget/timelinewidget/tool/record.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "record.h" #include "widget/timelinewidget/timelinewidget.h" diff --git a/app/widget/timelinewidget/tool/record.h b/app/widget/timelinewidget/tool/record.h index c3ab5805a..de244298a 100644 --- a/app/widget/timelinewidget/tool/record.h +++ b/app/widget/timelinewidget/tool/record.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/ripple.cpp b/app/widget/timelinewidget/tool/ripple.cpp index 4d54fb93d..6271496dd 100644 --- a/app/widget/timelinewidget/tool/ripple.cpp +++ b/app/widget/timelinewidget/tool/ripple.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/ripple.h b/app/widget/timelinewidget/tool/ripple.h index 6e68aa689..5f74f6eb7 100644 --- a/app/widget/timelinewidget/tool/ripple.h +++ b/app/widget/timelinewidget/tool/ripple.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/rolling.cpp b/app/widget/timelinewidget/tool/rolling.cpp index 2fc19f242..bad683c57 100644 --- a/app/widget/timelinewidget/tool/rolling.cpp +++ b/app/widget/timelinewidget/tool/rolling.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/rolling.h b/app/widget/timelinewidget/tool/rolling.h index 9ff5f6be9..a31cbcd42 100644 --- a/app/widget/timelinewidget/tool/rolling.h +++ b/app/widget/timelinewidget/tool/rolling.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/slide.cpp b/app/widget/timelinewidget/tool/slide.cpp index 5fc6a6ab7..b7f08c77e 100644 --- a/app/widget/timelinewidget/tool/slide.cpp +++ b/app/widget/timelinewidget/tool/slide.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/slide.h b/app/widget/timelinewidget/tool/slide.h index 00c5b0e4d..e299cac1f 100644 --- a/app/widget/timelinewidget/tool/slide.h +++ b/app/widget/timelinewidget/tool/slide.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/slip.cpp b/app/widget/timelinewidget/tool/slip.cpp index f3f838071..da5a60543 100644 --- a/app/widget/timelinewidget/tool/slip.cpp +++ b/app/widget/timelinewidget/tool/slip.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/slip.h b/app/widget/timelinewidget/tool/slip.h index 380855c5e..01ccd3650 100644 --- a/app/widget/timelinewidget/tool/slip.h +++ b/app/widget/timelinewidget/tool/slip.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/tool.cpp b/app/widget/timelinewidget/tool/tool.cpp index 6b3f765f2..75e718f20 100644 --- a/app/widget/timelinewidget/tool/tool.cpp +++ b/app/widget/timelinewidget/tool/tool.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/tool.h b/app/widget/timelinewidget/tool/tool.h index eb153a653..78d916bec 100644 --- a/app/widget/timelinewidget/tool/tool.h +++ b/app/widget/timelinewidget/tool/tool.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/trackselect.cpp b/app/widget/timelinewidget/tool/trackselect.cpp index dd794a217..a8d25ee8b 100644 --- a/app/widget/timelinewidget/tool/trackselect.cpp +++ b/app/widget/timelinewidget/tool/trackselect.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/trackselect.h b/app/widget/timelinewidget/tool/trackselect.h index 1a4d9bb75..619f04b08 100644 --- a/app/widget/timelinewidget/tool/trackselect.h +++ b/app/widget/timelinewidget/tool/trackselect.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp index 2a8e8de29..28b1e38d4 100644 --- a/app/widget/timelinewidget/tool/transition.cpp +++ b/app/widget/timelinewidget/tool/transition.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/transition.h b/app/widget/timelinewidget/tool/transition.h index 5012b5691..3d21aef69 100644 --- a/app/widget/timelinewidget/tool/transition.h +++ b/app/widget/timelinewidget/tool/transition.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/zoom.cpp b/app/widget/timelinewidget/tool/zoom.cpp index a7bead1e3..0d8580ba6 100644 --- a/app/widget/timelinewidget/tool/zoom.cpp +++ b/app/widget/timelinewidget/tool/zoom.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/tool/zoom.h b/app/widget/timelinewidget/tool/zoom.h index 9b77cb7f4..4f1ac7b24 100644 --- a/app/widget/timelinewidget/tool/zoom.h +++ b/app/widget/timelinewidget/tool/zoom.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/trackview/trackview.cpp b/app/widget/timelinewidget/trackview/trackview.cpp index f7fbf3a30..644308c98 100644 --- a/app/widget/timelinewidget/trackview/trackview.cpp +++ b/app/widget/timelinewidget/trackview/trackview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/trackview/trackview.h b/app/widget/timelinewidget/trackview/trackview.h index 3bb8d5791..d4610238a 100644 --- a/app/widget/timelinewidget/trackview/trackview.h +++ b/app/widget/timelinewidget/trackview/trackview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/trackview/trackviewitem.cpp b/app/widget/timelinewidget/trackview/trackviewitem.cpp index 8e01695d4..f318b753f 100644 --- a/app/widget/timelinewidget/trackview/trackviewitem.cpp +++ b/app/widget/timelinewidget/trackview/trackviewitem.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/trackview/trackviewitem.h b/app/widget/timelinewidget/trackview/trackviewitem.h index 8ab31ffb0..a63929dbb 100644 --- a/app/widget/timelinewidget/trackview/trackviewitem.h +++ b/app/widget/timelinewidget/trackview/trackviewitem.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/trackview/trackviewsplitter.cpp b/app/widget/timelinewidget/trackview/trackviewsplitter.cpp index 1f6cbf646..1c25b97c3 100644 --- a/app/widget/timelinewidget/trackview/trackviewsplitter.cpp +++ b/app/widget/timelinewidget/trackview/trackviewsplitter.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/trackview/trackviewsplitter.h b/app/widget/timelinewidget/trackview/trackviewsplitter.h index fd830f861..6ab70fe77 100644 --- a/app/widget/timelinewidget/trackview/trackviewsplitter.h +++ b/app/widget/timelinewidget/trackview/trackviewsplitter.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index e058d2b46..ee573c08c 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/view/timelineview.h b/app/widget/timelinewidget/view/timelineview.h index 67108eb40..21c5c3ab2 100644 --- a/app/widget/timelinewidget/view/timelineview.h +++ b/app/widget/timelinewidget/view/timelineview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/view/timelineviewghostitem.h b/app/widget/timelinewidget/view/timelineviewghostitem.h index 64de8737a..030050b4b 100644 --- a/app/widget/timelinewidget/view/timelineviewghostitem.h +++ b/app/widget/timelinewidget/view/timelineviewghostitem.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timelinewidget/view/timelineviewmouseevent.h b/app/widget/timelinewidget/view/timelineviewmouseevent.h index 3dbe4cece..9f670d5d5 100644 --- a/app/widget/timelinewidget/view/timelineviewmouseevent.h +++ b/app/widget/timelinewidget/view/timelineviewmouseevent.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timeruler/seekablewidget.cpp b/app/widget/timeruler/seekablewidget.cpp index 77b08d784..cdeabc2f8 100644 --- a/app/widget/timeruler/seekablewidget.cpp +++ b/app/widget/timeruler/seekablewidget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timeruler/seekablewidget.h b/app/widget/timeruler/seekablewidget.h index 34df0d70d..c17dec9b0 100644 --- a/app/widget/timeruler/seekablewidget.h +++ b/app/widget/timeruler/seekablewidget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index 20cce94f2..c4069d770 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timeruler/timeruler.h b/app/widget/timeruler/timeruler.h index e10bfc9e4..796f4dc4c 100644 --- a/app/widget/timeruler/timeruler.h +++ b/app/widget/timeruler/timeruler.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timetarget/timetarget.cpp b/app/widget/timetarget/timetarget.cpp index 1f09d7226..6ab4f6e72 100644 --- a/app/widget/timetarget/timetarget.cpp +++ b/app/widget/timetarget/timetarget.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/timetarget/timetarget.h b/app/widget/timetarget/timetarget.h index abbde4f65..b303193a5 100644 --- a/app/widget/timetarget/timetarget.h +++ b/app/widget/timetarget/timetarget.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/toolbar/toolbar.cpp b/app/widget/toolbar/toolbar.cpp index 183eefc56..5c487496a 100644 --- a/app/widget/toolbar/toolbar.cpp +++ b/app/widget/toolbar/toolbar.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/toolbar/toolbar.h b/app/widget/toolbar/toolbar.h index b7bf1e212..96ddc5ac5 100644 --- a/app/widget/toolbar/toolbar.h +++ b/app/widget/toolbar/toolbar.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/toolbar/toolbarbutton.cpp b/app/widget/toolbar/toolbarbutton.cpp index f934ccc13..057ef2b5e 100644 --- a/app/widget/toolbar/toolbarbutton.cpp +++ b/app/widget/toolbar/toolbarbutton.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/toolbar/toolbarbutton.h b/app/widget/toolbar/toolbarbutton.h index 0aa938c93..f4fe97cbe 100644 --- a/app/widget/toolbar/toolbarbutton.h +++ b/app/widget/toolbar/toolbarbutton.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/audiowaveformview.cpp b/app/widget/viewer/audiowaveformview.cpp index 72bfd8c13..cac2a5713 100644 --- a/app/widget/viewer/audiowaveformview.cpp +++ b/app/widget/viewer/audiowaveformview.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/audiowaveformview.h b/app/widget/viewer/audiowaveformview.h index cf26b5415..316fbf448 100644 --- a/app/widget/viewer/audiowaveformview.h +++ b/app/widget/viewer/audiowaveformview.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/footageviewer.cpp b/app/widget/viewer/footageviewer.cpp index 00c3a5927..82c8e4e22 100644 --- a/app/widget/viewer/footageviewer.cpp +++ b/app/widget/viewer/footageviewer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/footageviewer.h b/app/widget/viewer/footageviewer.h index efa78a789..e6a5f9d59 100644 --- a/app/widget/viewer/footageviewer.h +++ b/app/widget/viewer/footageviewer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index cc17e6993..67aad4020 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -573,10 +574,14 @@ void ViewerWidget::UpdateAudioProcessor() CloseAudioProcessor(); AudioParams ap = GetConnectedNode()->GetAudioParams(); + if (ap.sample_rate() <= 0 || ap.channel_count() <= 0) { + ap = AudioParams( + OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(), + OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(), + ViewerOutput::kDefaultSampleFormat); + } ap.set_format(ViewerOutput::kDefaultSampleFormat); - uint64_t layout = - OLIVE_CONFIG("AudioOutputChannelLayout").toULongLong(); AudioParams packed( OLIVE_CONFIG("AudioOutputSampleRate").toInt(), OLIVE_CONFIG("AudioOutputChannelLayout").toULongLong(), @@ -1203,8 +1208,11 @@ void ViewerWidget::UpdateMinimumScale() // Avoids divide by zero SetMinimumScale(0); } else { - SetMinimumScale(static_cast(ruler()->width()) / - GetConnectedNode()->GetLength().toDouble()); + double min_scale = static_cast(ruler()->width()) / + GetConnectedNode()->GetLength().toDouble(); + // Ensure min_scale doesn't exceed max_scale to prevent crash + min_scale = qMin(min_scale, GetMaximumScale()); + SetMinimumScale(min_scale); } } @@ -1265,6 +1273,7 @@ RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(bool increment) } watcher = new RenderTicketWatcher(); + watcher->setProperty("start", QDateTime::currentMSecsSinceEpoch()); watcher->setProperty("time", QVariant::fromValue(next_time)); DetectMulticamNode(next_time); connect(watcher, &RenderTicketWatcher::Finished, this, @@ -1278,6 +1287,10 @@ RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(bool increment) RenderTicketPtr ViewerWidget::GetFrame(const rational &t) { + if (IsPlaying() || prequeuing_video_) { + return GetSingleFrame(t); + } + QString cache_fn = GetConnectedNode()->video_frame_cache()->GetValidCacheFilename(t); @@ -1442,21 +1455,45 @@ void ViewerWidget::RendererGeneratedFrameForQueue() if (watcher->HasResult()) { QVariant frame = watcher->Get(); + bool drop_frame = false; // Ignore this signal if we've paused now if (IsPlaying() || prequeuing_video_) { + const qint64 start_ms = + watcher->property("start").toLongLong(); + const qint64 now_ms = + QDateTime::currentMSecsSinceEpoch(); + const int playback_step = qMax(1, qAbs(playback_speed_)); + const double frame_interval_ms = qMax( + 1.0, + timebase().toDouble() * 1000.0 / + static_cast(playback_step)); + if (start_ms > 0 && + (now_ms - start_ms) > frame_interval_ms) { + drop_frame = true; + } + rational ts = watcher->property("time").value(); - foreach (ViewerDisplayWidget *dw, playback_devices_) { - QVariant push; - if (dynamic_cast(dw)) { - push = - watcher->GetTicket()->property("multicam_output"); - } else { - push = frame; - } + if (!drop_frame) { + foreach (ViewerDisplayWidget *dw, playback_devices_) { + const bool is_multicam = + dynamic_cast(dw); + QVariant push; + if (is_multicam) { + push = watcher->GetTicket()->property( + "multicam_output"); + if (!push.isValid() || push.isNull()) { + // Fall back to the primary frame when multicam isn't available. + push = frame; + } + } else { + push = frame; + } - dw->queue()->AppendTimewise({ ts, push }, playback_speed_); + dw->queue()->AppendTimewise({ ts, push }, + playback_speed_); + } } if (prequeuing_video_) { diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 39a815b8d..4075f121c 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 1020e4b4a..00c6888b0 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -40,6 +41,7 @@ #include "config/config.h" #include "core.h" #include "node/block/subtitle/subtitle.h" +#include "codec/frame.h" #include "node/gizmo/path.h" #include "node/gizmo/point.h" #include "node/gizmo/polygon.h" @@ -374,7 +376,7 @@ bool ViewerDisplayWidget::eventFilter(QObject *o, QEvent *e) void ViewerDisplayWidget::OnPaint() { // Clear background to empty - QColor bg_color = show_widget_background_ ? palette().window().color() : + QColor bg_color = show_widget_background_ ? palette().window().color() : Qt::black; renderer()->ClearDestination(nullptr, bg_color.redF(), bg_color.greenF(), bg_color.blueF()); @@ -403,8 +405,35 @@ void ViewerDisplayWidget::OnPaint() texture_->Upload(frame->data(), frame->linesize_pixels()); } } else if (TexturePtr texture = load_frame_.value()) { - // This is a GPU texture, switch to it directly - texture_ = texture; + // This is a GPU texture, switch to it directly when possible. + if (texture && texture->renderer() && + texture->renderer() != renderer()) { + bool copied = false; + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx) { + QOpenGLFunctions *funcs = ctx->functions(); + GLuint tex_id = texture->id().value(); + if (funcs && tex_id && funcs->glIsTexture(tex_id)) { + FramePtr frame = Frame::Create(); + frame->set_video_params(texture->params()); + if (frame->allocate()) { + renderer()->DownloadFromTexture( + texture->id(), texture->params(), + frame->data(), frame->linesize_pixels()); + texture_ = renderer()->CreateTexture( + frame->video_params(), frame->data(), + frame->linesize_pixels()); + copied = true; + } + } + } + + if (!copied) { + texture_ = texture; + } + } else { + texture_ = texture; + } } else { texture_ = LoadCustomTextureFromFrame(load_frame_); } diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 35e2e7c09..268a95e65 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewerplaybacktimer.cpp b/app/widget/viewer/viewerplaybacktimer.cpp index 0fdf5ad82..9f807d66e 100644 --- a/app/widget/viewer/viewerplaybacktimer.cpp +++ b/app/widget/viewer/viewerplaybacktimer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewerplaybacktimer.h b/app/widget/viewer/viewerplaybacktimer.h index e2d8deaf1..a9ed2f9b8 100644 --- a/app/widget/viewer/viewerplaybacktimer.h +++ b/app/widget/viewer/viewerplaybacktimer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewerpreventsleep.cpp b/app/widget/viewer/viewerpreventsleep.cpp index 10f1323dc..48d1e6786 100644 --- a/app/widget/viewer/viewerpreventsleep.cpp +++ b/app/widget/viewer/viewerpreventsleep.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "viewerpreventsleep.h" #include @@ -62,7 +80,7 @@ void PreventSleep(bool on) if (on) { reply = interface.call(QStringLiteral("Inhibit"), - QStringLiteral("Olive Video Editor"), + QStringLiteral("Oak Video Editor"), QStringLiteral("Video Playback")); } else { reply = interface.call(QStringLiteral("UnInhibit"), diff --git a/app/widget/viewer/viewerpreventsleep.h b/app/widget/viewer/viewerpreventsleep.h index 9eeb8192a..fba8bb5ed 100644 --- a/app/widget/viewer/viewerpreventsleep.h +++ b/app/widget/viewer/viewerpreventsleep.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef VIEWERPREVENTSLEEP_H #define VIEWERPREVENTSLEEP_H diff --git a/app/widget/viewer/viewerqueue.h b/app/widget/viewer/viewerqueue.h index 626eff9dd..f367cc484 100644 --- a/app/widget/viewer/viewerqueue.h +++ b/app/widget/viewer/viewerqueue.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewersafemargininfo.h b/app/widget/viewer/viewersafemargininfo.h index 2cd009122..667472c98 100644 --- a/app/widget/viewer/viewersafemargininfo.h +++ b/app/widget/viewer/viewersafemargininfo.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewersizer.cpp b/app/widget/viewer/viewersizer.cpp index 134c18d6f..79bd3eaab 100644 --- a/app/widget/viewer/viewersizer.cpp +++ b/app/widget/viewer/viewersizer.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewersizer.h b/app/widget/viewer/viewersizer.h index 703470b5f..b731aff4f 100644 --- a/app/widget/viewer/viewersizer.h +++ b/app/widget/viewer/viewersizer.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewertexteditor.cpp b/app/widget/viewer/viewertexteditor.cpp index 2afade28a..e58cf5b63 100644 --- a/app/widget/viewer/viewertexteditor.cpp +++ b/app/widget/viewer/viewertexteditor.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewertexteditor.h b/app/widget/viewer/viewertexteditor.h index 9c582e6cd..a1de854ab 100644 --- a/app/widget/viewer/viewertexteditor.h +++ b/app/widget/viewer/viewertexteditor.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewerwindow.cpp b/app/widget/viewer/viewerwindow.cpp index 2c1b01072..49eb583d6 100644 --- a/app/widget/viewer/viewerwindow.cpp +++ b/app/widget/viewer/viewerwindow.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/widget/viewer/viewerwindow.h b/app/widget/viewer/viewerwindow.h index cc65bb8c2..9c77c8b69 100644 --- a/app/widget/viewer/viewerwindow.h +++ b/app/widget/viewer/viewerwindow.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index 365145ac6..253b368a7 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h index 090838a1f..ccd957a59 100644 --- a/app/window/mainwindow/mainmenu.h +++ b/app/window/mainwindow/mainmenu.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/window/mainwindow/mainstatusbar.cpp b/app/window/mainwindow/mainstatusbar.cpp index bbbf1bb8e..ad16b0edf 100644 --- a/app/window/mainwindow/mainstatusbar.cpp +++ b/app/window/mainwindow/mainstatusbar.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/window/mainwindow/mainstatusbar.h b/app/window/mainwindow/mainstatusbar.h index 096645384..e08dad895 100644 --- a/app/window/mainwindow/mainstatusbar.h +++ b/app/window/mainwindow/mainstatusbar.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index d556ebf8b..69343a9c1 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -29,18 +30,20 @@ #include #endif +#include "KDDockWidgets/src/qtwidgets/Window_p.h" #include "dialog/about/about.h" #include "mainmenu.h" #include "mainstatusbar.h" +#include "KDDockWidgets/src/LayoutSaver.h" #include "timeline/timelineundoworkarea.h" namespace olive { -#define super KDDockWidgets::MainWindow +#define super KDDockWidgets::QtWidgets::MainWindow MainWindow::MainWindow(QWidget *parent) - : super(QStringLiteral("OliveMain"), KDDockWidgets::MainWindowOption_None, + : super(QStringLiteral("OakMain"), KDDockWidgets::MainWindowOption_None, parent) , project_(nullptr) { @@ -95,7 +98,7 @@ MainWindow::MainWindow(QWidget *parent) // emit the "shown" signal before emitting the "hidden" signals, resulting // in Core thinking there are -1 pixel samplers open. To mitigate that, // we force "shown" to emit ourselves here. - emit pixel_sampler_panel_->shown(); + emit pixel_sampler_panel_->shown(Qt::OtherFocusReason); // Make node-related connections connect(node_panel_, &NodePanel::NodeSelectionChangedWithContexts, @@ -382,7 +385,7 @@ void MainWindow::ToggleMaximizedPanel() premaximized_state_.clear(); currently_focused_panel->raise(); - currently_focused_panel->setFocus(); + currently_focused_panel->setFocus(Qt::ActiveWindowFocusReason); PanelManager::instance()->SetSuppressChangedSignal(false); } @@ -430,7 +433,7 @@ void MainWindow::SetProject(Project *p) project_panel_->set_project(p); if (project_) { - project_panel_->setFocus(); + project_panel_->setFocus(Qt::OtherFocusReason); } } @@ -581,9 +584,9 @@ void MainWindow::ShowNouveauWarning() { QMessageBox::warning( this, tr("Driver Warning"), - tr("Olive has detected your system is using the Nouveau graphics driver.\n\nThis driver is " - "known to have stability and performance issues with Olive. It is highly recommended " - "you install the proprietary NVIDIA driver before continuing to use Olive."), + tr("Oak Video Editor has detected your system is using the Nouveau graphics driver.\n\nThis driver is " + "known to have stability and performance issues with Oak Video Editor. It is highly recommended " + "you install the proprietary NVIDIA driver before continuing to use Oak Video Editor."), QMessageBox::Ok); } #endif diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index ac925c5c5..cef97f795 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 @@ -53,7 +54,7 @@ namespace olive /** * @brief Olive's main window responsible for docking widgets and the main menu bar. */ -class MainWindow : public KDDockWidgets::MainWindow { +class MainWindow : public KDDockWidgets::QtWidgets::MainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); diff --git a/app/window/mainwindow/mainwindowlayoutinfo.cpp b/app/window/mainwindow/mainwindowlayoutinfo.cpp index f0c84c15c..7a824adb3 100644 --- a/app/window/mainwindow/mainwindowlayoutinfo.cpp +++ b/app/window/mainwindow/mainwindowlayoutinfo.cpp @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "mainwindowlayoutinfo.h" namespace olive diff --git a/app/window/mainwindow/mainwindowlayoutinfo.h b/app/window/mainwindow/mainwindowlayoutinfo.h index 44265fb7c..a0ab80ff7 100644 --- a/app/window/mainwindow/mainwindowlayoutinfo.h +++ b/app/window/mainwindow/mainwindowlayoutinfo.h @@ -1,3 +1,21 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2025 Olive CE Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef MAINWINDOWLAYOUTINFO_H #define MAINWINDOWLAYOUTINFO_H diff --git a/app/window/mainwindow/mainwindowundo.cpp b/app/window/mainwindow/mainwindowundo.cpp index 56b41b241..051083933 100644 --- a/app/window/mainwindow/mainwindowundo.cpp +++ b/app/window/mainwindow/mainwindowundo.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/app/window/mainwindow/mainwindowundo.h b/app/window/mainwindow/mainwindowundo.h index 82e782115..b0f2aa290 100644 --- a/app/window/mainwindow/mainwindowundo.h +++ b/app/window/mainwindow/mainwindowundo.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/docker/scripts/base/install_cmake.sh b/docker/scripts/base/install_cmake.sh index 2aeeb9f0e..cab8bc1ff 100644 --- a/docker/scripts/base/install_cmake.sh +++ b/docker/scripts/base/install_cmake.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (c) Contributors to the aswf-docker Project. All rights reserved. +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: Apache-2.0 + + + + set -ex if [ ! -f "$DOWNLOADS_DIR/cmake-${CMAKE_VERSION}-Linux-x86_64.sh" ]; then diff --git a/docker/scripts/build_crashpad.sh b/docker/scripts/build_crashpad.sh index f973b7152..7221ae297 100644 --- a/docker/scripts/build_crashpad.sh +++ b/docker/scripts/build_crashpad.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: GPL-3.0-or-later + + + + set -ex # Get Google's build tools diff --git a/docker/scripts/build_ffmpeg.sh b/docker/scripts/build_ffmpeg.sh index dc2e5db87..98ad4197f 100644 --- a/docker/scripts/build_ffmpeg.sh +++ b/docker/scripts/build_ffmpeg.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: GPL-3.0-or-later + + + + # Largely based on https://trac.ffmpeg.org/wiki/CompilationGuide/Centos # # Uses { command } & pattern for parallelism https://gist.github.com/thenadz/6c0584d42fb007582fbc diff --git a/docker/scripts/build_ocio.sh b/docker/scripts/build_ocio.sh index 9cc157dfe..fbddcfa82 100644 --- a/docker/scripts/build_ocio.sh +++ b/docker/scripts/build_ocio.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: GPL-3.0-or-later + + + + set -ex mkdir ocio diff --git a/docker/scripts/build_oiio.sh b/docker/scripts/build_oiio.sh index 97d8c8b51..b21bf6dcc 100644 --- a/docker/scripts/build_oiio.sh +++ b/docker/scripts/build_oiio.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: GPL-3.0-or-later + + + + set -ex # TODO: Move to install_yumpackages.sh diff --git a/docker/scripts/build_olive.sh b/docker/scripts/build_olive.sh index cb11f717a..76cc8ddf5 100644 --- a/docker/scripts/build_olive.sh +++ b/docker/scripts/build_olive.sh @@ -1,5 +1,23 @@ #!/usr/bin/env bash +# +# Oak Video Editor - Non-Linear Video Editor +# Copyright (C) 2025 Olive CE Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + git clone --depth 1 https://github.com/olive-editor/olive.git cd olive mkdir build diff --git a/docker/scripts/build_otio.sh b/docker/scripts/build_otio.sh index 56743a411..43edb61c1 100644 --- a/docker/scripts/build_otio.sh +++ b/docker/scripts/build_otio.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: GPL-3.0-or-later + + + + set -ex git clone --depth 1 --branch "$OTIO_VERSION" https://github.com/PixarAnimationStudios/OpenTimelineIO.git diff --git a/docker/scripts/common/before_build.sh b/docker/scripts/common/before_build.sh index fb7383c89..277d80fc4 100644 --- a/docker/scripts/common/before_build.sh +++ b/docker/scripts/common/before_build.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (c) Contributors to the aswf-docker Project. All rights reserved. +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: Apache-2.0 + + + + set -ex rm -rf /package diff --git a/docker/scripts/common/copy_new_files.sh b/docker/scripts/common/copy_new_files.sh index 8c1009b4d..78a8340f5 100644 --- a/docker/scripts/common/copy_new_files.sh +++ b/docker/scripts/common/copy_new_files.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash # Copyright (c) Contributors to the aswf-docker Project. All rights reserved. +# Modifications Copyright (C) 2025 mikesolar # SPDX-License-Identifier: Apache-2.0 + + + + set -ex mkdir -p /package diff --git a/docker/scripts/common/install_yumpackages.sh b/docker/scripts/common/install_yumpackages.sh index f32c55b22..636909da7 100644 --- a/docker/scripts/common/install_yumpackages.sh +++ b/docker/scripts/common/install_yumpackages.sh @@ -1,8 +1,13 @@ #!/usr/bin/env bash # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # Copyright (c) Contributors to the aswf-docker Project. All rights reserved. # SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + + + + set -ex # TODO: Check if this causes any problems. ASWF doesn't run a yum update. diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts new file mode 100644 index 000000000..9b13b7f50 --- /dev/null +++ b/docs/.vuepress/config.ts @@ -0,0 +1,63 @@ +import { defineUserConfig } from "vuepress"; +import { hopeTheme } from "vuepress-theme-hope"; + +export default defineUserConfig({ + base: process.env.BASE || "/", + locales: { + "/": { + lang: "en-US", + title: "Oak Video Editor", + description: + "Open-source, non-linear video editor focused on speed and clarity.", + }, + "/zh/": { + lang: "zh-CN", + title: "Oak 视频编辑器", + description: "面向创作者的开源非线性剪辑软件。", + }, + }, + theme: hopeTheme({ + logo: "/images/oak-icon.png", + locales: { + "/": { + selectLanguageName: "English", + navbar: [ + { text: "Home", link: "/" }, + { text: "Build", link: "/build.html" }, + { text: "Project Files", link: "/project-file-reference.html" }, + { text: "Test Plan", link: "/test-plan.html" }, + ], + sidebar: [ + { + text: "Documentation", + children: [ + "/build.md", + "/project-file-reference.md", + "/test-plan.md", + ], + }, + ], + }, + "/zh/": { + selectLanguageName: "简体中文", + navbar: [ + { text: "首页", link: "/zh/" }, + { text: "构建", link: "/zh/build.html" }, + { text: "工程文件", link: "/zh/project-file-reference.html" }, + { text: "测试计划", link: "/zh/test-plan.html" }, + ], + sidebar: [ + { + text: "文档", + children: [ + "/zh/build.md", + "/zh/project-file-reference.md", + "/zh/test-plan.md", + "/zh/structure.md", + ], + }, + ], + }, + }, + }), +}); diff --git a/docs/.vuepress/public/images/oak-icon.png b/docs/.vuepress/public/images/oak-icon.png new file mode 100644 index 000000000..393dea9fe Binary files /dev/null and b/docs/.vuepress/public/images/oak-icon.png differ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..eb6637999 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,33 @@ +--- +home: true +title: Oak Video Editor +heroImage: /images/oak-icon.png +heroText: Oak Video Editor +heroFullScreen: false +tagline: A modern, open-source, non-linear editor with a focus on speed and clarity. +actions: + - text: Read the Docs + link: /build.html + type: primary + - text: View Project Files + link: /project-file-reference.html + type: secondary +features: + - title: Fast Editing + details: Responsive timeline, smart caching, and efficient media handling. + - title: Built for Creators + details: Clean UI, configurable shortcuts, and clear project structure. + - title: Open Source + details: Transparent development with room for community ideas. +footer: Copyright © Oak Video Editor +--- + +## About Oak + +Oak Video Editor is a renamed fork of Olive, focused on delivering a polished, creator-friendly editing experience. This site hosts build notes, project file references, and test plans for contributors. + +## Quick Start + +- Build from source on Windows, macOS, or Linux using the Build guide. +- Learn how project data is stored in the Project File Reference. +- Keep releases solid by following the Test Plan. diff --git a/docs/build.md b/docs/build.md new file mode 100644 index 000000000..238f003a1 --- /dev/null +++ b/docs/build.md @@ -0,0 +1,118 @@ +# Build Guide + +This document describes how to build Oak Video Editor from source. For Chinese, see +[`docs/build-zh.md`](docs/build-zh.md). + +## Prerequisites + +- CMake 3.20+ +- Ninja (recommended) +- Qt 6 (with private headers) +- FFmpeg development libraries +- OpenImageIO +- OpenColorIO (2.x) +- OpenEXR +- Expat +- PortAudio +- OpenGL headers +- XKB common (Linux) + +## Linux (Ubuntu/Debian) + +Install dependencies: + +```bash +sudo apt-get update +sudo apt-get install -y \ + ninja-build pkg-config \ + qt6-base-dev qt6-base-dev-tools qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \ + libavcodec-dev libavformat-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev \ + libopencolorio-dev libopenimageio-dev libopenexr-dev libexpat1-dev \ + portaudio19-dev libgl1-mesa-dev libxkbcommon-dev +``` + +Configure and build: + +```bash +cmake -S . -B build -G Ninja -DBUILD_TESTS=ON -DBUILD_QT6=ON +cmake --build build --config Release +``` + +Run tests: + +```bash +ctest --test-dir build --output-on-failure -C Release +``` + +## macOS (Non-Official Support) + +Note: macOS support is **non-official**. We only run CI automation on macOS +and do not perform manual testing. + +Install dependencies: + +```bash +brew update +brew install ninja pkg-config qt@6 ffmpeg openimageio opencolorio openexr portaudio expat +``` + +Build OpenTimelineIO (optional, required for OTIO support): + +```bash +git clone --depth 1 --branch v0.16.0 https://github.com/PixarAnimationStudios/OpenTimelineIO.git +cmake -S OpenTimelineIO -B OpenTimelineIO/build -G Ninja \ + -DOTIO_SHARED_LIBS=ON \ + -DOTIO_PYTHON_BINDINGS=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${PWD}/otio-install" +cmake --build OpenTimelineIO/build +cmake --install OpenTimelineIO/build +``` + +Configure and build: + +```bash +export PATH="$(brew --prefix qt@6)/bin:$PATH" +export CMAKE_PREFIX_PATH="$(brew --prefix qt@6)" +export OTIO_LOCATION="${PWD}/otio-install" +export OCIO_LOCATION="$(brew --prefix opencolorio)" + +cmake -S . -B build -G Ninja -DBUILD_TESTS=ON -DBUILD_QT6=ON \ + -DOTIO_LOCATION="${OTIO_LOCATION}" \ + -DOCIO_LOCATION="${OCIO_LOCATION}" +cmake --build build --config Release +``` + +Run tests: + +```bash +ctest --test-dir build --output-on-failure -C Release +``` + +## Windows + +Install Qt 6 (system installer or CI action). Use vcpkg for dependencies. + +```powershell +choco install -y ninja +$env:VCPKG_ROOT = "C:\vcpkg" +& "$env:VCPKG_ROOT\vcpkg.exe" install ffmpeg openimageio opencolorio openexr expat portaudio --triplet x64-windows +``` + +Configure and build: + +```powershell +cmake -S . -B build -G Ninja ` + -DBUILD_TESTS=ON ` + -DBUILD_QT6=ON ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake" ` + -DCMAKE_PREFIX_PATH="$env:Qt6_DIR" +cmake --build build --config Release +``` + +Run tests: + +```powershell +ctest --test-dir build --output-on-failure -C Release +``` diff --git a/docs/ofx-pluginrenderer-functions-zh.md b/docs/ofx-pluginrenderer-functions-zh.md new file mode 100644 index 000000000..2a1dcc418 --- /dev/null +++ b/docs/ofx-pluginrenderer-functions-zh.md @@ -0,0 +1,44 @@ +# OFX PluginRenderer 函数说明(中文) + +日期:2026-01-11 +执行者:Codex + +## 说明 +本文档概述 `app/render/plugin/pluginrenderer.cpp` 与 `app/render/plugin/pluginrenderer.h` 中函数的职责,用于排查 OFX 渲染链路问题。 + +## 头文件(pluginrenderer.h) +- `olive::plugin::detail::BytesToPixels`:将字节行跨度转换为像素行跨度,供纹理读写使用。 +- `olive::plugin::PluginRenderer`:OFX 插件渲染器,负责插件调用与 GL/CPU 纹理桥接。 +- `PluginRenderer::AttachOutputTexture`:绑定输出纹理到 OFX 的 GL 输出路径。 +- `PluginRenderer::DetachOutputTexture`:解除 OFX 的 GL 输出绑定。 +- `PluginRenderer::RenderPlugin`:执行完整的 OFX 渲染流程(输入/输出准备、动作调用、结果处理)。 + +## 源文件(pluginrenderer.cpp) +- `GetOfxAVPixelFormat`:根据 OFX Image 的属性推导 FFmpeg 像素格式,并返回每像素字节数。 +- `ApplyClipPreferencesToParams`:读取 clip 偏好(深度/组件)并更新 VideoParams。 +- `PixelFormatFromOfxDepth`:OFX bit depth 字符串 → 内部 PixelFormat。 +- `OfxDepthFromPixelFormat`:内部 PixelFormat → OFX bit depth 字符串。 +- `ChannelCountFromOfxComponent`:OFX components 字符串 → 通道数。 +- `OfxComponentsFromChannels`:通道数 → OFX components 字符串。 +- `EffectSupportsPixelDepth`:检查插件是否支持指定像素深度。 +- `ClipSupportsComponents`:检查 clip 是否支持指定组件格式。 +- `ConversionCost`:估算源参数到目标参数的转换代价,用于排序。 +- `ParamsConvertible`:判断目标参数能否映射为可用的 AVPixelFormat。 +- `ConvertTextureForClip`:结合插件能力选择输入格式并执行转换。 +- `create_avframe_from_ofx_image`:从 OFX Image 复制数据到 AVFrame(按图像属性推导格式)。 +- `create_avframe_from_ofx_image_with_params`:按指定 VideoParams 复制 OFX Image 到 AVFrame。 +- `GetDestinationAVPixelFormat`:将 VideoParams 映射为最终输出 AVPixelFormat。 +- `GetRenderFieldForParams`:根据交错设置返回 OFX render field 字符串。 +- `ReadbackTextureToFrame`:从 GPU 纹理回读到 AVFrame(必要时做格式转换)。 +- `olive::plugin::detail::BytesToPixels`:字节行跨度 → 像素行跨度。 +- `ConvertFrameIfNeeded`:必要时将 AVFrame 转换为目标 VideoParams 对应格式。 +- `LinesizeToPixels`:字节行跨度 → 像素行跨度。 +- `ConvertTextureForParams`:将纹理转换为指定 VideoParams(CPU 路径,必要时回读)。 +- `PluginIdForInstance`:安全获取插件标识符,便于日志输出。 +- `LogOfxFailure`:统一 OFX 调用失败日志输出。 +- `LogClipState`:输出 clip 声明属性与 VideoParams,用于定位格式不一致。 +- `LogImageProps`:输出 OFX Image 属性(深度/组件/行跨度/边界)。 +- `MarkRenderFailure`:渲染失败时标记目标画面(紫色)。 +- `PluginRenderer::RenderPlugin`:执行 OFX 插件渲染全流程。 +- `PluginRenderer::AttachOutputTexture`:绑定输出纹理到 OFX GL 输出路径。 +- `PluginRenderer::DetachOutputTexture`:解除 OFX GL 输出绑定。 diff --git a/docs/project-file-reference.md b/docs/project-file-reference.md new file mode 100644 index 000000000..f79e6edf0 --- /dev/null +++ b/docs/project-file-reference.md @@ -0,0 +1,316 @@ +# Oak Video Editor Project File Reference + +This document describes Oak Video Editor's XML project format as implemented in the current codebase. It is intended to be detailed enough to implement a compatible reader/writer. + +> Source of truth: `app/node/project.cpp`, `app/node/node.cpp`, `app/node/value.*`, `app/node/keyframe.*`, `app/node/project/serializer/*`. + +## 1. Root Document + +```xml + + ... + +``` + +- `version`: serializer version in `YYMMDD` format (latest is `230220`). +- `url`: optional source path. + +## 2. Project Container + +For full saves, the serializer writes a project container: + +```xml + + ... + ... + +``` + +- Inner `` stores actual project data. +- `` stores UI layout (`MainWindowLayoutInfo::fromXml`). + +## 3. Project Data (`Project::Save`) + +```xml + + ... + ... + ... + ... + +``` + +### 3.1 `uuid` +- QUuid string. + +### 3.2 `plugins` +List of OpenFX plugins referenced by nodes in the project. This is used during load to rescan plugin paths **before** nodes are instantiated. + +```xml + + + +``` + +Attributes: +- `id`: OFX plugin identifier (matches node `id`). +- `major` / `minor`: OFX plugin version. +- `bundle`: bundle directory path (preferred). +- `file`: plugin binary path (fallback). + +Loading behavior: +- If `plugins` exists, Oak Video Editor adds each `bundle` (or `file` if `bundle` empty) to the OFX plugin path, scans, then registers plugin nodes before parsing ``. + +### 3.3 `nodes` +The node graph. Each `` is written by `Node::Save()` and read by `Node::Load()`. + +```xml + + + + 3 + + ... + ... + ... + ... + ... + ... + + +``` + +Attributes: +- `id`: node type identifier. For OpenFX nodes, this equals the OFX plugin identifier. +- `ptr`: numeric pointer ID used to resolve connections and context positions. +- `version`: currently `1`. + +### 3.4 `settings` +Project settings stored as key/value text elements. + +Known keys from code: +- `cachesetting` +- `customcachepath` +- `colorconfigfilename` +- `defaultinputcolorspace` +- `colorreferencespace` +- `root` (pointer id of the root Folder node) + +## 4. Node Serialization (`Node::Save` / `Node::Load`) + +### 4.1 `label` +User-visible node label. + +### 4.2 `color` +Override color index (integer), only written if not `-1`. + +### 4.3 `input` +Each input is serialized as: + +```xml + +``` + +- `primary`: element `-1` (the main input). +- `subelements`: array elements (if input is an array). `count` is the array size. + +#### 4.3.1 Immediate Values (`primary` / `element`) +Each immediate block contains: + +```xml +0|1 + + ... + ... + + + + ... + + +... +... +... +... +``` + +- `keyframing`: whether input is keyframed (only written if input is keyframable). +- `standard`: default/static values (one `` per keyframe track). +- `keyframes`: only written if `keyframing` is true. +- `cs*`: only written for `kColor` inputs (color management tags). + +#### 4.3.2 Track Count +Track count is determined by `NodeValue::get_number_of_keyframe_tracks()`: + +| Type | Tracks | +| --- | --- | +| kVec2 | 2 | +| kVec3 | 3 | +| kVec4 | 4 | +| kColor | 4 | +| kBezier | 6 | +| other | 1 | + +#### 4.3.3 Standard Value Encoding +Values are written with `NodeValue::ValueToString()` and read with `NodeValue::StringToValue()`. + +String encodings: +- `kVec2`: `x:y` +- `kVec3`: `x:y:z` +- `kVec4`: `x:y:z:w` +- `kColor`: `r:g:b:a` +- `kBezier`: `x:y:cp1x:cp1y:cp2x:cp2y` +- `kRational`: `num/den` (see `rational::toString()`) +- `kInt`: integer as text +- `kBinary`: Base64 +- `kText`, `kFont`, `kFile`, `kCombo`, `kStrCombo`: string +- `kTexture`, `kSamples`, `kNone`: no text + +Special cases: +- `kVideoParams` / `kAudioParams` are nested objects (see section 5). +- `kSubtitleParams` is **skipped on load** to avoid overwriting subtitle data. + +#### 4.3.4 Keyframes (`NodeKeyframe::save`) + +```xml +value +``` + +Attributes: +- `input`: input id. +- `time`: rational time (`rational::toString()`). +- `type`: integer enum `NodeKeyframe::Type` (e.g., linear/bezier/etc.). +- `inhandlex`, `inhandley`, `outhandlex`, `outhandley`: bezier handle coordinates. + +Text value uses `NodeValue::ValueToString(data_type, value, true)`. + +### 4.4 `links` +Block-to-block link list (for timeline items): + +```xml + + ptr + +``` + +### 4.5 `connections` +Input/output connections: + +```xml + + + ptr + + +``` + +- `output` is the serialized pointer (`ptr`) of the output node. + +### 4.6 `hints` (Value Hints) +Value hints are per-input UI hints: + +```xml + + + + ... + + 0 + ... + + +``` + +### 4.7 `context` (Node positions in contexts) + +```xml + + + 0 + 0 + 0|1 + + +``` + +### 4.8 `caches` +Node cache UUIDs: + +```xml + + + + uuid + uuid + +``` + +### 4.9 `custom` +Custom node data. Default `Node::SaveCustom()` writes nothing. Specific node subclasses may override. + +## 5. VideoParams +Serialized inside `` for inputs of type `kVideoParams`. + +```xml +... +... +... +num/den +int +int +num/den +int +int +0|1 +float +float +int +int +num/den +int64 +int64 +0|1 +string +int +``` + +## 6. AudioParams +Serialized inside `` for inputs of type `kAudioParams`. + +```xml +int +uint64 +string +0|1 +int +int64 +num/den +``` + +## 7. Keyframes-only / Markers-only / Nodes-only + +The serializer can emit partial documents: + +- `markers` (timeline markers) +- `keyframes` +- `nodes` (subset for copy/paste) + +These are written by `ProjectSerializer230220::Save()` depending on SaveData. + +## 8. OpenFX Node Compatibility Notes + +- OpenFX nodes are identified by OFX plugin identifier (`Plugin::getIdentifier()`). +- The `plugins` list ensures Oak Video Editor can locate external plugins before instantiating nodes. +- If a plugin cannot be found at load time, the node cannot be instantiated and will be skipped. + +## 9. Versioning + +- Root `olive` element `version` controls which serializer is used. +- Newer files may be rejected with `kProjectTooNew` if no serializer exists. diff --git a/docs/test-plan.md b/docs/test-plan.md new file mode 100644 index 000000000..534c2eee9 --- /dev/null +++ b/docs/test-plan.md @@ -0,0 +1,93 @@ +# Oak Video Editor Testing Strategy and Plan + +This document describes the automated testing strategy for Oak Video Editor, including unit tests, integration tests, and CI execution. + +## Goals + +- Maximize automation and reduce manual testing. +- Cover all modules with at least one automated test. +- Keep integration tests headless (no GUI interaction). +- Make failures reproducible on Windows/macOS/Linux CI. + +## Test Layers + +### 1) Unit Tests (GoogleTest) +- Focus: small units, deterministic behavior, no GUI. +- Location: `tests/gtest/`. +- Execution: `ctest` target `olive-gtest`. + +### 1.5) Module Smoke Tests (GoogleTest) +- Focus: compile-time and link-time coverage for GUI-heavy modules without instantiating widgets. +- Location: `tests/gtest/module_smoke_test.cpp`. +- Execution: `ctest` target `olive-gtest`. + +### 2) Integration Tests (GoogleTest) +- Focus: cross-module flows without GUI (e.g., serialize → deserialize → resolve). +- Location: `tests/gtest/` (prefixed with `ProjectSerializer`, `TaskManager`, etc.). + +### 3) Legacy Tests (Olive macro tests) +- Existing tests in `tests/general`, `tests/timeline`, `tests/compositing` remain. + +## Module Coverage Map + +Each top-level module has at least one test that exercises its core API or serialization path. + +- `app/common`: `common_current_test.cpp`, `common_xmlutils_test.cpp` +- `app/config`: `config_test.cpp` +- `app/node`: `node_value_test.cpp`, `node_keyframe_test.cpp`, `node_serialization_test.cpp` +- `app/node/project/serializer`: `project_serializer_test.cpp` +- `app/render`: `render_videoparams_test.cpp`, `render_audioparams_test.cpp` +- `app/timeline`: `timeline_marker_test.cpp` +- `app/undo`: `undo_stack_test.cpp` +- `app/task`: `task_taskmanager_test.cpp` +- `app/codec`: `codec_frame_test.cpp` +- `app/pluginSupport`: `plugin_support_test.cpp` +- `app/audio`, `app/cli`, `app/dialog`, `app/panel`, `app/tool`, `app/ui`, `app/widget`, `app/window`: `module_smoke_test.cpp` + +If a module has a GUI dependency (e.g., widgets), tests focus on non-visual data/model components. + +## Integration Test Details + +### Project Serializer Roundtrip +- Creates a minimal project with a built-in node. +- Saves to XML via `ProjectSerializer::Save`. +- Loads with `ProjectSerializer::Load`. +- Verifies that nodes are restored. + +### Task Manager Execution +- Adds a dummy task to `TaskManager`. +- Waits for completion using an event loop. +- Verifies the task ran. + +## Unit Coverage Highlights (Expanded) + +- `app/undo`: `undo_stack_test.cpp` now covers empty stack state, model data, redo list coloring, jump behavior, and ignored empty multi-commands. +- `app/timeline`: `timeline_marker_test.cpp` now covers list ordering, closest-marker lookup, list save/load with unknown elements, and marker add/remove/change commands. +- `app/pluginSupport`: `plugin_support_image_test.cpp` now checks OFX property wiring (bounds/ROD, pixel depth, components, premult) and allocation clearing behavior. +- `app/render`: `render_videoparams_branch_test.cpp` now covers auto divider selection, pixel aspect validation, square-pixel width, and Save/Load roundtrip. + +## Headless Execution + +- Tests avoid QWidget usage. +- CI sets `QT_QPA_PLATFORM=offscreen` to prevent GUI initialization issues. + +## Continuous Integration + +CI runs on Windows, macOS, and Linux: + +1. Install system dependencies (Qt, FFmpeg, OpenImageIO, OpenColorIO, OpenEXR, PortAudio, Expat). +2. Configure with `-DBUILD_TESTS=ON`. +3. Build with CMake + Ninja. +4. Run `ctest` with output on failure. + +### Dependency Installation Notes +- Linux: use distro packages (`apt` on Ubuntu) for Qt6, FFmpeg, OpenImageIO, OpenColorIO, OpenEXR, PortAudio, Expat, OpenGL headers. +- macOS: use Homebrew for Qt6 and media/color/image libraries. +- Windows: use system installers where available (Qt via `install-qt-action`), and vcpkg for the remaining C/C++ libraries. + +## Adding New Tests + +- Place new unit tests in `tests/gtest`. +- Use GoogleTest conventions. +- Prefer deterministic fixtures and local-only resources. +- When adding a new module, add at least one unit test and one integration scenario if applicable. diff --git a/docs/zh/README.md b/docs/zh/README.md new file mode 100644 index 000000000..9c1232fb3 --- /dev/null +++ b/docs/zh/README.md @@ -0,0 +1,33 @@ +--- +home: true +title: Oak 视频编辑器 +heroImage: /images/oak-icon.png +heroText: Oak 视频编辑器 +heroFullScreen: false +tagline: 现代开源的非线性剪辑器,强调速度与清晰度。 +actions: + - text: 阅读文档 + link: /zh/build.html + type: primary + - text: 查看工程文件 + link: /zh/project-file-reference.html + type: secondary +features: + - title: 快速剪辑 + details: 响应式时间线、智能缓存与高效媒体管理。 + - title: 面向创作者 + details: 简洁界面、可配置快捷键与清晰的工程结构。 + - title: 开源透明 + details: 公开开发流程,欢迎社区参与。 +footer: Copyright © Oak Video Editor +--- + +## 关于 Oak + +Oak 视频编辑器是 Olive 的重命名分支,目标是打造更完善、更友好的剪辑体验。本网站提供构建说明、工程文件参考与测试计划等贡献者文档。 + +## 快速开始 + +- 按《构建指南》在 Windows/macOS/Linux 上从源码构建。 +- 在《工程文件参考》了解项目数据结构。 +- 按《测试计划》确保发布质量。 diff --git a/docs/zh/build.md b/docs/zh/build.md new file mode 100644 index 000000000..0f1e550c5 --- /dev/null +++ b/docs/zh/build.md @@ -0,0 +1,116 @@ +# 构建指南 + +本文档介绍如何从源码构建 Oak Video Editor。 + +## 依赖 + +- CMake 3.20+ +- Ninja(推荐) +- Qt 6(含私有头文件) +- FFmpeg 开发库 +- OpenImageIO +- OpenColorIO(2.x) +- OpenEXR +- Expat +- PortAudio +- OpenGL 头文件 +- XKB common(Linux) + +## Linux(Ubuntu/Debian) + +安装依赖: + +```bash +sudo apt-get update +sudo apt-get install -y \ + ninja-build pkg-config \ + qt6-base-dev qt6-base-dev-tools qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \ + libavcodec-dev libavformat-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev \ + libopencolorio-dev libopenimageio-dev libopenexr-dev libexpat1-dev \ + portaudio19-dev libgl1-mesa-dev libxkbcommon-dev +``` + +配置并构建: + +```bash +cmake -S . -B build -G Ninja -DBUILD_TESTS=ON -DBUILD_QT6=ON +cmake --build build --config Release +``` + +运行测试: + +```bash +ctest --test-dir build --output-on-failure -C Release +``` + +## macOS(非官方支持) + +说明:macOS **非官方支持**,目前只做 CI 自动化测试,不做人工测试。 + +安装依赖: + +```bash +brew update +brew install ninja pkg-config qt@6 ffmpeg openimageio opencolorio openexr portaudio expat +``` + +构建 OpenTimelineIO(可选,如需 OTIO 支持): + +```bash +git clone --depth 1 --branch v0.16.0 https://github.com/PixarAnimationStudios/OpenTimelineIO.git +cmake -S OpenTimelineIO -B OpenTimelineIO/build -G Ninja \ + -DOTIO_SHARED_LIBS=ON \ + -DOTIO_PYTHON_BINDINGS=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${PWD}/otio-install" +cmake --build OpenTimelineIO/build +cmake --install OpenTimelineIO/build +``` + +配置并构建: + +```bash +export PATH="$(brew --prefix qt@6)/bin:$PATH" +export CMAKE_PREFIX_PATH="$(brew --prefix qt@6)" +export OTIO_LOCATION="${PWD}/otio-install" +export OCIO_LOCATION="$(brew --prefix opencolorio)" + +cmake -S . -B build -G Ninja -DBUILD_TESTS=ON -DBUILD_QT6=ON \ + -DOTIO_LOCATION="${OTIO_LOCATION}" \ + -DOCIO_LOCATION="${OCIO_LOCATION}" +cmake --build build --config Release +``` + +运行测试: + +```bash +ctest --test-dir build --output-on-failure -C Release +``` + +## Windows + +Qt 6 请使用系统安装器或 CI action。其余依赖建议用 vcpkg。 + +```powershell +choco install -y ninja +$env:VCPKG_ROOT = "C:\vcpkg" +& "$env:VCPKG_ROOT\vcpkg.exe" install ffmpeg openimageio opencolorio openexr expat portaudio --triplet x64-windows +``` + +配置并构建: + +```powershell +cmake -S . -B build -G Ninja ` + -DBUILD_TESTS=ON ` + -DBUILD_QT6=ON ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake" ` + -DCMAKE_PREFIX_PATH="$env:Qt6_DIR" +cmake --build build --config Release +``` + +运行测试: + +```powershell +ctest --test-dir build --output-on-failure -C Release +``` diff --git a/docs/zh/project-file-reference.md b/docs/zh/project-file-reference.md new file mode 100644 index 000000000..066fa281f --- /dev/null +++ b/docs/zh/project-file-reference.md @@ -0,0 +1,305 @@ +# Oak Video Editor 项目文件参考手册(详细版) + +本文档基于当前源代码实现,描述 Oak Video Editor 的 XML 项目文件格式,目标是足够详细以实现兼容读写器。 + +> 代码来源:`app/node/project.cpp`、`app/node/node.cpp`、`app/node/value.*`、`app/node/keyframe.*`、`app/node/project/serializer/*`。 + +## 1. 根元素 + +```xml + + ... + +``` + +- `version`:序列化版本号(`YYMMDD`)。 +- `url`:可选的项目文件路径。 + +## 2. 项目容器 + +完整保存时,会有 `project` 容器: + +```xml + + ... + ... + +``` + +- 内层 ``:项目数据。 +- ``:界面布局(`MainWindowLayoutInfo::fromXml`)。 + +## 3. 项目数据(`Project::Save`) + +```xml + + ... + ... + ... + ... + +``` + +### 3.1 `uuid` +项目 UUID(QUuid 字符串)。 + +### 3.2 `plugins` +项目中使用的 OpenFX 插件列表,用于加载节点前补充插件搜索路径。 + +```xml + + + +``` + +属性: +- `id`:OFX 插件标识符(与节点 `id` 相同)。 +- `major` / `minor`:插件版本。 +- `bundle`:插件 bundle 目录路径(优先使用)。 +- `file`:插件二进制路径(备用)。 + +加载策略: +- 若存在 ``,先把 `bundle`(或 `file`)加入 OFX 搜索路径并扫描,然后注册插件节点,再进入 `` 解析。 + +### 3.3 `nodes` +节点图,节点由 `Node::Save()` 写出: + +```xml + + + + ... + + ... + ... + ... + ... + ... + ... + + +``` + +关键属性: +- `id`:节点类型标识。OpenFX 节点为插件标识符。 +- `ptr`:序列化指针 ID,用于恢复连接与位置。 +- `version`:当前为 `1`。 + +### 3.4 `settings` +项目设置,键值对形式保存: + +已知键: +- `cachesetting` +- `customcachepath` +- `colorconfigfilename` +- `defaultinputcolorspace` +- `colorreferencespace` +- `root` + +## 4. 节点序列化(`Node::Save` / `Node::Load`) + +### 4.1 `label` +节点显示名。 + +### 4.2 `color` +节点覆盖颜色(整数索引)。 + +### 4.3 `input` +每个输入: + +```xml + +``` + +- `primary`:主元素(element = -1)。 +- `subelements`:数组输入,`count` 为数组长度。 + +#### 4.3.1 立即值结构(`primary` / `element`) + +```xml +0|1 + + ... + + + + ... + + +... +... +... +... +``` + +- `keyframing`:是否启用关键帧(仅在输入可关键帧时写出)。 +- `standard`:默认值(每条 track 一份)。 +- `keyframes`:仅当 `keyframing=1` 时写出。 +- `cs*`:仅用于 `kColor`,保存色彩管理信息。 + +#### 4.3.2 Track 数量 +由 `NodeValue::get_number_of_keyframe_tracks()` 决定: + +| 类型 | Track 数量 | +| --- | --- | +| kVec2 | 2 | +| kVec3 | 3 | +| kVec4 | 4 | +| kColor | 4 | +| kBezier | 6 | +| 其他 | 1 | + +#### 4.3.3 标准值编码 +由 `NodeValue::ValueToString()` 写出,`NodeValue::StringToValue()` 读入: + +- `kVec2`: `x:y` +- `kVec3`: `x:y:z` +- `kVec4`: `x:y:z:w` +- `kColor`: `r:g:b:a` +- `kBezier`: `x:y:cp1x:cp1y:cp2x:cp2y` +- `kRational`: `num/den` +- `kInt`: 整数文本 +- `kBinary`: Base64 +- `kText` / `kFont` / `kFile` / `kCombo` / `kStrCombo`: 纯文本 +- `kTexture` / `kSamples` / `kNone`: 无文本 + +特殊情况: +- `kVideoParams` / `kAudioParams` 以子对象形式保存(见第 5/6 节)。 +- `kSubtitleParams` 在加载时被跳过(避免覆盖实际字幕数据)。 + +#### 4.3.4 关键帧(`NodeKeyframe::save`) + +```xml +value +``` + +- `input`:输入 ID。 +- `time`:理性时间。 +- `type`:关键帧类型枚举值。 +- `inhandlex` / `inhandley` / `outhandlex` / `outhandley`:贝塞尔控制点。 + +文本值使用 `NodeValue::ValueToString(data_type, value, true)`。 + +### 4.4 `links` +节点间的“块”链接: + +```xml + + ptr + +``` + +### 4.5 `connections` +输入/输出连接: + +```xml + + + ptr + + +``` + +### 4.6 `hints`(输入提示) + +```xml + + + + ... + + 0 + ... + + +``` + +### 4.7 `context`(节点位置) + +```xml + + + 0 + 0 + 0|1 + + +``` + +### 4.8 `caches` + +```xml + + + + uuid + uuid + +``` + +### 4.9 `custom` +节点自定义内容,默认实现为空;各子类可覆盖。 + +## 5. VideoParams +`kVideoParams` 输入以子对象保存: + +```xml +... +... +... +num/den +int +int +num/den +int +int +0|1 +float +float +int +int +num/den +int64 +int64 +0|1 +string +int +``` + +## 6. AudioParams +`kAudioParams` 输入以子对象保存: + +```xml +int +uint64 +string +0|1 +int +int64 +num/den +``` + +## 7. 部分保存 +序列化器支持写出部分数据: + +- `` +- `` +- ``(子集) + +## 8. OpenFX 插件兼容 + +- OpenFX 节点 `id` 等于插件标识符。 +- `` 记录插件路径,加载时会先扫描并注册插件节点。 +- 插件缺失时节点无法实例化并被跳过。 + +## 9. 版本兼容 + +- 根元素 `version` 决定使用哪个序列化器。 +- 若缺少对应版本,会报 `kProjectTooNew` 或 `kProjectTooOld`。 diff --git a/docs/zh/structure.md b/docs/zh/structure.md new file mode 100644 index 000000000..8b029fd8d --- /dev/null +++ b/docs/zh/structure.md @@ -0,0 +1,168 @@ +Oak Video Editor 项目结构概览(中文) +========================== + +这份文档是基于当前仓库目录组织的快速导航,便于后续查找代码位置。 + +顶层目录 +-------- +- app: 主应用源码入口,涵盖核心、渲染、UI、插件、节点系统等。 +- cmake: CMake 相关脚本与模块。 +- docker: 构建/运行相关的容器配置。 +- docs: 项目文档(你现在正在看的位置)。 +- ext: 可能包含外部依赖或子模块(按需查看)。 +- tests: 测试代码与用例。 +- third_party: 第三方库及其源码(如 OpenFX HostSupport)。 +- build、cmake-build-debug、test_compile: 构建产物或构建目录(通常不需要手动改)。 + +app 目录(核心模块) +------------------- +- app/core.*: 应用核心入口、初始化流程。 +- app/main.cpp: 程序入口点。 +- app/version.*: 版本信息与构建元数据。 +- app/common: 通用基础设施与工具类(日志、路径、字符串等)。 +- app/config: 配置加载与项目设置。 +- app/render: 渲染子系统(帧缓存、渲染管线、插件渲染桥接等)。 +- app/node: 节点系统,节点类型与图结构的核心逻辑。 +- app/widget: UI 控件与节点视图(节点图、参数面板等)。 +- app/panel: UI 面板组织与管理。 +- app/window: 窗口与主界面。 +- app/timeline: 时间线与剪辑管理。 +- app/tool: 交互工具(选择、裁剪等)。 +- app/undo: 撤销/重做系统。 +- app/task: 异步任务与后台作业。 +- app/audio: 音频处理与播放。 +- app/codec: 编解码相关支持。 +- app/shaders: 渲染着色器资源。 +- app/ts: 时间/时间轴相关通用类型。 +- app/dialog: 对话框与提示类 UI。 +- app/cli: 命令行工具入口或相关实现。 +- app/pluginSupport: OpenFX 插件 Host 侧实现(Clip/Image/Param/Host/PluginInstance 等)。 +- app/packaging: 打包或发布相关逻辑。 + +重点文件索引(按模块) +---------------------- +下面列的是“常用/核心入口”文件,不是完整清单,但足够定位主要流程。 + +核心入口与全局 +------------- +- app/main.cpp: 程序入口。 +- app/core.h、app/core.cpp: 应用生命周期与初始化总控。 +- app/version.h、app/version.cpp: 版本与构建信息。 + +渲染系统 +-------- +- app/render/renderer.h、app/render/renderer.cpp: 渲染主调度。 +- app/render/rendermanager.h、app/render/rendermanager.cpp: 渲染队列与任务管理。 +- app/render/renderticket.h、app/render/renderticket.cpp: 单次渲染请求。 +- app/render/renderprocessor.h、app/render/renderprocessor.cpp: 渲染处理管线。 +- app/render/texture.h、app/render/texture.cpp: 纹理/帧数据容器。 +- app/render/videoparams.h、app/render/videoparams.cpp: 视频格式参数。 +- app/render/job/pluginjob.h、app/render/job/pluginjob.cpp: 插件渲染作业。 +- app/render/plugin/pluginrenderer.h、app/render/plugin/pluginrenderer.cpp: OpenFX 插件渲染桥接。 + +节点系统 +-------- +- app/node/node.h、app/node/node.cpp: 节点基类与生命周期。 +- app/node/param.h、app/node/param.cpp: 节点参数与动画/关键帧。 +- app/node/value.h、app/node/value.cpp: 节点值与运行时数据。 +- app/node/factory.h、app/node/factory.cpp: 节点注册与创建。 +- app/node/traverser.h、app/node/traverser.cpp: 图遍历与求值。 +- app/node/plugins/Plugin.h、app/node/plugins/Plugin.cpp: OpenFX 插件节点。 + +OpenFX Host 侧实现 +------------------ +- app/pluginSupport/OliveHost.h、app/pluginSupport/OliveHost.cpp: OpenFX Host 入口与消息接口。 +- app/pluginSupport/OlivePluginInstance.h、app/pluginSupport/OlivePluginInstance.cpp: 插件实例生命周期与参数管理。 +- app/pluginSupport/OliveClip.h、app/pluginSupport/OliveClip.cpp: Clip 实例与图像读写桥接。 +- app/pluginSupport/image.h、app/pluginSupport/image.cpp: OpenFX Image 封装与数据映射。 +- app/pluginSupport/paraminstance.h、app/pluginSupport/paraminstance.cpp: 参数实例实现。 +- third_party/openfx/HostSupport/include/ofxhImageEffect.h: HostSupport 核心接口。 + +节点 UI(Node View) +------------------- +- app/widget/nodeview/nodeview.h、app/widget/nodeview/nodeview.cpp: 节点视图主控。 +- app/widget/nodeview/nodeviewitem.h、app/widget/nodeview/nodeviewitem.cpp: 节点渲染与交互。 +- app/widget/nodeview/nodeviewscene.h、app/widget/nodeview/nodeviewscene.cpp: QGraphicsScene 逻辑。 +- app/widget/nodeview/nodeviewedge.h、app/widget/nodeview/nodeviewedge.cpp: 连线显示。 + +参数 UI(Param View) +-------------------- +- app/widget/nodeparamview/nodeparamview.h、app/widget/nodeparamview/nodeparamview.cpp: 参数面板主控。 +- app/widget/nodeparamview/nodeparamviewitem.h、app/widget/nodeparamview/nodeparamviewitem.cpp: 参数项容器与布局。 +- app/widget/nodeparamview/nodeparamviewwidgetbridge.h、app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp: 参数类型到控件的桥接。 +- app/widget/nodeparamview/nodeparamviewtextedit.h、app/widget/nodeparamview/nodeparamviewtextedit.cpp: 多行文本参数控件。 + +面板与窗口 +---------- +- app/panel/panelmanager.h、app/panel/panelmanager.cpp: 面板管理器与切换逻辑。 +- app/panel/timebased/timebased.h、app/panel/timebased/timebased.cpp: 时间基面板基类(时间轴/视图共享逻辑)。 +- app/panel/node/node.h、app/panel/node/node.cpp: 节点面板入口。 +- app/panel/param/param.h、app/panel/param/param.cpp: 参数面板入口。 +- app/window: 主窗口与窗口级 UI 结构。 + +时间线/播放核心 +-------------- +- app/node/output/viewer/viewer.h、app/node/output/viewer/viewer.cpp: Viewer 输出节点(播放头/长度/渲染请求)。 +- app/widget/viewer/viewer.h、app/widget/viewer/viewer.cpp: Viewer 面板与播放控制。 +- app/widget/timelinewidget/timelinewidget.h、app/widget/timelinewidget/timelinewidget.cpp: 时间线 UI 与交互主控。 + +进度与任务 UI +------------ +- app/dialog/progress/progress.h、app/dialog/progress/progress.cpp: 通用进度对话框。 +- app/widget/taskview/taskviewitem.h、app/widget/taskview/taskviewitem.cpp: 任务进度条展示。 + +撤销/编辑分组 +------------ +- app/undo/undocommand.h、app/undo/undocommand.cpp: UndoCommand 与 MultiUndoCommand 的基础实现。 +- app/undo/undostack.h、app/undo/undostack.cpp: 撤销栈(无原生“批量编辑”接口)。 +- app/pluginSupport/OlivePluginInstance.h、app/pluginSupport/OlivePluginInstance.cpp: OpenFX editBegin/editEnd 触发时创建批量撤销分组。 +- app/pluginSupport/OlivePluginInstance.cpp: DeferredRedoCommand 包装已应用的命令,避免批量 push 时重复执行。 +- app/pluginSupport/paraminstance.h、app/pluginSupport/paraminstance.cpp: 参数 Set 走统一的 SubmitUndoCommand 接口,支持批量合并。 + +与 OpenFX 相关的主要位置 +----------------------- +- app/pluginSupport: OpenFX HostSupport 的封装与 Olive 侧实现。 +- app/render/plugin: 插件渲染调度与帧处理逻辑。 +- app/node/plugins: 插件节点定义与 UI 参数桥接。 +- third_party/openfx: OpenFX HostSupport 源码与接口头文件。 + +构建与配置 +---------- +- CMakeLists.txt: 根构建配置入口。 +- cmake/: 自定义 CMake 模块与工具链脚本。 + +其他说明 +-------- +- README.md: 项目整体说明与开发入口。 +- TODO-zh.md: OpenFX 支持的中文 TODO 说明。 + +流程图/调用关系(ASCII) +----------------------- +OpenFX 插件渲染主流程(逻辑简化): +``` +Node(Graph) + -> app/node/plugins/Plugin.cpp + -> app/render/plugin/pluginrenderer.cpp + -> app/pluginSupport/OlivePluginInstance.cpp + -> app/pluginSupport/OliveClip.cpp + -> app/pluginSupport/image.cpp + -> app/render/texture.cpp / AVFrame 映射 +``` + +OpenFX 参数 UI 生成流程(逻辑简化): +``` +OFX Param Descriptor + -> app/pluginSupport/OlivePluginInstance.cpp (newParam) + -> app/node/plugins/Plugin.cpp (Node Input 生成) + -> app/widget/nodeparamview/nodeparamview.cpp + -> app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp (控件桥接) +``` + +插件消息展示流程(逻辑简化): +``` +OFX Host Message + -> app/pluginSupport/OliveHost.cpp (保存消息) + -> app/pluginSupport/OlivePluginInstance.cpp (发出消息数量变化) + -> app/widget/nodeview/nodeviewitem.cpp (节点右上角徽标) + -> app/widget/nodeparamview/nodeparamviewitem.cpp (面板顶部消息) +``` diff --git a/docs/zh/test-plan.md b/docs/zh/test-plan.md new file mode 100644 index 000000000..09f96873b --- /dev/null +++ b/docs/zh/test-plan.md @@ -0,0 +1,93 @@ +# Oak Video Editor 测试策略与计划 + +本文档描述 Oak Video Editor 的自动化测试策略,包括单元测试、集成测试以及 CI 执行方式。 + +## 目标 + +- 尽量自动化,减少人工测试。 +- 覆盖所有模块(至少一个自动化测试)。 +- 集成测试保持无 GUI(头less)。 +- 在 Windows/macOS/Linux 上可重复运行。 + +## 测试层级 + +### 1) 单元测试(GoogleTest) +- 目标:小范围、确定性、无 GUI。 +- 目录:`tests/gtest/`。 +- 执行:`ctest` 里的 `olive-gtest`。 + +### 1.5) 模块冒烟测试(GoogleTest) +- 目标:对 GUI 相关模块做编译期/链接期覆盖,不实例化控件。 +- 目录:`tests/gtest/module_smoke_test.cpp`。 +- 执行:`ctest` 里的 `olive-gtest`。 + +### 2) 集成测试(GoogleTest) +- 目标:跨模块流程但不依赖 GUI(例如序列化→反序列化)。 +- 目录:`tests/gtest/`(如 `ProjectSerializer`、`TaskManager`)。 + +### 3) 现有测试(Olive 宏测试) +- 目录:`tests/general`、`tests/timeline`、`tests/compositing` 保持不变。 + +## 模块覆盖映射 + +每个顶层模块至少有一个测试用例。 + +- `app/common`:`common_current_test.cpp`、`common_xmlutils_test.cpp` +- `app/config`:`config_test.cpp` +- `app/node`:`node_value_test.cpp`、`node_keyframe_test.cpp`、`node_serialization_test.cpp` +- `app/node/project/serializer`:`project_serializer_test.cpp` +- `app/render`:`render_videoparams_test.cpp`、`render_audioparams_test.cpp` +- `app/timeline`:`timeline_marker_test.cpp` +- `app/undo`:`undo_stack_test.cpp` +- `app/task`:`task_taskmanager_test.cpp` +- `app/codec`:`codec_frame_test.cpp` +- `app/pluginSupport`:`plugin_support_test.cpp` +- `app/audio`、`app/cli`、`app/dialog`、`app/panel`、`app/tool`、`app/ui`、`app/widget`、`app/window`:`module_smoke_test.cpp` + +若模块包含 GUI 依赖,则测试聚焦于其非可视逻辑/数据结构。 + +## 集成测试说明 + +### 项目序列化回归 +- 创建最小项目并添加内置节点。 +- 使用 `ProjectSerializer::Save` 写出 XML。 +- 再用 `ProjectSerializer::Load` 读回。 +- 验证节点恢复。 + +### 任务管理器执行 +- 向 `TaskManager` 添加一个 DummyTask。 +- 使用事件循环等待完成。 +- 验证任务确实执行。 + +## 单元覆盖重点(已扩展) + +- `app/undo`:`undo_stack_test.cpp` 覆盖空栈状态、模型数据、redo 区域颜色、jump 行为、空 MultiUndoCommand 忽略逻辑。 +- `app/timeline`:`timeline_marker_test.cpp` 覆盖列表排序、最近 marker 查询、含未知元素的保存/加载、marker 增删改命令。 +- `app/pluginSupport`:`plugin_support_image_test.cpp` 覆盖 OFX 属性映射(bounds/ROD、像素深度、通道、预乘)及分配/清理行为。 +- `app/render`:`render_videoparams_branch_test.cpp` 覆盖自动 divider、像素宽高比校验、方形像素宽度、Save/Load 回归。 + +## 无 GUI 运行 + +- 测试避免使用 QWidget。 +- CI 中设置 `QT_QPA_PLATFORM=offscreen` 防止 GUI 初始化问题。 + +## 持续集成 + +CI 在 Windows/macOS/Linux 上执行: + +1. 安装依赖(Qt、FFmpeg、OpenImageIO、OpenColorIO、OpenEXR、PortAudio、Expat)。 +2. `-DBUILD_TESTS=ON` 配置。 +3. 使用 CMake + Ninja 构建。 +4. 运行 `ctest` 输出失败信息。 + +### 依赖安装说明 +- Linux:优先使用发行版系统包(Ubuntu 上用 `apt`)安装 Qt6、FFmpeg、OpenImageIO、OpenColorIO、OpenEXR、PortAudio、Expat、OpenGL 头文件。 +- macOS:使用 Homebrew 安装 Qt6 和图像/色彩/多媒体相关库。 +- Windows:尽量使用系统安装器(Qt 通过 `install-qt-action`),其余 C/C++ 库通过 vcpkg 安装。 + +## 新增测试规范 + +- 新测试放在 `tests/gtest`。 +- 使用 GoogleTest 规范。 +- 尽量保持确定性与无外部依赖。 +- 新模块至少增加 1 个单元测试 + 1 个集成场景(可合并)。 diff --git a/ext/KDDockWidgets b/ext/KDDockWidgets index 8d2d0a576..6b0ef44eb 160000 --- a/ext/KDDockWidgets +++ b/ext/KDDockWidgets @@ -1 +1 @@ -Subproject commit 8d2d0a5764f8393cc148a2296d511276a8ffe559 +Subproject commit 6b0ef44eb189411d36c739ccde8a081a3e62034a diff --git a/ext/core b/ext/core index 50caae473..1be2a3eef 160000 --- a/ext/core +++ b/ext/core @@ -1 +1 @@ -Subproject commit 50caae473d6de11d129f1fb6a14d2c73dac83f51 +Subproject commit 1be2a3eefb39c33f2e827f5cd0da215dd214bf08 diff --git a/icon.png b/icon.png new file mode 100644 index 000000000..393dea9fe Binary files /dev/null and b/icon.png differ diff --git a/icon.xcf b/icon.xcf new file mode 100644 index 000000000..c953e0f70 Binary files /dev/null and b/icon.xcf differ diff --git a/package.json b/package.json new file mode 100644 index 000000000..7e41ea5f9 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "oak-video-editor-docs", + "private": true, + "type": "module", + "scripts": { + "docs:dev": "vuepress dev docs", + "docs:build": "vuepress build docs" + }, + "devDependencies": { + "@vuepress/bundler-vite": "^2.0.0-rc.19", + "vuepress": "^2.0.0-rc.19", + "vuepress-theme-hope": "^2.0.0-rc.42" + } +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3dbbd2ccd..2040ce48b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,6 @@ # Olive - Non-Linear Video Editor # Copyright (C) 2022 Olive Team +# Modifications Copyright (C) 2025 mikesolar # # 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 @@ -45,6 +46,8 @@ function(olive_add_test GROUP NAME SOURCE) PRIVATE ${CMAKE_SOURCE_DIR}/app ${CMAKE_SOURCE_DIR}/tests + ${CMAKE_SOURCE_DIR}/third_party/openfx/include + ${CMAKE_SOURCE_DIR}/third_party/openfx/HostSupport/include ${OLIVE_INCLUDE_DIRS} ) target_link_libraries( @@ -69,6 +72,18 @@ function(olive_add_test GROUP NAME SOURCE) endif() endfunction() +include(FetchContent) +find_package(GTest QUIET) +if (NOT GTest_FOUND) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip + ) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) +endif() + add_subdirectory(compositing) add_subdirectory(general) add_subdirectory(timeline) +add_subdirectory(gtest) diff --git a/tests/compositing/compositing-tests.cpp b/tests/compositing/compositing-tests.cpp index e757f1d78..10bb72fe5 100644 --- a/tests/compositing/compositing-tests.cpp +++ b/tests/compositing/compositing-tests.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/tests/general/common-tests.cpp b/tests/general/common-tests.cpp index 2a3e29737..25d1d73dd 100644 --- a/tests/general/common-tests.cpp +++ b/tests/general/common-tests.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/tests/gtest/CMakeLists.txt b/tests/gtest/CMakeLists.txt new file mode 100644 index 000000000..d1486c695 --- /dev/null +++ b/tests/gtest/CMakeLists.txt @@ -0,0 +1,73 @@ +add_executable(olive-gtest + main.cpp + common_current_test.cpp + common_xmlutils_test.cpp + config_test.cpp + node_value_test.cpp + node_keyframe_test.cpp + node_serialization_test.cpp + render_videoparams_test.cpp + render_videoparams_branch_test.cpp + render_audioparams_test.cpp + render_audioparams_branch_test.cpp + render_sampleformat_test.cpp + render_pixelformat_test.cpp + project_serializer_test.cpp + timeline_marker_test.cpp + undo_stack_test.cpp + plugin_support_test.cpp + plugin_support_image_test.cpp + plugin_support_clip_test.cpp + plugin_support_param_test.cpp + opengl_readback_guard_test.cpp + plugin_render_pipeline_test.cpp + plugin_renderer_readback_test.cpp + plugin_ofx_integration_test.cpp + codec_frame_test.cpp + codec_exportcodec_test.cpp + codec_exportformat_test.cpp + codec_encoder_test.cpp + task_taskmanager_test.cpp + module_smoke_test.cpp + shader_resources_test.cpp + timebased_widget_test.cpp + timeline_coordinate_test.cpp + timeline_workarea_test.cpp +) + +target_sources(olive-gtest PRIVATE $) + +target_include_directories( + olive-gtest + PRIVATE + ${CMAKE_SOURCE_DIR}/app + ${CMAKE_SOURCE_DIR}/tests + ${CMAKE_SOURCE_DIR}/third_party/openfx/include + ${CMAKE_SOURCE_DIR}/third_party/openfx/HostSupport/include + ${OLIVE_INCLUDE_DIRS} +) + +target_link_libraries( + olive-gtest + PRIVATE + ${OLIVE_LIBRARIES} + GTest::gtest +) + +target_compile_definitions( + olive-gtest + PRIVATE + ${OLIVE_DEFINITIONS} +) + +target_compile_options( + olive-gtest + PRIVATE + ${OLIVE_COMPILE_OPTIONS} +) + +if (MSVC) + add_test("Olive.gtest" olive-gtest) +else() + add_test(olive-gtest olive-gtest) +endif() diff --git a/tests/gtest/codec_encoder_test.cpp b/tests/gtest/codec_encoder_test.cpp new file mode 100644 index 000000000..05d7bc1f2 --- /dev/null +++ b/tests/gtest/codec_encoder_test.cpp @@ -0,0 +1,99 @@ +#include + +#include "codec/encoder.h" + +namespace { +class TestEncoder final : public olive::Encoder { +public: + explicit TestEncoder(const olive::EncodingParams ¶ms) + : olive::Encoder(params) + { + } + + bool Open() override + { + return true; + } + + bool WriteFrame(olive::FramePtr, olive::core::rational) override + { + return true; + } + + bool WriteAudio(const olive::SampleBuffer &) override + { + return true; + } + + bool WriteSubtitle(const olive::SubtitleBlock *) override + { + return true; + } + + void Close() override + { + } +}; +} + +TEST(CodecEncoder, ImageSequenceFilenames) +{ + olive::EncodingParams params; + params.SetFilename(QStringLiteral("frame_[####].png")); + params.set_video_is_image_sequence(true); + + olive::VideoParams video_params; + video_params.set_frame_rate(olive::core::rational(24, 1)); + params.EnableVideo(video_params, olive::ExportCodec::kCodecPNG); + + TestEncoder encoder(params); + + EXPECT_TRUE(olive::Encoder::FilenameContainsDigitPlaceholder( + QStringLiteral("frame_[####].png"))); + EXPECT_EQ(olive::Encoder::GetImageSequencePlaceholderDigitCount( + QStringLiteral("frame_[####].png")), + 4); + EXPECT_EQ(olive::Encoder::FilenameRemoveDigitPlaceholder( + QStringLiteral("frame_[####].png")), + QStringLiteral("frame.png")); + + const QString filename = encoder.GetFilenameForFrame( + olive::core::rational(1, 24)); + EXPECT_EQ(filename, QStringLiteral("frame_0001.png")); +} + +TEST(CodecEncoder, MatrixGeneration) +{ + using Method = olive::EncodingParams::VideoScalingMethod; + + QMatrix4x4 stretch = + olive::EncodingParams::GenerateMatrix(Method::kStretch, 1920, 1080, + 1280, 720); + EXPECT_TRUE(qFuzzyCompare(stretch(0, 0), 1.0f)); + EXPECT_TRUE(qFuzzyCompare(stretch(1, 1), 1.0f)); + + QMatrix4x4 fit = + olive::EncodingParams::GenerateMatrix(Method::kFit, 1920, 1080, + 1024, 1024); + EXPECT_TRUE(qFuzzyCompare(fit(0, 0), 1.0f)); + EXPECT_FALSE(qFuzzyCompare(fit(1, 1), 1.0f)); + + QMatrix4x4 crop = + olive::EncodingParams::GenerateMatrix(Method::kCrop, 1920, 1080, + 1024, 1024); + EXPECT_FALSE(qFuzzyCompare(crop(0, 0), 1.0f)); + EXPECT_TRUE(qFuzzyCompare(crop(1, 1), 1.0f)); +} + +TEST(CodecEncoder, TypeFromFormat) +{ + using olive::Encoder; + using olive::ExportFormat; + + EXPECT_EQ(Encoder::GetTypeFromFormat(ExportFormat::kFormatPNG), + Encoder::kEncoderTypeOIIO); + EXPECT_EQ(Encoder::GetTypeFromFormat(ExportFormat::kFormatDNxHD), + Encoder::kEncoderTypeFFmpeg); + EXPECT_EQ(Encoder::GetTypeFromFormat(ExportFormat::kFormatCount), + Encoder::kEncoderTypeNone); +} diff --git a/tests/gtest/codec_exportcodec_test.cpp b/tests/gtest/codec_exportcodec_test.cpp new file mode 100644 index 000000000..cfae6fcc9 --- /dev/null +++ b/tests/gtest/codec_exportcodec_test.cpp @@ -0,0 +1,20 @@ +#include + +#include "codec/exportcodec.h" + +TEST(CodecExportCodec, NamesAndFlags) +{ + using olive::ExportCodec; + + EXPECT_EQ(ExportCodec::GetCodecName(ExportCodec::kCodecH264), + QStringLiteral("H.264")); + EXPECT_EQ(ExportCodec::GetCodecName(ExportCodec::kCodecCount), + QStringLiteral("Unknown")); + + EXPECT_TRUE(ExportCodec::IsCodecAStillImage(ExportCodec::kCodecPNG)); + EXPECT_FALSE(ExportCodec::IsCodecAStillImage(ExportCodec::kCodecH264)); + + EXPECT_TRUE(ExportCodec::IsCodecLossless(ExportCodec::kCodecPCM)); + EXPECT_TRUE(ExportCodec::IsCodecLossless(ExportCodec::kCodecFLAC)); + EXPECT_FALSE(ExportCodec::IsCodecLossless(ExportCodec::kCodecH265)); +} diff --git a/tests/gtest/codec_exportformat_test.cpp b/tests/gtest/codec_exportformat_test.cpp new file mode 100644 index 000000000..a27ffb727 --- /dev/null +++ b/tests/gtest/codec_exportformat_test.cpp @@ -0,0 +1,44 @@ +#include + +#include "codec/exportformat.h" + +TEST(CodecExportFormat, NamesAndExtensions) +{ + using olive::ExportFormat; + + EXPECT_EQ(ExportFormat::GetName(ExportFormat::kFormatDNxHD), + QStringLiteral("DNxHD")); + EXPECT_EQ(ExportFormat::GetExtension(ExportFormat::kFormatDNxHD), + QStringLiteral("mxf")); + EXPECT_EQ(ExportFormat::GetName(ExportFormat::kFormatCount), + QStringLiteral("Unknown")); + EXPECT_TRUE(ExportFormat::GetExtension(ExportFormat::kFormatCount).isEmpty()); +} + +TEST(CodecExportFormat, CodecLists) +{ + using olive::ExportCodec; + using olive::ExportFormat; + + const QList matroska_video = + ExportFormat::GetVideoCodecs(ExportFormat::kFormatMatroska); + EXPECT_TRUE(matroska_video.contains(ExportCodec::kCodecH264)); + EXPECT_TRUE(matroska_video.contains(ExportCodec::kCodecVP9)); + + const QList ogg_audio = + ExportFormat::GetAudioCodecs(ExportFormat::kFormatOgg); + EXPECT_TRUE(ogg_audio.contains(ExportCodec::kCodecOpus)); + EXPECT_TRUE(ogg_audio.contains(ExportCodec::kCodecVorbis)); + + const QList png_video = + ExportFormat::GetVideoCodecs(ExportFormat::kFormatPNG); + EXPECT_EQ(png_video, QList{ ExportCodec::kCodecPNG }); + + const QList srt_subs = + ExportFormat::GetSubtitleCodecs(ExportFormat::kFormatMatroska); + EXPECT_EQ(srt_subs, QList{ ExportCodec::kCodecSRT }); + + const QList wav_audio = + ExportFormat::GetAudioCodecs(ExportFormat::kFormatWAV); + EXPECT_EQ(wav_audio, QList{ ExportCodec::kCodecPCM }); +} diff --git a/tests/gtest/codec_frame_test.cpp b/tests/gtest/codec_frame_test.cpp new file mode 100644 index 000000000..1ffec9ae4 --- /dev/null +++ b/tests/gtest/codec_frame_test.cpp @@ -0,0 +1,11 @@ +#include + +#include "codec/frame.h" + +TEST(CodecFrame, DefaultState) +{ + olive::Frame frame; + EXPECT_EQ(frame.width(), 0); + EXPECT_EQ(frame.height(), 0); + EXPECT_EQ(frame.format(), olive::core::PixelFormat::INVALID); +} diff --git a/tests/gtest/common_current_test.cpp b/tests/gtest/common_current_test.cpp new file mode 100644 index 000000000..bff3a4c0e --- /dev/null +++ b/tests/gtest/common_current_test.cpp @@ -0,0 +1,27 @@ +#include + +#include "common/Current.h" +#include "render/videoparams.h" +#include "olive/core/render/audioparams.h" + +TEST(CommonCurrent, SetAndGetVideoParams) +{ + olive::VideoParams params; + params.set_width(1920); + params.set_height(1080); + Current::getInstance().setCurrentVideoParams(params); + + const olive::VideoParams &stored = Current::getInstance().currentVideoParams(); + EXPECT_EQ(stored.width(), 1920); + EXPECT_EQ(stored.height(), 1080); +} + +TEST(CommonCurrent, SetAndGetAudioParams) +{ + olive::AudioParams params; + params.set_sample_rate(48000); + Current::getInstance().setCurrentAudioParams(params); + + const olive::AudioParams &stored = Current::getInstance().currentAudioParams(); + EXPECT_EQ(stored.sample_rate(), 48000); +} diff --git a/tests/gtest/common_xmlutils_test.cpp b/tests/gtest/common_xmlutils_test.cpp new file mode 100644 index 000000000..9d04380ea --- /dev/null +++ b/tests/gtest/common_xmlutils_test.cpp @@ -0,0 +1,20 @@ +#include + +#include +#include +#include + +#include "common/xmlutils.h" + +TEST(CommonXmlUtils, ReadNextStartElement) +{ + QByteArray xml = "value"; + QBuffer buffer(&xml); + buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&buffer); + + EXPECT_TRUE(olive::XMLReadNextStartElement(&reader)); + EXPECT_EQ(reader.name().toString(), QStringLiteral("root")); + EXPECT_TRUE(olive::XMLReadNextStartElement(&reader)); + EXPECT_EQ(reader.name().toString(), QStringLiteral("child")); +} diff --git a/tests/gtest/config_test.cpp b/tests/gtest/config_test.cpp new file mode 100644 index 000000000..94322588d --- /dev/null +++ b/tests/gtest/config_test.cpp @@ -0,0 +1,20 @@ +#include + +#include "config/config.h" + +TEST(Config, DefaultsPresent) +{ + olive::Config &cfg = olive::Config::Current(); + cfg.SetDefaults(); + + EXPECT_TRUE(cfg[QStringLiteral("Style")].isValid()); + EXPECT_TRUE(cfg[QStringLiteral("TimecodeDisplay")].isValid()); + EXPECT_TRUE(cfg[QStringLiteral("DefaultStillLength")].isValid()); +} + +TEST(Config, SetAndGetValues) +{ + olive::Config &cfg = olive::Config::Current(); + cfg[QStringLiteral("UnitTestValue")] = 42; + EXPECT_EQ(cfg[QStringLiteral("UnitTestValue")].toInt(), 42); +} diff --git a/tests/gtest/main.cpp b/tests/gtest/main.cpp new file mode 100644 index 000000000..0bf0dbde7 --- /dev/null +++ b/tests/gtest/main.cpp @@ -0,0 +1,9 @@ +#include +#include + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/gtest/module_smoke_test.cpp b/tests/gtest/module_smoke_test.cpp new file mode 100644 index 000000000..aa13980c3 --- /dev/null +++ b/tests/gtest/module_smoke_test.cpp @@ -0,0 +1,15 @@ +#include + +#include "audio/audiomanager.h" +#include "cli/cliexport/cliexportmanager.h" +#include "dialog/progress/progress.h" +#include "panel/panelmanager.h" +#include "tool/tool.h" +#include "ui/humanstrings.h" +#include "widget/nodeview/nodeview.h" +#include "window/mainwindow/mainwindow.h" + +TEST(ModuleSmoke, HeadersBuild) +{ + SUCCEED(); +} diff --git a/tests/gtest/node_keyframe_test.cpp b/tests/gtest/node_keyframe_test.cpp new file mode 100644 index 000000000..25817d736 --- /dev/null +++ b/tests/gtest/node_keyframe_test.cpp @@ -0,0 +1,47 @@ +#include + +#include +#include +#include + +#include "node/keyframe.h" +#include "node/value.h" + +TEST(NodeKeyframe, SaveLoadRoundTrip) +{ + olive::NodeKeyframe key; + key.set_input(QStringLiteral("Value")); + key.set_time(olive::core::rational(1, 24)); + key.set_type(olive::NodeKeyframe::kLinear); + key.set_value(42.0); + key.set_bezier_control_in(QPointF(0.1, 0.2)); + key.set_bezier_control_out(QPointF(0.3, 0.4)); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("key")); + key.save(&writer, olive::NodeValue::kFloat); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + EXPECT_TRUE(reader.readNextStartElement()); + EXPECT_EQ(reader.name().toString(), QStringLiteral("key")); + + olive::NodeKeyframe loaded; + EXPECT_TRUE(loaded.load(&reader, olive::NodeValue::kFloat)); + EXPECT_EQ(loaded.input(), QStringLiteral("Value")); + EXPECT_EQ(loaded.time(), olive::core::rational(1, 24)); + EXPECT_EQ(loaded.type(), olive::NodeKeyframe::kLinear); + EXPECT_DOUBLE_EQ(loaded.value().toDouble(), 42.0); + EXPECT_DOUBLE_EQ(loaded.bezier_control_in().x(), 0.1); + EXPECT_DOUBLE_EQ(loaded.bezier_control_in().y(), 0.2); + EXPECT_DOUBLE_EQ(loaded.bezier_control_out().x(), 0.3); + EXPECT_DOUBLE_EQ(loaded.bezier_control_out().y(), 0.4); +} diff --git a/tests/gtest/node_serialization_test.cpp b/tests/gtest/node_serialization_test.cpp new file mode 100644 index 000000000..8fae79f64 --- /dev/null +++ b/tests/gtest/node_serialization_test.cpp @@ -0,0 +1,95 @@ +#include + +#include +#include +#include + +#include "node/node.h" +#include "node/serializeddata.h" +#include "node/splitvalue.h" +#include "node/value.h" +#include "render/diskmanager.h" + +namespace { +class TestNode final : public olive::Node { +public: + TestNode() + { + AddInput(QStringLiteral("Value"), olive::NodeValue::kFloat); + olive::SplitValue value; + value.append(3.5); + SetSplitStandardValue(QStringLiteral("Value"), value, -1); + } + + TestNode *copy() const override + { + return new TestNode(); + } + + QString Name() const override + { + return QStringLiteral("TestNode"); + } + + QString id() const override + { + return QStringLiteral("org.olivevideoeditor.TestNode"); + } + + QVector Category() const override + { + return { kCategoryUnknown }; + } + + QString Description() const override + { + return QStringLiteral("Test node for serialization"); + } + + void Value(const olive::NodeValueRow &, const olive::NodeGlobals &, + olive::NodeValueTable *) const override + { + } +}; +} + +TEST(NodeSerialization, SaveAndLoadInput) +{ + const bool created_disk_manager = (olive::DiskManager::instance() == nullptr); + if (created_disk_manager) { + olive::DiskManager::CreateInstance(); + } + + TestNode node; + node.SetLabel(QStringLiteral("MyNode")); + node.SetOverrideColor(2); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("node")); + node.Save(&writer); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + TestNode loaded; + olive::SerializedData data; + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + EXPECT_TRUE(reader.readNextStartElement()); + EXPECT_EQ(reader.name().toString(), QStringLiteral("node")); + EXPECT_TRUE(loaded.Load(&reader, &data)); + + EXPECT_EQ(loaded.GetLabel(), QStringLiteral("MyNode")); + EXPECT_EQ(loaded.GetOverrideColor(), 2); + EXPECT_DOUBLE_EQ(loaded.GetSplitStandardValue(QStringLiteral("Value"), -1) + .first().toDouble(), 3.5); + + if (created_disk_manager) { + olive::DiskManager::DestroyInstance(); + } +} diff --git a/tests/gtest/node_value_test.cpp b/tests/gtest/node_value_test.cpp new file mode 100644 index 000000000..91f094b51 --- /dev/null +++ b/tests/gtest/node_value_test.cpp @@ -0,0 +1,50 @@ +#include + +#include +#include +#include + +#include "node/value.h" + +TEST(NodeValue, VectorRoundTrip) +{ + QVector2D v2(1.5f, -2.0f); + QString encoded = olive::NodeValue::ValueToString( + olive::NodeValue::kVec2, QVariant::fromValue(v2), false); + QVariant decoded = olive::NodeValue::StringToValue( + olive::NodeValue::kVec2, encoded, false); + QVector2D v2_out = decoded.value(); + EXPECT_FLOAT_EQ(v2_out.x(), v2.x()); + EXPECT_FLOAT_EQ(v2_out.y(), v2.y()); + + QVector3D v3(1.0f, 2.0f, 3.0f); + encoded = olive::NodeValue::ValueToString( + olive::NodeValue::kVec3, QVariant::fromValue(v3), false); + decoded = olive::NodeValue::StringToValue( + olive::NodeValue::kVec3, encoded, false); + QVector3D v3_out = decoded.value(); + EXPECT_FLOAT_EQ(v3_out.x(), v3.x()); + EXPECT_FLOAT_EQ(v3_out.y(), v3.y()); + EXPECT_FLOAT_EQ(v3_out.z(), v3.z()); + + QVector4D v4(1.0f, 2.0f, 3.0f, 4.0f); + encoded = olive::NodeValue::ValueToString( + olive::NodeValue::kVec4, QVariant::fromValue(v4), false); + decoded = olive::NodeValue::StringToValue( + olive::NodeValue::kVec4, encoded, false); + QVector4D v4_out = decoded.value(); + EXPECT_FLOAT_EQ(v4_out.x(), v4.x()); + EXPECT_FLOAT_EQ(v4_out.y(), v4.y()); + EXPECT_FLOAT_EQ(v4_out.z(), v4.z()); + EXPECT_FLOAT_EQ(v4_out.w(), v4.w()); +} + +TEST(NodeValue, BinaryRoundTrip) +{ + QByteArray data("OliveTest"); + QString encoded = olive::NodeValue::ValueToString( + olive::NodeValue::kBinary, data, false); + QVariant decoded = olive::NodeValue::StringToValue( + olive::NodeValue::kBinary, encoded, false); + EXPECT_EQ(decoded.toByteArray(), data); +} diff --git a/tests/gtest/opengl_readback_guard_test.cpp b/tests/gtest/opengl_readback_guard_test.cpp new file mode 100644 index 000000000..bf4e41df8 --- /dev/null +++ b/tests/gtest/opengl_readback_guard_test.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include + +#include "render/opengl/openglrenderer.h" + +TEST(OpenGLRenderer, DownloadFromTextureWithoutCurrentContext) +{ + QOpenGLContext context; + ASSERT_TRUE(context.create()); + ASSERT_EQ(QOpenGLContext::currentContext(), nullptr); + + olive::OpenGLRenderer renderer; + renderer.Init(&context); + + olive::VideoParams params(4, 4, olive::core::PixelFormat::U8, 4, + olive::core::rational(1, 1), + olive::VideoParams::kInterlaceNone, 1); + + unsigned char buffer[4 * 4 * 4] = {}; + renderer.DownloadFromTexture(QVariant::fromValue(0), params, + buffer, 4 * 4); + + EXPECT_EQ(QOpenGLContext::currentContext(), nullptr); +} diff --git a/tests/gtest/plugin_ofx_integration_test.cpp b/tests/gtest/plugin_ofx_integration_test.cpp new file mode 100644 index 000000000..25e2bbf56 --- /dev/null +++ b/tests/gtest/plugin_ofx_integration_test.cpp @@ -0,0 +1,120 @@ +#include + +#include + +extern "C" { +#include +} + +#include "common/ffmpegutils.h" +#include "node/value.h" +#include "pluginSupport/OliveHost.h" +#include "pluginSupport/OlivePluginInstance.h" +#include "render/job/pluginjob.h" +#include "render/plugin/pluginrenderer.h" +#include "render/texture.h" +#include "render/videoparams.h" + +namespace { + +olive::TexturePtr CreateSolidTexture(const olive::VideoParams ¶ms) +{ + olive::AVFramePtr frame = olive::CreateAVFramePtr(); + frame->format = olive::FFmpegUtils::GetFFmpegPixelFormat( + params.format(), params.channel_count()); + frame->width = params.width(); + frame->height = params.height(); + if (frame->format == AV_PIX_FMT_NONE) { + return nullptr; + } + if (av_frame_get_buffer(frame.get(), 0) < 0) { + return nullptr; + } + if (av_frame_make_writable(frame.get()) < 0) { + return nullptr; + } + + const int linesize = frame->linesize[0]; + for (int y = 0; y < frame->height; ++y) { + std::memset(frame->data[0] + y * linesize, 0x7f, linesize); + } + + olive::TexturePtr texture = std::make_shared(params); + texture->handleFrame(frame); + return texture; +} + +} // namespace + +TEST(PluginIntegration, ChromaKeyerCreateAndRender) +{ + const char *itest = std::getenv("OAK_OFX_ITEST"); + if (!itest || std::string(itest) != "1") { + GTEST_SKIP() << "OAK_OFX_ITEST not enabled"; + } + + const char *path = std::getenv("OAK_OFX_PLUGIN_PATH"); + if (!path || std::string(path).empty()) { + GTEST_SKIP() << "OAK_OFX_PLUGIN_PATH not set"; + } + + std::string plugin_id = "net.sf.openfx.ChromaKeyerPlugin"; + if (const char *env_id = std::getenv("OAK_OFX_PLUGIN_ID")) { + if (*env_id) { + plugin_id = env_id; + } + } + + olive::plugin::loadPlugins(QString::fromUtf8(path)); + + auto *cache = OFX::Host::PluginCache::getPluginCache(); + OFX::Host::Plugin *found = nullptr; + for (auto *plug : cache->getPlugins()) { + if (plug && plug->getIdentifier() == plugin_id) { + found = plug; + break; + } + } + if (!found) { + GTEST_SKIP() << "Plugin not found: " << plugin_id; + } + + auto *image_effect = + dynamic_cast(found); + ASSERT_TRUE(image_effect); + + const auto &contexts = image_effect->getContexts(); + std::string context = kOfxImageEffectContextFilter; + if (!contexts.empty() && + contexts.find(kOfxImageEffectContextFilter) == contexts.end()) { + context = *contexts.begin(); + } + + OFX::Host::ImageEffect::Instance *instance = + image_effect->createInstance(context, nullptr); + ASSERT_TRUE(instance); + + auto *olive_instance = + dynamic_cast(instance); + ASSERT_TRUE(olive_instance); + + olive::VideoParams params(320, 240, olive::core::PixelFormat::U8, 4); + olive_instance->setVideoParam(params); + + olive::TexturePtr input = CreateSolidTexture(params); + ASSERT_TRUE(input); + + olive::NodeValueRow row; + row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName), + olive::NodeValue(olive::NodeValue::kTexture, input)); + row.insert(QStringLiteral("Bg"), + olive::NodeValue(olive::NodeValue::kTexture, input)); + + olive::plugin::PluginJob job(instance, nullptr, row); + olive::TexturePtr output = std::make_shared(params); + + olive::plugin::PluginRenderer renderer; + renderer.RenderPlugin(input, job, output, params, true, false); + + EXPECT_TRUE(output->frame()); +} diff --git a/tests/gtest/plugin_render_pipeline_test.cpp b/tests/gtest/plugin_render_pipeline_test.cpp new file mode 100644 index 000000000..8cf406f23 --- /dev/null +++ b/tests/gtest/plugin_render_pipeline_test.cpp @@ -0,0 +1,54 @@ +#include + +#include "node/traverser.h" +#include "node/value.h" +#include "render/job/pluginjob.h" +#include "render/texture.h" +#include "render/videoparams.h" + +namespace { + +class PluginJobTraverser : public olive::NodeTraverser { +public: + void Resolve(olive::NodeValue &value) + { + ResolveJobs(value); + } + + bool called() const + { + return called_; + } + +protected: + olive::TexturePtr ProcessPluginJob(olive::TexturePtr /*texture*/, + olive::TexturePtr destination, + const olive::Node * /*node*/) override + { + called_ = true; + return destination; + } + +private: + bool called_ = false; +}; + +} // namespace + +TEST(PluginRenderPipeline, PluginJobIsResolved) +{ + olive::VideoParams params(320, 240, olive::core::PixelFormat::U8, 4); + + olive::plugin::PluginJob job(nullptr, nullptr, olive::NodeValueRow()); + olive::TexturePtr job_tex = olive::Texture::Job(params, job); + + olive::NodeValue val(olive::NodeValue::kTexture, job_tex); + + PluginJobTraverser traverser; + traverser.SetCacheVideoParams(params); + traverser.Resolve(val); + + EXPECT_TRUE(traverser.called()); + ASSERT_TRUE(val.toTexture()); + EXPECT_NE(val.toTexture().get(), job_tex.get()); +} diff --git a/tests/gtest/plugin_renderer_readback_test.cpp b/tests/gtest/plugin_renderer_readback_test.cpp new file mode 100644 index 000000000..054811942 --- /dev/null +++ b/tests/gtest/plugin_renderer_readback_test.cpp @@ -0,0 +1,19 @@ +#include + +#include "render/plugin/pluginrenderer.h" + +TEST(PluginRendererReadback, BytesToPixels) +{ + olive::VideoParams params(16, 16, olive::core::PixelFormat::U8, 4, + olive::core::rational(1, 1), + olive::VideoParams::kInterlaceNone, 1); + + const int bytes_per_pixel = + olive::VideoParams::GetBytesPerPixel(params.format(), + params.channel_count()); + ASSERT_EQ(bytes_per_pixel, 4); + + EXPECT_EQ(olive::plugin::detail::BytesToPixels(64, params), 16); + EXPECT_EQ(olive::plugin::detail::BytesToPixels(0, params), 0); + EXPECT_EQ(olive::plugin::detail::BytesToPixels(-1, params), 0); +} diff --git a/tests/gtest/plugin_support_clip_test.cpp b/tests/gtest/plugin_support_clip_test.cpp new file mode 100644 index 000000000..75e218d66 --- /dev/null +++ b/tests/gtest/plugin_support_clip_test.cpp @@ -0,0 +1,96 @@ +#include + +#include "ofxImageEffect.h" +#include "ofxhClip.h" +#include "pluginSupport/OliveClip.h" + +namespace { +olive::VideoParams MakeParams(int width, int height, + olive::core::PixelFormat format, + int channels, + bool premultiplied) +{ + olive::VideoParams params; + params.set_width(width); + params.set_height(height); + params.set_format(format); + params.set_channel_count(channels); + params.set_premultiplied_alpha(premultiplied); + return params; +} +} + +TEST(PluginSupportClip, PropertyGetters) +{ + OFX::Host::ImageEffect::ClipDescriptor desc(kOfxImageEffectOutputClipName); + olive::VideoParams params = + MakeParams(1920, 1080, olive::core::PixelFormat::U16, 3, false); + params.set_pixel_aspect_ratio(olive::core::rational(2, 1)); + params.set_frame_rate(olive::core::rational(30, 1)); + params.set_start_time(2); + params.set_duration(4); + params.set_interlacing(olive::VideoParams::kInterlacedTopFirst); + + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + EXPECT_EQ(clip.getUnmappedBitDepth(), kOfxBitDepthShort); + EXPECT_EQ(clip.getUnmappedComponents(), kOfxImageComponentRGB); + EXPECT_EQ(clip.getPremult(), kOfxImageUnPreMultiplied); + EXPECT_DOUBLE_EQ(clip.getAspectRatio(), 2.0); + EXPECT_DOUBLE_EQ(clip.getFrameRate(), 30.0); + + double start_frame = 0.0; + double end_frame = 0.0; + clip.getFrameRange(start_frame, end_frame); + EXPECT_DOUBLE_EQ(start_frame, 60.0); + EXPECT_DOUBLE_EQ(end_frame, 180.0); + + EXPECT_EQ(clip.getFieldOrder(), kOfxImageFieldUpper); + EXPECT_DOUBLE_EQ(clip.getUnmappedFrameRate(), 30.0); + + clip.getUnmappedFrameRange(start_frame, end_frame); + EXPECT_DOUBLE_EQ(start_frame, 60.0); + EXPECT_DOUBLE_EQ(end_frame, 180.0); + + EXPECT_FALSE(clip.getContinuousSamples()); + EXPECT_FALSE(clip.getConnected()); +} + +TEST(PluginSupportClip, GetImageClampsBoundsAndCachesOutput) +{ + OFX::Host::ImageEffect::ClipDescriptor desc(kOfxImageEffectOutputClipName); + olive::VideoParams params = + MakeParams(100, 80, olive::core::PixelFormat::U8, 4, true); + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + OfxRectD optional_bounds = { -10.0, -10.0, 200.0, 200.0 }; + OFX::Host::ImageEffect::Image *image = + clip.getImage(0.0, &optional_bounds); + ASSERT_NE(image, nullptr); + + auto *olive_image = static_cast(image); + EXPECT_EQ(olive_image->width(), 100); + EXPECT_EQ(olive_image->height(), 80); + + OFX::Host::ImageEffect::Image *image_again = + clip.getImage(0.0, nullptr); + EXPECT_EQ(image, image_again); +} + +TEST(PluginSupportClip, GetImageReturnsNewImageForNonOutput) +{ + OFX::Host::ImageEffect::ClipDescriptor desc("Source"); + olive::VideoParams params = + MakeParams(64, 64, olive::core::PixelFormat::U8, 4, false); + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + OFX::Host::ImageEffect::Image *first = clip.getImage(0.0, nullptr); + OFX::Host::ImageEffect::Image *second = clip.getImage(0.0, nullptr); + + EXPECT_NE(first, nullptr); + EXPECT_NE(second, nullptr); + EXPECT_NE(first, second); + + first->releaseReference(); + second->releaseReference(); +} diff --git a/tests/gtest/plugin_support_image_test.cpp b/tests/gtest/plugin_support_image_test.cpp new file mode 100644 index 000000000..3e13dac06 --- /dev/null +++ b/tests/gtest/plugin_support_image_test.cpp @@ -0,0 +1,147 @@ +#include + +#include "ofxImageEffect.h" +#include "ofxhClip.h" +#include "pluginSupport/OliveClip.h" +#include "pluginSupport/image.h" + +namespace { +olive::VideoParams MakeParams(int width, int height, + olive::core::PixelFormat format, + int channels, + bool premultiplied) +{ + olive::VideoParams params; + params.set_width(width); + params.set_height(height); + params.set_format(format); + params.set_channel_count(channels); + params.set_premultiplied_alpha(premultiplied); + return params; +} +} + +TEST(PluginSupportImage, AllocateFromParamsSetsProperties) +{ + OFX::Host::ImageEffect::ClipDescriptor desc(kOfxImageEffectOutputClipName); + olive::VideoParams params = + MakeParams(640, 480, olive::core::PixelFormat::U8, 4, true); + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + olive::plugin::Image image(clip); + OfxRectI bounds = { 0, 0, 640, 480 }; + OfxRectI rod = bounds; + image.AllocateFromParams(params, bounds, rod, true); + + EXPECT_NE(image.data(), nullptr); + EXPECT_EQ(image.width(), 640); + EXPECT_EQ(image.height(), 480); + EXPECT_EQ(image.row_bytes(), 640 * 4); + EXPECT_EQ(image.pixel_format(), olive::core::PixelFormat::U8); + EXPECT_EQ(image.channel_count(), 4); + EXPECT_TRUE(image.premultiplied_alpha()); +} + +TEST(PluginSupportImage, EnsureAllocatedFromParamsClearsAndResizes) +{ + OFX::Host::ImageEffect::ClipDescriptor desc(kOfxImageEffectOutputClipName); + olive::VideoParams params = + MakeParams(64, 32, olive::core::PixelFormat::U8, 3, false); + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + olive::plugin::Image image(clip); + OfxRectI bounds = { 0, 0, 64, 32 }; + OfxRectI rod = bounds; + image.AllocateFromParams(params, bounds, rod, true); + ASSERT_NE(image.data(), nullptr); + image.data()[0] = 0xAB; + + image.EnsureAllocatedFromParams(params, bounds, rod, true); + EXPECT_EQ(image.data()[0], 0); + + OfxRectI new_bounds = { 0, 0, 16, 16 }; + image.EnsureAllocatedFromParams(params, new_bounds, rod, false); + EXPECT_EQ(image.width(), 16); + EXPECT_EQ(image.height(), 16); +} + +TEST(PluginSupportImage, PropertyFallbacks) +{ + OFX::Host::ImageEffect::ClipDescriptor desc(kOfxImageEffectOutputClipName); + olive::VideoParams params = + MakeParams(1, 1, olive::core::PixelFormat::INVALID, 0, false); + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + olive::plugin::Image image(clip); + image.setStringProperty(kOfxImageEffectPropPixelDepth, kOfxBitDepthHalf); + image.setStringProperty(kOfxImageEffectPropComponents, + kOfxImageComponentRGB); + image.setStringProperty(kOfxImageEffectPropPreMultiplication, + kOfxImagePreMultiplied); + image.setIntProperty(kOfxImagePropBounds, 10, 0); + image.setIntProperty(kOfxImagePropBounds, 20, 1); + image.setIntProperty(kOfxImagePropBounds, 42, 2); + image.setIntProperty(kOfxImagePropBounds, 70, 3); + + EXPECT_EQ(image.pixel_format(), olive::core::PixelFormat::F16); + EXPECT_EQ(image.channel_count(), 3); + EXPECT_TRUE(image.premultiplied_alpha()); + EXPECT_EQ(image.width(), 32); + EXPECT_EQ(image.height(), 50); +} + +TEST(PluginSupportImage, AllocateSetsOfxProperties) +{ + OFX::Host::ImageEffect::ClipDescriptor desc(kOfxImageEffectOutputClipName); + olive::VideoParams params = + MakeParams(8, 6, olive::core::PixelFormat::F16, 4, false); + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + olive::plugin::Image image(clip); + OfxRectI bounds = { 2, 3, 10, 9 }; + OfxRectI rod = { 0, 0, 12, 12 }; + image.Allocate(8, 6, olive::core::PixelFormat::F16, 4, false, bounds, rod, + true); + + EXPECT_NE(image.data(), nullptr); + EXPECT_EQ(image.row_bytes(), 8 * 4 * 2); + + int bounds_props[4] = {0}; + image.getIntPropertyN(kOfxImagePropBounds, bounds_props, 4); + EXPECT_EQ(bounds_props[0], bounds.x1); + EXPECT_EQ(bounds_props[1], bounds.y1); + EXPECT_EQ(bounds_props[2], bounds.x2); + EXPECT_EQ(bounds_props[3], bounds.y2); + + int rod_props[4] = {0}; + image.getIntPropertyN(kOfxImagePropRegionOfDefinition, rod_props, 4); + EXPECT_EQ(rod_props[0], rod.x1); + EXPECT_EQ(rod_props[1], rod.y1); + EXPECT_EQ(rod_props[2], rod.x2); + EXPECT_EQ(rod_props[3], rod.y2); + + EXPECT_EQ(image.getStringProperty(kOfxImageEffectPropComponents), + std::string(kOfxImageComponentRGBA)); + EXPECT_EQ(image.getStringProperty(kOfxImageEffectPropPixelDepth), + std::string(kOfxBitDepthHalf)); + EXPECT_EQ(image.getStringProperty(kOfxImageEffectPropPreMultiplication), + std::string(kOfxImageUnPreMultiplied)); +} + +TEST(PluginSupportImage, EnsureAllocatedPreservesWithoutClear) +{ + OFX::Host::ImageEffect::ClipDescriptor desc(kOfxImageEffectOutputClipName); + olive::VideoParams params = + MakeParams(4, 4, olive::core::PixelFormat::U8, 3, false); + olive::plugin::OliveClipInstance clip(nullptr, desc, params); + + olive::plugin::Image image(clip); + OfxRectI bounds = { 0, 0, 4, 4 }; + OfxRectI rod = bounds; + image.AllocateFromParams(params, bounds, rod, true); + ASSERT_NE(image.data(), nullptr); + image.data()[0] = 0x5A; + + image.EnsureAllocatedFromParams(params, bounds, rod, false); + EXPECT_EQ(image.data()[0], 0x5A); +} diff --git a/tests/gtest/plugin_support_param_test.cpp b/tests/gtest/plugin_support_param_test.cpp new file mode 100644 index 000000000..d784a1462 --- /dev/null +++ b/tests/gtest/plugin_support_param_test.cpp @@ -0,0 +1,24 @@ +#include + +#include "ofxParam.h" +#include "ofxhParam.h" +#include "pluginSupport/paraminstance.h" + +TEST(PluginSupportParam, IntegerInstanceNullNodeRoundTrip) +{ + OFX::Host::Param::Descriptor descriptor(kOfxParamTypeInteger, + "TestInteger"); + olive::plugin::IntegerInstance instance(nullptr, descriptor); + + int value = -1; + EXPECT_EQ(instance.get(value), kOfxStatOK); + EXPECT_EQ(value, 0); + + EXPECT_EQ(instance.set(7), kOfxStatOK); + EXPECT_EQ(instance.get(value), kOfxStatOK); + EXPECT_EQ(value, 7); + + int time_value = -1; + EXPECT_EQ(instance.get(1.0, time_value), kOfxStatOK); + EXPECT_EQ(time_value, 7); +} diff --git a/tests/gtest/plugin_support_test.cpp b/tests/gtest/plugin_support_test.cpp new file mode 100644 index 000000000..5acad6e79 --- /dev/null +++ b/tests/gtest/plugin_support_test.cpp @@ -0,0 +1,10 @@ +#include + +#include "pluginSupport/OliveHost.h" + +TEST(PluginSupport, LoadPluginsEmptyPath) +{ + EXPECT_NO_THROW({ + olive::plugin::loadPlugins(QString()); + }); +} diff --git a/tests/gtest/project_serializer_test.cpp b/tests/gtest/project_serializer_test.cpp new file mode 100644 index 000000000..b08203f0a --- /dev/null +++ b/tests/gtest/project_serializer_test.cpp @@ -0,0 +1,58 @@ +#include + +#include +#include +#include + +#include "node/factory.h" +#include "node/project.h" +#include "node/input/time/timeinput.h" +#include "node/project/serializer/serializer.h" +#include "node/color/colormanager/colormanager.h" +#include "render/diskmanager.h" + +TEST(ProjectSerializer, SaveLoadProjectRoundTrip) +{ + const bool created_disk_manager = (olive::DiskManager::instance() == nullptr); + if (created_disk_manager) { + olive::DiskManager::CreateInstance(); + } + + olive::ColorManager::SetUpDefaultConfig(); + olive::NodeFactory::Initialize(); + olive::ProjectSerializer::Initialize(); + + olive::Project project; + project.Initialize(); + + auto *node = new olive::TimeInput(); + node->SetLabel(QStringLiteral("TimeInput")); + node->setParent(&project); + + olive::ProjectSerializer::SaveData save_data( + olive::ProjectSerializer::kProject, &project, QString()); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + olive::ProjectSerializer::Result save_result = + olive::ProjectSerializer::Save(&writer, save_data); + EXPECT_EQ(save_result.code(), olive::ProjectSerializer::kSuccess); + buffer.close(); + + olive::Project loaded_project; + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + olive::ProjectSerializer::Result result = + olive::ProjectSerializer::Load(&loaded_project, &reader, + olive::ProjectSerializer::kProject); + EXPECT_EQ(result.code(), olive::ProjectSerializer::kSuccess); + EXPECT_FALSE(loaded_project.nodes().isEmpty()); + + olive::ProjectSerializer::Destroy(); + if (created_disk_manager) { + olive::DiskManager::DestroyInstance(); + } +} diff --git a/tests/gtest/render_audioparams_branch_test.cpp b/tests/gtest/render_audioparams_branch_test.cpp new file mode 100644 index 000000000..60ba7595f --- /dev/null +++ b/tests/gtest/render_audioparams_branch_test.cpp @@ -0,0 +1,42 @@ +#include + +#include "olive/core/render/audioparams.h" + +TEST(RenderAudioParams, ValidityAndEquality) +{ + olive::core::AudioParams invalid; + EXPECT_FALSE(invalid.is_valid()); + + olive::core::AudioParams params( + 48000, AV_CH_LAYOUT_STEREO, olive::core::SampleFormat::S16); + EXPECT_TRUE(params.is_valid()); + + olive::core::AudioParams other( + 48000, AV_CH_LAYOUT_STEREO, olive::core::SampleFormat::S16); + EXPECT_TRUE(params == other); + + other.set_sample_rate(44100); + EXPECT_TRUE(params != other); +} + +TEST(RenderAudioParams, TimeAndSampleConversions) +{ + olive::core::AudioParams params( + 48000, AV_CH_LAYOUT_STEREO, olive::core::SampleFormat::S16); + + EXPECT_EQ(params.channel_count(), 2); + EXPECT_EQ(params.bytes_per_sample_per_channel(), 2); + EXPECT_EQ(params.bits_per_sample(), 16); + + EXPECT_EQ(params.time_to_samples(1.0), 48000); + EXPECT_EQ(params.time_to_bytes_per_channel(1.0), 96000); + EXPECT_EQ(params.time_to_bytes(1.0), 192000); + + EXPECT_EQ(params.samples_to_bytes(48000), 192000); + EXPECT_EQ(params.samples_to_bytes_per_channel(48000), 96000); + + EXPECT_EQ(params.bytes_to_samples(192000), 48000); + EXPECT_EQ(params.bytes_to_time(192000), olive::core::rational(1, 1)); + EXPECT_EQ(params.bytes_per_channel_to_time(96000), + olive::core::rational(1, 1)); +} diff --git a/tests/gtest/render_audioparams_test.cpp b/tests/gtest/render_audioparams_test.cpp new file mode 100644 index 000000000..48da336fc --- /dev/null +++ b/tests/gtest/render_audioparams_test.cpp @@ -0,0 +1,38 @@ +#include + +#include +#include +#include + +#include "node/project/serializer/typeserializer.h" +#include "olive/core/render/audioparams.h" + +TEST(RenderAudioParams, SaveLoadRoundTrip) +{ + olive::AudioParams params; + params.set_sample_rate(48000); + params.set_enabled(true); + params.set_time_base(olive::core::rational(1, 48000)); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("audioparams")); + olive::TypeSerializer::SaveAudioParams(&writer, params); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + EXPECT_TRUE(reader.readNextStartElement()); + EXPECT_EQ(reader.name().toString(), QStringLiteral("audioparams")); + olive::AudioParams loaded = olive::TypeSerializer::LoadAudioParams(&reader); + + EXPECT_EQ(loaded.sample_rate(), 48000); + EXPECT_TRUE(loaded.enabled()); + EXPECT_EQ(loaded.time_base(), olive::core::rational(1, 48000)); +} diff --git a/tests/gtest/render_pixelformat_test.cpp b/tests/gtest/render_pixelformat_test.cpp new file mode 100644 index 000000000..d0cccbb02 --- /dev/null +++ b/tests/gtest/render_pixelformat_test.cpp @@ -0,0 +1,28 @@ +#include + +#include "olive/core/render/pixelformat.h" + +TEST(RenderPixelFormat, ByteCountAndString) +{ + using olive::core::PixelFormat; + + EXPECT_EQ(PixelFormat::byte_count(PixelFormat::INVALID), 0); + EXPECT_EQ(PixelFormat::byte_count(PixelFormat::U8), 1); + EXPECT_EQ(PixelFormat::byte_count(PixelFormat::U16), 2); + EXPECT_EQ(PixelFormat::byte_count(PixelFormat::F16), 2); + EXPECT_EQ(PixelFormat::byte_count(PixelFormat::F32), 4); + + EXPECT_EQ(PixelFormat(PixelFormat::U8).to_string(), std::string("u8")); + EXPECT_EQ(PixelFormat(PixelFormat::INVALID).to_string(), std::string("")); +} + +TEST(RenderPixelFormat, FloatChecks) +{ + using olive::core::PixelFormat; + + EXPECT_FALSE(PixelFormat::is_float(PixelFormat::U8)); + EXPECT_FALSE(PixelFormat::is_float(PixelFormat::U16)); + EXPECT_TRUE(PixelFormat::is_float(PixelFormat::F16)); + EXPECT_TRUE(PixelFormat::is_float(PixelFormat::F32)); + EXPECT_FALSE(PixelFormat::is_float(PixelFormat::INVALID)); +} diff --git a/tests/gtest/render_sampleformat_test.cpp b/tests/gtest/render_sampleformat_test.cpp new file mode 100644 index 000000000..811332061 --- /dev/null +++ b/tests/gtest/render_sampleformat_test.cpp @@ -0,0 +1,29 @@ +#include + +#include "olive/core/render/sampleformat.h" + +TEST(RenderSampleFormat, ByteCountAndStringRoundTrip) +{ + using olive::core::SampleFormat; + + EXPECT_EQ(SampleFormat::byte_count(SampleFormat::INVALID), 0); + EXPECT_EQ(SampleFormat::byte_count(SampleFormat::U8), 1); + EXPECT_EQ(SampleFormat::byte_count(SampleFormat::S16), 2); + EXPECT_EQ(SampleFormat::byte_count(SampleFormat::F32), 4); + EXPECT_EQ(SampleFormat::byte_count(SampleFormat::F64), 8); + + EXPECT_EQ(SampleFormat::to_string(SampleFormat::S16), "s16"); + EXPECT_EQ(SampleFormat::from_string("s16"), SampleFormat::S16); + EXPECT_EQ(SampleFormat::from_string(""), SampleFormat::INVALID); + EXPECT_EQ(SampleFormat::from_string("unknown"), SampleFormat::INVALID); +} + +TEST(RenderSampleFormat, PackedAndPlanarChecks) +{ + using olive::core::SampleFormat; + + EXPECT_TRUE(SampleFormat::is_packed(SampleFormat::S16)); + EXPECT_FALSE(SampleFormat::is_packed(SampleFormat::S16P)); + EXPECT_TRUE(SampleFormat::is_planar(SampleFormat::S16P)); + EXPECT_FALSE(SampleFormat::is_planar(SampleFormat::S16)); +} diff --git a/tests/gtest/render_videoparams_branch_test.cpp b/tests/gtest/render_videoparams_branch_test.cpp new file mode 100644 index 000000000..563f44f3f --- /dev/null +++ b/tests/gtest/render_videoparams_branch_test.cpp @@ -0,0 +1,165 @@ +#include + +extern "C" { +#include +} + +#include +#include +#include + +#include "render/videoparams.h" + +TEST(RenderVideoParams, BytesPerChannelAndPixel) +{ + EXPECT_EQ(olive::VideoParams::GetBytesPerChannel( + olive::core::PixelFormat::INVALID), + 0); + EXPECT_EQ(olive::VideoParams::GetBytesPerChannel( + olive::core::PixelFormat::U8), + 1); + EXPECT_EQ(olive::VideoParams::GetBytesPerChannel( + olive::core::PixelFormat::U16), + 2); + EXPECT_EQ(olive::VideoParams::GetBytesPerChannel( + olive::core::PixelFormat::F16), + 2); + EXPECT_EQ(olive::VideoParams::GetBytesPerChannel( + olive::core::PixelFormat::F32), + 4); + EXPECT_EQ(olive::VideoParams::GetBytesPerPixel( + olive::core::PixelFormat::U8, 4), + 4); +} + +TEST(RenderVideoParams, DividerAndFormatNames) +{ + EXPECT_EQ(olive::VideoParams::GetNameForDivider(1), + QStringLiteral("Full")); + EXPECT_EQ(olive::VideoParams::GetNameForDivider(3), + QStringLiteral("1/3")); + + const QString unknown = + olive::VideoParams::GetFormatName(olive::core::PixelFormat::INVALID); + EXPECT_TRUE(unknown.contains(QStringLiteral("Unknown"))); +} + +TEST(RenderVideoParams, ScalingAndDividerForTarget) +{ + EXPECT_EQ(olive::VideoParams::GetScaledDimension(100, 3), 33); + EXPECT_EQ(olive::VideoParams::GetDividerForTargetResolution( + 1920, 1080, 960, 540), + 2); + EXPECT_EQ(olive::VideoParams::GetDividerForTargetResolution( + 1920, 1080, 480, 270), + 4); +} + +TEST(RenderVideoParams, FrameRateStringsAndPixelAspect) +{ + const QString fps = + olive::VideoParams::FrameRateToString(olive::core::rational(24, 1)); + EXPECT_TRUE(fps.contains(QStringLiteral("24"))); + EXPECT_TRUE(fps.contains(QStringLiteral("FPS"))); + + const QStringList names = + olive::VideoParams::GetStandardPixelAspectRatioNames(); + ASSERT_EQ(names.size(), 6); + EXPECT_TRUE(names.at(0).contains(QStringLiteral("1.0000"))); +} + +TEST(RenderVideoParams, AutoDividerAndPixelAspect) +{ + EXPECT_EQ(olive::VideoParams::generate_auto_divider(640, 480), 1); + EXPECT_EQ(olive::VideoParams::generate_auto_divider(7680, 4320), 6); + EXPECT_EQ(olive::VideoParams::generate_auto_divider(50000, 50000), 16); + + olive::VideoParams params(100, 50, olive::core::PixelFormat::U8, 4); + params.set_pixel_aspect_ratio(olive::core::rational(0, 1)); + EXPECT_EQ(params.pixel_aspect_ratio(), olive::core::rational(1, 1)); + EXPECT_EQ(params.square_pixel_width(), 100); + + params.set_pixel_aspect_ratio(olive::core::rational(2, 1)); + EXPECT_EQ(params.square_pixel_width(), 200); +} + +TEST(RenderVideoParams, ValidityAndTimebase) +{ + olive::VideoParams params; + EXPECT_FALSE(params.is_valid()); + EXPECT_EQ(params.get_time_in_timebase_units(olive::core::rational(1, 1)), + AV_NOPTS_VALUE); + + params.set_width(1920); + params.set_height(1080); + params.set_format(olive::core::PixelFormat::U8); + params.set_channel_count(4); + params.set_pixel_aspect_ratio(olive::core::rational(1, 1)); + params.set_time_base(olive::core::rational(1, 1)); + params.set_start_time(10); + EXPECT_TRUE(params.is_valid()); + EXPECT_EQ(params.get_time_in_timebase_units(olive::core::rational(2, 1)), + 12); +} + +TEST(RenderVideoParams, SaveLoadRoundTripExtended) +{ + olive::VideoParams params(1920, 1080, olive::core::rational(1, 24), + olive::core::PixelFormat::U16, 4); + params.set_depth(2); + params.set_pixel_aspect_ratio(olive::core::rational(4, 3)); + params.set_interlacing(olive::VideoParams::kInterlacedTopFirst); + params.set_divider(2); + params.set_enabled(false); + params.set_x(1.5f); + params.set_y(-2.25f); + params.set_stream_index(7); + params.set_video_type(olive::VideoParams::kVideoTypeImageSequence); + params.set_frame_rate(olive::core::rational(30000, 1001)); + params.set_start_time(123); + params.set_duration(456); + params.set_premultiplied_alpha(true); + params.set_colorspace(QStringLiteral("Rec.709")); + params.set_color_range(olive::VideoParams::kColorRangeFull); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("videoparams")); + params.Save(&writer); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + olive::VideoParams loaded; + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + ASSERT_TRUE(reader.readNextStartElement()); + EXPECT_EQ(reader.name().toString(), QStringLiteral("videoparams")); + loaded.Load(&reader); + + EXPECT_EQ(loaded.width(), 1920); + EXPECT_EQ(loaded.height(), 1080); + EXPECT_EQ(loaded.depth(), 2); + EXPECT_EQ(loaded.time_base(), olive::core::rational(1, 24)); + EXPECT_EQ(loaded.format(), olive::core::PixelFormat::U16); + EXPECT_EQ(loaded.channel_count(), 4); + EXPECT_EQ(loaded.pixel_aspect_ratio(), olive::core::rational(4, 3)); + EXPECT_EQ(loaded.interlacing(), olive::VideoParams::kInterlacedTopFirst); + EXPECT_EQ(loaded.divider(), 2); + EXPECT_EQ(loaded.enabled(), false); + EXPECT_FLOAT_EQ(loaded.x(), 1.5f); + EXPECT_FLOAT_EQ(loaded.y(), -2.25f); + EXPECT_EQ(loaded.stream_index(), 7); + EXPECT_EQ(loaded.video_type(), + olive::VideoParams::kVideoTypeImageSequence); + EXPECT_EQ(loaded.frame_rate(), olive::core::rational(30000, 1001)); + EXPECT_EQ(loaded.start_time(), 123); + EXPECT_EQ(loaded.duration(), 456); + EXPECT_TRUE(loaded.premultiplied_alpha()); + EXPECT_EQ(loaded.colorspace(), QStringLiteral("Rec.709")); + EXPECT_EQ(loaded.color_range(), olive::VideoParams::kColorRangeFull); +} diff --git a/tests/gtest/render_videoparams_test.cpp b/tests/gtest/render_videoparams_test.cpp new file mode 100644 index 000000000..de4ab6503 --- /dev/null +++ b/tests/gtest/render_videoparams_test.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include +#include + +#include "render/videoparams.h" + +TEST(RenderVideoParams, SaveLoadRoundTrip) +{ + olive::VideoParams params; + params.set_width(1280); + params.set_height(720); + params.set_frame_rate(olive::core::rational(24, 1)); + params.set_pixel_aspect_ratio(olive::core::rational(1, 1)); + params.set_colorspace(QStringLiteral("test")); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("videoparams")); + params.Save(&writer); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + olive::VideoParams loaded; + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + EXPECT_TRUE(reader.readNextStartElement()); + EXPECT_EQ(reader.name().toString(), QStringLiteral("videoparams")); + loaded.Load(&reader); + + EXPECT_EQ(loaded.width(), 1280); + EXPECT_EQ(loaded.height(), 720); + EXPECT_EQ(loaded.frame_rate(), olive::core::rational(24, 1)); + EXPECT_EQ(loaded.pixel_aspect_ratio(), olive::core::rational(1, 1)); + EXPECT_EQ(loaded.colorspace(), QStringLiteral("test")); +} diff --git a/tests/gtest/shader_resources_test.cpp b/tests/gtest/shader_resources_test.cpp new file mode 100644 index 000000000..8997a0d75 --- /dev/null +++ b/tests/gtest/shader_resources_test.cpp @@ -0,0 +1,26 @@ +#include + +#include + +TEST(Shaders, ResourcesAvailable) +{ + const QStringList shader_paths = { + QStringLiteral(":/shaders/default.frag"), + QStringLiteral(":/shaders/default.vert"), + QStringLiteral(":/shaders/yuv2rgb.frag"), + QStringLiteral(":/shaders/deinterlace2.frag"), + QStringLiteral(":/shaders/rgbhistogram.frag"), + QStringLiteral(":/shaders/rgbhistogram.vert") + }; + + for (const QString &path : shader_paths) { + QFile file(path); + ASSERT_TRUE(file.exists()) << "Missing shader resource: " + << path.toStdString(); + ASSERT_TRUE(file.open(QIODevice::ReadOnly)) + << "Failed to open shader resource: " << path.toStdString(); + const QByteArray contents = file.readAll(); + EXPECT_FALSE(contents.isEmpty()) + << "Shader resource is empty: " << path.toStdString(); + } +} diff --git a/tests/gtest/task_taskmanager_test.cpp b/tests/gtest/task_taskmanager_test.cpp new file mode 100644 index 000000000..452059075 --- /dev/null +++ b/tests/gtest/task_taskmanager_test.cpp @@ -0,0 +1,52 @@ +#include + +#include +#include + +#include "task/taskmanager.h" + +namespace { +class DummyTask final : public olive::Task { +public: + explicit DummyTask(bool *ran) + : ran_(ran) + { + SetTitle(QStringLiteral("DummyTask")); + } + +protected: + bool Run() override + { + if (ran_) { + *ran_ = true; + } + return true; + } + +private: + bool *ran_ = nullptr; +}; +} + +TEST(TaskManager, AddAndRunTask) +{ + olive::TaskManager::CreateInstance(); + olive::TaskManager *mgr = olive::TaskManager::instance(); + ASSERT_NE(mgr, nullptr); + + bool ran = false; + DummyTask *task = new DummyTask(&ran); + + QEventLoop loop; + QObject::connect(task, &olive::Task::Finished, &loop, [&loop](olive::Task *, bool) { + loop.quit(); + }); + + mgr->AddTask(task); + + QTimer::singleShot(5000, &loop, &QEventLoop::quit); + loop.exec(); + + EXPECT_TRUE(ran); + olive::TaskManager::DestroyInstance(); +} diff --git a/tests/gtest/timebased_widget_test.cpp b/tests/gtest/timebased_widget_test.cpp new file mode 100644 index 000000000..d134528a5 --- /dev/null +++ b/tests/gtest/timebased_widget_test.cpp @@ -0,0 +1,21 @@ +#include + +#include "widget/timebased/timebasedwidget.h" +#include "node/output/viewer/viewer.h" + +TEST(TimeBasedWidget, ConnectViewerNodeNullSafe) +{ + olive::TimeBasedWidget widget(false, false); + widget.ConnectViewerNode(nullptr); + EXPECT_EQ(widget.GetConnectedNode(), nullptr); +} + +TEST(TimeBasedWidget, ConnectedNodeClearsOnDelete) +{ + olive::TimeBasedWidget widget(false, false); + auto *viewer = new olive::ViewerOutput(); + widget.ConnectViewerNode(viewer); + EXPECT_EQ(widget.GetConnectedNode(), viewer); + delete viewer; + EXPECT_EQ(widget.GetConnectedNode(), nullptr); +} diff --git a/tests/gtest/timeline_coordinate_test.cpp b/tests/gtest/timeline_coordinate_test.cpp new file mode 100644 index 000000000..527862e46 --- /dev/null +++ b/tests/gtest/timeline_coordinate_test.cpp @@ -0,0 +1,34 @@ +#include + +#include "timeline/timelinecoordinate.h" + +TEST(TimelineCoordinate, DefaultAndSetters) +{ + olive::TimelineCoordinate coord; + EXPECT_EQ(coord.GetTrack().type(), olive::Track::kNone); + EXPECT_EQ(coord.GetTrack().index(), 0); + + const olive::core::rational frame(10, 1); + olive::Track::Reference ref(olive::Track::kVideo, 2); + + coord.SetFrame(frame); + coord.SetTrack(ref); + + EXPECT_EQ(coord.GetFrame(), frame); + EXPECT_EQ(coord.GetTrack(), ref); +} + +TEST(TimelineCoordinate, Constructors) +{ + const olive::core::rational frame(5, 1); + olive::Track::Reference ref(olive::Track::kAudio, 1); + + olive::TimelineCoordinate with_ref(frame, ref); + EXPECT_EQ(with_ref.GetFrame(), frame); + EXPECT_EQ(with_ref.GetTrack(), ref); + + olive::TimelineCoordinate with_type(frame, olive::Track::kSubtitle, 3); + EXPECT_EQ(with_type.GetFrame(), frame); + EXPECT_EQ(with_type.GetTrack().type(), olive::Track::kSubtitle); + EXPECT_EQ(with_type.GetTrack().index(), 3); +} diff --git a/tests/gtest/timeline_marker_test.cpp b/tests/gtest/timeline_marker_test.cpp new file mode 100644 index 000000000..6d576c841 --- /dev/null +++ b/tests/gtest/timeline_marker_test.cpp @@ -0,0 +1,160 @@ +#include + +#include +#include +#include + +#include "timeline/timelinemarker.h" + +TEST(TimelineMarker, SaveLoadRoundTrip) +{ + olive::TimelineMarker marker; + marker.set_time(olive::core::rational(10, 1)); + marker.set_name(QStringLiteral("Marker")); + marker.set_color(5); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("marker")); + marker.save(&writer); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + olive::TimelineMarker loaded; + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + EXPECT_TRUE(reader.readNextStartElement()); + EXPECT_EQ(reader.name().toString(), QStringLiteral("marker")); + loaded.load(&reader); + + EXPECT_EQ(loaded.time().in(), olive::core::rational(10, 1)); + EXPECT_EQ(loaded.name(), QStringLiteral("Marker")); + EXPECT_EQ(loaded.color(), 5); +} + +TEST(TimelineMarkerList, OrderAndLookup) +{ + olive::TimelineMarkerList list; + olive::TimelineMarker marker_a( + 1, + olive::core::TimeRange(olive::core::rational(10, 1), + olive::core::rational(10, 1)), + QStringLiteral("A"), + &list); + olive::TimelineMarker marker_b( + 2, + olive::core::TimeRange(olive::core::rational(5, 1), + olive::core::rational(5, 1)), + QStringLiteral("B"), + &list); + olive::TimelineMarker marker_c( + 3, + olive::core::TimeRange(olive::core::rational(20, 1), + olive::core::rational(20, 1)), + QStringLiteral("C"), + &list); + + ASSERT_EQ(list.size(), 3); + auto it = list.cbegin(); + EXPECT_EQ((*it)->time().in(), olive::core::rational(5, 1)); + ++it; + EXPECT_EQ((*it)->time().in(), olive::core::rational(10, 1)); + ++it; + EXPECT_EQ((*it)->time().in(), olive::core::rational(20, 1)); + + EXPECT_EQ(list.GetMarkerAtTime(olive::core::rational(10, 1)), &marker_a); + EXPECT_EQ(list.GetClosestMarkerToTime(olive::core::rational(7, 1)), + &marker_b); + EXPECT_EQ(list.GetClosestMarkerToTime(olive::core::rational(9, 1)), + &marker_a); +} + +TEST(TimelineMarkerList, SaveLoadWithUnknownElements) +{ + olive::TimelineMarkerList list; + olive::TimelineMarker marker( + 4, + olive::core::TimeRange(olive::core::rational(12, 1), + olive::core::rational(15, 1)), + QStringLiteral("Span"), + &list); + + QByteArray xml; + QBuffer buffer(&xml); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("markers")); + writer.writeStartElement(QStringLiteral("unknown")); + writer.writeEndElement(); + list.save(&writer); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + olive::TimelineMarkerList loaded; + QBuffer read_buffer(&xml); + read_buffer.open(QIODevice::ReadOnly); + QXmlStreamReader reader(&read_buffer); + EXPECT_TRUE(reader.readNextStartElement()); + EXPECT_EQ(reader.name().toString(), QStringLiteral("markers")); + EXPECT_TRUE(loaded.load(&reader)); + EXPECT_EQ(loaded.size(), 1); + EXPECT_EQ(loaded.front()->name(), QStringLiteral("Span")); + EXPECT_EQ(loaded.front()->time().in(), olive::core::rational(12, 1)); +} + +TEST(TimelineMarkerCommands, AddRemoveAndChange) +{ + olive::TimelineMarkerList list; + olive::MarkerAddCommand add( + &list, + olive::core::TimeRange(olive::core::rational(1, 1), + olive::core::rational(2, 1)), + QStringLiteral("One"), + 1); + add.redo_now(); + ASSERT_EQ(list.size(), 1); + auto *marker = list.front(); + EXPECT_EQ(marker->name(), QStringLiteral("One")); + + olive::MarkerChangeNameCommand rename(marker, QStringLiteral("Renamed")); + rename.redo_now(); + EXPECT_EQ(marker->name(), QStringLiteral("Renamed")); + rename.undo_now(); + EXPECT_EQ(marker->name(), QStringLiteral("One")); + + olive::MarkerChangeColorCommand recolor(marker, 9); + recolor.redo_now(); + EXPECT_EQ(marker->color(), 9); + recolor.undo_now(); + EXPECT_EQ(marker->color(), 1); + + olive::MarkerRemoveCommand remove(marker); + remove.redo_now(); + EXPECT_TRUE(list.empty()); + remove.undo_now(); + EXPECT_EQ(list.size(), 1); + + olive::TimelineMarker other( + 2, + olive::core::TimeRange(olive::core::rational(5, 1), + olive::core::rational(5, 1)), + QStringLiteral("Two"), + &list); + EXPECT_EQ(list.front()->time().in(), olive::core::rational(1, 1)); + + olive::MarkerChangeTimeCommand move( + marker, + olive::core::TimeRange(olive::core::rational(0, 1), + olive::core::rational(0, 1))); + move.redo_now(); + EXPECT_EQ(list.front(), marker); + move.undo_now(); + EXPECT_EQ(list.front()->time().in(), olive::core::rational(1, 1)); +} diff --git a/tests/gtest/timeline_workarea_test.cpp b/tests/gtest/timeline_workarea_test.cpp new file mode 100644 index 000000000..318f063b2 --- /dev/null +++ b/tests/gtest/timeline_workarea_test.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include +#include + +#include "timeline/timelineworkarea.h" + +TEST(TimelineWorkArea, DefaultsAndSetters) +{ + olive::TimelineWorkArea workarea; + EXPECT_FALSE(workarea.enabled()); + + olive::core::TimeRange range(olive::core::rational(5, 1), + olive::core::rational(10, 1)); + workarea.set_enabled(true); + workarea.set_range(range); + + EXPECT_TRUE(workarea.enabled()); + EXPECT_EQ(workarea.range(), range); + EXPECT_EQ(workarea.in(), range.in()); + EXPECT_EQ(workarea.out(), range.out()); + EXPECT_EQ(workarea.length(), range.length()); +} + +TEST(TimelineWorkArea, SaveLoadRoundTrip) +{ + olive::TimelineWorkArea workarea; + workarea.set_enabled(true); + workarea.set_range(olive::core::TimeRange(olive::core::rational(2, 1), + olive::core::rational(6, 1))); + + QByteArray xml; + QBuffer buffer(&xml); + ASSERT_TRUE(buffer.open(QIODevice::WriteOnly)); + QXmlStreamWriter writer(&buffer); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("workarea")); + workarea.save(&writer); + writer.writeEndElement(); + writer.writeEndDocument(); + buffer.close(); + + olive::TimelineWorkArea loaded; + QBuffer read_buffer(&xml); + ASSERT_TRUE(read_buffer.open(QIODevice::ReadOnly)); + QXmlStreamReader reader(&read_buffer); + ASSERT_TRUE(reader.readNextStartElement()); + EXPECT_TRUE(loaded.load(&reader)); + + EXPECT_TRUE(loaded.enabled()); + EXPECT_EQ(loaded.range(), + olive::core::TimeRange(olive::core::rational(2, 1), + olive::core::rational(6, 1))); +} diff --git a/tests/gtest/undo_stack_test.cpp b/tests/gtest/undo_stack_test.cpp new file mode 100644 index 000000000..451961491 --- /dev/null +++ b/tests/gtest/undo_stack_test.cpp @@ -0,0 +1,122 @@ +#include + +#include + +#include "undo/undostack.h" +#include "undo/undocommand.h" + +namespace { +class TestCommand final : public olive::UndoCommand { +public: + explicit TestCommand(int *value) + : value_(value) + { + } + + olive::Project *GetRelevantProject() const override + { + return nullptr; + } + +protected: + void redo() override + { + if (value_) { + (*value_)++; + } + } + + void undo() override + { + if (value_) { + (*value_)--; + } + } + +private: + int *value_ = nullptr; +}; +} + +TEST(UndoStack, PushUndoRedo) +{ + int counter = 0; + olive::UndoStack stack; + stack.push(new TestCommand(&counter), QStringLiteral("Test")); + EXPECT_EQ(counter, 1); + stack.undo(); + EXPECT_EQ(counter, 0); + stack.redo(); + EXPECT_EQ(counter, 1); +} + +TEST(UndoStack, EmptyStateAndModelData) +{ + olive::UndoStack stack; + EXPECT_FALSE(stack.CanUndo()); + EXPECT_FALSE(stack.CanRedo()); + EXPECT_EQ(stack.columnCount(), 2); + EXPECT_EQ(stack.rowCount(), 1); + EXPECT_TRUE(stack.hasChildren(QModelIndex())); + + QModelIndex name_index = stack.index(0, 1); + EXPECT_EQ(stack.data(name_index, Qt::DisplayRole).toString(), + QStringLiteral("New/Open Project")); + EXPECT_EQ(stack.headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), + QStringLiteral("Number")); + EXPECT_EQ(stack.headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), + QStringLiteral("Action")); +} + +TEST(UndoStack, UndoRedoListsAndColors) +{ + int counter = 0; + olive::UndoStack stack; + stack.push(new TestCommand(&counter), QStringLiteral("First")); + stack.push(new TestCommand(&counter), QStringLiteral("Second")); + EXPECT_EQ(counter, 2); + EXPECT_EQ(stack.rowCount(), 3); + + stack.undo(); + EXPECT_EQ(counter, 1); + EXPECT_TRUE(stack.CanRedo()); + + QModelIndex undone_name = stack.index(2, 1); + EXPECT_EQ(stack.data(undone_name, Qt::DisplayRole).toString(), + QStringLiteral("Second")); + QColor undone_color = + stack.data(undone_name, Qt::ForegroundRole).value(); + EXPECT_EQ(undone_color, QColor(Qt::gray)); + + stack.redo(); + EXPECT_EQ(counter, 2); + EXPECT_FALSE(stack.CanRedo()); +} + +TEST(UndoStack, JumpRestoresState) +{ + int counter = 0; + olive::UndoStack stack; + stack.push(new TestCommand(&counter), QStringLiteral("A")); + stack.push(new TestCommand(&counter), QStringLiteral("B")); + stack.push(new TestCommand(&counter), QStringLiteral("C")); + EXPECT_EQ(counter, 3); + EXPECT_EQ(stack.rowCount(), 4); + + stack.jump(1); + EXPECT_EQ(counter, 0); + EXPECT_TRUE(stack.CanRedo()); + + stack.jump(4); + EXPECT_EQ(counter, 3); + EXPECT_FALSE(stack.CanRedo()); +} + +TEST(UndoStack, EmptyMultiUndoCommandIsIgnored) +{ + olive::UndoStack stack; + auto *empty_multi = new olive::MultiUndoCommand(); + stack.push(empty_multi, QStringLiteral("Empty")); + EXPECT_EQ(stack.rowCount(), 1); + EXPECT_FALSE(stack.CanUndo()); +} diff --git a/tests/testutil.h b/tests/testutil.h index bd16dacbd..8d995b2b8 100644 --- a/tests/testutil.h +++ b/tests/testutil.h @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/tests/timeline/timeline-tests.cpp b/tests/timeline/timeline-tests.cpp index e25cef1d8..01dd6e426 100644 --- a/tests/timeline/timeline-tests.cpp +++ b/tests/timeline/timeline-tests.cpp @@ -2,6 +2,7 @@ Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team + Modifications Copyright (C) 2025 mikesolar 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 diff --git a/third_party/openfx/HostSupport/BUILDING b/third_party/openfx/HostSupport/BUILDING new file mode 100644 index 000000000..de4d2328c --- /dev/null +++ b/third_party/openfx/HostSupport/BUILDING @@ -0,0 +1,37 @@ +Dependencies +------------ + +Dependent upon the following + +*the expat library (expat.h) - to parse XML +*ofx header files + +How to build the library +------------------------ + +UNIX + - simply type 'make' in this directory, it will create 'libofxHost.a' in directory ./lib + - the Makefile assumes expat is installed in a standard system location, if it is not, + you need to do the following + + make EXPAT_INCLUDE=-IDIRECTORY_WITH_EXPAT + +WINDOWS + - use the vc8 projects + + +How to build the examples +------------------------ + +UNIX + - make the ofxHostLib.a library + - in the examples directory type 'make', + - the Makefile assumes expat is installed in a standard system location, if it is not, + you need to do the following + + make EXPAT_INCLUDE=-IDIRECTORY_WITH_EXPAT EXPAT_LIB=SOMEWHERE/libexpat.a + +WINDOWS + - use the vc8 projects + + diff --git a/third_party/openfx/HostSupport/CMakeLists.txt b/third_party/openfx/HostSupport/CMakeLists.txt new file mode 100644 index 000000000..61fc531d3 --- /dev/null +++ b/third_party/openfx/HostSupport/CMakeLists.txt @@ -0,0 +1,22 @@ +set(OFX_HOSTSUPPORT_HEADER_DIR "include") +set(OFX_HOSTSUPPORT_LIBRARY_DIR "src") +set(OFX_HEADER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../include") +aux_source_directory(OFX_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/../include") +file(GLOB_RECURSE OFX_HOSTSUPPORT_HEADER_FILES "${OFX_HOSTSUPPORT_HEADER_DIR}/*.h") +file(GLOB_RECURSE OFX_HOSTSUPPORT_LIBRARY_FILES "${OFX_HOSTSUPPORT_LIBRARY_DIR}/*.cpp") +add_library(OfxHost STATIC + ${OFX_HEADER_FILES} + ${OFX_HOSTSUPPORT_HEADER_FILES} + ${OFX_HOSTSUPPORT_LIBRARY_FILES}) + +set_target_properties(OfxHost PROPERTIES LINKER_LANGUAGE CXX) +if(NOT MSVC) + set_target_properties(OfxHost PROPERTIES COMPILE_FLAGS "-fPIC") +endif() + +target_link_libraries(OfxHost PUBLIC expat::expat) + +target_include_directories(OfxHost PUBLIC + ${OFX_HEADER_DIR} + ${OFX_HOSTSUPPORT_HEADER_DIR} + ${expat_INCLUDE_DIR}) diff --git a/third_party/openfx/HostSupport/README b/third_party/openfx/HostSupport/README new file mode 100644 index 000000000..83d00609f --- /dev/null +++ b/third_party/openfx/HostSupport/README @@ -0,0 +1,69 @@ +This directory contains source to an implementation of an OFX host C++ support library. +This library skins the raw C API with a C++ layer, which is easy to program and abstracts +the base API. + +It does several things, + - skins the C API with C++ classes, the host application 'only' needs to + - derive several classes + - implement a bunch of virtual methods + - set some OFX properties + - does most of the complicated logic in OFX, + - regions of interest calls + - clip preferences calls + - provides a persistent plug-in caching mechanism so that + - newly installed plug-ins are described into a cache file, + - the cache persists as an XML file with enough information + to construct simple menus etc.. + - once cached, plug-ins need only be loaded on demand. + - is extensible beyond the base API, + - allows hosts to provide extra suites and properties fairly easily. + - it is generic beyond ImageEffects APIs, so other APIs can be implemented + on the core sections of it. + +Apart from standard C and C++ libraries it is dependent on the expat XML library. + +You'll still need to understand what the API actually does, its just that the implementation details that become easier. + +The layer could do with some improvement, specifically, + - support for the external XML resource file, + - a degree more tidying up, + - parameter interacts + - more documentation. + +Released under a BSD-style licence: see source. + +Authors: + Abigail Brady + Andrew Whitmore + Bruno Nicoletti + +Release Notes +------------- + +26/03/2007 + +Minimum implementation, which allows plugin descriptions to be cached. Includes property sets and +property suite and implementation of plugin description. Support for describing in context and +parameters not fully enabled. + +29/03/2007 + +Support for describing in contexts and parameters. These are cached as well. + +25/06/2007 + +Major overhaul of the thing, + - propertys made simpler to use + - re-namespaced several classes so that anything to do with image effects are + in the ImageEffect namespace + - made the host layer do the logic for several Image Effect actions + - clip preferences + - regions of interest + - simplified the function signatures of the actions + - the 'Host' class now acts as, + - a factory, + - a filter for constructed objects, + - a description of the host application to the plugin. + +# SPDX-License-Identifier: BSD-3-Clause + diff --git a/third_party/openfx/HostSupport/TTD b/third_party/openfx/HostSupport/TTD new file mode 100644 index 000000000..525a5e760 --- /dev/null +++ b/third_party/openfx/HostSupport/TTD @@ -0,0 +1,17 @@ +Things to do. This is a wish list of features to add to the host layer... + +Common Base Class for All Plugin Instances + - currently using a void * to pass instance pointers to components that do not + need to know about image effects (eg: interact base classes). + - Should have a base 'Plugin::Instance' class that ImageEffect::Instance and any + other kind of plugin instance should derive from. + +XML Resource Support + - have the host layer manage the external XML resource file and relabel things appropriately. + +Support for Custom Params + - not there yet + - should have the host layer manage most of the custom param animation stuff as well. + + + diff --git a/third_party/openfx/HostSupport/include/ofxhBinary.h b/third_party/openfx/HostSupport/include/ofxhBinary.h new file mode 100644 index 000000000..70b4d05f8 --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhBinary.h @@ -0,0 +1,96 @@ + + +#ifndef OFX_BINARY_H +#define OFX_BINARY_H + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause +#include +#include + +#if defined(WIN32) || defined(WIN64) +#define I386 +#elif defined(__linux__) || defined(__FreeBSD__) +#define UNIX +#ifdef __i386__ +#define I386 +#elif defined(__amd64__) +#define AMD64 +#else +#error cannot detect architecture +#endif +#elif defined( __APPLE__) +#define UNIX +#else +#error cannot detect operating system +#endif + +#if defined(UNIX) +#include +#elif defined (WINDOWS) +#include "windows.h" +#include +#endif + +#include + +namespace OFX +{ + + /// class representing a DLL/Shared Object/etc + class Binary { + /// destruction will close the library and invalidate + /// any function pointers returned by lookupSymbol() + protected : + std::string _binaryPath; + bool _invalid; +#if defined(UNIX) + void *_dlHandle; +#elif defined (WINDOWS) + HINSTANCE _dlHandle; +#endif + time_t _time; + off_t _size; + int _users; + public : + + /// create object representing the binary. will stat() it, + /// and this fails, will set binary to be invalid. + Binary(const std::string &binaryPath); + + ~Binary() { unload(); } + + bool isLoaded() const { return _dlHandle != 0; } + + /// is this binary invalid? (did the a stat() or load() on the file fail, + /// or are we missing a some of the symbols? + bool isInvalid() const { return _invalid; } + + /// set invalid status (e.g. called by user if a mandatory symbol was missing) + void setInvalid(bool invalid) { _invalid = invalid; } + + /// Last modification time of the file. + time_t getTime() const { return _time; } + + /// Current size of the file. + off_t getSize() const { return _size; } + + /// Path to the file. + const std::string &getBinaryPath() const { return _binaryPath; } + + void ref(); + void unref(); + + /// open the binary. + void load(); + + /// close the binary + void unload(); + + /// look up a symbol in the binary file and return it as a pointer. + /// returns null pointer if not found, or if the library is not loaded. + void *findSymbol(const std::string &symbol); + }; +} + +#endif diff --git a/third_party/openfx/HostSupport/include/ofxhClip.h b/third_party/openfx/HostSupport/include/ofxhClip.h new file mode 100755 index 000000000..495f4355f --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhClip.h @@ -0,0 +1,499 @@ + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef OFX_CLIP_H +#define OFX_CLIP_H + +#include "ofxImageEffect.h" +#include "ofxhPropertySuite.h" +#include "ofxhUtilities.h" + +namespace OFX { + + namespace Host { + + namespace ImageEffect { + // forward declarations + class Image; + class Instance; +# ifdef OFX_SUPPORTS_OPENGLRENDER + class Texture; +# endif + + /// Base to both descriptor and instance it + /// is used to basically fetch common properties + /// by function name + class ClipBase { + protected : + Property::Set _properties; + + public : + /// base ctor, for a descriptor + ClipBase(); + + virtual ~ClipBase() { } + + /// ctor, when copy constructing an instance from a descripto + explicit ClipBase(const ClipBase &other); + + /// name of the clip + const std::string &getName() const + { + return _properties.getStringProperty(kOfxPropName); + } + + /// name of the clip + const std::string &getShortLabel() const; + + /// name of the clip + const std::string &getLabel() const; + + /// name of the clip + const std::string &getLongLabel() const; + + /// return a std::vector of supported comp + const std::vector &getSupportedComponents() const; + + /// is the given component supported + bool isSupportedComponent(const std::string &comp) const; + + /// does the clip do random temporal access + bool temporalAccess() const; + + /// is the clip optional + bool isOptional() const; + + /// is the clip a nominal 'mask' clip + bool isMask() const; + + /// how does this clip like fielded images to be presented to it + const std::string &getFieldExtraction() const; + + /// is the clip a nominal 'mask' clip + bool supportsTiles() const; + + /// get property set, const version + const Property::Set &getProps() const; + + /// get property set , non const version + Property::Set &getProps(); + + /// get a handle on the properties of the clip descriptor for the C api + OfxPropertySetHandle getPropHandle() const; + + /// get a handle on the clip descriptor/instance for the C api + OfxImageClipHandle getHandle() const; + + virtual bool verifyMagic() { + return true; + } + }; + + /// a clip descriptor + class ClipDescriptor : public ClipBase { + public: + /// constructor + ClipDescriptor(const std::string &name); + + /// is the clip an output clip + bool isOutput() const {return getName() == kOfxImageEffectOutputClipName; } + }; + + /// a clip instance + class ClipInstance : public ClipBase + , protected Property::GetHook + , protected Property::NotifyHook { + protected: + ImageEffect::Instance* _effectInstance; ///< image effect instance + bool _isOutput; ///< are we the output clip + std::string _pixelDepth; ///< what is the bit depth we is at. Set during the clip prefernces action. + std::string _components; ///< what components do we have. Set during the clip prefernces action. + + public: + ClipInstance(ImageEffect::Instance* effectInstance, ClipDescriptor& desc); + + /// is the clip an output clip + bool isOutput() const {return _isOutput;} + + /// notify override properties + virtual void notify(const std::string &name, bool isSingle, int indexOrN); + + /// get hook override + virtual void reset(const std::string &name); + + // get the virtuals for viewport size, pixel scale, background colour + virtual double getDoubleProperty(const std::string &name, int index) const; + + // get the virtuals for viewport size, pixel scale, background colour + virtual void getDoublePropertyN(const std::string &name, double *values, int count) const; + + // get the virtuals for viewport size, pixel scale, background colour + virtual int getIntProperty(const std::string &name, int index) const; + + // get the virtuals for viewport size, pixel scale, background colour + virtual void getIntPropertyN(const std::string &name, int *values, int count) const; + + // get the virtuals for viewport size, pixel scale, background colour + virtual const std::string &getStringProperty(const std::string &name, int index) const; + + // fetch multiple values in a multi-dimension property + virtual void getStringPropertyN(const std::string &name, const char** values, int count) const; + + // get hook virtuals + virtual int getDimension(const std::string &name) const; + + // instance changed action + OfxStatus instanceChangedAction(const std::string &why, + OfxTime time, + OfxPointD renderScale); + + // properties of an instance that are live + + /// Pixel Depth - fetch depth of all chromatic component in this clip + /// + /// kOfxBitDepthNone (implying a clip is unconnected, not valid for an image) + /// kOfxBitDepthByte + /// kOfxBitDepthShort + /// kOfxBitDepthHalf + /// kOfxBitDepthFloat + const std::string &getPixelDepth() const + { + return _pixelDepth; + } + + /// set the current pixel depth + /// called by clip preferences action + void setPixelDepth(const std::string &s) + { + _pixelDepth = s; + } + + /// Components that can be fetched from this clip - + /// + /// kOfxImageComponentNone (implying a clip is unconnected, not valid for an image) + /// kOfxImageComponentRGBA + /// kOfxImageComponentRGB + /// kOfxImageComponentAlpha + /// and any custom ones you may think of + virtual const std::string &getComponents() const; + + /// set the current set of components + /// called by clip preferences action + virtual void setComponents(const std::string &s); + + /// Get the Raw Unmapped Pixel Depth from the host for chromatic planes + /// + /// \returns + /// - kOfxBitDepthNone (implying a clip is unconnected image) + /// - kOfxBitDepthByte + /// - kOfxBitDepthShort + /// - kOfxBitDepthHalf + /// - kOfxBitDepthFloat + virtual const std::string &getUnmappedBitDepth() const = 0; + + /// Get the Raw Unmapped Components from the host + /// + /// \returns + /// - kOfxImageComponentNone (implying a clip is unconnected, not valid for an image) + /// - kOfxImageComponentRGBA + /// - kOfxImageComponentAlpha + virtual const std::string &getUnmappedComponents() const = 0; + + // PreMultiplication - + // + // kOfxImageOpaque - the image is opaque and so has no premultiplication state + // kOfxImagePreMultiplied - the image is premultiplied by it's alpha + // kOfxImageUnPreMultiplied - the image is unpremultiplied + virtual const std::string &getPremult() const = 0; + + // Pixel Aspect Ratio - + // + // The pixel aspect ratio of a clip or image. + virtual double getAspectRatio() const = 0; + + // Frame Rate - + // + // The frame rate of a clip or instance's project. + virtual double getFrameRate() const = 0; + + // Frame Range (startFrame, endFrame) - + // + // The frame range over which a clip has images. + virtual void getFrameRange(double &startFrame, double &endFrame) const = 0; + + /// Field Order - Which spatial field occurs temporally first in a frame. + /// \returns + /// - kOfxImageFieldNone - the clip material is unfielded + /// - kOfxImageFieldLower - the clip material is fielded, with image rows 0,2,4.... occuring first in a frame + /// - kOfxImageFieldUpper - the clip material is fielded, with image rows line 1,3,5.... occuring first in a frame + virtual const std::string &getFieldOrder() const = 0; + + // Connected - + // + // Says whether the clip is actually connected at the moment. + virtual bool getConnected() const = 0; + + // Unmapped Frame Rate - + // + // The unmapped frame rate. + virtual double getUnmappedFrameRate() const = 0; + + // Unmapped Frame Range - + // + // The unmapped frame range over which an output clip has images. + virtual void getUnmappedFrameRange(double &unmappedStartFrame, double &unmappedEndFrame) const = 0; + + // Continuous Samples - + // + // 0 if the images can only be sampled at discreet times (eg: the clip is a sequence of frames), + // 1 if the images can only be sampled continuously (eg: the clip is infact an animating roto spline and can be rendered anywhen). + virtual bool getContinuousSamples() const = 0; + + /// override this to fill in the image at the given time. + /// The bounds of the image on the image plane should be + /// 'appropriate', typically the value returned in getRegionsOfInterest + /// on the effect instance. Outside a render call, the optionalBounds should + /// be 'appropriate' for the. + /// If bounds is not null, fetch the indicated section of the canonical image plane. + virtual ImageEffect::Image* getImage(OfxTime time, const OfxRectD *optionalBounds) = 0; + +# ifdef OFX_SUPPORTS_OPENGLRENDER + /// override this to fill in the OpenGL texture at the given time. + /// The bounds of the image on the image plane should be + /// 'appropriate', typically the value returned in getRegionsOfInterest + /// on the effect instance. Outside a render call, the optionalBounds should + /// be 'appropriate' for the. + /// If bounds is not null, fetch the indicated section of the canonical image plane. + virtual ImageEffect::Texture* loadTexture(OfxTime time, const char *format, const OfxRectD *optionalBounds) = 0; +# endif + + /// override this to return the rod on the clip + virtual OfxRectD getRegionOfDefinition(OfxTime time) const = 0; + + /// given the colour component, find the nearest set of supported colour components + /// override this for extra wierd custom component depths + virtual const std::string &findSupportedComp(const std::string &s) const; + }; + + + /// instance of an image inside an image effect + class ImageBase : public Property::Set { + protected : + /// called during ctors to get bits from the clip props into ours + void getClipBits(ClipInstance& instance); + int _referenceCount; ///< reference count on this image + + public: + // default constructor + virtual ~ImageBase(); + + /// basic ctor, makes empty property set but sets not value + ImageBase(); + + /// construct from a clip instance, but leave the + /// filling it to the calling code via the propery set + explicit ImageBase(ClipInstance& instance); + + // Render Scale (renderScaleX,renderScaleY) - + // + // The proxy render scale currently being applied. + // ------ + // Bounds (bx1,by1,bx2,by2) - + // + // The bounds of an image's pixels. The bounds, in PixelCoordinates, are of the + // addressable pixels in an image's data pointer. The order of the values is + // x1, y1, x2, y2. X values are x1 <= X < x2 Y values are y1 <= Y < y2 + // ------ + // ROD (rodx1,rody1,rodx2,rody2) - + // + // The full region of definition. The ROD, in PixelCoordinates, are of the + // addressable pixels in an image's data pointer. The order of the values is + // x1, y1, x2, y2. X values are x1 <= X < x2 Y values are y1 <= Y < y2 + // ------ + // Row Bytes - + // + // The number of bytes in a row of an image. + // ------ + // Field - + // + // kOfxImageFieldNone - the image is an unfielded frame + // kOfxImageFieldBoth - the image is fielded and contains both interlaced fields + // kOfxImageFieldLower - the image is fielded and contains a single field, being the lower field (rows 0,2,4...) + // kOfxImageFieldUpper - the image is fielded and contains a single field, being the upper field (rows 1,3,5...) + // ------ + // Unique Identifier - + // + // Uniquely labels an image. This is host set and allows a plug-in to differentiate between images. This is + // especially useful if a plugin caches analysed information about the image (for example motion vectors). The + // plugin can label the cached information with this identifier. If a user connects a different clip to the + // analysed input, or the image has changed in some way then the plugin can detect this via an identifier change + // and re-evaluate the cached information. + + // construction based on clip instance + ImageBase(ClipInstance& instance, // construct from clip instance taking pixel depth, components, pre mult and aspect ratio + double renderScaleX, + double renderScaleY, + const OfxRectI &bounds, + const OfxRectI &rod, + int rowBytes, + std::string field, + std::string uniqueIdentifier); + + // OfxImageClipHandle getHandle(); + OfxPropertySetHandle getPropHandle() const { return Property::Set::getHandle(); } + + /// get the bounds of the pixels in memory + OfxRectI getBounds() const; + + /// get the full region of this image + OfxRectI getROD() const; + + /// release the reference count, which, if zero, deletes this + void releaseReference(); + + /// add a reference to this image + void addReference() {_referenceCount++;} + }; + + /// instance of an image inside an image effect + class Image : public ImageBase { + public: + // default constructor + virtual ~Image(); + + /// basic ctor, makes empty property set but sets not value + Image(); + + /// construct from a clip instance, but leave the + /// filling it to the calling code via the propery set + explicit Image(ClipInstance& instance); + + // Render Scale (renderScaleX,renderScaleY) - + // + // The proxy render scale currently being applied. + // ------ + // Data - + // + // The pixel data pointer of an image. + // ------ + // Bounds (bx1,by1,bx2,by2) - + // + // The bounds of an image's pixels. The bounds, in PixelCoordinates, are of the + // addressable pixels in an image's data pointer. The order of the values is + // x1, y1, x2, y2. X values are x1 <= X < x2 Y values are y1 <= Y < y2 + // ------ + // ROD (rodx1,rody1,rodx2,rody2) - + // + // The full region of definition. The ROD, in PixelCoordinates, are of the + // addressable pixels in an image's data pointer. The order of the values is + // x1, y1, x2, y2. X values are x1 <= X < x2 Y values are y1 <= Y < y2 + // ------ + // Row Bytes - + // + // The number of bytes in a row of an image. + // ------ + // Field - + // + // kOfxImageFieldNone - the image is an unfielded frame + // kOfxImageFieldBoth - the image is fielded and contains both interlaced fields + // kOfxImageFieldLower - the image is fielded and contains a single field, being the lower field (rows 0,2,4...) + // kOfxImageFieldUpper - the image is fielded and contains a single field, being the upper field (rows 1,3,5...) + // ------ + // Unique Identifier - + // + // Uniquely labels an image. This is host set and allows a plug-in to differentiate between images. This is + // especially useful if a plugin caches analysed information about the image (for example motion vectors). The + // plugin can label the cached information with this identifier. If a user connects a different clip to the + // analysed input, or the image has changed in some way then the plugin can detect this via an identifier change + // and re-evaluate the cached information. + + // construction based on clip instance + Image(ClipInstance& instance, // construct from clip instance taking pixel depth, components, pre mult and aspect ratio + double renderScaleX, + double renderScaleY, + void* data, + const OfxRectI &bounds, + const OfxRectI &rod, + int rowBytes, + std::string field, + std::string uniqueIdentifier); + }; + +# ifdef OFX_SUPPORTS_OPENGLRENDER + /// instance of an OpenGL texture inside an image effect + class Texture : public ImageBase { + public: + // default constructor + virtual ~Texture(); + + /// basic ctor, makes empty property set but sets not value + Texture(); + + /// construct from a clip instance, but leave the + /// filling it to the calling code via the propery set + explicit Texture(ClipInstance& instance); + + // Render Scale (renderScaleX,renderScaleY) - + // + // The proxy render scale currently being applied. + // ------ + // Index - + // + // The texture id (cast to GLuint). + // ------ + // Target - + // + // The texture target (cast to GLenum). + // ------ + // Bounds (bx1,by1,bx2,by2) - + // + // The bounds of an image's pixels. The bounds, in PixelCoordinates, are of the + // addressable pixels in an image's data pointer. The order of the values is + // x1, y1, x2, y2. X values are x1 <= X < x2 Y values are y1 <= Y < y2 + // ------ + // ROD (rodx1,rody1,rodx2,rody2) - + // + // The full region of definition. The ROD, in PixelCoordinates, are of the + // addressable pixels in an image's data pointer. The order of the values is + // x1, y1, x2, y2. X values are x1 <= X < x2 Y values are y1 <= Y < y2 + // ------ + // Row Bytes - + // + // The number of bytes in a row of an image. + // ------ + // Field - + // + // kOfxImageFieldNone - the image is an unfielded frame + // kOfxImageFieldBoth - the image is fielded and contains both interlaced fields + // kOfxImageFieldLower - the image is fielded and contains a single field, being the lower field (rows 0,2,4...) + // kOfxImageFieldUpper - the image is fielded and contains a single field, being the upper field (rows 1,3,5...) + // ------ + // Unique Identifier - + // + // Uniquely labels an image. This is host set and allows a plug-in to differentiate between images. This is + // especially useful if a plugin caches analysed information about the image (for example motion vectors). The + // plugin can label the cached information with this identifier. If a user connects a different clip to the + // analysed input, or the image has changed in some way then the plugin can detect this via an identifier change + // and re-evaluate the cached information. + + // construction based on clip instance + Texture(ClipInstance& instance, // construct from clip instance taking pixel depth, components, pre mult and aspect ratio + double renderScaleX, + double renderScaleY, + int index, + int target, + const OfxRectI &bounds, + const OfxRectI &rod, + int rowBytes, + std::string field, + std::string uniqueIdentifier); + }; +# endif + } // Memory + + } // Host + +} // OFX + +#endif // OFX_CLIP_H diff --git a/third_party/openfx/HostSupport/include/ofxhHost.h b/third_party/openfx/HostSupport/include/ofxhHost.h new file mode 100644 index 000000000..c74158ee3 --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhHost.h @@ -0,0 +1,84 @@ + +#ifndef OFX_HOST_H +#define OFX_HOST_H + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include + +#include "ofxCore.h" +#include "ofxImageEffect.h" +#include "ofxTimeLine.h" +#include "ofxhPropertySuite.h" + +namespace OFX { + + namespace Host { + + /// a plugin what we use + class Plugin; + + /// a param descriptor + namespace Param { + class Descriptor; + } + + /// Base class for all objects passed to a plugin by the 'setHost' function + /// passed back by any plug-in. + class Host { + protected : + OfxHost _host; + Property::Set _properties; + + public: + Host(); + virtual ~Host() {} + + + /// get the props on this host + Property::Set &getProperties() {return _properties; } + + /// fetch a suite + /// The base class returns the following suites + /// PropertySuite + /// MemorySuite + virtual const void *fetchSuite(const char *suiteName, int suiteVersion); + + /// get the C API handle that is passed across the API to represent this host + OfxHost *getHandle(); + + /// override this to handle do post-construction initialisation on a Param::Descriptor + virtual void initParamDescriptor(Param::Descriptor *) { } + + /// is my magic number valid? + bool verifyMagic() { return true; } + + /// message (called when an exception occurs, calls vmessage) + OfxStatus message(const char* type, + const char* id, + const char* format, + ...); + + /// vmessage + virtual OfxStatus vmessage(const char* type, + const char* id, + const char* format, + va_list args) = 0; + + /// setPersistentMessage + virtual OfxStatus setPersistentMessage(const char* type, + const char* id, + const char* format, + va_list args) = 0; + /// clearPersistentMessage + virtual OfxStatus clearPersistentMessage() = 0; + }; + + } +} + +#endif + diff --git a/third_party/openfx/HostSupport/include/ofxhImageEffect.h b/third_party/openfx/HostSupport/include/ofxhImageEffect.h new file mode 100755 index 000000000..167e768ed --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhImageEffect.h @@ -0,0 +1,695 @@ + + + +#ifndef OFX_IMAGE_EFFECT_H +#define OFX_IMAGE_EFFECT_H + +#include "ofxCore.h" +#include "ofxImageEffect.h" + +#include "ofxhHost.h" +#include "ofxhClip.h" +#include "ofxhProgress.h" +#include "ofxhTimeLine.h" +#include "ofxhParam.h" +#include "ofxhMemory.h" +#include "ofxhInteract.h" +#include +namespace olive { +namespace plugin { +class PluginNode; +} +} +#ifdef _MSC_VER +//Use visual studio extension +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + +namespace OFX { + + namespace Host { + + // forward declare + class Plugin; + + namespace Memory { + class Instance; + } + + namespace ImageEffect { + + // forward declare + class ImageEffectPlugin; + class OverlayInstance; + class Instance; + class Descriptor; + + /// An image effect host, passed to the setHost function of all image effect plugins + class Host : public OFX::Host::Host { + public : + Host(); + + /// fetch a suite + virtual const void *fetchSuite(const char *suiteName, int suiteVersion); + + /// Create a new instance of an image effect plug-in. + /// + /// It is called by ImageEffectPlugin::createInstance which the + /// client code calls when it wants to make a new instance. + /// + /// \arg clientData - the clientData passed into the ImageEffectPlugin::createInstance + /// \arg plugin - the plugin being created + /// \arg desc - the descriptor for that plugin + /// \arg context - the context to be created in + virtual Instance* newInstance(void *clientData, + ImageEffectPlugin* plugin, + Descriptor& desc, + const std::string& context) = 0; + + /// Function called as each plugin binary is found and loaded from disk + /// + /// Use this in any dialogue etc... showing progress + virtual void loadingStatus(const std::string &); + + /// Override this to filter out plugins which the host can't support for whatever reason + /// + /// \arg plugin - the plugin to examine + /// \arg reason - set this to report the reason the plugin was not loaded + virtual bool pluginSupported(ImageEffectPlugin *plugin, std::string &reason) const; + + /// Override this to create a descriptor, this makes the 'root' descriptor + virtual std::shared_ptr makeDescriptor(ImageEffectPlugin* plugin) = 0; + + /// used to construct a context description, rootContext is the main context + virtual std::shared_ptr makeDescriptor(const Descriptor &rootContext, ImageEffectPlugin *plug) = 0; + + /// used to construct populate the cache + virtual std::shared_ptr makeDescriptor(const std::string &bundlePath, ImageEffectPlugin *plug) = 0; + + /// Override this to initialise an image effect descriptor after it has been + /// created. + virtual void initDescriptor(Descriptor* desc); + +#ifdef OFX_SUPPORTS_MULTITHREAD + // these functions must be implemented if the host supports OfxMultiThreadSuiteV1 + // all the following functions are described in ofxMultiThread.h + // + + /// @see OfxMultiThreadSuiteV1.multiThread() + virtual OfxStatus multiThread(OfxThreadFunctionV1 func,unsigned int nThreads, void *customArg) = 0; + + /// @see OfxMultiThreadSuiteV1.multiThreadNumCPUS() + virtual OfxStatus multiThreadNumCPUS(unsigned int *nCPUs) const = 0; + + /// @see OfxMultiThreadSuiteV1.multiThreadIndex() + virtual OfxStatus multiThreadIndex(unsigned int *threadIndex) const = 0; + + /// @see OfxMultiThreadSuiteV1.multiThreadIsSpawnedThread() + virtual int multiThreadIsSpawnedThread() const = 0; + + /// @see OfxMultiThreadSuiteV1.mutexCreate() + virtual OfxStatus mutexCreate(OfxMutexHandle *mutex, int lockCount) = 0; + + /// @see OfxMultiThreadSuiteV1.mutexDestroy() + virtual OfxStatus mutexDestroy(const OfxMutexHandle mutex) = 0; + + /// @see OfxMultiThreadSuiteV1.mutexLock() + virtual OfxStatus mutexLock(const OfxMutexHandle mutex) = 0; + + /// @see OfxMultiThreadSuiteV1.mutexUnLock() + virtual OfxStatus mutexUnLock(const OfxMutexHandle mutex) = 0; + + /// @see OfxMultiThreadSuiteV1.mutexTryLock() + virtual OfxStatus mutexTryLock(const OfxMutexHandle mutex) = 0; +#endif // OFX_SUPPORTS_MULTITHREAD + +# ifdef OFX_SUPPORTS_OPENGLRENDER + /// @see OfxImageEffectOpenGLRenderSuiteV1.flushResources() + virtual OfxStatus flushOpenGLResources() const = 0; +# endif + + /// override this to use your own memory instance - must inherrit from memory::instance + virtual Memory::Instance* newMemoryInstance(size_t nBytes); + + // return an memory::instance calls makeMemoryInstance that can be overriden + Memory::Instance* imageMemoryAlloc(size_t nBytes); + }; + + /// our global host object, set when the plugin cache is created + extern Host *gImageEffectHost; + + //////////////////////////////////////////////////////////////////////////////// + /// base class to both effect descriptors and instances + class Base { + protected: + Property::Set _properties; + + public: + Base(const Property::Set &set); + Base(const Property::PropSpec * propSpec); + virtual ~Base(); + + /// is my magic number valid? + virtual bool verifyMagic() { return true; } + + /// obtain a handle on this for passing to the C api + OfxImageEffectHandle getHandle() const; + + /// get the properties set + Property::Set &getProps(); + + /// get the properties set, const version + const Property::Set &getProps() const; + + /// name of the clip + const std::string &getShortLabel() const; + + /// name of the clip + const std::string &getLabel() const; + + /// name of the clip + const std::string &getLongLabel() const; + + /// is the given context supported + bool isContextSupported(const std::string &s) const; + + /// what is the name of the group the plug-in belongs to + const std::string &getPluginGrouping() const; + + /// is the effect single instance + bool isSingleInstance() const; + + /// what is the thread safety on this effect + const std::string &getRenderThreadSafety() const; + + /// should the host attempt to managed multi-threaded rendering if it can + /// via tiling or some such + bool getHostFrameThreading() const; + + /// get the overlay interact main entry if it exists + OfxPluginEntryPoint *getOverlayInteractMainEntry() const; + + /// does the effect support images of differing sizes + bool supportsMultiResolution() const; + + /// does the effect support tiled rendering + bool supportsTiles() const; + + /// does this effect need random temporal access + bool temporalAccess() const; + + /// is the given RGBA/A pixel depth supported by the effect + bool isPixelDepthSupported(const std::string &s) const; + + /// when field rendering, does the effect need to be called + /// twice to render a frame in all circumstances (with different fields) + bool fieldRenderTwiceAlways() const; + + /// does the effect support multiple clip depths + bool supportsMultipleClipDepths() const; + + /// does the effect support multiple clip pixel aspect ratios + bool supportsMultipleClipPARs() const; + + /// does changing the named param re-tigger a clip preferences action + bool isClipPreferencesSlaveParam(const std::string &s) const; + + }; + + /// an image effect plugin descriptor + class Descriptor + : public Base + , public Param::SetDescriptor { + private : + // private CC + Descriptor(const Descriptor &other) + : Base(other._properties) + , Param::SetDescriptor() + , _plugin(other._plugin) + {} + + protected: + Plugin *_plugin; ///< the plugin I belong to + std::map _clips; ///< clips descriptors by name + std::vector _clipsByOrder; ///< clip descriptors in order of declaration + mutable Interact::Descriptor _overlayDescriptor; ///< descriptor to use for overlays, it has delayed description + + public: + /// used to construct the global description + Descriptor(Plugin *plug); + + /// used to construct a context description, 'other' is the main context + Descriptor(const Descriptor &rootContext, Plugin *plug); + + /// used to construct populate the cache + Descriptor(const std::string &bundlePath, Plugin *plug); + + /// dtor + virtual ~Descriptor(); + + /// implemented for Param::SetDescriptor + virtual Property::Set &getParamSetProps(); + + /// get the plugin I belong to + Plugin *getPlugin() const {return _plugin;} + + /// create a new clip and add this to the clip map + virtual ClipDescriptor *defineClip(const std::string &name); + + /// get the clips + const std::map &getClips() const; + + /// add a new clip + void addClip(const std::string &name, ClipDescriptor *clip); + + /// get the clips in order of construction + const std::vector &getClipsByOrder() const + { + return _clipsByOrder; + } + + /// Get the interact description, this will also call describe on the interact + /// This will return NULL if there is not main entry point or if the description failed + /// otherwise it will return the described overlay + Interact::Descriptor &getOverlayDescriptor(int bitDepthPerComponent = 8, bool hasAlpha = false); + }; + + /// a map used to specify needed frame ranges on set of clips + typedef std::map > RangeMap; + + /// an image effect plugin instance. + /// + /// Client code needs to filling the pure virtuals in this. + class Instance : public Base, + public Param::SetInstance, + public Progress::ProgressI, + public TimeLine::TimeLineI, + private Property::NotifyHook, + private Property::GetHook + { + protected: + OFX::Host::ImageEffect::ImageEffectPlugin *_plugin; + std::string _context; + Descriptor *_descriptor; + std::map _clips; + bool _interactive; + bool _created; + + bool _clipPrefsDirty; ///< do we need to re-run the clip prefs action + bool _continuousSamples; ///< set by clip prefs + bool _frameVarying; ///< set by clip prefs + std::string _outputPreMultiplication; ///< set by clip prefs + std::string _outputFielding; ///< set by clip prefs + double _outputFrameRate; ///< set by clip prefs + + public: + /// constructor based on clip descriptor + Instance(ImageEffectPlugin* plugin, + Descriptor &other, + const std::string &context, + bool interactive); + Instance(Instance& instance) + : Base(_properties) + { + _clips = instance._clips; + _created = instance._created; + _clipPrefsDirty = instance._clipPrefsDirty; + _continuousSamples = instance._continuousSamples; + _frameVarying = instance._frameVarying; + _outputPreMultiplication = instance._outputPreMultiplication; + _outputFielding = instance._outputFielding; + _outputFrameRate = instance._outputFrameRate; + } + virtual ~Instance(); + + /// implemented for Param::SetInstance + virtual Property::Set &getParamSetProps(); + + /// implemented for Param::SetInstance + virtual void paramChangedByPlugin(Param::Instance *param); + + /// get the descriptor for this instance + const Descriptor &getDescriptor() const {return *_descriptor;} + + /// return the plugin this instance was created with + OFX::Host::ImageEffect::ImageEffectPlugin*getPlugin() const { return _plugin; } + + /// return the context this instance was created with + const std::string &getContext() const { return _context; } + + /// get the descriptor for this instance + Descriptor &getDescriptor() {return *_descriptor;} + + /// get default output fielding. This is passed into the clip prefs action + /// and might be mapped (if the host allows such a thing) + virtual const std::string &getDefaultOutputFielding() const = 0; + + /// get output fielding as set in the clip preferences action. + const std::string &getOutputFielding() const {return _outputFielding; } + + /// get output fielding as set in the clip preferences action. + const std::string &getOutputPreMultiplication() const {return _outputPreMultiplication; } + + /// get the output frame rate, as set in the clip prefences action. + double getOutputFrameRate() const {return _outputFrameRate;} + + + /// called after construction to populate the various members + /// ideally should be called in the ctor, but it relies on + /// virtuals so has to be delayed until after the effect is + /// constructed + OfxStatus populate(); + + /// get the nth clip, in order of declaration + ClipInstance* getNthClip(int index); + + /// get the nth clip, in order of declaration + int getNClips() const + { + return int(_clips.size()); + } + + /// are the clip preferences currently dirty + bool areClipPrefsDirty() const {return _clipPrefsDirty;} + + /// are all the non optional clips connected + bool checkClipConnectionStatus() const; + + /// can this this instance render images at arbitrary times, not just frame boundaries + /// set by getClipPreferenceAction() + bool continuousSamples() const {return _continuousSamples;} + + /// does this instance generate a different picture on a frame change, even if the + /// params and input images are exactly the same. eg: random noise generator + bool isFrameVarying() const {return _frameVarying;} + + /// pure virtuals that must be overriden + virtual ClipInstance* getClip(const std::string& name) const; + + /// override this to make processing abort, return 1 to abort processing + virtual int abort(); + + /// override this to use your own memory instance - must inherrit from memory::instance + virtual Memory::Instance* newMemoryInstance(size_t nBytes); + + // return an memory::instance calls makeMemoryInstance that can be overriden + Memory::Instance* imageMemoryAlloc(size_t nBytes); + + /// make a clip + virtual ClipInstance* newClipInstance(ImageEffect::Instance* plugin, + ClipDescriptor* descriptor, + int index) = 0; + + /// message suite + virtual OfxStatus vmessage(const char* type, + const char* id, + const char* format, + va_list args) = 0; + + virtual OfxStatus setPersistentMessage(const char* type, + const char* id, + const char* format, + va_list args) = 0; + + virtual OfxStatus clearPersistentMessage() = 0; + + + /// call the effect entry point + virtual OfxStatus mainEntry(const char *action, + const void *handle, + Property::Set *inArgs, + Property::Set *outArgs); + + int upperGetDimension(const std::string &name); + + /// overridden from Property::Notify + virtual void notify(const std::string &name, bool singleValue, int indexOrN); + + /// overridden from gethook, get the virutals for viewport size, pixel scale, background colour + virtual double getDoubleProperty(const std::string &name, int index) const; + + /// overridden from gethook, get the virutals for viewport size, pixel scale, background colour + virtual void getDoublePropertyN(const std::string &name, double *values, int count) const; + + /// overridden from gethook, don't know what to do + virtual void reset(const std::string &name); + + //// overridden from gethook + virtual int getDimension(const std::string &name) const; + + // + // live parameters + // + + // The size of the current project in canonical coordinates. + // The size of a project is a sub set of the kOfxImageEffectPropProjectExtent. For example a + // project may be a PAL SD project, but only be a letter-box within that. The project size is + // the size of this sub window. + virtual void getProjectSize(double& xSize, double& ySize) const = 0; + + // The offset of the current project in canonical coordinates. + // The offset is related to the kOfxImageEffectPropProjectSize and is the offset from the origin + // of the project 'subwindow'. For example for a PAL SD project that is in letterbox form, the + // project offset is the offset to the bottom left hand corner of the letter box. The project + // offset is in canonical coordinates. + virtual void getProjectOffset(double& xOffset, double& yOffset) const = 0; + + // The extent of the current project in canonical coordinates. + // The extent is the size of the 'output' for the current project. See ProjectCoordinateSystems + // for more infomation on the project extent. The extent is in canonical coordinates and only + // returns the top right position, as the extent is always rooted at 0,0. For example a PAL SD + // project would have an extent of 768, 576. + virtual void getProjectExtent(double& xSize, double& ySize) const = 0; + + // The pixel aspect ratio of the current project + virtual double getProjectPixelAspectRatio() const = 0; + + // The duration of the effect + // This contains the duration of the plug-in effect, in frames. + virtual double getEffectDuration() const = 0; + + // For an instance, this is the frame rate of the project the effect is in. + virtual double getFrameRate() const = 0; + + /// This is called whenever a param is changed by the plugin so that + /// the recursive instanceChangedAction will be fed the correct frame + virtual double getFrameRecursive() const = 0; + + /// This is called whenever a param is changed by the plugin so that + /// the recursive instanceChangedAction will be fed the correct + /// renderScale + virtual void getRenderScaleRecursive(double &x, double &y) const = 0; + + /// Get whether the component is a supported 'chromatic' component (RGBA or alpha) in + /// the base API. + /// Override this if you have extended your chromatic colour types (eg RGB) and want + /// the clip preferences logic to still work + virtual bool isChromaticComponent(const std::string &str) const; + + /// function to check for multiple bit depth support + /// The answer will depend on host, plugin and context + virtual bool canCurrentlyHandleMultipleClipDepths() const; + + /// calculate the default rod for this effect instance + virtual OfxRectD calcDefaultRegionOfDefinition(OfxTime time, + OfxPointD renderScale) const; + + // + // actions + // + + /// this is used to populate with any extra action in argumnents that may be needed + virtual void setCustomInArgs(const std::string &action, Property::Set &inArgs); + + /// this is used to populate with any extra action out argumnents that may be needed + virtual void setCustomOutArgs(const std::string &action, Property::Set &outArgs); + + /// this is used retrieve any out args after the action was called in mainEntry + virtual void examineOutArgs(const std::string &action, OfxStatus stat, const Property::Set &outArgs); + + /// create an instance. This needs to be called _after_ construction and + /// _after_ the host populates it's params and clips with the 'correct' + /// values (either persisted ones or the defaults) + virtual OfxStatus createInstanceAction(); + + // begin/change/end instance changed + + // + // why - + // + // kOfxChangeUserEdited - the user or host changed the instance somehow and + // caused a change to something, this includes undo/redos, + // resets and loading values from files or presets, + // kOfxChangePluginEdited - the plugin itself has changed the value of the instance + // in some action + // kOfxChangeTime - the time has changed and this has affected the value + // of the object because it varies over time + // + virtual OfxStatus beginInstanceChangedAction(const std::string &why); + + virtual OfxStatus paramInstanceChangedAction(const std::string ¶mName, + const std::string & why, + OfxTime time, + OfxPointD renderScale); + + virtual OfxStatus clipInstanceChangedAction(const std::string &clipName, + const std::string & why, + OfxTime time, + OfxPointD renderScale); + + virtual OfxStatus endInstanceChangedAction(const std::string &why); + + // purge your caches + virtual OfxStatus purgeCachesAction(); + + // sync your private data + virtual OfxStatus syncPrivateDataAction(); + + // begin/end edit instance + virtual OfxStatus beginInstanceEditAction(); + virtual OfxStatus endInstanceEditAction(); + +# ifdef OFX_SUPPORTS_OPENGLRENDER + // attach/detach OpenGL context + virtual OfxStatus contextAttachedAction(); + virtual OfxStatus contextDetachedAction(); +# endif + + // render action + virtual OfxStatus beginRenderAction(OfxTime startFrame, + OfxTime endFrame, + OfxTime step, + bool interactive, + OfxPointD renderScale, + bool sequentialRender, + bool interactiveRender + ); + + virtual OfxStatus renderAction(OfxTime time, + const std::string & field, + const OfxRectI &renderRoI, + OfxPointD renderScale, + bool sequentialRender, + bool interactiveRender, + bool draftRender + ); + + virtual OfxStatus endRenderAction(OfxTime startFrame, + OfxTime endFrame, + OfxTime step, + bool interactive, + OfxPointD renderScale, + bool sequentialRender, + bool interactiveRender + ); + + /// Call the region of definition action the plugin at the given time + /// and with the given render scales. The value is returned in rod. + /// Note that if the plugin does not trap the action the default + /// RoD is calculated and returned. + virtual OfxStatus getRegionOfDefinitionAction(OfxTime time, + OfxPointD renderScale, + OfxRectD &rod); + + /// call the get region of interest action on the plugin for the + /// given frame and renderscale. The render RoI is passed in in + /// roi, the std::map will contain the requested rois. Note + /// That this call will check for tiling support and for + /// default replies and set up the correct rois in these cases + /// as well + virtual OfxStatus getRegionOfInterestAction(OfxTime time, + OfxPointD renderScale, + const OfxRectD &roi, + std::map &rois); + + // get frames needed to render the given frame + virtual OfxStatus getFrameNeededAction(OfxTime time, + RangeMap &rangeMap); + + // is identity + virtual OfxStatus isIdentityAction(OfxTime &time, + const std::string & field, + const OfxRectI &renderRoI, + OfxPointD renderScale, + std::string &clip); + + // time domain + virtual OfxStatus getTimeDomainAction(OfxRangeD& range); + + /// Get the interact description, this will also call describe on the interact + /// This will return NULL if there is not main entry point or if the description failed + /// otherwise it will return the described overlay + /// This is called by the CTOR of OverlayInteract to get the descriptor to do things with + Interact::Descriptor &getOverlayDescriptor(int bitDepthPerComponent = 8, bool hasAlpha = false); + + /// Setup the default clip preferences on the clips + virtual void setDefaultClipPreferences(); + + /// Initialise the clip preferences arguments, override this to do + /// stuff with wierd components etc... Calls setDefaultClipPreferences + virtual void setupClipPreferencesArgs(Property::Set &args); + + /// Run the clip preferences action from the effect. + /// + /// This will look into the input clips and output clip + /// and set the following properties that the effect should + /// fetch the image at. + /// - pixel depth + /// - components + /// - pixel aspect ratio + /// It will also set on the effect itselff + /// - whether it is continuously samplable + /// - the premult state of the output + /// - whether the effect is frame varying + /// - the fielding of the output clip + /// + /// This will be run automatically by the effect in the following situations... + /// - an input clip is changed + /// - a clip preferences slave param is changed + /// + /// The host still needs to call this explicitly just after the effect is wired + /// up. + virtual bool getClipPreferences(); + + /// calls getClipPreferences only if the prefs are dirty + /// + /// returns whether the clips prefs were dirty or not + bool runGetClipPrefsConditionally() + { + if(areClipPrefsDirty()) { + getClipPreferences(); + return true; + } + return false; + } + + /// find the best supported bit depth for the given one. Override this if you define + /// more depths + virtual const std::string &bestSupportedDepth(const std::string &depth) const; + + /// find the most chromatic components out of the two. Override this if you define + /// more chromatic components + virtual const std::string &findMostChromaticComponents(const std::string &a, const std::string &b) const; + }; + + //////////////////////////////////////////////////////////////////////////////// + /// An overlay interact for image effects, derived from one of these to + /// be an overlay interact + class OverlayInteract : public Interact::Instance { + protected : + /// our image effect instance + ImageEffect::Instance &_instance; + + public : + /// ctor this calls Instance->getOverlayDescriptor to get the descriptor + OverlayInteract(ImageEffect::Instance &v, int bitDepthPerComponent = 8, bool hasAlpha = false); + }; + + + } // namespace ImageEffect + + } // namespace Host + +} // namespace OFX + +#endif // OFX_IMAGE_EFFECT_H diff --git a/third_party/openfx/HostSupport/include/ofxhImageEffectAPI.h b/third_party/openfx/HostSupport/include/ofxhImageEffectAPI.h new file mode 100644 index 000000000..638b46d1c --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhImageEffectAPI.h @@ -0,0 +1,223 @@ + + + +#ifndef OFXH_IMAGE_EFFECT_API_H +#define OFXH_IMAGE_EFFECT_API_H + + + +#include "ofxhPluginAPICache.h" +#include "ofxhPluginCache.h" +#include +#include +#include +#include +#include + +#include "ofxCore.h" +#include "ofxImageEffect.h" +#include "ofxhImageEffect.h" +#include "ofxhHost.h" + + + + + namespace OFX::Host::ImageEffect { + + class PluginCache; + + /// subclass of Plugin representing an ImageEffect plugin. used to store API-specific + /// data + class ImageEffectPlugin : public Plugin { + + PluginCache &_pc; + + // this comes off Descriptor's property set after a describe + // context independent + std::shared_ptr _baseDescriptor; /// NEEDS TO BE MADE WITH A FACTORY FUNCTION ON THE HOST!!!!!! + + /// map to store contexts in + std::map> _contexts; + + mutable std::set _knownContexts; + mutable bool _madeKnownContexts; + + std::unique_ptr _pluginHandle; + + void addContextInternal(const std::string &context) const; + + public: + ImageEffectPlugin(PluginCache &pc, PluginBinary *pb, int pi, OfxPlugin *pl); + + ImageEffectPlugin(PluginCache &pc, + PluginBinary *pb, + int pi, + const std::string &api, + int apiVersion, + const std::string &pluginId, + const std::string &rawId, + int pluginMajorVersion, + int pluginMinorVersion); + + ~ImageEffectPlugin() override; + + /// return the API handler this plugin was constructed by + APICache::PluginAPICacheI &getApiHandler() override; + + + /// get the base image effect descriptor + Descriptor &getDescriptor(); + + /// get the base image effect descriptor, const version + const Descriptor &getDescriptor() const; + + /// get the image effect descriptor for the context + Descriptor *getContext(const std::string &context); + + void addContext(const std::string &context); + void addContext(const std::string &context, std::shared_ptr ied); + + virtual void saveXML(std::ostream &os); + + const std::set& getContexts() const; + + PluginHandle *getPluginHandle(); + + void unload(); + + /// this is called to make an instance of the effect + /// the client data ptr is what is passed back to the client creation function + ImageEffect::Instance* createInstance(const std::string &context, void *clientDataPtr); + + }; + + class MajorPlugin { + std::string _id; + int _major; + + public: + MajorPlugin(std::string id, int major) : _id(std::move(id)), _major(major) { + } + + explicit MajorPlugin(ImageEffectPlugin *iep) : _id(iep->getIdentifier()), _major(iep->getVersionMajor()) { + } + + [[nodiscard]] const std::string &getId() const { + return _id; + } + + [[nodiscard]] int getMajor() const { + return _major; + } + + bool operator<(const MajorPlugin &other) const { + if (_id < other._id) + return true; + + if (_id > other._id) + return false; + + if (_major < other._major) + return true; + + return false; + } + }; + + /// implementation of the specific Image Effect handler API cache. + class PluginCache : public APICache::PluginAPICacheI { + public: + + private: + /// all plugins + std::vector _plugins; + + /// latest version of each plugin by ID + std::map _pluginsByID; + + /// latest minor version of each plugin by (ID,major) + std::map _pluginsByIDMajor; + + /// xml parsing state + ImageEffectPlugin *_currentPlugin; + /// xml parsing state + Property::Property *_currentProp; + + Descriptor *_currentContext; + Param::Descriptor *_currentParam; + ClipDescriptor *_currentClip; + + /// pointer to our image effect host + OFX::Host::ImageEffect::Host* _host; + + public: + + explicit PluginCache(OFX::Host::ImageEffect::Host &host); + + ~PluginCache() override; + + /// get the plugin by id. vermaj and vermin can be specified. if they are not it will + /// pick the highest found version. + ImageEffectPlugin *getPluginById(const std::string &id, int vermaj=-1, int vermin=-1); + + /// get the plugin by label. vermaj and vermin can be specified. if they are not it will + /// pick the highest found version. + ImageEffectPlugin *getPluginByLabel(const std::string &label, int vermaj=-1, int vermin=-1); + + OFX::Host::ImageEffect::Host *getHost() { + return _host; + } + + [[nodiscard]] const std::vector& getPlugins() const; + + [[nodiscard]] const std::map& getPluginsByID() const; + + [[nodiscard]] const std::map& getPluginsByIDMajor() const + { + return _pluginsByIDMajor; + } + + /// handle the case where the info needs filling in from the file. runs the "describe" action on the plugin. + void loadFromPlugin(Plugin *p) const override; + + /// handler for preparing to read in a chunk of XML from the cache, set up context to do this + void beginXmlParsing(Plugin *p) override; + + /// XML handler : element begins (everything is stored in elements and attributes) + void xmlElementBegin(const std::string &el, std::map map) override; + + void xmlCharacterHandler(const std::string &) override; + + void xmlElementEnd(const std::string &el) override; + + void endXmlParsing() override; + + void saveXML(Plugin *ip, std::ostream &os) const override; + + void confirmPlugin(Plugin *p) override; + + bool pluginSupported(Plugin *p, std::string &reason) const override; + + Plugin *newPlugin(PluginBinary *pb, + int pi, + OfxPlugin *pl) override; + + Plugin *newPlugin(PluginBinary *pb, + int pi, + const std::string &api, + int apiVersion, + const std::string &pluginId, + const std::string &rawId, + int pluginMajorVersion, + int pluginMinorVersion) override; + + void dumpToStdOut(); + }; + + } // ImageEffect + + // Host + +// OFX + +#endif diff --git a/third_party/openfx/HostSupport/include/ofxhInteract.h b/third_party/openfx/HostSupport/include/ofxhInteract.h new file mode 100755 index 000000000..c38aad487 --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhInteract.h @@ -0,0 +1,278 @@ + + + +#ifndef OFX_INTERACT_H +#define OFX_INTERACT_H + +#include "ofxInteract.h" +#include "ofxOld.h" // old plugins may rely on deprecated properties being present +#include "ofxhPropertySuite.h" + +namespace OFX { + + namespace Host { + + namespace Interact { + + /// fetch a versioned suite for our interact + const void *GetSuite(int version); + + class Base { + public: + virtual ~Base() { + } + + /// grab a handle on the parameter for passing to the C API + OfxInteractHandle getHandle() {return (OfxInteractHandle)this;} + + /// get the property handle for this instance/descriptor + virtual OfxPropertySetHandle getPropHandle() = 0; + }; + + /// state the interact can be in + enum State { + eUninitialised, + eDescribed, + eCreated, + eFailed + }; + + /// Descriptor for an interact. Interacts all share a single description + class Descriptor : public Base { + protected: + Property::Set _properties; ///< its props + State _state; ///< how is it feeling today + OfxPluginEntryPoint *_entryPoint; ///< the entry point for this overlay + + public: + /// CTOR + Descriptor(); + + /// dtor + virtual ~Descriptor(); + + /// set the main entry points + void setEntryPoint(OfxPluginEntryPoint *entryPoint) {_entryPoint = entryPoint;} + + /// call describe on this descriptor, returns true if all went well + bool describe(int bitDepthPerComponent, bool hasAlpha); + + /// grab a handle on the properties of this parameter for the C api + OfxPropertySetHandle getPropHandle() {return _properties.getHandle();} + + /// get prop set + const Property::Set &getProperties() const {return _properties;} + + /// get a non const prop set + Property::Set &getProperties() {return _properties;} + + /// call the entry point with action and the given args + OfxStatus callEntry(const char *action, + void *handle, + OfxPropertySetHandle inArgs, + OfxPropertySetHandle outArgs); + + /// what is it's state? + State getState() const {return _state;} + }; + + /// a generic interact, it doesn't belong to anything in particular + /// we need to generify this slighty more and remove the renderscale args + /// into a derived class, as they only belong to image effect plugins + class Instance : public Base, protected Property::GetHook { + protected: + Descriptor &_descriptor; ///< who we are + Property::Set _properties; ///< its props + State _state; ///< how is it feeling today + void *_effectInstance; ///< this is ugly, we need a base class to all plugin instances at some point. + Property::Set _argProperties; + + /// initialise the argument properties + void initArgProp(OfxTime time, + const OfxPointD &renderScale); + + /// set pen props in the args + void setPenArgProps(const OfxPointD &penPos, + const OfxPointI &penPosViewport, + double pressure); + + /// set key args in the props + void setKeyArgProps(int key, + char* keyString); + + public: + Instance(Descriptor &desc, void *effectInstance); + + virtual ~Instance(); + + /// what is it's state? + State getState() const {return _state;} + + /// grab a handle on the properties of this parameter for the C api + OfxPropertySetHandle getPropHandle() {return _properties.getHandle();} + + /// get prop set + const Property::Set &getProperties() const {return _properties;} + + /// call the entry point in the descriptor with action and the given args + virtual OfxStatus callEntry(const char *action, + Property::Set *inArgs); + +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + /// hooks to kOfxInteractPropViewportSize in the property set + /// this is actually redundant and is to be deprecated + virtual void getViewportSize(double &width, double &height) const = 0; +#endif + + // hooks to live kOfxInteractPropPixelScale in the property set + virtual void getPixelScale(double& xScale, double& yScale) const = 0; + + // hooks to kOfxInteractPropBackgroundColour in the property set + virtual void getBackgroundColour(double &r, double &g, double &b) const = 0; + + // hooks to kOfxInteractPropSuggestedColour and kOfxPropOverlayColour in the property set + // return false if there is no color suggestion by the host. + virtual bool getSuggestedColour(double &r, double &g, double &b) const = 0; + + /// implement + virtual OfxStatus swapBuffers() = 0; + + /// implement this + virtual OfxStatus redraw() = 0; + + /// returns the params the interact uses + virtual void getSlaveToParam(std::vector& params) const; + + // do nothing + virtual int getDimension(const std::string &name) const; + + // don't know what to do + virtual void reset(const std::string &name); + + /// the gethook virutals for pixel scale, background colour + virtual double getDoubleProperty(const std::string &name, int index) const; + + /// for pixel scale and background colour + virtual void getDoublePropertyN(const std::string &name, double *first, int n) const; + + /// call create instance + virtual OfxStatus createInstanceAction(); + + // interact action - kOfxInteractActionDraw + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + virtual OfxStatus drawAction(OfxTime time, const OfxPointD &renderScale); + + // interact action - kOfxInteractActionPenMotion + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + // penX - the X position + // penY - the Y position + // pressure - the pen pressue 0 to 1 + virtual OfxStatus penMotionAction(OfxTime time, + const OfxPointD &renderScale, + const OfxPointD &penPos, + const OfxPointI &penPosViewport, + double pressure); + + // interact action - kOfxInteractActionPenUp + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + // penX - the X position + // penY - the Y position + // pressure - the pen pressue 0 to 1 + virtual OfxStatus penUpAction(OfxTime time, + const OfxPointD &renderScale, + const OfxPointD &penPos, + const OfxPointI &penPosViewport, + double pressure); + + // interact action - kOfxInteractActionPenDown + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + // penX - the X position + // penY - the Y position + // pressure - the pen pressue 0 to 1 + virtual OfxStatus penDownAction(OfxTime time, + const OfxPointD &renderScale, + const OfxPointD &penPos, + const OfxPointI &penPosViewport, + double pressure); + + // interact action - kOfxInteractActionkeyDown + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + // key - the pressed key + // keyString - the pressed key string + virtual OfxStatus keyDownAction(OfxTime time, + const OfxPointD &renderScale, + int key, + char* keyString); + + // interact action - kOfxInteractActionkeyUp + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + // key - the pressed key + // keyString - the pressed key string + virtual OfxStatus keyUpAction(OfxTime time, + const OfxPointD &renderScale, + int key, + char* keyString); + + // interact action - kOfxInteractActionkeyRepeat + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + // key - the pressed key + // keyString - the pressed key string + virtual OfxStatus keyRepeatAction(OfxTime time, + const OfxPointD &renderScale, + int key, + char* keyString); + + // interact action - kOfxInteractActionLoseFocus + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + virtual OfxStatus gainFocusAction(OfxTime time, + const OfxPointD &renderScale); + + // interact action - kOfxInteractActionLoseFocus + // + // Params - + // + // time - the effect time at which changed occured + // renderScale - the render scale + virtual OfxStatus loseFocusAction(OfxTime time, + const OfxPointD &renderScale); + }; + + } // Interact + + } // Host + +} // OFX + +#endif // OFX_INTERACT_H diff --git a/third_party/openfx/HostSupport/include/ofxhMemory.h b/third_party/openfx/HostSupport/include/ofxhMemory.h new file mode 100755 index 000000000..a16e817c5 --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhMemory.h @@ -0,0 +1,39 @@ + + + +#ifndef OFX_MEMORY_H +#define OFX_MEMORY_H + +#include "ofxImageEffect.h" +namespace OFX { + + namespace Host { + + namespace Memory { + + class Instance { + public: + Instance(); + + virtual ~Instance(); + virtual bool alloc(size_t nBytes); + virtual OfxImageMemoryHandle getHandle(); + virtual void freeMem(); + virtual void* getPtr(); + virtual void lock(); + virtual void unlock(); + + virtual bool verifyMagic() { return true; } + + protected: + char* _ptr; + int _locked; + }; + + } // Memory + + } // Host + +} // OFX + +#endif // OFX_MEMORY_H diff --git a/third_party/openfx/HostSupport/include/ofxhParam.h b/third_party/openfx/HostSupport/include/ofxhParam.h new file mode 100755 index 000000000..bbc15336e --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhParam.h @@ -0,0 +1,678 @@ + + + +#ifndef OFXH_PARAM_H +#define OFXH_PARAM_H + +#include +#include +#include +#include + +//ofx +#include "ofxParam.h" + +//ofxh +#include "ofxhPropertySuite.h" + + +namespace OFX { + + namespace Host { + + namespace Param { + + /// fetch the param suite + const void *GetSuite(int version); + + bool isColourParam(const std::string ¶mType); + + bool isIntParam(const std::string ¶mType); + + /// is this a standard type + bool isStandardType(const std::string &type); + + /// base class for all params + class Base { + + private: + Base(); + protected: + std::string _paramName; + std::string _paramType; + Property::Set _properties; + public: + Base(const std::string &name, const std::string &type); + Base(const std::string &name, const std::string &type, const Property::Set &properties); + virtual ~Base(); + + /// grab a handle on the parameter for passing to the C API + OfxParamHandle getHandle() const; + + virtual bool verifyMagic() { return true; } + + /// grab a handle on the properties of this parameter for the C api + OfxPropertySetHandle getPropHandle() const; + + const Property::Set &getProperties() const; + + Property::Set &getProperties(); + + const std::string &getType() const; + + const std::string &getName() const; + + const std::string &getParentName() const; + + const std::string &getLabel() const; + + const std::string &getShortLabel() const; + + const std::string &getLongLabel() const; + + const std::string &getScriptName() const; + + const std::string &getDoubleType() const; + + const std::string &getDefaultCoordinateSystem() const; + + const std::string &getCacheInvalidation() const; + + const std::string &getHint() const; + + bool getEnabled() const; + + bool getCanUndo() const; + + bool getSecret() const; + + bool getIsPersistant() const; + + bool getEvaluateOnChange() const; + + bool getCanAnimate() const; + }; + + /// the Descriptor of a plugin parameter + class Descriptor : public Base { + Descriptor(); + + public: + /// make a parameter, with the given type and name + Descriptor(const std::string &type, const std::string &name); + + /// add standard param props, will call the below + void addStandardParamProps(const std::string &type); + + /// add standard properties to a params that can take an interact + void addInteractParamProps(const std::string &type); + + /// add standard properties to a value holding param + void addValueParamProps(const std::string &type, Property::TypeEnum valueType, int dim); + + /// add standard properties to a value holding param + void addNumericParamProps(const std::string &type, Property::TypeEnum valueType, int dim); + }; + + /// base class to the param set instance and param set descriptor + class BaseSet { + public: + virtual ~BaseSet(); + + /// obtain a handle on this set for passing to the C api + OfxParamSetHandle getParamSetHandle() const; + + /// get the property handle that lives with the set + /// The plugin descriptor/instance that derives from + /// this will provide this. + virtual Property::Set &getParamSetProps() = 0; + }; + + /// a set of parameters + class SetDescriptor : public BaseSet { + std::map _paramMap; + std::list _paramList; + + /// CC doesn't exist + SetDescriptor(const SetDescriptor &); + + public: + /// default ctor + SetDescriptor(); + + /// dtor + virtual ~SetDescriptor(); + + /// get the map of params + const std::map &getParams() const; + + /// get the list of params + const std::list &getParamList() const; + + /// define a param + virtual Descriptor *paramDefine(const char *paramType, + const char *name); + + /// add a param in + virtual void addParam(const std::string &name, Descriptor *p); + }; + + // forward declare + class SetInstance; + + /// the description of a plugin parameter + class Instance : public Base, protected Property::NotifyHook { + Instance(); + protected: + SetInstance* _paramSetInstance; + Instance* _parentInstance; + public: + virtual ~Instance(); + + /// make a parameter, with the given type and name + explicit Instance(Descriptor& descriptor, Param::SetInstance* instance = 0); + + // OfxStatus instanceChangedAction(const std::string &why, + // OfxTime time, + // double renderScaleX, + // double renderScaleY); + + // get the param instance + OFX::Host::Param::SetInstance* getParamSetInstance() { return _paramSetInstance; } + + // set/get parent instance + void setParentInstance(Instance* instance); + Instance* getParentInstance(); + + // copy one parameter to another, with a range (NULL means to copy all animation) + virtual OfxStatus copyFrom(const Instance &instance, OfxTime offset, const OfxRangeD* range); + + // callback which should set enabled state as appropriate + virtual void setEnabled(); + + // callback which should set secret state as appropriate + virtual void setSecret(); + + /// callback which should update label + virtual void setLabel(); + + /// callback which should set range + virtual void setRange(); + + /// callback which should set display range + virtual void setDisplayRange(); + + /// callback which should set evaluate on change + virtual void setEvaluateOnChange(); + + // va list calls below turn the var args (oh what a mistake) + // suite functions into virtual function calls on instances + // they are not to be overridden by host implementors by + // by the various typeed param instances so that they can + // deconstruct the var args lists + + /// get a value, implemented by instances to deconstruct var args + virtual OfxStatus getV(va_list arg); + + /// get a value, implemented by instances to deconstruct var args + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// set a value, implemented by instances to deconstruct var args + virtual OfxStatus setV(va_list arg); + + /// key a value, implemented by instances to deconstruct var args + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// derive a value, implemented by instances to deconstruct var args + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// integrate a value, implemented by instances to deconstruct var args + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + + /// overridden from Property::NotifyHook + virtual void notify(const std::string &name, bool single, int num); + }; + + class KeyframeParam { + public: + virtual OfxStatus getNumKeys(unsigned int &nKeys) const ; + virtual OfxStatus getKeyTime(int nth, OfxTime& time) const ; + virtual OfxStatus getKeyIndex(OfxTime time, int direction, int & index) const ; + virtual OfxStatus deleteKey(OfxTime time) ; + virtual OfxStatus deleteAllKeys() ; + + virtual ~KeyframeParam() { + } + }; + + class GroupInstance : public Instance { + protected: + std::vector _children; + public: + GroupInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + void setChildren(std::vector children); + const std::vector &getChildren() const; + }; + + class PageInstance : public Instance { + public: + PageInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + const std::map &getChildren() const; + protected : + mutable std::map _children; // if set in a notify hook, this need not be mutable + }; + + class IntegerInstance : public Instance, public KeyframeParam { + public: + IntegerInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(int&) = 0; + virtual OfxStatus get(OfxTime time, int&) = 0; + virtual OfxStatus set(int) = 0; + virtual OfxStatus set(OfxTime time, int) = 0; + + // probably derived class does not need to implement, default is an approximation + virtual OfxStatus derive(OfxTime time, int&) ; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, int&) ; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class ChoiceInstance : public Instance, public KeyframeParam { + public: + ChoiceInstance(Descriptor& descriptor, Param::SetInstance* instance = 0); + + // callback which should set option as appropriate + virtual void setOption(int num); + + // Deriving implementatation needs to overide these + virtual OfxStatus get(int&) = 0; + virtual OfxStatus get(OfxTime time, int&) = 0; + virtual OfxStatus set(int) = 0; + virtual OfxStatus set(OfxTime time, int) = 0; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// overridden from Instance + virtual void notify(const std::string &name, bool single, int num); + }; + + class DoubleInstance : public Instance, public KeyframeParam { + public: + DoubleInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(double&) = 0; + virtual OfxStatus get(OfxTime time, double&) = 0; + virtual OfxStatus set(double) = 0; + virtual OfxStatus set(OfxTime time, double) = 0; + virtual OfxStatus derive(OfxTime time, double&) = 0; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, double&) = 0; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class BooleanInstance : public Instance, public KeyframeParam { + public: + BooleanInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(bool&) = 0; + virtual OfxStatus get(OfxTime time, bool&) = 0; + virtual OfxStatus set(bool) = 0; + virtual OfxStatus set(OfxTime time, bool) = 0; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + }; + + class RGBAInstance : public Instance, public KeyframeParam { + public: + RGBAInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(double&,double&,double&,double&) = 0; + virtual OfxStatus get(OfxTime time, double&,double&,double&,double&) = 0; + virtual OfxStatus set(double,double,double,double) = 0; + virtual OfxStatus set(OfxTime time, double,double,double,double) = 0; + + // derived class does not need to implement, default is an approximation + virtual OfxStatus derive(OfxTime time, double&,double&,double&,double&) ; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, double&,double&,double&,double&) ; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class RGBInstance : public Instance, public KeyframeParam { + public: + RGBInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(double&,double&,double&) = 0; + virtual OfxStatus get(OfxTime time, double&,double&,double&) = 0; + virtual OfxStatus set(double,double,double) = 0; + virtual OfxStatus set(OfxTime time, double,double,double) = 0; + + // derived class does not need to implement, default is an approximation + virtual OfxStatus derive(OfxTime time, double&,double&,double&) ; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, double&,double&,double&) ; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class Double2DInstance : public Instance, public KeyframeParam { + public: + Double2DInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(double&,double&) = 0; + virtual OfxStatus get(OfxTime time, double&,double&) = 0; + virtual OfxStatus set(double,double) = 0; + virtual OfxStatus set(OfxTime time, double,double) = 0; + + // derived class does not need to implement, default is an approximation + virtual OfxStatus derive(OfxTime time, double&,double&) ; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, double&,double&) ; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class Integer2DInstance : public Instance, public KeyframeParam { + public: + Integer2DInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(int&,int&) = 0; + virtual OfxStatus get(OfxTime time, int&,int&) = 0; + virtual OfxStatus set(int,int) = 0; + virtual OfxStatus set(OfxTime time, int,int) = 0; + + // derived class does not need to implement, default is an approximation + virtual OfxStatus derive(OfxTime time, int&,int&) ; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, int&,int&) ; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class Double3DInstance : public Instance , public KeyframeParam{ + public: + Double3DInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + // Deriving implementatation needs to overide these + virtual OfxStatus get(double&,double&,double&) = 0; + virtual OfxStatus get(OfxTime time, double&,double&,double&) = 0; + virtual OfxStatus set(double,double,double) = 0; + virtual OfxStatus set(OfxTime time, double,double,double) = 0; + + // derived class does not need to implement, default is an approximation + virtual OfxStatus derive(OfxTime time, double&,double&,double&) ; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, double&,double&,double&) ; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class Integer3DInstance : public Instance, public KeyframeParam { + public: + Integer3DInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + virtual OfxStatus get(int&,int&,int&) = 0; + virtual OfxStatus get(OfxTime time, int&,int&,int&) = 0; + virtual OfxStatus set(int,int,int) = 0; + virtual OfxStatus set(OfxTime time, int,int,int) = 0; + + // derived class does not need to implement, default is an approximation + virtual OfxStatus derive(OfxTime time, int&,int&,int&) ; + virtual OfxStatus integrate(OfxTime time1, OfxTime time2, int&,int&,int&) ; + + /// implementation of var args function + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus deriveV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus integrateV(OfxTime time1, OfxTime time2, va_list arg); + }; + + class StringInstance : public Instance, public KeyframeParam { + std::string _returnValue; ///< location to hold temporary return value. Should delegate this to implementation!!! + public: + StringInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + + virtual OfxStatus get(std::string &) = 0; + virtual OfxStatus get(OfxTime time, std::string &) = 0; + virtual OfxStatus set(const char*) = 0; + virtual OfxStatus set(OfxTime time, const char*) = 0; + + /// implementation of var args function + /// Be careful: the char* is only valid until next API call + /// see http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#ArchitectureStrings + virtual OfxStatus getV(va_list arg); + + /// implementation of var args function + /// Be careful: the char* is only valid until next API call + /// see http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#ArchitectureStrings + virtual OfxStatus getV(OfxTime time, va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(va_list arg); + + /// implementation of var args function + virtual OfxStatus setV(OfxTime time, va_list arg); + }; + + class CustomInstance : public StringInstance { + public: + CustomInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : StringInstance(descriptor,instance) {} + }; + + class PushbuttonInstance : public Instance, public KeyframeParam { + public: + PushbuttonInstance(Descriptor& descriptor, Param::SetInstance* instance = 0) : Instance(descriptor,instance) {} + }; + + /// A set of parameters + /// + /// As we are the owning object we delete the params inside ourselves. It was tempting + /// to make params autoref objects and have shared ownership with the client code + /// but that adds complexity for no strong gain. + class SetInstance : public BaseSet { + protected: + std::map _params; ///< params by name + std::list _paramList; ///< params list + + public : + /// ctor + /// + /// The propery set being passed in belongs to the owning + /// plugin instance. + explicit SetInstance(); + + /// dtor. + virtual ~SetInstance(); + + /// get the params + const std::map &getParams() const; + + /// get the params + const std::list &getParamList() const; + + // get the param + Instance* getParam(const std::string &name) const { + std::map::const_iterator it = _params.find(name); + if(it!=_params.end()) + return it->second; + else + return 0; + } + + /// The inheriting plugin instance needs to set this up to deal with + /// plug-ins changing their own values. + virtual void paramChangedByPlugin(Param::Instance *param) = 0; + + /// add a param + virtual OfxStatus addParam(const std::string& name, Instance* instance); + + /// make a parameter instance + /// + /// Client host code needs to implement this + virtual Instance* newParam(const std::string& name, Descriptor& Descriptor) = 0; + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditBegin + /// + /// Client host code needs to implement this + virtual OfxStatus editBegin(const std::string& name) = 0; + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditEnd + /// + /// Client host code needs to implement this + virtual OfxStatus editEnd() = 0; + + }; + } + } +} + +#endif // OFXH_PARAM_H diff --git a/third_party/openfx/HostSupport/include/ofxhPluginAPICache.h b/third_party/openfx/HostSupport/include/ofxhPluginAPICache.h new file mode 100644 index 000000000..25c3d28ef --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhPluginAPICache.h @@ -0,0 +1,87 @@ + + +#ifndef OFX_PLUGIN_API_CACHE +#define OFX_PLUGIN_API_CACHE + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include + +#include "ofxhPropertySuite.h" + +namespace OFX +{ + namespace Host { + class Plugin; + class PluginBinary; + class PluginCache; + + namespace ImageEffect { + class ImageEffectDescriptor; + } + } +} + +namespace OFX +{ + namespace Host + { + namespace APICache { + + /// this acts as an interface for the Plugin Cache, handling api-specific cacheing + class PluginAPICacheI + { + protected: + std::string _apiName; + int _apiVersionMin, _apiVersionMax; + public: + PluginAPICacheI(const std::string &apiName, int verMin, int verMax) + : _apiName(apiName) + , _apiVersionMin(verMin) + , _apiVersionMax(verMax) + { + } + + virtual ~PluginAPICacheI() {} + + virtual void loadFromPlugin(Plugin *) const = 0; + + /// factory method, to create a new plugin (from binary) + virtual Plugin *newPlugin(PluginBinary *, int pi, OfxPlugin *plug) = 0; + + /// factory method, to create a new plugin (from the + virtual Plugin *newPlugin(PluginBinary *pb, int pi, const std::string &api, int apiVersion, const std::string &pluginId, + const std::string &rawId, int pluginMajorVersion, int pluginMinorVersion) = 0; + + virtual void beginXmlParsing(Plugin *) = 0; + virtual void xmlElementBegin(const std::string &, std::map) = 0; + virtual void xmlCharacterHandler(const std::string &) = 0; + virtual void xmlElementEnd(const std::string &) = 0; + virtual void endXmlParsing() = 0; + + virtual void saveXML(Plugin *, std::ostream &) const = 0; + + virtual void confirmPlugin(Plugin *) = 0; + + virtual bool pluginSupported(Plugin *, std::string &reason) const = 0; + + void registerInCache(OFX::Host::PluginCache &pluginCache); + }; + + /// helper function to build a property set from XML. Really should be a member of the property set!!! + void propertySetXMLRead(const std::string &el, std::map map, Property::Set &set, Property::Property*&); + + /// helper function to write a property set to XML. Really should be a member of the property set!!! + void propertySetXMLWrite(std::ostream &o, const Property::Set &set, int indent=0); + + /// helper function to write a single property from a set to XML. Really should be a member of the property set!!! + void propertyXMLWrite(std::ostream &o, const Property::Set &set, const std::string &name, int indent=0); + + } + } +} +#endif diff --git a/third_party/openfx/HostSupport/include/ofxhPluginCache.h b/third_party/openfx/HostSupport/include/ofxhPluginCache.h new file mode 100644 index 000000000..776e8d6c7 --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhPluginCache.h @@ -0,0 +1,432 @@ + + +#ifndef OFX_PLUGIN_CACHE_H +#define OFX_PLUGIN_CACHE_H + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include +#include + +#include + +#include "expat.h" + +#include "ofxCore.h" +#include "ofxhPropertySuite.h" +#include "ofxhPluginAPICache.h" +#include "ofxhBinary.h" + +namespace OFX { + + namespace Host { + + class Host; + + // forward delcarations + class PluginDesc; + class Plugin; + class PluginBinary; + class PluginCache; + + /// C++ version of the information kept inside an OfxPlugin struct + class PluginDesc { + protected : + std::string _pluginApi; ///< the API I implement + int _apiVersion; ///< the version of the API + + std::string _identifier; ///< the identifier of the plugin + std::string _rawIdentifier; ///< the original identifier of the plugin + int _versionMajor; ///< the plugin major version + int _versionMinor; ///< the plugin minor version + + public: + + const std::string &getPluginApi() const { + return _pluginApi; + } + + int getApiVersion() const { + return _apiVersion; + } + + const std::string &getIdentifier() const { + return _identifier; + } + + const std::string &getRawIdentifier() const { + return _rawIdentifier; + } + + int getVersionMajor() const { + return _versionMajor; + } + + int getVersionMinor() const { + return _versionMinor; + } + + PluginDesc() : _apiVersion(-1) { + } + + virtual ~PluginDesc() {} + + PluginDesc(const std::string &api, + int apiVersion, + const std::string &identifier, + const std::string &rawIdentifier, + int versionMajor, + int versionMinor) + : _pluginApi(api) + , _apiVersion(apiVersion) + , _identifier(identifier) + , _rawIdentifier(rawIdentifier) + , _versionMajor(versionMajor) + , _versionMinor(versionMinor) + { + } + + + /// constructor for the case where we have already loaded the plugin binary and + /// are populating this object from it + PluginDesc(OfxPlugin *ofxPlugin) { + _pluginApi = ofxPlugin->pluginApi; + _apiVersion = ofxPlugin->apiVersion; + _rawIdentifier = ofxPlugin->pluginIdentifier; + _identifier = ofxPlugin->pluginIdentifier; + + // Who says the pluginIdentifier is case-insensitive? OFX 1.3 spec doesn't mention this. + // http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#id472588 + //for (size_t i=0;i<_identifier.size();i++) { + // _identifier[i] = tolower(_identifier[i]); + //} + _versionMajor = ofxPlugin->pluginVersionMajor; + _versionMinor = ofxPlugin->pluginVersionMinor; + } + + }; + + /// class that we use to manipulate a plugin + class Plugin : public PluginDesc { + /// owned by the PluginBinary it lives inside + /// Plugins can only be pass about either by pointer or reference + private : + Plugin(const Plugin&) : PluginDesc() {} ///< hidden + Plugin &operator= (const Plugin&) {return *this;} ///< hidden + + protected : + PluginBinary *_binary; ///< the file I live inside + int _index; ///< where I live inside that file + public : + Plugin(); + + PluginBinary *getBinary() + { + return _binary; + } + + const PluginBinary *getBinary() const + { + return _binary; + } + + int getIndex() const + { + return _index; + } + + /// construct this based on the struct returned by the getNthPlugin() in the binary + Plugin(PluginBinary *bin, int idx, OfxPlugin *o) : PluginDesc(o), _binary(bin), _index(idx) + { + } + + /// construct me from the cache + Plugin(PluginBinary *bin, int idx, const std::string &api, + int apiVersion, const std::string &identifier, + const std::string &rawIdentifier, + int majorVersion, int minorVersion) + : PluginDesc(api, apiVersion, identifier, rawIdentifier, majorVersion, minorVersion) + , _binary(bin) + , _index(idx) + { + } + + virtual ~Plugin() { + } + + virtual APICache::PluginAPICacheI &getApiHandler() = 0; + + bool trumps(Plugin *other) { + int myMajor = getVersionMajor(); + int theirMajor = other->getVersionMajor(); + + int myMinor = getVersionMinor(); + int theirMinor = other->getVersionMinor(); + + if (myMajor > theirMajor) { + return true; + } + + if (myMajor == theirMajor && myMinor > theirMinor) { + return true; + } + + return false; + } + }; + + class PluginHandle; + + /// class that represents a binary file which holds plugins + class PluginBinary { + /// has a set of plugins inside it and which it owns + /// These are owned by a PluginCache + friend class PluginHandle; + + protected : + Binary _binary; ///< our binary object, abstracted layer ontop of OS calls, defined in ofxhBinary.h + std::string _filePath; ///< full path to the file + std::string _bundlePath; ///< path to the .bundle directory + std::vector _plugins; ///< my plugins + time_t _fileModificationTime; ///< used as a time stamp to check modification times, used for caching + off_t _fileSize; ///< file size last time we check, used for caching + bool _binaryChanged; ///< whether the timestamp/filesize in this cache is different from that in the actual binary + + public : + + /// create one from the cache. this will invoke the Binary() constructor which + /// will stat() the file. + explicit PluginBinary(const std::string &file, const std::string &bundlePath, time_t mtime, off_t size) + : _binary(file) + , _filePath(file) + , _bundlePath(bundlePath) + , _fileModificationTime(mtime) + , _fileSize(size) + , _binaryChanged(false) + { + if (isInvalid()) { + return; + } + if (_fileModificationTime != _binary.getTime() || _fileSize != _binary.getSize()) { + _binaryChanged = true; + } + } + + + /// constructor which will open a library file, call things inside it, and then + /// create Plugin objects as appropriate for the plugins exported therefrom + explicit PluginBinary(const std::string &file, const std::string &bundlePath, PluginCache *cache) + : _binary(file) + , _filePath(file) + , _bundlePath(bundlePath) + , _binaryChanged(false) + { + loadPluginInfo(cache); + } + + /// dtor + virtual ~PluginBinary(); + + + time_t getFileModificationTime() const { + return _fileModificationTime; + } + + off_t getFileSize() { + return _fileSize; + } + + const std::string &getFilePath() const { + return _filePath; + } + + const std::string &getBundlePath() const { + return _bundlePath; + } + + bool hasBinaryChanged() const { + return _binaryChanged; + } + + bool isLoaded() const { + return _binary.isLoaded(); + } + + bool isInvalid() const { + return _binary.isInvalid(); + } + + void addPlugin(Plugin *pe) { + _plugins.push_back(pe); + } + + void loadPluginInfo(PluginCache *); + + /// how many plugins? + int getNPlugins() const {return (int)_plugins.size(); } + + /// get a plugin + Plugin &getPlugin(int idx) {return *_plugins[idx];} + + /// get a plugin + const Plugin &getPlugin(int idx) const {return *_plugins[idx];} + }; + + /// wrapper class for Plugin/PluginBinary. use in a RAIA fashion to make sure the binary gets unloaded when needed and not before. + class PluginHandle { + PluginBinary *_b; + OfxPlugin *_op; + + public: + PluginHandle(Plugin *p, OFX::Host::Host *_host); + virtual ~PluginHandle(); + + OfxPlugin *getOfxPlugin() { + return _op; + } + + OfxPlugin *operator->() { + return _op; + } + }; + + /// for later + struct PluginCacheSupportedApi { + std::string api; + int minVersion; + int maxVersion; + APICache::PluginAPICacheI *handler; + + PluginCacheSupportedApi(const std::string &_api, int _minVersion, int _maxVersion, APICache::PluginAPICacheI *_handler) : + api(_api), minVersion(_minVersion), maxVersion(_maxVersion), handler(_handler) + { + } + + bool matches(const std::string &_api, int _version) const + { + if (_api == api && _version >= minVersion && _version <= maxVersion) { + return true; + } + return false; + } + }; + + /// Where we keep our plugins. + class PluginCache { + protected : + OFX::Host::Property::PropSpec* _hostSpec; + + std::list _pluginPath; ///< list of directories to look in + std::set _nonrecursePath; ///< list of directories to look in (non-recursively) + std::list _pluginDirs; ///< list of directories we found + std::list _binaries; ///< all the binaries we know about, we own these + std::list _plugins; ///< all the plugins inside the binaries, we don't own these, populated from _binaries + std::set _knownBinFiles; + + PluginBinary *_xmlCurrentBinary; + Plugin *_xmlCurrentPlugin; + + std::list _apiHandlers; + + void scanDirectory(std::set &foundBinFiles, const std::string &dir, bool recurse); + + bool _ignoreCache; + std::string _cacheVersion; + + bool _dirty; + bool _enablePluginSeek; ///< Turn off to make all seekPluginFile() calls return an empty string + + static PluginCache* gPluginCachePtr; ///< singleton plugin cache + + public: + /// ctor, which inits _pluginPath to default locations and not much else + PluginCache(); + + /// dtor + ~PluginCache(); + + /// get our plugin cache + static PluginCache* getPluginCache(); + + /// clear our plugin cache + static void clearPluginCache(); + + /// get the list in which plugins are sought + const std::list &getPluginPath() { + return _pluginPath; + } + + /// was the cache outdated? + bool dirty() const { + return _dirty; + } + + /// add a file to the plugin path + void addFileToPath(const std::string &f, bool recurse=true) { + _pluginPath.push_back(f); + if (!recurse) { + _nonrecursePath.insert(f); + } + } + + /// prepend a file to the plugin path + void prependFileToPath(const std::string &f, bool recurse=true) { + _pluginPath.push_front(f); + if (!recurse) { + _nonrecursePath.insert(f); + } + } + + /// specify which subdirectory of /usr/OFX or equivilant + /// (as well as 'Plugins') to look in for plugins. + void setPluginHostPath(const std::string &hostId); + + /// set the version string to write to the cache, + /// and also that we expect on cachess read in + void setCacheVersion(const std::string &cacheVersion) { + _cacheVersion = cacheVersion; + } + + // populate the cache. must call scanPluginFiles() after to check for changes. + void readCache(std::istream &is); + + // seek a particular file on the OFX plugin path + std::string seekPluginFile(const std::string &baseName) const; + + /// Sets behaviour of seekPluginFile(). + /// Enable (the default): normal operation; disable: returns an empty string instead + void setPluginSeekEnabled(bool enabled) { _enablePluginSeek = enabled; } + + /// scan for plugins + void scanPluginFiles(); + + // write the plugin cache output file to the given stream + void writePluginCache(std::ostream &os) const; + + // callback function for the XML + void elementBeginCallback(void *userData, const XML_Char *name, const XML_Char **attrs); + void elementCharCallback(void *userData, const XML_Char *data, int len); + void elementEndCallback(void *userData, const XML_Char *name); + + /// register an API cache handler + void registerAPICache(const std::string &api, int min, int max, APICache::PluginAPICacheI *apiCache) { + _apiHandlers.push_back(PluginCacheSupportedApi(api, min, max, apiCache)); + } + + /// find the API cache handler for the given api/apiverson + APICache::PluginAPICacheI* findApiHandler(const std::string &api, int apiver); + + /// obtain a list of plugins to walk through + const std::list &getPlugins() const { + return _plugins; + } + }; + + } +} + +#endif diff --git a/third_party/openfx/HostSupport/include/ofxhProgress.h b/third_party/openfx/HostSupport/include/ofxhProgress.h new file mode 100644 index 000000000..5e1a85f7a --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhProgress.h @@ -0,0 +1,34 @@ + + + +#ifndef _ofxhProgress_h_ +#define _ofxhProgress_h_ + +#include "ofxProgress.h" + +namespace OFX { + namespace Host { + namespace Progress { + + /// Things that display progress derive from this ABC and implement the following + /// functions. + class ProgressI { + public : + virtual ~ProgressI() {} + + /// Start doing progress. + virtual void progressStart(const std::string &message, const std::string &messageid) = 0; + + /// finish yer progress + virtual void progressEnd() = 0; + + /// set the progress to some level of completion, returns + /// false if you should abandon processing, true to continue + virtual bool progressUpdate(double t) = 0; + }; + + } // namespace progress + } // namespace Host +} // namespace OFX + +#endif diff --git a/third_party/openfx/HostSupport/include/ofxhPropertySuite.h b/third_party/openfx/HostSupport/include/ofxhPropertySuite.h new file mode 100644 index 000000000..cb73d922d --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhPropertySuite.h @@ -0,0 +1,545 @@ + + +#ifndef OFX_PROPERTY_SUITE_H +#define OFX_PROPERTY_SUITE_H +#include "ofxCore.h" +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include +#include + +namespace OFX { + namespace Host { + namespace Property { + /// simple function to turn a thing into a std string + template inline std::string castToString(T i) { + std::ostringstream o; + o << i; + return o.str(); + } + + /// simple function to turn a string into an int + inline int stringToInt(const std::string &s) { + std::istringstream is(s); + int number; + is >> number; + return number; + } + + /// simple function to turn a string into a double + inline double stringToDouble(const std::string &s) { + std::istringstream is(s); + double number; + is >> number; + return number; + } + + // forward declarations + class Property; + class Set; + + /// exception, representing an OfxStatus + class Exception { + OfxStatus _stat; + + public: + /// ctor + Exception(OfxStatus stat) : _stat(stat) + { + } + + /// get the status + OfxStatus getStatus() const + { + return _stat; + } + }; + + /// type of a property + enum TypeEnum { + eNone = -1, + eInt = 0, + eDouble = 1, + eString = 2, + ePointer = 3 + }; + + /// type holder, for integers, used to template up int properties + struct IntValue { + typedef int APIType; ///< C type of the property that is passed across the raw API + typedef int APITypeConstless; ///< C type of the property that is passed across the raw API, without any const it + typedef int Type; ///< Type we actually hold and deal with the propery in everything by the raw API + typedef int ReturnType; ///< type to return from a function call + static const TypeEnum typeCode = eInt; + static int kEmpty; + }; + + /// type holder, for doubles, used to template up double properties + struct DoubleValue { + typedef double APIType; + typedef double APITypeConstless; + typedef double Type; + typedef double ReturnType; ///< type to return from a function call + static const TypeEnum typeCode = eDouble; + static double kEmpty; + }; + + /// type holder, for pointers, used to template up pointer properties + struct PointerValue { + typedef void *APIType; + typedef void *APITypeConstless; + typedef void *Type; + typedef void *ReturnType; ///< type to return from a function call + static const TypeEnum typeCode = ePointer; + static void *kEmpty; + }; + + /// type holder, for strings, used to template up string properties + struct StringValue { + typedef const char *APIType; + typedef char *APITypeConstless; + typedef std::string Type; + typedef const std::string &ReturnType; ///< type to return from a function call + static const TypeEnum typeCode = eString; + static std::string kEmpty; + }; + + /// array representing the names of the various types, in order of TypeEnum + extern const char *gTypeNames[]; + + /// Sits on a property and can override the local property value when a value is being fetched + /// only one of these can be in any property (as the thing has only a single value). + class GetHook { + public : + /// dtor + virtual ~GetHook() + { + } + + /// We specialise this to do some magic so that it calls get string/int/double/pointer appropriately + /// this is what is called by the propertytemplate code to fetch values out of a hook. + template typename T::ReturnType getProperty(const std::string &name, int index=0) const; + + /// We specialise this to do some magic so that it calls get int/double/pointer appropriately + /// this is what is called by the propertytemplate code to fetch values out of a hook. + template void getPropertyN(const std::string &name, typename T::APIType *values, int count) const; + + /// override this to fetch a single value at the given index. + virtual const std::string& getStringProperty(const std::string &name, int index = 0) const; + + /// override this to fetch a multiple values in a multi-dimension property + virtual void getStringPropertyN(const std::string &name, const char** values, int count) const; + + /// override this to fetch a single value at the given index. + virtual int getIntProperty(const std::string &name, int index = 0) const; + + /// override this to fetch a multiple values in a multi-dimension property + virtual void getIntPropertyN(const std::string &name, int *values, int count) const; + + /// override this to fetch a single value at the given index. + virtual double getDoubleProperty(const std::string &name, int index = 0) const; + + /// override this to fetch a multiple values in a multi-dimension property + virtual void getDoublePropertyN(const std::string &name, double *values, int count) const; + + /// override this to fetch a single value at the given index. + virtual void *getPointerProperty(const std::string &name, int index = 0) const; + + /// override this to fetch a multiple values in a multi-dimension property + virtual void getPointerPropertyN(const std::string &name, void **values, int count) const; + + /// override this to fetch the dimension size. + virtual int getDimension(const std::string &name) const; + + /// override this to handle a reset(). + virtual void reset(const std::string &name); + }; + + /// Sits on a property and is called when the local property is being set. + /// It notify or notifyN is called whenever the plugin sets a property + /// Many of these can sit on a property, as various objects will need to know when a property + /// has been changed. On notification you should fetch properties with a 'raw' call, rather + /// than the standard calls, as you may be fetching through a getHook and you won't see + /// the local value that has been shoved into the property. + class NotifyHook { + public : + /// dtor + virtual ~NotifyHook() {} + + /// override this to be notified when a property changes + /// \arg name is the name of the property just set + /// \arg singleValue is whether setProperty on a single index was call, otherwise N properties were set + /// \arg indexOrN is the index if single value is true, or the count if singleValue is false + virtual void notify(const std::string &name, bool singleValue, int indexOrN) = 0; + }; + + /// base class for all properties + class Property { + protected : + std::string _name; ///< name of this property + TypeEnum _type; ///< type of this property + int _dimension; ///< the fixed dimension of this property + bool _pluginReadOnly; ///< set is forbidden through suite: value may still change between get() calls + std::vector _notifyHooks; ///< hooks to call whenever the property is set + GetHook *_getHook; ///< if we are not storing props locally, they are stored via fetching from here + + friend class Set; + public : + /// ctor + Property(const std::string &name, + TypeEnum type, + int dimension = 1, + bool pluginReadOnly=false); + + /// copy ctor + Property(const Property &other); + + /// dtor + virtual ~Property() + { + } + + /// is it read only? + bool getPluginReadOnly() const {return _pluginReadOnly; } + + /// change the state of readonlyness + void setPluginReadOnly(bool v) {_pluginReadOnly = v;} + + /// override this to return a clone of the property + virtual Property *deepCopy() = 0; + + /// get the name of this property + const std::string &getName() + { + return _name; + } + + /// get the type of this property + TypeEnum getType() + { + return _type; + } + + /// add a notify hook + void addNotifyHook(NotifyHook *hook) + { + _notifyHooks.push_back(hook); + } + + /// set the get hook + void setGetHook(GetHook *hook) + { + _getHook = hook; + } + + /// call notify on the contained notify hooks + void notify(bool single, int indexOrN); + + // get the current dimension of this property + virtual int getDimension() const = 0; + + /// get the fixed dimension of this property + int getFixedDimension() const { + return _dimension; + } + + /// are we a fixed dim property + bool isFixedSize() const + { + return _dimension != 0; + } + + /// reset this property to the default + virtual void reset() = 0; + + // get a string representing the value of this property at element nth + virtual std::string getStringValue(int nth) = 0; + }; + + /// this represents a generic property. + /// template parameter T is the type descriptor of the + /// type of property to model. the class holds an internal _value vector which can be used + /// to store the values. if set and get hooks are installed, these will be called instead + /// of using this variable. + /// Make sure that T::ReturnType is const if appropriate, as no extra qualifiers are applied here. + template + class PropertyTemplate : public Property + { + public : + typedef typename T::Type Type; + typedef typename T::ReturnType ReturnType; + typedef typename T::APIType APIType; + + protected : + /// this is the present value of the property + std::vector _value; + + /// this is the default value of the property + std::vector _defaultValue; + + public : + /// constructor + PropertyTemplate(const std::string &name, + int dimension, + bool pluginReadOnly, + APIType defaultValue); + + PropertyTemplate(const PropertyTemplate &pt); + + PropertyTemplate *deepCopy() { + return new PropertyTemplate(*this); + } + + virtual ~PropertyTemplate() + { + } + + /// get the vector + const std::vector &getValues() + { + return _value; + } + + // get multiple values + void getValueN(APIType *value, int count) const; + +#ifdef WINDOWS +#pragma warning( disable : 4181 ) +#endif + /// get one value + const ReturnType getValue(int index=0) const; + + /// get one value, without going through the getHook + const ReturnType getValueRaw(int index=0) const; + +#ifdef WINDOWS +#pragma warning( default : 4181 ) +#endif + // get multiple values, without going through the getHook + void getValueNRaw(APIType *value, int count) const; + + /// set one value + void setValue(const Type &value, int index=0); + + /// set multiple values + void setValueN(const APIType *value, int count); + + /// reset + void reset(); + + /// get the size of the vector + int getDimension() const; + + /// return the value as a string + inline std::string getStringValue(int idx) { + return castToString(_value[idx]); + } + }; + + + typedef PropertyTemplate Int; /// Our int property + typedef PropertyTemplate Double; /// Our double property + typedef PropertyTemplate String; /// Our string property + typedef PropertyTemplate Pointer; /// Our pointer property + + /// A class that is used to initialise a property set. Feed in an array of these to + /// a property and it will construct a bunch of properties. Terminate such an array + /// with an empty (all zero) set. + struct PropSpec { + const char *name; ///< name of the property + TypeEnum type; ///< type + int dimension; ///< fixed dimension of the property, set to zero if variable dimension + bool readonly; ///< is the property plug-in read only + const char *defaultValue; ///< Default value as a string. Pointers are ignored and always null. + }; + static const PropSpec propSpecEnd = {0, eNone, 0, false, 0}; + + /// A std::map of properties by name + typedef std::map PropertyMap; + + + //................................................................................ + /// Class that holds a set of properties and manipulates them + /// The 'fetch' methods return a property object. + /// The 'get' methods return a property value + class Set { + private : + static const int kMagic = 0x12082007; ///< magic number for property sets, and Connie's birthday :-) + const int _magic; ///< to check for handles being nice + + protected : + PropertyMap _props; ///< Our properties. + + /// chained property set, which is read only + /// these are searched on a get if not found + /// on a local search + Set *_chainedSet; + + /// hide assignment + void operator=(const Set &); + + /// set a particular property + template void setProperty(const std::string &property, int index, const typename T::Type &value); + + /// set the first N of a particular property + template void setPropertyN(const std::string &property, int count, const typename T::APIType *value); + + /// get a particular property + template typename T::ReturnType getProperty(const std::string &property, int index) const; + + /// get the first N of a particular property + template void getPropertyN(const std::string &property, int index, typename T::APIType *v) const; + + /// get a particular property without going through any getHook + template typename T::ReturnType getPropertyRaw(const std::string &property, int index) const; + + /// get a particular property without going through any getHook + template void getPropertyRawN(const std::string &property, int count, typename T::APIType *v) const; + + public : + /// take an array of of PropSpecs (which must be terminated with an entry in which + /// ->name is null), and turn these into a Set + explicit Set(const PropSpec *); + + /// deep copies the property set + explicit Set(const Set &); + + /// empty ctor + explicit Set(); + + /// destructor + virtual ~Set(); + + /// adds a bunch of properties from PropSpec + void addProperties(const PropSpec *); + + /// add one new property + void createProperty(const PropSpec &s); + + /// add one new property + void addProperty(Property *prop); + + /// set the chained property set + void setChainedSet(Set *s) {_chainedSet = s;} + + /// grab the internal properties map + const PropertyMap &getProperties() const + { + return _props; + } + + /// set the get hook for a particular property. users may need to call particular + /// specialised versions of this. + void setGetHook(const std::string &s, GetHook *ghook) const; + + /// add a set hook for a particular property. users may need to call particular + /// specialised versions of this. + void addNotifyHook(const std::string &name, NotifyHook *hook) const; + + /// Fetchs a pointer to a property of the given name, following the property chain if the + /// 'followChain' arg is not false. + Property *fetchProperty(const std::string &name, bool followChain = false) const; + + /// get property with the particular name and type. if the property is + /// missing or is of the wrong type, return an error status. if this is a sloppy + /// property set and the property is missing, a new one will be created of the right + /// type + template bool fetchTypedProperty(const std::string &name, T *&prop, bool followChain = false) const; + + /// retrieve the nameed string property + String *fetchStringProperty(const std::string &name, bool followChain = false) const; + + /// retrieve the named double property + Double *fetchDoubleProperty(const std::string &name, bool followChain = false) const; + + /// retrieve the named double property + Pointer *fetchPointerProperty(const std::string &name, bool followChain = false) const; + + /// retrieve the named double property + Int *fetchIntProperty(const std::string &name, bool followChain = false) const; + + + + /// get a particular int property without fetching via a get hook, useful for notifies + int getIntPropertyRaw(const std::string &property, int index = 0) const; + + /// get a particular double property without fetching via a get hook, useful for notifies + double getDoublePropertyRaw(const std::string &property, int index = 0) const; + + /// get a particular pointer property without fetching via a get hook, useful for notifies + void *getPointerPropertyRaw(const std::string &property, int index = 0) const; + + /// get a particular string property + const std::string &getStringPropertyRaw(const std::string &property, int index = 0) const; + + /// get the value of a particular string property + const std::string &getStringProperty(const std::string &property, int index = 0) const; + + /// get the value of a particular int property + int getIntProperty(const std::string &property, int index = 0) const; + + /// get the value of a particular double property + void getIntPropertyN(const std::string &property, int *v, int N) const; + + /// get the value of a particular double property + double getDoubleProperty(const std::string &property, int index = 0) const; + + /// get the value of a particular double property + void getDoublePropertyN(const std::string &property, double *v, int N) const; + + /// get the value of a particular pointer property + void *getPointerProperty(const std::string &property, int index = 0) const; + + + + /// set a particular string property without fetching via a get hook, useful for notifies + void setStringProperty(const std::string &property, const std::string &value, int index = 0); + + /// get a particular int property + void setIntProperty(const std::string &property, int v, int index = 0); + + /// get a particular double property + void setIntPropertyN(const std::string &property, const int *v, int N); + + /// get a particular double property + void setDoubleProperty(const std::string &property, double v, int index = 0); + + /// get a particular double property + void setDoublePropertyN(const std::string &property, const double *v, int N); + + /// get a particular double property + void setPointerProperty(const std::string &property, void *v, int index = 0); + + + + /// get the dimension of a particular property + int getDimension(const std::string &property) const; + + /// is the given string one of the values of a multi-dimensional string prop + /// this returns a non negative index if it is found, otherwise, -1 + int findStringPropValueIndex(const std::string &propName, + const std::string &propValue) const; + + + /// get a handle on this object for passing to the C API + OfxPropertySetHandle getHandle() const + { + return (OfxPropertySetHandle)this; + } + + /// is this a nice property set, or a dodgy pointer passed back to us + bool verifyMagic() { return _magic == kMagic; } + }; + + + /// return the OFX function suite that manages properties + const void *GetSuite(int version); + } + } +} + +#endif diff --git a/third_party/openfx/HostSupport/include/ofxhTimeLine.h b/third_party/openfx/HostSupport/include/ofxhTimeLine.h new file mode 100644 index 000000000..95f73f65e --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhTimeLine.h @@ -0,0 +1,34 @@ + + + +#ifndef _ofxhTimeLine_h_ +#define _ofxhTimeLine_h_ + +#include "ofxTimeLine.h" + + + + namespace OFX::Host::TimeLine { + + /// Things that implement timeline controls derive from this ABC and implement the following + /// functions. + class TimeLineI { + public : + virtual ~TimeLineI() = default; + + /// get the current time on the timeline. This is not necessarily the same + /// time as being passed to an action (eg render) + virtual double timeLineGetTime() = 0; + + /// set the timeline to a specific time + virtual void timeLineGotoTime(double t) = 0; + + /// get the first and last times available on the effect's timeline + virtual void timeLineGetBounds(double &t1, double &t2) = 0; + }; + + } // namespace progress + + + +#endif diff --git a/third_party/openfx/HostSupport/include/ofxhUtilities.h b/third_party/openfx/HostSupport/include/ofxhUtilities.h new file mode 100644 index 000000000..30d84c024 --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhUtilities.h @@ -0,0 +1,156 @@ + + +#ifndef _ofxhUtilities_h_ +#define _ofxhUtilities_h_ + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include "ofxCore.h" +#include "ofxImageEffect.h" + +// macro that intercepts any exception that passes through a plugin's entry point, and transforms it into a message on the host using Host::vmessage() +#define CatchAllSetStatus(stat,host,plugin,msg) \ + catch ( const std::bad_alloc& ba ) { \ + (stat) = kOfxStatErrMemory; \ + if (host) { \ + try { \ + (host)->message(kOfxMessageError, "", \ + "%s: Memory allocation error occured in plugin %s (%s)", \ + (msg), (plugin)->pluginIdentifier, ba.what()); \ + } catch (...) { \ + } \ + } \ + } catch ( const std::exception &e ) { \ + (stat) = kOfxStatFailed; \ + if (host) { \ + try { \ + (host)->message(kOfxMessageError, "", \ + "%s: Exception occured in plugin %s (%s)", \ + (msg), (plugin)->pluginIdentifier, e.what()); \ + } catch (...) { \ + } \ + } \ + } catch ( ... ) { \ + (stat) = kOfxStatFailed; \ + if (host) { \ + try { \ + (host)->message(kOfxMessageError, "", \ + "%s:Exception occured in plugin %s", \ + (msg), (plugin)->pluginIdentifier); \ + } catch (...) { \ + } \ + } \ + } + +namespace OFX { + + /// class that is a std::vector of std::strings + typedef std::vector StringVec; + + /// class that is a std::vector of std::strings + inline void SetStringVecValue(StringVec &sv, const std::string &value, size_t index = 0) + { + size_t size = sv.size(); + if(size <= index) { + while(size < index) { + sv.push_back(""); + ++size; + } + sv.push_back(value); + } + else + sv[index] = value; + } + + /// get me deepest bit depth + std::string FindDeepestBitDepth(const std::string &s1, const std::string &s2); + + /// get the min value + template inline T Minimum(const T &a, const T &b) + { + return a < b ? a : b; + } + + /// get the min value + template inline T Maximum(const T &a, const T &b) + { + return a > b ? a : b; + } + + /// clamp the value + template inline T Clamp(const T &v, const T &mn, const T &mx) + { + if(v < mn) return mn; + if(v > mx) return mx; + return v; + } + + /// clamp the rect in v to the given bounds + inline OfxRectD Clamp(const OfxRectD &v, + const OfxRectD &bounds) + { + OfxRectD r; + r.x1 = Clamp(v.x1, bounds.x1, bounds.x2); + r.x2 = Clamp(v.x2, bounds.x1, bounds.x2); + r.y1 = Clamp(v.y1, bounds.y1, bounds.y2); + r.y2 = Clamp(v.y2, bounds.y1, bounds.y2); + return r; + } + + /// get the union of the two rects + inline OfxRectD Union(const OfxRectD &a, + const OfxRectD &b) + { + OfxRectD r; + r.x1 = Minimum(a.x1, b.x1); + r.x2 = Maximum(a.x2, b.x2); + r.y1 = Minimum(a.y1, b.y1); + r.y2 = Maximum(a.y2, b.y2); + return r; + } + + inline const char* StatStr(OfxStatus stat) { + switch(stat) { + case kOfxStatOK: + return "kOfxStatOK"; + case kOfxStatFailed: + return "kOfxStatFailed"; + case kOfxStatErrFatal: + return "kOfxStatErrFatal"; + case kOfxStatErrUnknown: + return "kOfxStatErrUnknown"; + case kOfxStatErrMissingHostFeature: + return "kOfxStatErrMissingHostFeature"; + case kOfxStatErrUnsupported: + return "kOfxStatErrUnsupported"; + case kOfxStatErrExists: + return "kOfxStatErrExists"; + case kOfxStatErrFormat: + return "kOfxStatErrFormat"; + case kOfxStatErrMemory: + return "kOfxStatErrMemory"; + case kOfxStatErrBadHandle: + return "kOfxStatErrBadHandle"; + case kOfxStatErrBadIndex: + return "kOfxStatErrBadIndex"; + case kOfxStatErrValue: + return "kOfxStatErrValue"; + case kOfxStatErrImageFormat: + return "kOfxStatErrImageFormat"; + case kOfxStatReplyYes: + return "kOfxStatReplyYes"; + case kOfxStatReplyNo: + return "kOfxStatReplyNo"; + case kOfxStatReplyDefault: + return "kOfxStatReplyDefault"; + default: + return "(unknown error code)"; + } + } +} +#endif + diff --git a/third_party/openfx/HostSupport/include/ofxhXml.h b/third_party/openfx/HostSupport/include/ofxhXml.h new file mode 100644 index 000000000..194397914 --- /dev/null +++ b/third_party/openfx/HostSupport/include/ofxhXml.h @@ -0,0 +1,74 @@ + + +#ifndef OFX_XML_H +#define OFX_XML_H + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +namespace OFX { + + namespace XML { + + inline std::string escape(const std::string &s) { + std::string ns; + for (size_t i=0;i': + ns += ">"; + break; + case '&': + ns += "&"; + break; + case '"': + ns += """; + break; + case '\'': + ns += "'"; + break; + default: { + unsigned char c = (unsigned char)(s[i]); + // Escape even the whitespace characters '\n' '\r' '\t', although they are valid + // XML, because they would be converted to space when re-read. + // See http://www.w3.org/TR/xml/#AVNormalize + if ((0x01 <= c && c <= 0x1f) || (0x7F <= c && c <= 0x9F)) { + // these characters must be escaped in XML 1.1 + // http://www.w3.org/TR/xml/#sec-references + ns += "&#x"; + if (c > 0xf) { + int d = c / 0x10; + ns += d < 10 ? ('0' + d) : ('A' + d - 10); + } + int d = c & 0xf; + ns += d < 10 ? ('0' + d) : ('A' + d - 10); + ns += ';'; + } else { + ns += s[i]; + } + } break; + } + } + return ns; + } + + inline std::string attribute(const std::string &at, const std::string &val) + { + return at + "=" + "\"" + escape(val) + "\" "; + } + + inline std::string attribute(const std::string &st, int val) + { + std::ostringstream o; + o << val; + return attribute(st, o.str()); + } + + } +} + +#endif diff --git a/third_party/openfx/HostSupport/src/ofxhBinary.cpp b/third_party/openfx/HostSupport/src/ofxhBinary.cpp new file mode 100755 index 000000000..265afbd8d --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhBinary.cpp @@ -0,0 +1,104 @@ + + +#include "ofxhBinary.h" + +using namespace OFX; + +Binary::Binary(const std::string &binaryPath): _binaryPath(binaryPath), _invalid(false), _dlHandle(0), _users(0) +{ + struct stat sb; + if (stat(binaryPath.c_str(), &sb) != 0) { + _invalid = true; + _time = 0; + _size = 0; + } + else { + _time = sb.st_mtime; + _size = sb.st_size; + } +} + + +// actually open the binary. +void Binary::load() +{ + if(_invalid) + return; + +#if defined (UNIX) + _dlHandle = dlopen(_binaryPath.c_str(), RTLD_LAZY|RTLD_LOCAL); +#else + _dlHandle = LoadLibrary(_binaryPath.c_str()); +#endif + if (_dlHandle == 0) { +#if defined (UNIX) + std::cerr << "couldn't open library " << _binaryPath << " because " << dlerror() << std::endl; +#else + LPVOID lpMsgBuf = NULL; + DWORD err = GetLastError(); + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + + std::cerr << "couldn't open library " << _binaryPath << " because " << (char*)lpMsgBuf << " was returned" << std::endl; + if (lpMsgBuf != NULL) { + LocalFree(lpMsgBuf); + } +#endif + _invalid = true; + } +} + +/// close the binary +void Binary::unload() { + if (_dlHandle != 0) { +#if defined (UNIX) + dlclose(_dlHandle); +#elif defined (WINDOWS) + FreeLibrary(_dlHandle); +#endif + _dlHandle = 0; + } +} + +/// look up a symbol in the binary file and return it as a pointer. +/// returns null pointer if not found, or if the library is not loaded. +void *Binary::findSymbol(const std::string &symbol) { + if (_dlHandle != 0) { +#if defined(UNIX) + return dlsym(_dlHandle, symbol.c_str()); +#elif defined (WINDOWS) + return (void*)GetProcAddress(_dlHandle, symbol.c_str()); +#endif + } else { + return 0; + } +} + + +void Binary::ref() +{ + if (_users == 0) { + load(); + } + _users++; +} + +void Binary::unref() +{ + _users--; + if (_users == 0) { + unload(); + } + if (_users < 0) { + _users = 0; + } +} + + diff --git a/third_party/openfx/HostSupport/src/ofxhClip.cpp b/third_party/openfx/HostSupport/src/ofxhClip.cpp new file mode 100755 index 000000000..aea7f7610 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhClip.cpp @@ -0,0 +1,655 @@ + + +#include + +// ofx +#include "ofxCore.h" + +// ofx host +#include "ofxhBinary.h" +#include "ofxhPropertySuite.h" +#include "ofxhClip.h" +#include "ofxhPropertySuite.h" +#include "ofxhImageEffect.h" +#ifdef OFX_SUPPORTS_OPENGLRENDER +#include "ofxGPURender.h" +#endif + +namespace OFX { + + namespace Host { + + namespace ImageEffect { + + /// properties common to the desciptor and instance + /// the desc and set them, the instance cannot + static const Property::PropSpec clipDescriptorStuffs[] = { + { kOfxPropType, Property::eString, 1, true, kOfxTypeClip }, + { kOfxPropName, Property::eString, 1, true, "SET ME ON CONSTRUCTION" }, + { kOfxPropLabel, Property::eString, 1, false, "" } , + { kOfxPropShortLabel, Property::eString, 1, false, "" }, + { kOfxPropLongLabel, Property::eString, 1, false, "" }, + { kOfxImageEffectPropSupportedComponents, Property::eString, 0, false, "" }, + { kOfxImageEffectPropTemporalClipAccess, Property::eInt, 1, false, "0" }, + { kOfxImageClipPropOptional, Property::eInt, 1, false, "0" }, + { kOfxImageClipPropIsMask, Property::eInt, 1, false, "0" }, + { kOfxImageClipPropFieldExtraction, Property::eString, 1, false, kOfxImageFieldDoubled }, + { kOfxImageEffectPropSupportsTiles, Property::eInt, 1, false, "1" }, + Property::propSpecEnd, + }; + + //////////////////////////////////////////////////////////////////////////////// + // props to clips descriptors and instances + + // base ctor, for a descriptor + ClipBase::ClipBase() + : _properties(clipDescriptorStuffs) + { + } + + /// props to clips and + ClipBase::ClipBase(const ClipBase &v) + : _properties(v._properties) + { + /// we are an instance, we need to reset the props to read only + const Property::PropertyMap &map = _properties.getProperties(); + Property::PropertyMap::const_iterator i; + for(i = map.begin(); i != map.end(); ++i) { + (*i).second->setPluginReadOnly(false); + } + } + + /// name of the clip + const std::string &ClipBase::getShortLabel() const + { + const std::string &s = _properties.getStringProperty(kOfxPropShortLabel); + if(s == "") { + return getLabel(); + } + return s; + } + + /// name of the clip + const std::string &ClipBase::getLabel() const + { + const std::string &s = _properties.getStringProperty(kOfxPropLabel); + if(s == "") { + return getName(); + } + return s; + } + + /// name of the clip + const std::string &ClipBase::getLongLabel() const + { + const std::string &s = _properties.getStringProperty(kOfxPropLongLabel); + if(s == "") { + return getLabel(); + } + return s; + } + + /// return a std::vector of supported comp + const std::vector &ClipBase::getSupportedComponents() const + { + Property::String *p = _properties.fetchStringProperty(kOfxImageEffectPropSupportedComponents); + assert(p != NULL); + return p->getValues(); + } + + /// is the given component supported + bool ClipBase::isSupportedComponent(const std::string &comp) const + { + return _properties.findStringPropValueIndex(kOfxImageEffectPropSupportedComponents, comp) != -1; + } + + /// does the clip do random temporal access + bool ClipBase::temporalAccess() const + { + return _properties.getIntProperty(kOfxImageEffectPropTemporalClipAccess) != 0; + } + + /// is the clip optional + bool ClipBase::isOptional() const + { + return _properties.getIntProperty(kOfxImageClipPropOptional) != 0; + } + + /// is the clip a nominal 'mask' clip + bool ClipBase::isMask() const + { + return _properties.getIntProperty(kOfxImageClipPropIsMask) != 0; + } + + /// how does this clip like fielded images to be presented to it + const std::string &ClipBase::getFieldExtraction() const + { + return _properties.getStringProperty(kOfxImageClipPropFieldExtraction); + } + + /// is the clip a nominal 'mask' clip + bool ClipBase::supportsTiles() const + { + return _properties.getIntProperty(kOfxImageEffectPropSupportsTiles) != 0; + } + + const Property::Set& ClipBase::getProps() const + { + return _properties; + } + + Property::Set& ClipBase::getProps() + { + return _properties; + } + + /// get a handle on the properties of the clip descriptor for the C api + OfxPropertySetHandle ClipBase::getPropHandle() const + { + return _properties.getHandle(); + } + + /// get a handle on the clip descriptor for the C api + OfxImageClipHandle ClipBase::getHandle() const + { + return (OfxImageClipHandle)this; + } + + //////////////////////////////////////////////////////////////////////////////// + /// descriptor + ClipDescriptor::ClipDescriptor(const std::string &name) + : ClipBase() + { + _properties.setStringProperty(kOfxPropName,name); + } + + /// extra properties for the instance, these are fetched from the host + /// via a get hook and some virtuals + static const Property::PropSpec clipInstanceStuffs[] = { + { kOfxImageEffectPropPixelDepth, Property::eString, 1, true, kOfxBitDepthNone }, + { kOfxImageEffectPropComponents, Property::eString, 1, true, kOfxImageComponentNone }, + { kOfxImageClipPropUnmappedPixelDepth, Property::eString, 1, true, kOfxBitDepthNone }, + { kOfxImageClipPropUnmappedComponents, Property::eString, 1, true, kOfxImageComponentNone }, + { kOfxImageEffectPropPreMultiplication, Property::eString, 1, true, kOfxImageOpaque }, + { kOfxImagePropPixelAspectRatio, Property::eDouble, 1, true, "1.0" }, + { kOfxImageEffectPropFrameRate, Property::eDouble, 1, true, "25.0" }, + { kOfxImageEffectPropFrameRange, Property::eDouble, 2, true, "0" }, + { kOfxImageClipPropFieldOrder, Property::eString, 1, true, kOfxImageFieldNone }, + { kOfxImageClipPropConnected, Property::eInt, 1, true, "0" }, + { kOfxImageEffectPropUnmappedFrameRange, Property::eDouble, 2, true, "0" }, + { kOfxImageEffectPropUnmappedFrameRate, Property::eDouble, 1, true, "25.0" }, + { kOfxImageClipPropContinuousSamples, Property::eInt, 1, true, "0" }, + Property::propSpecEnd, + }; + + + //////////////////////////////////////////////////////////////////////////////// + // instance + ClipInstance::ClipInstance(ImageEffect::Instance* effectInstance, ClipDescriptor& desc) + : ClipBase(desc) + , _effectInstance(effectInstance) + , _isOutput(desc.isOutput()) + , _pixelDepth(kOfxBitDepthNone) + , _components(kOfxImageComponentNone) + { + // this will a parameters that are needed in an instance but not a + // Descriptor + _properties.addProperties(clipInstanceStuffs); + int i = 0; + while(clipInstanceStuffs[i].name) { + const Property::PropSpec& spec = clipInstanceStuffs[i]; + + switch (spec.type) { + case Property::eDouble: + case Property::eString: + case Property::eInt: + _properties.setGetHook(spec.name, this); + break; + default: + break; + } + + i++; + } + } + + // do nothing + int ClipInstance::getDimension(const std::string &name) const + { + if(name == kOfxImageEffectPropUnmappedFrameRange || name == kOfxImageEffectPropFrameRange) + return 2; + return 1; + } + + // don't know what to do + void ClipInstance::reset(const std::string &/*name*/) { + //printf("failing in %s\n", __PRETTY_FUNCTION__); + throw Property::Exception(kOfxStatErrMissingHostFeature); + } + + const std::string &ClipInstance::getComponents() const + { + return _components; + } + + /// set the current set of components + /// called by clip preferences action + void ClipInstance::setComponents(const std::string &s) + { + _components = s; + } + + // get the virutals for viewport size, pixel scale, background colour + void ClipInstance::getDoublePropertyN(const std::string &name, double *values, int n) const + { + if(name==kOfxImagePropPixelAspectRatio){ + if(n>1) throw Property::Exception(kOfxStatErrValue); + *values = getAspectRatio(); + } + else if(name==kOfxImageEffectPropFrameRate){ + if(n>1) throw Property::Exception(kOfxStatErrValue); + *values = getFrameRate(); + } + else if(name==kOfxImageEffectPropFrameRange){ + if(n>2) throw Property::Exception(kOfxStatErrValue); + getFrameRange(values[0], values[1]); + } + else if(name==kOfxImageEffectPropUnmappedFrameRate){ + if(n>1) throw Property::Exception(kOfxStatErrValue); + *values = getUnmappedFrameRate(); + } + else if(name==kOfxImageEffectPropUnmappedFrameRange){ + if(n>2) throw Property::Exception(kOfxStatErrValue); + getUnmappedFrameRange(values[0], values[1]); + } + else + throw Property::Exception(kOfxStatErrValue); + } + + // get the virutals for viewport size, pixel scale, background colour + double ClipInstance::getDoubleProperty(const std::string &name, int n) const + { + if(name==kOfxImagePropPixelAspectRatio){ + if(n!=0) throw Property::Exception(kOfxStatErrValue); + return getAspectRatio(); + } + else if(name==kOfxImageEffectPropFrameRate){ + if(n!=0) throw Property::Exception(kOfxStatErrValue); + return getFrameRate(); + } + else if(name==kOfxImageEffectPropFrameRange){ + if(n>1) throw Property::Exception(kOfxStatErrValue); + double range[2]; + getFrameRange(range[0], range[1]); + return range[n]; + } + else if(name==kOfxImageEffectPropUnmappedFrameRate){ + if(n>0) throw Property::Exception(kOfxStatErrValue); + return getUnmappedFrameRate(); + } + else if(name==kOfxImageEffectPropUnmappedFrameRange){ + if(n>1) throw Property::Exception(kOfxStatErrValue); + double range[2]; + getUnmappedFrameRange(range[0], range[1]); + return range[n]; + } + else + throw Property::Exception(kOfxStatErrValue); + } + + // get the virutals for viewport size, pixel scale, background colour + int ClipInstance::getIntProperty(const std::string &name, int n) const + { + if(n!=0) throw Property::Exception(kOfxStatErrValue); + if(name==kOfxImageClipPropConnected){ + return getConnected(); + } + else if(name==kOfxImageClipPropContinuousSamples){ + return getContinuousSamples(); + } + else + throw Property::Exception(kOfxStatErrValue); + } + + // get the virutals for viewport size, pixel scale, background colour + void ClipInstance::getIntPropertyN(const std::string &name, int *values, int n) const + { + if(n!=0) throw Property::Exception(kOfxStatErrValue); + *values = getIntProperty(name, 0); + } + + // get the virutals for viewport size, pixel scale, background colour + const std::string &ClipInstance::getStringProperty(const std::string &name, int n) const + { + if(n!=0) throw Property::Exception(kOfxStatErrValue); + if(name==kOfxImageEffectPropPixelDepth){ + return getPixelDepth(); + } + else if(name==kOfxImageEffectPropComponents){ + return getComponents(); + } + else if(name==kOfxImageClipPropUnmappedComponents){ + return getUnmappedComponents(); + } + else if(name==kOfxImageClipPropUnmappedPixelDepth){ + return getUnmappedBitDepth(); + } + else if(name==kOfxImageEffectPropPreMultiplication){ + return getPremult(); + } + else if(name==kOfxImageClipPropFieldOrder){ + return getFieldOrder(); + } + else + throw Property::Exception(kOfxStatErrValue); + } + + // fetch multiple values in a multi-dimension property + void ClipInstance::getStringPropertyN(const std::string &name, const char** values, int count) const + { + if (count == 0) { + return; + } + if(count!=1) throw Property::Exception(kOfxStatErrValue); + if(name==kOfxImageEffectPropPixelDepth){ + values[0] = getPixelDepth().c_str(); + } + else if(name==kOfxImageEffectPropComponents){ + values[0] = getComponents().c_str(); + } + else if(name==kOfxImageClipPropUnmappedComponents){ + values[0] = getUnmappedComponents().c_str(); + } + else if(name==kOfxImageClipPropUnmappedPixelDepth){ + values[0] = getUnmappedBitDepth().c_str(); + } + else if(name==kOfxImageEffectPropPreMultiplication){ + values[0] = getPremult().c_str(); + } + else if(name==kOfxImageClipPropFieldOrder){ + values[0] = getFieldOrder().c_str(); + } + else + throw Property::Exception(kOfxStatErrValue); + } + + // notify override properties + void ClipInstance::notify(const std::string &/*name*/, bool /*isSingle*/, int /*indexOrN*/) + { + } + + OfxStatus ClipInstance::instanceChangedAction(const std::string &why, + OfxTime time, + OfxPointD renderScale) + { + Property::PropSpec stuff[] = { + { kOfxPropType, Property::eString, 1, true, kOfxTypeClip }, + { kOfxPropName, Property::eString, 1, true, getName().c_str() }, + { kOfxPropChangeReason, Property::eString, 1, true, why.c_str() }, + { kOfxPropTime, Property::eDouble, 1, true, "0" }, + { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" }, + Property::propSpecEnd + }; + + Property::Set inArgs(stuff); + + // add the second dimension of the render scale + inArgs.setDoubleProperty(kOfxPropTime,time); + inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)_effectInstance<<"->"<mainEntry(kOfxActionInstanceChanged, _effectInstance->getHandle(), &inArgs, 0); + } else { + st = kOfxStatFailed; + } +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)_effectInstance<<"->"<"<isChromaticComponent(s)) + return s; + + /// Means we have RGBA or Alpha being passed in and the clip + /// only supports the other one, so return that + if(s == rgba) { + if(isSupportedComponent(rgb)) + return rgb; + if(isSupportedComponent(alpha)) + return alpha; + } else if(s == alpha) { + if(isSupportedComponent(rgba)) + return rgba; + if(isSupportedComponent(rgb)) + return rgb; + } + + /// wierd, must be some custom bit , if only one, choose that, otherwise no idea + /// how to map, you need to derive to do so. + const std::vector &supportedComps = getSupportedComponents(); + if(supportedComps.size() == 1) + return supportedComps[0]; + + return none; + } + + + //////////////////////////////////////////////////////////////////////////////// + // Image + // + + static const Property::PropSpec imageBaseStuffs[] = { + { kOfxPropType, Property::eString, 1, false, kOfxTypeImage }, + { kOfxImageEffectPropPixelDepth, Property::eString, 1, true, kOfxBitDepthNone }, + { kOfxImageEffectPropComponents, Property::eString, 1, true, kOfxImageComponentNone }, + { kOfxImageEffectPropPreMultiplication, Property::eString, 1, true, kOfxImageOpaque }, + { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "1.0" }, + { kOfxImagePropPixelAspectRatio, Property::eDouble, 1, true, "1.0" }, + { kOfxImagePropBounds, Property::eInt, 4, true, "0" }, + { kOfxImagePropRegionOfDefinition, Property::eInt, 4, true, "0", }, + { kOfxImagePropRowBytes, Property::eInt, 1, true, "0", }, + { kOfxImagePropField, Property::eString, 1, true, "", }, + { kOfxImagePropUniqueIdentifier, Property::eString, 1, true, "" }, + Property::propSpecEnd + }; + + ImageBase::ImageBase() + : Property::Set(imageBaseStuffs) + , _referenceCount(1) + { + } + + /// called during ctor to get bits from the clip props into ours + void ImageBase::getClipBits(ClipInstance& instance) + { + Property::Set& clipProperties = instance.getProps(); + + // get and set the clip instance pixel depth + const std::string &depth = clipProperties.getStringProperty(kOfxImageEffectPropPixelDepth); + setStringProperty(kOfxImageEffectPropPixelDepth, depth); + + // get and set the clip instance components + const std::string &comps = clipProperties.getStringProperty(kOfxImageEffectPropComponents); + setStringProperty(kOfxImageEffectPropComponents, comps); + + // get and set the clip instance premultiplication + setStringProperty(kOfxImageEffectPropPreMultiplication, clipProperties.getStringProperty(kOfxImageEffectPropPreMultiplication)); + + // get and set the clip instance pixel aspect ratio + setDoubleProperty(kOfxImagePropPixelAspectRatio, clipProperties.getDoubleProperty(kOfxImagePropPixelAspectRatio)); + } + + /// make an image from a clip instance + ImageBase::ImageBase(ClipInstance& instance) + : Property::Set(imageBaseStuffs) + , _referenceCount(1) + { + getClipBits(instance); + } + + // construction based on clip instance + ImageBase::ImageBase(ClipInstance& instance, + double renderScaleX, + double renderScaleY, + const OfxRectI &bounds, + const OfxRectI &rod, + int rowBytes, + std::string field, + std::string uniqueIdentifier) + : Property::Set(imageBaseStuffs) + , _referenceCount(1) + { + getClipBits(instance); + + // set other data + setDoubleProperty(kOfxImageEffectPropRenderScale,renderScaleX, 0); + setDoubleProperty(kOfxImageEffectPropRenderScale,renderScaleY, 1); + setIntProperty(kOfxImagePropBounds,bounds.x1, 0); + setIntProperty(kOfxImagePropBounds,bounds.y1, 1); + setIntProperty(kOfxImagePropBounds,bounds.x2, 2); + setIntProperty(kOfxImagePropBounds,bounds.y2, 3); + setIntProperty(kOfxImagePropRegionOfDefinition,rod.x1, 0); + setIntProperty(kOfxImagePropRegionOfDefinition,rod.y1, 1); + setIntProperty(kOfxImagePropRegionOfDefinition,rod.x2, 2); + setIntProperty(kOfxImagePropRegionOfDefinition,rod.y2, 3); + setIntProperty(kOfxImagePropRowBytes,rowBytes); + + setStringProperty(kOfxImagePropField,field); + setStringProperty(kOfxImageClipPropFieldOrder,field); + setStringProperty(kOfxImagePropUniqueIdentifier,uniqueIdentifier); + } + + OfxRectI ImageBase::getBounds() const + { + OfxRectI bounds = {0, 0, 0, 0}; + getIntPropertyN(kOfxImagePropBounds, &bounds.x1, 4); + return bounds; + } + + OfxRectI ImageBase::getROD() const + { + OfxRectI rod = {0, 0, 0, 0}; + getIntPropertyN(kOfxImagePropRegionOfDefinition, &rod.x1, 4); + return rod; + } + + ImageBase::~ImageBase() { + //assert(_referenceCount <= 0); + } + + // release the reference + void ImageBase::releaseReference() + { + _referenceCount -= 1; + if(_referenceCount <= 0) + delete this; + } + + + static const Property::PropSpec imageStuffs[] = { + { kOfxImagePropData, Property::ePointer, 1, true, NULL }, + Property::propSpecEnd + }; + + Image::Image() + : ImageBase() + { + addProperties(imageStuffs); + } + + /// make an image from a clip instance + Image::Image(ClipInstance& instance) + : ImageBase(instance) + { + addProperties(imageStuffs); + } + + // construction based on clip instance + Image::Image(ClipInstance& instance, + double renderScaleX, + double renderScaleY, + void* data, + const OfxRectI &bounds, + const OfxRectI &rod, + int rowBytes, + std::string field, + std::string uniqueIdentifier) + : ImageBase(instance, renderScaleX, renderScaleY, bounds, rod, rowBytes, field, uniqueIdentifier) + { + addProperties(imageStuffs); + + // set other data + setPointerProperty(kOfxImagePropData,data); + } + + Image::~Image() { + //assert(_referenceCount <= 0); + } +# ifdef OFX_SUPPORTS_OPENGLRENDER + static const Property::PropSpec textureStuffs[] = { + { kOfxImageEffectPropOpenGLTextureIndex, Property::eInt, 1, true, "-1" }, + { kOfxImageEffectPropOpenGLTextureTarget, Property::eInt, 1, true, "-1" }, + Property::propSpecEnd + }; + + Texture::Texture() + : ImageBase() + { + addProperties(textureStuffs); + } + + /// make an image from a clip instance + Texture::Texture(ClipInstance& instance) + : ImageBase(instance) + { + addProperties(textureStuffs); + } + + // construction based on clip instance + Texture::Texture(ClipInstance& instance, + double renderScaleX, + double renderScaleY, + int index, + int target, + const OfxRectI &bounds, + const OfxRectI &rod, + int rowBytes, + std::string field, + std::string uniqueIdentifier) + : ImageBase(instance, renderScaleX, renderScaleY, bounds, rod, rowBytes, field, uniqueIdentifier) + { + addProperties(textureStuffs); + + // set other data + setIntProperty(kOfxImageEffectPropOpenGLTextureIndex, index); + setIntProperty(kOfxImageEffectPropOpenGLTextureTarget, target); + } + + + Texture::~Texture() { + //assert(_referenceCount <= 0); + } +# endif + } // Clip + + } // Host + +} // OFX diff --git a/third_party/openfx/HostSupport/src/ofxhHost.cpp b/third_party/openfx/HostSupport/src/ofxhHost.cpp new file mode 100644 index 000000000..27b12d318 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhHost.cpp @@ -0,0 +1,124 @@ + + +#include +#include +#include +#include + +// ofx +#include "ofxCore.h" +#include "ofxProperty.h" +#include "ofxMultiThread.h" +#include "ofxMemory.h" + +#include "ofxhHost.h" + +typedef OfxPlugin* (*OfxGetPluginType)(int); + +namespace OFX { + + namespace Host { + + //////////////////////////////////////////////////////////////////////////////// + /// simple memory suite + namespace Memory { + static OfxStatus memoryAlloc(void */*handle*/, size_t bytes, void **data) + { + *data = malloc(bytes); + if (*data) { + return kOfxStatOK; + } else { + return kOfxStatErrMemory; + } + } + + static OfxStatus memoryFree(void *data) + { + free(data); + return kOfxStatOK; + } + + static const struct OfxMemorySuiteV1 gMallocSuite = { + memoryAlloc, + memoryFree + }; + } + + } + +} + +namespace OFX { + namespace Host { + /// our own internal property for storing away our private pointer to our host descriptor +#define kOfxHostSupportHostPointer "sf.openfx.net.OfxHostSupportHostPointer" + + static const Property::PropSpec hostStuffs[] = { + { kOfxPropAPIVersion, Property::eInt, 0, false, "" }, + { kOfxPropType, Property::eString, 1, false, "Host" }, + { kOfxPropName, Property::eString, 1, false, "UNKNOWN" }, + { kOfxPropLabel, Property::eString, 1, false, "UNKNOWN" }, + { kOfxPropVersion, Property::eInt, 0, false, "0" }, + { kOfxPropVersionLabel, Property::eString, 1, false, "" }, + { kOfxHostSupportHostPointer, Property::ePointer, 0, false, NULL }, + Property::propSpecEnd + }; + + static const void *fetchSuite(OfxPropertySetHandle hostProps, const char *suiteName, int suiteVersion) + { + Property::Set* properties = reinterpret_cast(hostProps); + + Host* host = (Host*)properties->getPointerProperty(kOfxHostSupportHostPointer); + + if(host) + return host->fetchSuite(suiteName,suiteVersion); + else + return 0; + } + + // Base Host + Host::Host() : _properties(hostStuffs) + { + _host.host = _properties.getHandle(); + _host.fetchSuite = OFX::Host::fetchSuite; + + // record the host descriptor in the propert set + _properties.setPointerProperty(kOfxHostSupportHostPointer,this); + } + + OfxHost *Host::getHandle() { + return &_host; + } + + OfxStatus Host::message(const char* type, + const char* id, + const char* format, + ...) { + try { + OfxStatus stat; + va_list args; + va_start(args,format); + stat = vmessage(type,id,format,args); + va_end(args); + return stat; + } catch (...) { + return kOfxStatFailed; + } + } + + const void *Host::fetchSuite(const char *suiteName, int suiteVersion) + { + if (strcmp(suiteName, kOfxPropertySuite)==0 && suiteVersion == 1) { + return Property::GetSuite(suiteVersion); + } + else if (strcmp(suiteName, kOfxMemorySuite)==0 && suiteVersion == 1) { + return (void*)&Memory::gMallocSuite; + } + + ///printf("fetchSuite failed with host = %p, name = %s, version = %i\n", this, suiteName, suiteVersion); + return NULL; + } + + } // Host + +} // OFX diff --git a/third_party/openfx/HostSupport/src/ofxhImageEffect.cpp b/third_party/openfx/HostSupport/src/ofxhImageEffect.cpp new file mode 100644 index 000000000..042e44491 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhImageEffect.cpp @@ -0,0 +1,2809 @@ +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#include + +// ofx +#include "ofxCore.h" +#include "ofxImageEffect.h" + +// ofx host +#include "ofxhBinary.h" +#include "ofxhPropertySuite.h" +#include "ofxhClip.h" +#include "ofxhParam.h" +#include "ofxhMemory.h" +#include "ofxhImageEffect.h" +#include "ofxhPluginAPICache.h" +#include "ofxhPluginCache.h" +#include "ofxhHost.h" +#include "ofxhImageEffectAPI.h" +#include "ofxhUtilities.h" +#ifdef OFX_SUPPORTS_PARAMETRIC +#include "ofxhParametricParam.h" +#endif +#ifdef OFX_SUPPORTS_OPENGLRENDER +#include "ofxGPURender.h" +#endif +#include "ofxOld.h" // old plugins may rely on deprecated properties being present + +#include +#include + +namespace OFX { + + namespace Host { + + namespace ImageEffect { + + /// properties common on an effect and a descriptor + static const Property::PropSpec effectDescriptorStuff[] = { + /* name type dim. r/o default value */ + { kOfxPropType, Property::eString, 1, true, kOfxTypeImageEffect }, + { kOfxPropLabel, Property::eString, 1, false, "" }, + { kOfxPropShortLabel, Property::eString, 1, false, "" }, + { kOfxPropLongLabel, Property::eString, 1, false, "" }, + { kOfxPropVersion, Property::eInt, 0, false, "0" }, + { kOfxPropVersionLabel, Property::eString, 1, false, "" }, + { kOfxPropPluginDescription, Property::eString, 1, false, "" }, + { kOfxImageEffectPropSupportedContexts, Property::eString, 0, false, "" }, + { kOfxImageEffectPluginPropGrouping, Property::eString, 1, false, "" }, + { kOfxImageEffectPluginPropSingleInstance, Property::eInt, 1, false, "0" }, + { kOfxImageEffectPluginRenderThreadSafety, Property::eString, 1, false, kOfxImageEffectRenderInstanceSafe }, + { kOfxImageEffectPluginPropHostFrameThreading, Property::eInt, 1, false, "1" }, + { kOfxImageEffectPluginPropOverlayInteractV1, Property::ePointer, 1, false, NULL }, + { kOfxImageEffectPropSupportsMultiResolution, Property::eInt, 1, false, "1" } , + { kOfxImageEffectPropSupportsTiles, Property::eInt, 1, false, "1" }, + { kOfxImageEffectPropTemporalClipAccess, Property::eInt, 1, false, "0" }, + { kOfxImageEffectPropSupportedPixelDepths, Property::eString, 0, false, "" }, + { kOfxImageEffectPluginPropFieldRenderTwiceAlways, Property::eInt, 1, false, "1" } , + { kOfxImageEffectPropSupportsMultipleClipDepths, Property::eInt, 1, false, "0" }, + { kOfxImageEffectPropSupportsMultipleClipPARs, Property::eInt, 1, false, "0" }, + { kOfxImageEffectPropClipPreferencesSlaveParam, Property::eString, 0, false, "" }, + { kOfxImageEffectInstancePropSequentialRender, Property::eInt, 1, false, "0" }, + { kOfxPluginPropFilePath, Property::eString, 1, true, ""}, +#ifdef OFX_SUPPORTS_OPENGLRENDER + { kOfxImageEffectPropOpenGLRenderSupported, Property::eString, 1, false, "false"}, // OFX 1.3 + { kOfxImageEffectPropCudaRenderSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropCudaStreamSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropMetalRenderSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropOpenCLRenderSupported, Property::eString, 1, false, "false" }, +#endif + + Property::propSpecEnd + }; + + // + // Base + // + + Base::Base(const Property::Set &set) + : _properties(set) + {} + + Base::Base(const Property::PropSpec * propSpec) + : _properties(propSpec) + {} + + Base::~Base() {} + + /// obtain a handle on this for passing to the C api + OfxImageEffectHandle Base::getHandle() const { + return (OfxImageEffectHandle)this; + } + + /// get the properties set + Property::Set &Base::getProps() { + return _properties; + } + + /// get the properties set, const version + const Property::Set &Base::getProps() const { + return _properties; + } + + /// name of the clip + const std::string &Base::getShortLabel() const + { + const std::string &s = _properties.getStringProperty(kOfxPropShortLabel); + if(s == "") { + const std::string &s2 = _properties.getStringProperty(kOfxPropLabel); + if(s2 == "") { + return _properties.getStringProperty(kOfxPropName); + } + } + return s; + } + + /// name of the clip + const std::string &Base::getLabel() const + { + const std::string &s = _properties.getStringProperty(kOfxPropLabel); + if(s == "") { + return _properties.getStringProperty(kOfxPropName); + } + return s; + } + + /// name of the clip + const std::string &Base::getLongLabel() const + { + const std::string &s = _properties.getStringProperty(kOfxPropLongLabel); + if(s == "") { + const std::string &s2 = _properties.getStringProperty(kOfxPropLabel); + if(s2 == "") { + return _properties.getStringProperty(kOfxPropName); + } + } + return s; + } + + /// is the given context supported + bool Base::isContextSupported(const std::string &s) const + { + return _properties.findStringPropValueIndex(kOfxImageEffectPropSupportedContexts, s) != -1; + } + + /// what is the name of the group the plug-in belongs to + const std::string &Base::getPluginGrouping() const + { + return _properties.getStringProperty(kOfxImageEffectPluginPropGrouping); + } + + /// is the effect single instance + bool Base::isSingleInstance() const + { + return _properties.getIntProperty(kOfxImageEffectPluginPropSingleInstance) != 0; + } + + /// what is the thread safety on this effect + const std::string &Base::getRenderThreadSafety() const + { + return _properties.getStringProperty(kOfxImageEffectPluginRenderThreadSafety); + } + + /// should the host attempt to managed multi-threaded rendering if it can + /// via tiling or some such + bool Base::getHostFrameThreading() const + { + return _properties.getIntProperty(kOfxImageEffectPluginPropHostFrameThreading) != 0; + } + + /// get the overlay interact main entry if it exists + OfxPluginEntryPoint *Base::getOverlayInteractMainEntry() const + { + return (OfxPluginEntryPoint *)(_properties.getPointerProperty(kOfxImageEffectPluginPropOverlayInteractV1)); + } + + /// does the effect support images of differing sizes + bool Base::supportsMultiResolution() const + { + return _properties.getIntProperty(kOfxImageEffectPropSupportsMultiResolution) != 0; + } + + /// does the effect support tiled rendering + bool Base::supportsTiles() const + { + return _properties.getIntProperty(kOfxImageEffectPropSupportsTiles) != 0; + } + + /// does this effect need random temporal access + bool Base::temporalAccess() const + { + return _properties.getIntProperty(kOfxImageEffectPropTemporalClipAccess) != 0; + } + + /// is the given RGBA/A pixel depth supported by the effect + bool Base::isPixelDepthSupported(const std::string &s) const + { + return _properties.findStringPropValueIndex(kOfxImageEffectPropSupportedPixelDepths, s) != -1; + } + + /// when field rendering, does the effect need to be called + /// twice to render a frame in all Base::circumstances (with different fields) + bool Base::fieldRenderTwiceAlways() const + { + return _properties.getIntProperty(kOfxImageEffectPluginPropFieldRenderTwiceAlways) != 0; + } + + /// does the effect support multiple clip depths + bool Base::supportsMultipleClipDepths() const + { + return _properties.getIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths) != 0; + } + + /// does the effect support multiple clip pixel aspect ratios + bool Base::supportsMultipleClipPARs() const + { + return _properties.getIntProperty(kOfxImageEffectPropSupportsMultipleClipPARs) != 0; + } + + /// does changing the named param re-tigger a clip preferences action + bool Base::isClipPreferencesSlaveParam(const std::string &s) const + { + return _properties.findStringPropValueIndex(kOfxImageEffectPropClipPreferencesSlaveParam, s) != -1; + } + + + //////////////////////////////////////////////////////////////////////////////// + // descriptor + + Descriptor::Descriptor(Plugin *plug) + : Base(effectDescriptorStuff) + , _plugin(plug) + { + _properties.setStringProperty(kOfxPluginPropFilePath, plug->getBinary()->getBundlePath()); + gImageEffectHost->initDescriptor(this); + } + + Descriptor::Descriptor(const Descriptor &other, Plugin *plug) + : Base(other._properties) + , _plugin(plug) + { + _properties.setStringProperty(kOfxPluginPropFilePath, plug->getBinary()->getBundlePath()); + gImageEffectHost->initDescriptor(this); + } + + Descriptor::Descriptor(const std::string &bundlePath, Plugin *plug) + : Base(effectDescriptorStuff) + , _plugin(plug) + { + _properties.setStringProperty(kOfxPluginPropFilePath, bundlePath); + gImageEffectHost->initDescriptor(this); + } + + Descriptor::~Descriptor() + { + for(std::map::iterator it = _clips.begin(); it != _clips.end(); ++it) + delete it->second; + _clips.clear(); + } + + + /// create a new clip and add this to the clip map + ClipDescriptor *Descriptor::defineClip(const std::string &name) { + ClipDescriptor *c = new ClipDescriptor(name); + _clips[name] = c; + _clipsByOrder.push_back(c); + return c; + } + + /// implemented for Param::SetDescriptor + Property::Set &Descriptor::getParamSetProps() + { + return _properties; + } + + /// get the interact description, this will also call describe on the interact + Interact::Descriptor &Descriptor::getOverlayDescriptor(int bitDepthPerComponent, bool hasAlpha) + { + if(_overlayDescriptor.getState() == Interact::eUninitialised) { + // OK, we need to describe it, set the entry point and describe away + _overlayDescriptor.setEntryPoint(getOverlayInteractMainEntry()); + _overlayDescriptor.describe(bitDepthPerComponent, hasAlpha); + } + + return _overlayDescriptor; + } + + /// get the clips + const std::map &Descriptor::getClips() const { + return _clips; + } + + void Descriptor::addClip(const std::string &name, ClipDescriptor *clip) { + _clips[name] = clip; + _clipsByOrder.push_back(clip); + } + + // + // Instance + // + + static const Property::PropSpec effectInstanceStuff[] = { + /* name type dim. r/o default value */ + { kOfxPropType, Property::eString, 1, true, kOfxTypeImageEffectInstance }, + { kOfxImageEffectPropContext, Property::eString, 1, true, "" }, + { kOfxPropInstanceData, Property::ePointer, 1, false, NULL }, + { kOfxImageEffectPropPluginHandle, Property::ePointer, 1, false, NULL }, + { kOfxImageEffectPropProjectSize, Property::eDouble, 2, true, "0" }, + { kOfxImageEffectPropProjectOffset, Property::eDouble, 2, true, "0" }, + { kOfxImageEffectPropProjectExtent, Property::eDouble, 2, true, "0" }, + { kOfxImageEffectPropProjectPixelAspectRatio, Property::eDouble, 1, true, "0" }, + { kOfxImageEffectInstancePropEffectDuration, Property::eDouble, 1, true, "0" }, + { kOfxImageEffectInstancePropSequentialRender, Property::eInt, 1, false, "0" }, + { kOfxImageEffectPropFrameRate , Property::eDouble, 1, true, "0" }, + { kOfxPropIsInteractive, Property::eInt, 1, true, "0" }, +# ifdef kOfxImageEffectPropInAnalysis + { kOfxImageEffectPropInAnalysis, Property::eInt, 1, false, "0" }, // removed in OFX 1.4 +# endif + { kOfxImageEffectPropSupportsTiles, Property::eInt, 1, false, "1" }, // OFX 1.4 +#ifdef OFX_SUPPORTS_OPENGLRENDER + { kOfxImageEffectPropOpenGLRenderSupported, Property::eString, 1, false, "false"}, // OFX 1.4 + { kOfxImageEffectPropCudaRenderSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropCudaStreamSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropMetalRenderSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropOpenCLRenderSupported, Property::eString, 1, false, "false" }, +#endif + Property::propSpecEnd + }; + + Instance::Instance(ImageEffectPlugin* plugin, + Descriptor &other, + const std::string &context, + bool interactive) + : Base(effectInstanceStuff) + , _plugin(plugin) + , _context(context) + , _descriptor(&other) + , _interactive(interactive) + , _created(false) + , _clipPrefsDirty(true) + , _continuousSamples(false) + , _frameVarying(false) + , _outputFrameRate(24) + { + int i = 0; + _properties.setChainedSet(&other.getProps()); + + _properties.setPointerProperty(kOfxImageEffectPropPluginHandle, _plugin->getPluginHandle()->getOfxPlugin()); + + _properties.setStringProperty(kOfxImageEffectPropContext,context); + _properties.setIntProperty(kOfxPropIsInteractive,interactive); + + // copy is sequential over + bool sequential = other.getProps().getIntProperty(kOfxImageEffectInstancePropSequentialRender) != 0; + _properties.setIntProperty(kOfxImageEffectInstancePropSequentialRender,sequential); + + while(effectInstanceStuff[i].name) { + + // don't set hooks for context or isinteractive + + if(strcmp(effectInstanceStuff[i].name,kOfxImageEffectPropContext) && + strcmp(effectInstanceStuff[i].name,kOfxPropIsInteractive) && + strcmp(effectInstanceStuff[i].name,kOfxImageEffectInstancePropSequentialRender) ) + { + const Property::PropSpec& spec = effectInstanceStuff[i]; + + switch (spec.type) { + case Property::eDouble: + _properties.setGetHook(spec.name, this); + break; + default: + break; + } + } + + i++; + } + } + + /// implemented for Param::SetDescriptor + Property::Set &Instance::getParamSetProps() + { + return _properties; + } + + /// called after construction to populate clips and params + OfxStatus Instance::populate() + { + const std::vector& clips = _descriptor->getClipsByOrder(); + + int counter = 0; + for(std::vector::const_iterator it=clips.begin(); + it!=clips.end(); + ++it, ++counter) { + const std::string &name = (*it)->getName(); + // foreach clip descriptor make a clip instance + ClipInstance* instance = newClipInstance(this, *it, counter); + if(!instance) return kOfxStatFailed; + + _clips[name] = instance; + } + + const std::list& map = _descriptor->getParamList(); + + std::map > parameters; + std::map groups; + + for(std::list::const_iterator it=map.begin(); + it!=map.end(); + ++it) { + Param::Descriptor* descriptor = (*it); + // get the param descriptor + if(!descriptor) return kOfxStatErrValue; + + // name of the parameter + std::string name = descriptor->getName(); + + // get a param instance from a param descriptor + Param::Instance* instance = newParam(name,*descriptor); + if(!instance) return kOfxStatFailed; + + // add the value into the param set instance + OfxStatus st = addParam(name,instance); + if(st != kOfxStatOK) return st; + + std::string parent = instance->getParentName(); + + if(parent!="") + parameters[parent].push_back(instance); + + if(instance->getType()==kOfxParamTypeGroup){ + groups[instance->getName()]=instance; + } + } + + // for each group parameter made + for(std::map::iterator it=groups.begin(); + it!=groups.end(); + ++it) { + // cast to a group instance + Param::GroupInstance* group = dynamic_cast(it->second); + + // if cast ok + if(group){ + // find the parameters whose parent was this group + std::map >::iterator it2 = parameters.find(group->getName()); + if(it2!=parameters.end()){ + // associate the group with its children, and the children with its parent group + group->setChildren(it2->second); + } + } + } + + return kOfxStatOK; + } + + // do nothing + int Instance::getDimension(const std::string &name) const { + printf("failing in %s with name=%s\n", __PRETTY_FUNCTION__, name.c_str()); + throw Property::Exception(kOfxStatErrMissingHostFeature); + } + + int Instance::upperGetDimension(const std::string &name) { + return _properties.getDimension(name); + } + + void Instance::notify(const std::string &/*name*/, bool /*singleValue*/, int /*indexOrN*/) + { + printf("failing in %s\n", __PRETTY_FUNCTION__); + } + + // don't know what to do + void Instance::reset(const std::string &/*name*/) { + printf("failing in %s\n", __PRETTY_FUNCTION__); + throw Property::Exception(kOfxStatErrMissingHostFeature); + } + + // get the virutals for viewport size, pixel scale, background colour + double Instance::getDoubleProperty(const std::string &name, int index) const + { + if(name==kOfxImageEffectPropProjectSize){ + if(index>=2) throw Property::Exception(kOfxStatErrBadIndex); + double values[2]; + getProjectSize(values[0],values[1]); + return values[index]; + } + else if(name==kOfxImageEffectPropProjectOffset){ + if(index>=2) throw Property::Exception(kOfxStatErrBadIndex); + double values[2]; + getProjectOffset(values[0],values[1]); + return values[index]; + } + else if(name==kOfxImageEffectPropProjectExtent){ + if(index>=2) throw Property::Exception(kOfxStatErrBadIndex); + double values[2]; + getProjectExtent(values[0],values[1]); + return values[index]; + } + else if(name==kOfxImageEffectPropProjectPixelAspectRatio){ + if(index>=1) throw Property::Exception(kOfxStatErrBadIndex); + return getProjectPixelAspectRatio(); + } + else if(name==kOfxImageEffectInstancePropEffectDuration){ + if(index>=1) throw Property::Exception(kOfxStatErrBadIndex); + return getEffectDuration(); + } + else if(name==kOfxImageEffectPropFrameRate){ + if(index>=1) throw Property::Exception(kOfxStatErrBadIndex); + return getFrameRate(); + } + else + throw Property::Exception(kOfxStatErrUnknown); + } + + void Instance::getDoublePropertyN(const std::string &name, double* first, int n) const + { + if(name==kOfxImageEffectPropProjectSize){ + if(n>2) throw Property::Exception(kOfxStatErrBadIndex); + getProjectSize(first[0],first[1]); + } + else if(name==kOfxImageEffectPropProjectOffset){ + if(n>2) throw Property::Exception(kOfxStatErrBadIndex); + getProjectOffset(first[0],first[1]); + } + else if(name==kOfxImageEffectPropProjectExtent){ + if(n>2) throw Property::Exception(kOfxStatErrBadIndex); + getProjectExtent(first[0],first[1]); + } + else if(name==kOfxImageEffectPropProjectPixelAspectRatio){ + if(n>1) throw Property::Exception(kOfxStatErrBadIndex); + *first = getProjectPixelAspectRatio(); + } + else if(name==kOfxImageEffectInstancePropEffectDuration){ + if(n>1) throw Property::Exception(kOfxStatErrBadIndex); + *first = getEffectDuration(); + } + else if(name==kOfxImageEffectPropFrameRate){ + if(n>1) throw Property::Exception(kOfxStatErrBadIndex); + *first = getFrameRate(); + } + else + throw Property::Exception(kOfxStatErrUnknown); + } + + Instance::~Instance(){ + // destroy the instance, only if succesfully created + if (_created) { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(),0,0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<::iterator i; + for(i = _clips.begin(); i != _clips.end(); ++i) { + if(i->second) + delete i->second; + i->second = NULL; + } + } + + /// this is used to populate with any extra action in argumnents that may be needed + void Instance::setCustomInArgs(const std::string &/*action*/, Property::Set &/*inArgs*/) + { + } + + /// this is used to populate with any extra action out argumnents that may be needed + void Instance::setCustomOutArgs(const std::string &/*action*/, Property::Set &/*outArgs*/) + { + } + + /// this is used to populate with any extra action out argumnents that may be needed + void Instance::examineOutArgs(const std::string &/*action*/, OfxStatus, const Property::Set &/*outArgs*/) + { + } + + /// check for connection + bool Instance::checkClipConnectionStatus() const + { + std::map::const_iterator i; + for(i = _clips.begin(); i != _clips.end(); ++i) { + if(!i->second->isOptional() && !i->second->getConnected()) { + return false; + } + } + return true; + } + + // override this to make processing abort, return 1 to abort processing + int Instance::abort() { + return 0; + } + + // override this to use your own memory instance - must inherrit from memory::instance + Memory::Instance* Instance::newMemoryInstance(size_t /*nBytes*/) { + return 0; + } + + // return an memory::instance calls makeMemoryInstance that can be overriden + Memory::Instance* Instance::imageMemoryAlloc(size_t nBytes){ + Memory::Instance* instance = newMemoryInstance(nBytes); + if(instance) + return instance; + else{ + Memory::Instance* instance = new Memory::Instance; + instance->alloc(nBytes); + return instance; + } + } + + // call the effect entry point + OfxStatus Instance::mainEntry(const char *action, + const void *handle, + Property::Set *inArgs, + Property::Set *outArgs) + { + if(_plugin){ + PluginHandle* pHandle = _plugin->getPluginHandle(); + if(pHandle){ + OfxPlugin* ofxPlugin = pHandle->getOfxPlugin(); + if(ofxPlugin){ + + OfxPropertySetHandle inHandle = 0; + if(inArgs) { + setCustomInArgs(action, *inArgs); + inHandle = inArgs->getHandle(); + } + + OfxPropertySetHandle outHandle = 0; + if(outArgs) { + setCustomOutArgs(action, *outArgs); + outHandle = outArgs->getHandle(); + } + + OfxStatus stat; + try { + stat = ofxPlugin->mainEntry(action, handle, inHandle, outHandle); + } CatchAllSetStatus(stat, gImageEffectHost, ofxPlugin, action); + + if(outArgs) + examineOutArgs(action, stat, *outArgs); + + return stat; + } + return kOfxStatFailed; + } + return kOfxStatFailed; + } + return kOfxStatFailed; + } + + // get the nth clip, in order of declaration + ClipInstance* Instance::getNthClip(int index) + { + const std::string name = _descriptor->getClipsByOrder()[index]->getName(); + return _clips[name]; + } + + ClipInstance* Instance::getClip(const std::string& name) const { + std::map::const_iterator it = _clips.find(name); + if(it!=_clips.end()){ + return it->second; + } + return 0; + } + + // create a clip instance + OfxStatus Instance::createInstanceAction() + { + /// we need to init the clips before we call create instance incase + /// they try and fetch something in create instance, which they are allowed + setDefaultClipPreferences(); + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(),0,0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(), &inArgs, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(), &inArgs, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<::iterator it=_clips.find(clipName); + if(it!=_clips.end()) + return (it->second)->instanceChangedAction(why,time,renderScale); + else + return kOfxStatFailed; + } + + OfxStatus Instance::endInstanceChangedAction(const std::string & why) + { + Property::PropSpec whyStuff[] = { + { kOfxPropChangeReason, Property::eString, 1, true, why.c_str() }, + Property::propSpecEnd + }; + + Property::Set inArgs(whyStuff); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(), &inArgs, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(),0,0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getValue() : true; + OfxStatus st = kOfxStatReplyDefault; + if (needsSyncing) { + st = mainEntry(kOfxActionSyncPrivateData,this->getHandle(),0,0); + if (s) { + s->setValue(0); + } + } +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(),0,0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(),0,0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(),0,0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(),0,0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(), &inArgs, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(), &inArgs, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<"<getHandle(), &inArgs, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<getRegionOfDefinition(time); + } else { + throw Property::Exception(kOfxStatFailed); + } + } + else if(_context == kOfxImageEffectContextTransition) { + // transition is the union of the two clips + ClipInstance *clipFrom = getClip(kOfxImageEffectTransitionSourceFromClipName); + ClipInstance *clipTo = getClip(kOfxImageEffectTransitionSourceToClipName); + if(clipFrom && clipTo) { + rod = clipFrom->getRegionOfDefinition(time); + rod = Union(rod, clipTo->getRegionOfDefinition(time)); + } else { + throw Property::Exception(kOfxStatFailed); + } + } + else if(_context == kOfxImageEffectContextGeneral + ) { + // general context is the union of all the non optional clips + bool gotOne = false; + for(std::map::const_iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + ClipInstance *clip = it->second; + if(!clip->isOutput() && (!clip->isOptional() || (clip->getConnected() && clip->getName() == kOfxImageEffectSimpleSourceClipName))) { + if(!gotOne) + rod = clip->getRegionOfDefinition(time); + else + rod = Union(rod, clip->getRegionOfDefinition(time)); + gotOne = true; + } + } + + if(!gotOne) { + /// no non optionals? then be the extent + rod.x1 = rod.y1 = 0; + getProjectExtent(rod.x2, rod.y2); + } + + } + else if(_context == kOfxImageEffectContextRetimer) { + // retimer + ClipInstance *clip = getClip(kOfxImageEffectSimpleSourceClipName); + if(clip) { + Param::DoubleInstance *param = dynamic_cast(getParam(kOfxImageEffectRetimerParamName)); + if(param) { + rod = clip->getRegionOfDefinition(floor(time)); + rod = Union(rod, clip->getRegionOfDefinition(floor(time) + 1)); + } else { + throw Property::Exception(kOfxStatFailed); + } + } else { + throw Property::Exception(kOfxStatFailed); + } + } + else { + // unknown context + throw Property::Exception(kOfxStatErrMissingHostFeature); + } + + return rod; + } + + //////////////////////////////////////////////////////////////////////////////// + // RoD call + OfxStatus Instance::getRegionOfDefinitionAction(OfxTime time, + OfxPointD renderScale, + OfxRectD &rod) + { + static const Property::PropSpec inStuff[] = { + { kOfxPropTime, Property::eDouble, 1, true, "0" }, + { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" }, + Property::propSpecEnd + }; + + static const Property::PropSpec outStuff[] = { + { kOfxImageEffectPropRegionOfDefinition , Property::eDouble, 4, false, "0" }, + Property::propSpecEnd + }; + + Property::Set inArgs(inStuff); + Property::Set outArgs(outStuff); + + inArgs.setDoubleProperty(kOfxPropTime,time); + inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2); + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(), + &inArgs, + &outArgs); + if(stat == kOfxStatOK) { + outArgs.getDoublePropertyN(kOfxImageEffectPropRegionOfDefinition, &rod.x1, 4); + } + else if(stat == kOfxStatReplyDefault) { + rod = calcDefaultRegionOfDefinition(time, renderScale); + } + + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<& rois) + { + OfxStatus stat = kOfxStatReplyDefault; + + // reset the map + rois.clear(); + + if(!supportsTiles()) { + /// No tiling support on the effect at all. So set the roi of each input clip to be the RoD of that clip. + for(std::map::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + if(!it->second->isOutput() || + getContext() == kOfxImageEffectContextGenerator) { + if (it->second->isOutput() || it->second->getConnected()) {// needed to be able to fetch the RoD + /// @todo tuttle: how to support size on generators... check if this is correct in all cases. + OfxRectD roi = it->second->getRegionOfDefinition(time); + rois[it->second] = roi; + } + } + } + stat = kOfxStatOK; + } + else { + /// set up the in args + static const Property::PropSpec inStuff[] = { + { kOfxPropTime, Property::eDouble, 1, true, "0" }, + { kOfxImageEffectPropRenderScale, Property::eDouble, 2, true, "0" }, + { kOfxImageEffectPropRegionOfInterest , Property::eDouble, 4, true, 0 }, + Property::propSpecEnd + }; + Property::Set inArgs(inStuff); + + inArgs.setDoublePropertyN(kOfxImageEffectPropRenderScale, &renderScale.x, 2); + inArgs.setDoubleProperty(kOfxPropTime,time); + inArgs.setDoublePropertyN(kOfxImageEffectPropRegionOfInterest, &roi.x1, 4); + + Property::Set outArgs; + for(std::map::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + if(!it->second->isOutput() || + getContext() == kOfxImageEffectContextGenerator) { + Property::PropSpec s; + std::string name = "OfxImageClipPropRoI_"+it->first; + + s.name = name.c_str(); + s.type = Property::eDouble; + s.dimension = 4; + s.readonly = false; + s.defaultValue = ""; + outArgs.createProperty(s); + + /// initialise to the default + outArgs.setDoublePropertyN(s.name, &roi.x1, 4); + } + } + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(), + &inArgs, + &outArgs); + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + std::string name = "OfxImageClipPropRoI_"+it->first; + OfxRectD thisRoi; + thisRoi.x1 = outArgs.getDoubleProperty(name,0); + thisRoi.y1 = outArgs.getDoubleProperty(name,1); + thisRoi.x2 = outArgs.getDoubleProperty(name,2); + thisRoi.y2 = outArgs.getDoubleProperty(name,3); + std::cout << it->first << "->("<::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + if(!it->second->isOutput() || + getContext() == kOfxImageEffectContextGenerator) { + if (it->second->isOutput() || it->second->getConnected()) { // needed to be able to fetch the RoD + + if(it->second->supportsTiles()) { + std::string name = "OfxImageClipPropRoI_"+it->first; + OfxRectD thisRoi; + thisRoi.x1 = outArgs.getDoubleProperty(name,0); + thisRoi.y1 = outArgs.getDoubleProperty(name,1); + thisRoi.x2 = outArgs.getDoubleProperty(name,2); + thisRoi.y2 = outArgs.getDoubleProperty(name,3); + + // and DON'T clamp it to the clip's rod + // We cannot clip it against the RoD because the RoI may be used for frames + // at different a time or view than the current time and view passed to this action + // which would result in a wrong clipping. Unfortunately only the implementation of + // the host can do the correct clipping. + //thisRoi = Clamp(thisRoi, rod); + rois[it->second] = thisRoi; + } + else { + /// not supporting tiles on this input, so set it to the rod + OfxRectD rod = it->second->getRegionOfDefinition(time + ); + rois[it->second] = rod; + } + } + } + } + } + + return stat; + } + + + //////////////////////////////////////////////////////////////////////////////// + /// see how many frames are needed from each clip to render the indicated frame + OfxStatus Instance::getFrameNeededAction(OfxTime time, + RangeMap &rangeMap) + { + OfxStatus stat = kOfxStatReplyDefault; + Property::Set outArgs; + + if(temporalAccess()) { + static const Property::PropSpec inStuff[] = { + { kOfxPropTime, Property::eDouble, 1, true, "0" }, + Property::propSpecEnd + }; + Property::Set inArgs(inStuff); + inArgs.setDoubleProperty(kOfxPropTime,time); + + + for(std::map::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + if(!it->second->isOutput()) { + Property::PropSpec s; + std::string name = "OfxImageClipPropFrameRange_"+it->first; + + s.name = name.c_str(); + s.type = Property::eDouble; + s.dimension = 0; + s.readonly = false; + s.defaultValue = ""; + outArgs.createProperty(s); + /// intialise it to the current frame + outArgs.setDoubleProperty(name, time, 0); + outArgs.setDoubleProperty(name, time, 1); + } + } + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(), + &inArgs, + &outArgs); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + ClipInstance *clip = it->second; + + if(!clip->isOutput()) { + std::string name = "OfxImageClipPropFrameRange_"+it->first; + std::cout << it->first << "->["; + + int nRanges = outArgs.getDimension(name); + for(int r=0;r::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + ClipInstance *clip = it->second; + + if(!clip->isOutput()) { + if(stat != kOfxStatOK) { + rangeMap[clip].push_back(defaultRange); + } + else { + std::string name = "OfxImageClipPropFrameRange_"+it->first; + + int nRanges = outArgs.getDimension(name); + if(nRanges%2 != 0) + return kOfxStatFailed; // bad! needs to be divisible by 2 + + if(nRanges == 0) { + rangeMap[clip].push_back(defaultRange); + } + else { + for(int r=0;r"<getHandle(), + &inArgs, + &outArgs); + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<getProperties().getIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths) != 0;; + + /// does the plug-in support 'em + bool pluginSupports = supportsMultipleClipDepths(); + + /// no support, so no + if(!hostSupports || !pluginSupports) + return false; + + /// if filter context, no support, tempted to change this though + if(_context == kOfxImageEffectContextFilter) + return false; + + /// if filter context, no support + if(_context == kOfxImageEffectContextGenerator || + _context == kOfxImageEffectContextTransition || + _context == kOfxImageEffectContextPaint || + _context == kOfxImageEffectContextRetimer) + return false; + + /// OK we're cool + return true; + } + + /// Setup the default clip preferences on the clips + void Instance::setDefaultClipPreferences() + { + /// is there multiple bit depth support? Depends on host, plugin and context + bool multiBitDepth = canCurrentlyHandleMultipleClipDepths(); + + /// OK find the deepest chromatic component on our input clips and the one with the + /// most components + bool hasSetCompsAndDepth = false; + std::string deepestBitDepth = kOfxBitDepthNone; + std::string mostComponents = kOfxImageComponentNone; + double frameRate = getFrameRate(); //< default to the project frame rate + std::string premult = kOfxImageOpaque; + for(std::map::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + ClipInstance *clip = it->second; + + if(!clip->isOutput()) { + bool connected = clip->getConnected(); + + if (connected) { + frameRate = Maximum(frameRate, clip->getFrameRate()); + } + + std::string rawComp = clip->getUnmappedComponents(); + rawComp = clip->findSupportedComp(rawComp); // turn that into a comp the plugin expects on that clip + + const std::string &rawDepth = clip->getUnmappedBitDepth(); + const std::string &rawPreMult = clip->getPremult(); + + if(isChromaticComponent(rawComp)) { + if(connected) { + if(rawPreMult == kOfxImagePreMultiplied) + premult = kOfxImagePreMultiplied; + else if(rawPreMult == kOfxImageUnPreMultiplied && premult != kOfxImagePreMultiplied) + premult = kOfxImageUnPreMultiplied; + } + + if(connected) { + //Update deepest bitdepth and most components only if the infos are relevant, i.e: only if the clip is connected + hasSetCompsAndDepth = true; + deepestBitDepth = FindDeepestBitDepth(deepestBitDepth, rawDepth); + mostComponents = findMostChromaticComponents(mostComponents, rawComp); + } + } + } + } + // default to a reasonable value if there is no input + if (!hasSetCompsAndDepth) { + mostComponents = kOfxImageComponentRGBA; + deepestBitDepth = kOfxBitDepthFloat; + } + + /// set some stuff up + _outputFrameRate = frameRate; + _outputFielding = getDefaultOutputFielding(); + _outputPreMultiplication = premult; + _continuousSamples = false; + _frameVarying = false; + + /// now find the best depth that the plugin supports + deepestBitDepth = bestSupportedDepth(deepestBitDepth); + + /// now add the clip gubbins to the out args + for(std::map::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + ClipInstance *clip = it->second; + + std::string comp, depth; + + std::string rawComp = clip->getUnmappedComponents(); + rawComp = clip->findSupportedComp(rawComp); // turn that into a comp the plugin expects on that clip + const std::string &rawDepth = clip->getUnmappedBitDepth(); + + if(isChromaticComponent(rawComp)) { + + if(clip->isOutput() || clip->isOptional()) { + // "Optional input clips can always have their component types remapped" + // http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#id482755 + depth = deepestBitDepth; + comp = clip->findSupportedComp(mostComponents); + + clip->setPixelDepth(depth); + clip->setComponents(comp); + } + else { + comp = rawComp; + depth = multiBitDepth ? bestSupportedDepth(rawDepth) : deepestBitDepth; + + clip->setPixelDepth(depth); + clip->setComponents(comp); + } + } + else { + /// hmm custom component type, don't touch it and pass it through + clip->setPixelDepth(rawDepth); + clip->setComponents(rawComp); + } + } + } + + /// Initialise the clip preferences arguments, override this to do + /// stuff with wierd components etc... + void Instance::setupClipPreferencesArgs(Property::Set &outArgs) + { + /// reset all the clip prefs stuff to their defaults + setDefaultClipPreferences(); + + static const Property::PropSpec clipPrefsStuffs []= + { + { kOfxImageEffectPropFrameRate, Property::eDouble, 1, false, "1" }, + { kOfxImageEffectPropPreMultiplication, Property::eString, 1, false, "" }, + { kOfxImageClipPropFieldOrder, Property::eString, 1, false, "" }, + { kOfxImageClipPropContinuousSamples, Property::eInt, 1, false, "0" }, + { kOfxImageEffectFrameVarying, Property::eInt, 1, false, "0" }, + Property::propSpecEnd + }; + + outArgs.addProperties(clipPrefsStuffs); + + /// set the default for those + + /// is there multiple bit depth support? Depends on host, plugin and context + bool multiBitDepth = canCurrentlyHandleMultipleClipDepths(); + + outArgs.setStringProperty(kOfxImageClipPropFieldOrder, _outputFielding); + outArgs.setStringProperty(kOfxImageEffectPropPreMultiplication, _outputPreMultiplication); + + /// now add the clip gubbins to the out args + double projectPAR = getProjectPixelAspectRatio(); + bool multipleClipsPAR = supportsMultipleClipPARs(); + /// get the PAR of inputs, if it has different PARs and the effect does not support multiple clips PAR, throw an exception + double inputPar; + bool inputParSet = false; + for (std::map::iterator it2 = _clips.begin(); it2 != _clips.end(); ++it2) { + if (!it2->second->isOutput() && it2->second->getConnected()) { + if (!inputParSet) { + inputPar = it2->second->getAspectRatio(); + inputParSet = true; + } else if (!multipleClipsPAR && inputPar != it2->second->getAspectRatio()) { + // We have several inputs with different aspect ratio, which should be forbidden by the host. + throw Property::Exception(kOfxStatErrValue); + } + } + } + + + for(std::map::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + ClipInstance *clip = it->second; + + std::string componentParamName = "OfxImageClipPropComponents_"+it->first; + std::string depthParamName = "OfxImageClipPropDepth_"+it->first; + std::string parParamName = "OfxImageClipPropPAR_"+it->first; + + Property::PropSpec specComp = {componentParamName.c_str(), Property::eString, 0, false, ""}; // note the support for multi-planar clips + outArgs.createProperty(specComp); + outArgs.setStringProperty(componentParamName.c_str(), clip->getComponents().c_str()); // as it is variable dimension, there is no default value, so we have to set it explicitly + + Property::PropSpec specDep = {depthParamName.c_str(), Property::eString, 1, !multiBitDepth, clip->getPixelDepth().c_str()}; + outArgs.createProperty(specDep); + + Property::PropSpec specPAR = {parParamName.c_str(), Property::eDouble, 1, false, "1"}; + outArgs.createProperty(specPAR); + if (!clip->isOutput()) { + // If the clip is input, use the same par for all inputs unless the plug-in supports multiple clips PAR + double par; + if (!multipleClipsPAR && inputParSet) { + par = inputPar; + } else if (multipleClipsPAR) { + par = clip->getAspectRatio(); + } else { + par = projectPAR; + } + outArgs.setDoubleProperty(parParamName, par); + } else { + // If the clip is output we should propagate the pixel aspect ratio of the inputs + outArgs.setDoubleProperty(parParamName, inputParSet ? inputPar : projectPAR); + } + } + + //Set the output frame rate according to what input clips have. Several inputs with different frame rates should be + //forbidden by the host. + bool outputFrameRateSet = false; + double outputFrameRate = _outputFrameRate; + for (std::map::iterator it2 = _clips.begin(); it2 != _clips.end(); ++it2) { + if (!it2->second->isOutput() && it2->second->getConnected()) { + if (!outputFrameRateSet) { + outputFrameRate = it2->second->getFrameRate(); + outputFrameRateSet = true; + } else if (outputFrameRate != it2->second->getFrameRate()) { + // We have several inputs with different frame rates + throw Property::Exception(kOfxStatErrValue); + } + } + } + + outArgs.setDoubleProperty(kOfxImageEffectPropFrameRate, outputFrameRate); + + } + + /// the idea here is the clip prefs live as active props on the effect + /// and are set up by clip preferences. The action manages the clip + /// preferences bits. We also monitor clip and param changes and + /// flag when clip prefs is dirty. + /// call the clip preferences action + bool Instance::getClipPreferences() + { + /// create the out args with the stuff that does not depend on individual clips + Property::Set outArgs; + + setupClipPreferencesArgs(outArgs); + + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(), + 0, + &outArgs); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<::iterator it=_clips.begin(); + it!=_clips.end(); + ++it) { + ClipInstance *clip = it->second; + + std::string componentParamName = "OfxImageClipPropComponents_"+it->first; + std::string depthParamName = "OfxImageClipPropDepth_"+it->first; + std::string parParamName = "OfxImageClipPropPAR_"+it->first; + +# ifdef OFX_DEBUG_ACTIONS + std::cout << it->first<<"->"<setPixelDepth(outArgs.getStringProperty(depthParamName)); + clip->setComponents(outArgs.getStringProperty(componentParamName)); + //clip->setPixelAspect(outArgs.getDoubleProperty(parParamName)); + } + + _outputFrameRate = outArgs.getDoubleProperty(kOfxImageEffectPropFrameRate); + _outputFielding = outArgs.getStringProperty(kOfxImageClipPropFieldOrder); + _outputPreMultiplication = outArgs.getStringProperty(kOfxImageEffectPropPreMultiplication); + _continuousSamples = outArgs.getIntProperty(kOfxImageClipPropContinuousSamples) != 0; + _frameVarying = outArgs.getIntProperty(kOfxImageEffectFrameVarying) != 0; +# ifdef OFX_DEBUG_ACTIONS + std::cout << _outputFrameRate<<","<<_outputFielding<<","<<_outputPreMultiplication<<","<<_continuousSamples<<","<<_frameVarying<getOverlayDescriptor(bitDepthPerComponent, hasAlpha); + } + + OfxStatus Instance::getTimeDomainAction(OfxRangeD& range) + { + static const Property::PropSpec outStuff[] = { + { kOfxImageEffectPropFrameRange , Property::eDouble, 2, false, "0.0" }, + Property::propSpecEnd + }; + + Property::Set outArgs(outStuff); + +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<getHandle(), + 0, + &outArgs); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)this<<"->"<"<getName(), kOfxChangePluginEdited, frame, renderScale); + endInstanceChangedAction(kOfxChangePluginEdited); + } + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// The image effect suite functions + static OfxStatus getPropertySet(OfxImageEffectHandle h1, + OfxPropertySetHandle *h2) + { + try { + if (!h2) { + return kOfxStatErrBadHandle; + } + + Base *effectBase = reinterpret_cast(h1); + + if (!effectBase || !effectBase->verifyMagic()) { + *h2 = NULL; + + return kOfxStatErrBadHandle; + } + + *h2 = effectBase->getProps().getHandle(); + + return kOfxStatOK; + } catch (...) { + *h2 = NULL; + + return kOfxStatErrBadHandle; + } + } + + static OfxStatus getParamSet(OfxImageEffectHandle h1, + OfxParamSetHandle *h2) + { + try { + if (!h2) { + return kOfxStatErrBadHandle; + } + + ImageEffect::Base *effectBase = reinterpret_cast(h1); + + if (!effectBase || !effectBase->verifyMagic()) { + *h2 = NULL; + + return kOfxStatErrBadHandle; + } + + ImageEffect::Descriptor *effectDescriptor = dynamic_cast(effectBase); + + if(effectDescriptor) { + *h2 = effectDescriptor->getParamSetHandle(); + + return kOfxStatOK; + } + + ImageEffect::Instance *effectInstance = dynamic_cast(effectBase); + + if(effectInstance) { + *h2 = effectInstance->getParamSetHandle(); + + return kOfxStatOK; + } + + *h2 = NULL; + + return kOfxStatErrBadHandle; + } catch (...) { + *h2 = NULL; + + return kOfxStatErrBadHandle; + } + } + + static OfxStatus clipDefine(OfxImageEffectHandle h1, + const char *name, + OfxPropertySetHandle *h2) + { + try { + if (!h2) { + return kOfxStatErrBadHandle; + } + + ImageEffect::Base *effectBase = reinterpret_cast(h1); + + if (!effectBase || !effectBase->verifyMagic()) { + *h2 = NULL; + + return kOfxStatErrBadHandle; + } + + ImageEffect::Descriptor *effectDescriptor = dynamic_cast(effectBase); + + if(effectDescriptor){ + ClipDescriptor *clip = effectDescriptor->defineClip(name); + *h2 = clip->getPropHandle(); + + return kOfxStatOK; + } + + *h2 = NULL; + + return kOfxStatErrBadHandle; + } catch (...) { + *h2 = NULL; + + return kOfxStatErrBadHandle; + } + } + + static OfxStatus clipGetPropertySet(OfxImageClipHandle clip, + OfxPropertySetHandle *propHandle){ + try { + if (!propHandle) { + return kOfxStatErrBadHandle; + } + + ClipInstance *clipInstance = reinterpret_cast(clip); + + if (!clipInstance || !clipInstance->verifyMagic()) { + *propHandle = NULL; + + return kOfxStatErrBadHandle; + } + + *propHandle = clipInstance->getPropHandle(); + return kOfxStatOK; + } catch (...) { + *propHandle = NULL; + + return kOfxStatErrBadHandle; + } + } + + static OfxStatus clipGetImage(OfxImageClipHandle h1, + OfxTime time, + const OfxRectD *h2, + OfxPropertySetHandle *h3) + { + try { + if (!h3) { + return kOfxStatErrBadHandle; + } + + ClipInstance *clipInstance = reinterpret_cast(h1); + + if (!clipInstance || !clipInstance->verifyMagic()) { + *h3 = NULL; + return kOfxStatErrBadHandle; + } + + Image* image = clipInstance->getImage(time,h2); + if(!image) { + *h3 = NULL; + + return kOfxStatFailed; + } + + *h3 = image->getPropHandle(); + + return kOfxStatOK; + } catch (...) { + *h3 = NULL; + + return kOfxStatErrBadHandle; + } + } + + static OfxStatus clipReleaseImage(OfxPropertySetHandle h1) + { + try { + Property::Set *pset = reinterpret_cast(h1); + + if (!pset || !pset->verifyMagic()) { + return kOfxStatErrBadHandle; + } + + Image *image = dynamic_cast(pset); + + if(image){ + // clip::image has a virtual destructor for derived classes + image->releaseReference(); + + return kOfxStatOK; + } + + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatErrBadHandle; + } + } + + static OfxStatus clipGetHandle(OfxImageEffectHandle imageEffect, + const char *name, + OfxImageClipHandle *clip, + OfxPropertySetHandle *propertySet) + { + try { + if (!clip) { + return kOfxStatErrBadHandle; + } + + ImageEffect::Base *effectBase = reinterpret_cast(imageEffect); + + if (!effectBase || !effectBase->verifyMagic()) { + return kOfxStatErrBadHandle; + } + + ImageEffect::Instance *effectInstance = reinterpret_cast(effectBase); + + if(effectInstance){ + ClipInstance* instance = effectInstance->getClip(name); + if(!instance) + return kOfxStatErrBadHandle; + *clip = instance->getHandle(); + if(propertySet) + *propertySet = instance->getPropHandle(); + return kOfxStatOK; + } + + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatErrBadHandle; + } + } + + static OfxStatus clipGetRegionOfDefinition(OfxImageClipHandle clip, + OfxTime time, + OfxRectD *bounds) + { + try { + if (!bounds) { + return kOfxStatErrBadHandle; + } + + ClipInstance *clipInstance = reinterpret_cast(clip); + + if (!clipInstance || !clipInstance->verifyMagic()) { + bounds->x1 = bounds->y1 = bounds->x2 = bounds->y2 = 0.; + + return kOfxStatErrBadHandle; + } + + *bounds = clipInstance->getRegionOfDefinition(time); + if (bounds->x2 < bounds->x1 || bounds->y2 < bounds->y1) { + // the RoD is invalid (empty is OK) + + return kOfxStatFailed; + } + + return kOfxStatOK; + } catch (...) { + return kOfxStatErrBadHandle; + } + } + + // should processing be aborted? + static int abort(OfxImageEffectHandle imageEffect) + { + try { + ImageEffect::Base *effectBase = reinterpret_cast(imageEffect); + + if (!effectBase || !effectBase->verifyMagic()) { + return kOfxStatErrBadHandle; + } + + ImageEffect::Instance *effectInstance = dynamic_cast(effectBase); + + if(effectInstance) + return effectInstance->abort(); + else + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatErrBadHandle; + } + } + + static OfxStatus imageMemoryAlloc(OfxImageEffectHandle instanceHandle, + size_t nBytes, + OfxImageMemoryHandle *memoryHandle) + { + try { + if (!memoryHandle) { + return kOfxStatErrBadHandle; + } + + ImageEffect::Base *effectBase = reinterpret_cast(instanceHandle); + ImageEffect::Instance *effectInstance = reinterpret_cast(effectBase); + Memory::Instance* memory; + + if(effectInstance){ + + if (!effectInstance->verifyMagic()) { + *memoryHandle = NULL; + return kOfxStatErrBadHandle; + } + + memory = effectInstance->imageMemoryAlloc(nBytes); + } + else { + memory = gImageEffectHost->imageMemoryAlloc(nBytes); + } + + if (memory) { + *memoryHandle = memory->getHandle(); + return kOfxStatOK; + } else { + *memoryHandle = NULL; + return kOfxStatErrMemory; + } + } catch (std::bad_alloc&) { + *memoryHandle = NULL; + return kOfxStatErrMemory; + } catch (...) { + *memoryHandle = NULL; + return kOfxStatErrBadHandle; + } + } + + static OfxStatus imageMemoryFree(OfxImageMemoryHandle memoryHandle){ + try { + Memory::Instance *memoryInstance = reinterpret_cast(memoryHandle); + + if(memoryInstance && memoryInstance->verifyMagic()) { + memoryInstance->freeMem(); + delete memoryInstance; + return kOfxStatOK; + } + else + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatErrBadHandle; + } + } + + static + OfxStatus imageMemoryLock(OfxImageMemoryHandle memoryHandle, + void **returnedPtr){ + try { + if (!returnedPtr) { + return kOfxStatErrBadHandle; + } + + Memory::Instance *memoryInstance = reinterpret_cast(memoryHandle); + + if(memoryInstance && memoryInstance->verifyMagic()) { + memoryInstance->lock(); + *returnedPtr = memoryInstance->getPtr(); + + return (*returnedPtr) ? kOfxStatOK : kOfxStatErrMemory; + } + + *returnedPtr = NULL; + + return kOfxStatErrBadHandle; + } catch (...) { + *returnedPtr = NULL; + return kOfxStatErrBadHandle; + } + } + + static OfxStatus imageMemoryUnlock(OfxImageMemoryHandle memoryHandle){ + try { + Memory::Instance *memoryInstance = reinterpret_cast(memoryHandle); + + if(memoryInstance && memoryInstance->verifyMagic()){ + memoryInstance->unlock(); + + return kOfxStatOK; + } + + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatErrBadHandle; + } + } + + static const struct OfxImageEffectSuiteV1 gImageEffectSuite = { + getPropertySet, + getParamSet, + clipDefine, + clipGetHandle, + clipGetPropertySet, + clipGetImage, + clipReleaseImage, + clipGetRegionOfDefinition, + abort, + imageMemoryAlloc, + imageMemoryFree, + imageMemoryLock, + imageMemoryUnlock + }; + +# ifdef OFX_SUPPORTS_OPENGLRENDER + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// The OpenGL render suite functions + + static OfxStatus clipLoadTexture(OfxImageClipHandle h1, + OfxTime time, + const char *format, + const OfxRectD *h2, + OfxPropertySetHandle *h3) + { + try { + if (!h3) { + return kOfxStatErrBadHandle; + } + + ClipInstance *clipInstance = reinterpret_cast(h1); + + if (!clipInstance || !clipInstance->verifyMagic()) { + return kOfxStatErrBadHandle; + } + + if(clipInstance){ + Texture* texture = clipInstance->loadTexture(time,format,h2); + if(!texture) { + *h3 = NULL; + + return kOfxStatFailed; + } + + *h3 = texture->getPropHandle(); + + return kOfxStatOK; + } + + return kOfxStatErrBadHandle; + } catch (...) { + *h3 = NULL; + + return kOfxStatErrBadHandle; + } + } + + static OfxStatus clipFreeTexture(OfxPropertySetHandle h1) + { + try { + Property::Set *pset = reinterpret_cast(h1); + + if (!pset || !pset->verifyMagic()) { + return kOfxStatErrBadHandle; + } + + Texture *texture = dynamic_cast(pset); + + if(texture){ + // clip::texture has a virtual destructor for derived classes + texture->releaseReference(); + return kOfxStatOK; + } + else + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatErrBadHandle; + } + } + + static OfxStatus flushResources( ) + { + return gImageEffectHost->flushOpenGLResources(); + } + + static const struct OfxImageEffectOpenGLRenderSuiteV1 gOpenGLRenderSuite = { + clipLoadTexture, + clipFreeTexture, + flushResources + }; +# endif + + /// message suite function for an image effect + static OfxStatus message(void *handle, const char *type, const char *id, const char *format, ...) + { + try { + ImageEffect::Instance *effectInstance = reinterpret_cast(handle); + OfxStatus stat; + if(effectInstance){ + va_list args; + va_start(args,format); + stat = effectInstance->vmessage(type,id,format,args); + va_end(args); + } + else{ + va_list args; + va_start(args,format); + vprintf(format,args); + va_end(args); + stat = kOfxStatErrBadHandle; + } + return stat; + } catch (...) { + return kOfxStatFailed; + } + } + + static OfxStatus setPersistentMessage(void *handle, const char *type, const char *id, const char *format, ...) + { + try { + ImageEffect::Instance *effectInstance = reinterpret_cast(handle); + OfxStatus stat; + if(effectInstance){ + va_list args; + va_start(args,format); + stat = effectInstance->setPersistentMessage(type,id,format,args); + va_end(args); + } + else{ + va_list args; + va_start(args,format); + vprintf(format,args); + va_end(args); + stat = kOfxStatErrBadHandle; + } + return stat; + } catch (...) { + return kOfxStatFailed; + } + } + + static OfxStatus clearPersistentMessage(void *handle) + { + try { + ImageEffect::Instance *effectInstance = reinterpret_cast(handle); + OfxStatus stat; + if(effectInstance){ + stat = effectInstance->clearPersistentMessage(); + } + else{ + stat = kOfxStatErrBadHandle; + } + return stat; + } catch (...) { + return kOfxStatFailed; + } + } + + /// message suite for an image effect plugin (backward-compatible with OfxMessageSuiteV1) + static const struct OfxMessageSuiteV2 gMessageSuite = { + message, + setPersistentMessage, + clearPersistentMessage + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// make an overlay interact for an image effect + OverlayInteract::OverlayInteract(ImageEffect::Instance &effect, int bitDepthPerComponent, bool hasAlpha) + : Interact::Instance(effect.getOverlayDescriptor(bitDepthPerComponent, hasAlpha), + (void *)(effect.getHandle())) + , _instance(effect) + { + } + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // Progress suite functions + + /// begin progressing + static OfxStatus ProgressStartV1(void *effectInstance, + const char *label) + { + if (!effectInstance) + return kOfxStatErrBadHandle; + Instance *me = reinterpret_cast(effectInstance); + me->progressStart(label, ""); + return kOfxStatOK; + } + + + /// begin progressing + static OfxStatus ProgressStart(void *effectInstance, + const char *message, + const char *messageid) + { + if (!effectInstance) + return kOfxStatErrBadHandle; + Instance *me = reinterpret_cast(effectInstance); + me->progressStart(message, messageid); + return kOfxStatOK; + } + + /// finish progressing + static OfxStatus ProgressEnd(void *effectInstance) + { + if (!effectInstance) + return kOfxStatErrBadHandle; + Instance *me = reinterpret_cast(effectInstance); + me->progressEnd(); + return kOfxStatOK; + } + + /// update progressing + static OfxStatus ProgressUpdate(void *effectInstance, double progress) + { + if (!effectInstance) + return kOfxStatErrBadHandle; + Instance *me = reinterpret_cast(effectInstance); + bool v = me->progressUpdate(progress); + return v ? kOfxStatOK : kOfxStatReplyNo; + } + + /// our progress suite + struct OfxProgressSuiteV1 gProgressSuiteV1 = { + ProgressStartV1, + ProgressUpdate, + ProgressEnd + }; + + struct OfxProgressSuiteV2 gProgressSuiteV2 = { + ProgressStart, + ProgressUpdate, + ProgressEnd + }; + + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // timeline suite functions + + /// timeline suite function + static OfxStatus TimeLineGetTime(void *effectInstance, double *time) + { + if (!effectInstance) + return kOfxStatErrBadHandle; + Instance *me = reinterpret_cast(effectInstance); + *time = me->timeLineGetTime(); + return kOfxStatOK; + } + + /// timeline suite function + static OfxStatus TimeLineGotoTime(void *effectInstance, double time) + { + if (!effectInstance) + return kOfxStatErrBadHandle; + Instance *me = reinterpret_cast(effectInstance); + me->timeLineGotoTime(time); + return kOfxStatOK; + } + + /// timeline suite function + static OfxStatus TimeLineGetBounds(void *effectInstance, double *firstTime, double *lastTime) + { + if (!effectInstance) + return kOfxStatErrBadHandle; + Instance *me = reinterpret_cast(effectInstance); + me->timeLineGetBounds(*firstTime, *lastTime); + return kOfxStatOK; + } + + /// our progress suite + struct OfxTimeLineSuiteV1 gTimelineSuite = { + TimeLineGetTime, + TimeLineGotoTime, + TimeLineGetBounds + }; + + //////////////////////////////////////////////////////////////////////////////// +#ifdef OFX_SUPPORTS_MULTITHREAD + // Forward all multithread suite calls to the host implementation. + + static OfxStatus multiThread(OfxThreadFunctionV1 func, + unsigned int nThreads, + void *customArg) + { + return gImageEffectHost->multiThread(func, nThreads, customArg); + } + + static OfxStatus multiThreadNumCPUs(unsigned int *nCPUs) + { + return gImageEffectHost->multiThreadNumCPUS(nCPUs); + } + + static OfxStatus multiThreadIndex(unsigned int *threadIndex){ + return gImageEffectHost->multiThreadIndex(threadIndex); + } + + static int multiThreadIsSpawnedThread(void){ + return gImageEffectHost->multiThreadIsSpawnedThread(); + } + + static OfxStatus mutexCreate(OfxMutexHandle *mutex, int lockCount) + { + return gImageEffectHost->mutexCreate(mutex, lockCount); + } + + static OfxStatus mutexDestroy(const OfxMutexHandle mutex) + { + return gImageEffectHost->mutexDestroy(mutex); + } + + static OfxStatus mutexLock(const OfxMutexHandle mutex){ + return gImageEffectHost->mutexLock(mutex); + } + + static OfxStatus mutexUnLock(const OfxMutexHandle mutex){ + return gImageEffectHost->mutexUnLock(mutex); + } + + static OfxStatus mutexTryLock(const OfxMutexHandle mutex){ + return gImageEffectHost->mutexTryLock(mutex); + } +#else // !OFX_SUPPORTS_MULTITHREAD + /// a simple multithread suite + static OfxStatus multiThread(OfxThreadFunctionV1 func, + unsigned int /*nThreads*/, + void *customArg) + { + if (!func) + return kOfxStatFailed; + func(0,1,customArg); + return kOfxStatOK; + } + + static OfxStatus multiThreadNumCPUs(unsigned int *nCPUs) + { + if (!nCPUs) + return kOfxStatFailed; + *nCPUs = 1; + return kOfxStatOK; + } + + static OfxStatus multiThreadIndex(unsigned int *threadIndex){ + if (!threadIndex) + return kOfxStatFailed; + *threadIndex = 0; + return kOfxStatOK; + } + + static int multiThreadIsSpawnedThread(void){ + return false; + } + + static OfxStatus mutexCreate(OfxMutexHandle *mutex, int /*lockCount*/) + { + if (!mutex) + return kOfxStatFailed; + // do nothing single threaded + *mutex = 0; + return kOfxStatOK; + } + + static OfxStatus mutexDestroy(const OfxMutexHandle mutex) + { + if (mutex != 0) + return kOfxStatErrBadHandle; + // do nothing single threaded + return kOfxStatOK; + } + + static OfxStatus mutexLock(const OfxMutexHandle mutex){ + if (mutex != 0) + return kOfxStatErrBadHandle; + // do nothing single threaded + return kOfxStatOK; + } + + static OfxStatus mutexUnLock(const OfxMutexHandle mutex){ + if (mutex != 0) + return kOfxStatErrBadHandle; + // do nothing single threaded + return kOfxStatOK; + } + + static OfxStatus mutexTryLock(const OfxMutexHandle mutex){ + if (mutex != 0) + return kOfxStatErrBadHandle; + // do nothing single threaded + return kOfxStatOK; + } +#endif // !OFX_SUPPORTS_MULTITHREAD + + static const struct OfxMultiThreadSuiteV1 gMultiThreadSuite = { + multiThread, + multiThreadNumCPUs, + multiThreadIndex, + multiThreadIsSpawnedThread, + mutexCreate, + mutexDestroy, + mutexLock, + mutexUnLock, + mutexTryLock + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// The image effect host + + /// properties for the image effect host + static const Property::PropSpec hostStuffs[] = { + { kOfxImageEffectHostPropIsBackground, Property::eInt, 1, true, "0" }, + { kOfxImageEffectPropSupportsOverlays, Property::eInt, 1, true, "1" }, + { kOfxImageEffectPropSupportsMultiResolution, Property::eInt, 1, true, "1" }, + { kOfxImageEffectPropSupportsTiles, Property::eInt, 1, true, "1" }, + { kOfxImageEffectPropTemporalClipAccess, Property::eInt, 1, true, "1" }, + + + + /// xxx this needs defaulting manually + { kOfxImageEffectPropSupportedComponents, Property::eString, 0, true, "" }, + /// xxx this needs defaulting manually + + { kOfxImageEffectPropSupportedPixelDepths, Property::eString, 0, true, "" }, + + /// xxx this needs defaulting manually + + { kOfxImageEffectPropSupportedContexts, Property::eString, 0, true, "" }, + /// xxx this needs defaulting manually + + { kOfxImageEffectPropSupportsMultipleClipDepths, Property::eInt, 1, true, "1" }, + { kOfxImageEffectPropSupportsMultipleClipPARs, Property::eInt, 1, true, "0" }, + { kOfxImageEffectPropSetableFrameRate, Property::eInt, 1, true, "0" }, + { kOfxImageEffectPropSetableFielding, Property::eInt, 1, true, "0" }, + { kOfxParamHostPropSupportsCustomInteract, Property::eInt, 1, true, "0" }, + { kOfxParamHostPropSupportsStringAnimation, Property::eInt, 1, true, "0" }, + { kOfxParamHostPropSupportsChoiceAnimation, Property::eInt, 1, true, "0" }, + { kOfxParamHostPropSupportsBooleanAnimation, Property::eInt, 1, true, "0" }, + { kOfxParamHostPropSupportsCustomAnimation, Property::eInt, 1, true, "0" }, + { kOfxPropHostOSHandle, Property::ePointer, 1, true, NULL }, +#ifdef OFX_SUPPORTS_PARAMETRIC + { kOfxParamHostPropSupportsParametricAnimation, Property::eInt, 1, true, "0"}, +#endif + { kOfxParamHostPropMaxParameters, Property::eInt, 1, true, "-1" }, + { kOfxParamHostPropMaxPages, Property::eInt, 1, true, "0" }, + { kOfxParamHostPropPageRowColumnCount, Property::eInt, 2, true, "0" }, + { kOfxImageEffectInstancePropSequentialRender, Property::eInt, 1, true, "0" }, // OFX 1.2 +#ifdef OFX_SUPPORTS_OPENGLRENDER + { kOfxImageEffectPropOpenGLRenderSupported, Property::eString, 1, true, "false"}, // OFX 1.3 + { kOfxImageEffectPropCudaRenderSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropCudaStreamSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropMetalRenderSupported, Property::eString, 1, false, "false" }, + { kOfxImageEffectPropOpenCLRenderSupported, Property::eString, 1, false, "false" }, +#endif + { kOfxImageEffectPropRenderQualityDraft, Property::eInt, 1, true, "0" }, // OFX 1.4 + { kOfxImageEffectHostPropNativeOrigin, Property::eString, 0, true, kOfxHostNativeOriginBottomLeft }, // OFX 1.4 + Property::propSpecEnd + }; + + /// ctor + Host::Host() + { + /// add the properties for an image effect host, derived classs to set most of them + _properties.addProperties(hostStuffs); + } + + /// optionally over-ridden function to register the creation of a new descriptor in the host app + void Host::initDescriptor(Descriptor* /*desc*/) + { + } + + /// Use this in any dialogue etc... showing progress + void Host::loadingStatus(const std::string &) + { + } + + bool Host::pluginSupported(ImageEffectPlugin */*plugin*/, std::string &/*reason*/) const + { + return true; + } + + // override this to use your own memory instance - must inherrit from memory::instance + Memory::Instance* Host::newMemoryInstance(size_t /*nBytes*/) { + return 0; + } + + // return an memory::instance calls makeMemoryInstance that can be overriden + Memory::Instance* Host::imageMemoryAlloc(size_t nBytes){ + Memory::Instance* instance = newMemoryInstance(nBytes); + if(instance) + return instance; + else{ + Memory::Instance* instance = new Memory::Instance; + instance->alloc(nBytes); + return instance; + } + } + + /// our suite fetcher + const void *Host::fetchSuite(const char *suiteName, int suiteVersion) + { + if (strcmp(suiteName, kOfxImageEffectSuite)==0) { + if(suiteVersion==1) + return (void *)&gImageEffectSuite; + else + return NULL; + } + else if (strcmp(suiteName, kOfxParameterSuite)==0) { + return Param::GetSuite(suiteVersion); + } + else if (strcmp(suiteName, kOfxMessageSuite)==0) { + // version 2 is backward-compatible + if(suiteVersion==1 || suiteVersion==2) + return (void *)&gMessageSuite; + else + return NULL; + } + else if (strcmp(suiteName, kOfxInteractSuite)==0) { + return Interact::GetSuite(suiteVersion); + } + else if (strcmp(suiteName, kOfxProgressSuite)==0) { + if(suiteVersion==1) + return (void*)&gProgressSuiteV1; + else if(suiteVersion==2) + return (void*)&gProgressSuiteV2; + else + return 0; + } + else if (strcmp(suiteName, kOfxTimeLineSuite)==0) { + if(suiteVersion==1) + return (void*)&gTimelineSuite; + else + return 0; + } + else if (strcmp(suiteName, kOfxMultiThreadSuite)==0) { + if(suiteVersion == 1) + return (void*)&gMultiThreadSuite; + else + return NULL; + } +# ifdef OFX_SUPPORTS_OPENGLRENDER + else if (strcmp(suiteName, kOfxOpenGLRenderSuite)==0) { + if(suiteVersion == 1) + return (void*)&gOpenGLRenderSuite; + else + return NULL; + } +# endif +# ifdef OFX_SUPPORTS_PARAMETRIC + else if (strcmp(suiteName, kOfxParametricParameterSuite)==0) { + return ParametricParam::GetSuite(suiteVersion); + } +# endif + else /// otherwise just grab the base class one, which is props and memory + return OFX::Host::Host::fetchSuite(suiteName, suiteVersion); + } + + } // ImageEffect + + } // Host + +} // OFX diff --git a/third_party/openfx/HostSupport/src/ofxhImageEffectAPI.cpp b/third_party/openfx/HostSupport/src/ofxhImageEffectAPI.cpp new file mode 100755 index 000000000..a402770fd --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhImageEffectAPI.cpp @@ -0,0 +1,606 @@ + + +#include + +#include +#include +#include +#include + +// ofx +#include "ofxImageEffect.h" + +// ofx host +#include "ofxhBinary.h" +#include "ofxhPropertySuite.h" +#include "ofxhClip.h" +#include "ofxhParam.h" +#include "ofxhMemory.h" +#include "ofxhImageEffect.h" +#include "ofxhPluginAPICache.h" +#include "ofxhPluginCache.h" +#include "ofxhHost.h" +#include "ofxhImageEffectAPI.h" +#include "ofxhXml.h" + +// Disable the "this pointer used in base member initialiser list" warning in Windows +namespace OFX { + + namespace Host { + + namespace ImageEffect { + + /// our global host bobject, set when the cache is created + OFX::Host::ImageEffect::Host *gImageEffectHost; + + /// ctor +#ifdef WINDOWS +#pragma warning( disable : 4355 ) +#endif + ImageEffectPlugin::ImageEffectPlugin(PluginCache &pc, PluginBinary *pb, int pi, OfxPlugin *pl) + : Plugin(pb, pi, pl) + , _pc(pc) + , _baseDescriptor(NULL) + , _madeKnownContexts(false) + { + _baseDescriptor = gImageEffectHost->makeDescriptor(this); + } + + ImageEffectPlugin::ImageEffectPlugin(PluginCache &pc, + PluginBinary *pb, + int pi, + const std::string &api, + int apiVersion, + const std::string &pluginId, + const std::string &rawId, + int pluginMajorVersion, + int pluginMinorVersion) + : Plugin(pb, pi, api, apiVersion, pluginId, rawId, pluginMajorVersion, pluginMinorVersion) + , _pc(pc) + , _baseDescriptor(NULL) + , _madeKnownContexts(false) + { + _baseDescriptor = gImageEffectHost->makeDescriptor(this); + } + +#ifdef WINDOWS +#pragma warning( default : 4355 ) +#endif + + ImageEffectPlugin::~ImageEffectPlugin() + { + _contexts.clear(); + if(_pluginHandle) { + OfxPlugin *op = _pluginHandle->getOfxPlugin(); + OfxStatus stat; + try { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)op<<"->"<mainEntry(kOfxActionUnload, 0, 0, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)op<<"->"<"< ied) + { + _contexts[context] = ied; + _knownContexts.insert(context); + _madeKnownContexts = true; + } + + void ImageEffectPlugin::addContext(const std::string &context) + { + _knownContexts.insert(context); + _madeKnownContexts = true; + } + + void ImageEffectPlugin::addContextInternal(const std::string &context) const + { + _knownContexts.insert(context); + _madeKnownContexts = true; + } + + void ImageEffectPlugin::saveXML(std::ostream &os) + { + APICache::propertySetXMLWrite(os, getDescriptor().getProps(), 6); + } + + const std::set &ImageEffectPlugin::getContexts() const { + if (_madeKnownContexts) { + return _knownContexts; + } + else { + const OFX::Host::Property::Set &eProps = getDescriptor().getProps(); + int size = eProps.getDimension(kOfxImageEffectPropSupportedContexts); + for (int j=0;jgetOfxPlugin(); + + if (!op) { + _pluginHandle.reset(); + return nullptr; + } + + OfxStatus stat; + try { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)op<<"->"<mainEntry(kOfxActionLoad, 0, 0, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)op<<"->"<"<"<mainEntry(kOfxActionDescribe, getDescriptor().getHandle(), 0, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)op<<"->"<"<>::iterator it = _contexts.find(context); + + if (it != _contexts.end()) { + //printf("found context description.\n"); + return it->second.get(); + } + + if (_knownContexts.find(context) == _knownContexts.end()) { + return nullptr; + } + + // printf("doing context description.\n"); + + OFX::Host::Property::PropSpec inargspec[] = { + { kOfxImageEffectPropContext, OFX::Host::Property::eString, 1, true, context.c_str() }, + Property::propSpecEnd + }; + + OFX::Host::Property::Set inarg(inargspec); + + PluginHandle *ph = getPluginHandle(); + if (!ph) { + return nullptr; + } + std::shared_ptr newContext( gImageEffectHost->makeDescriptor(getDescriptor(), this)); + + OfxStatus stat; + try { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)ph->getOfxPlugin()<<"->"<getOfxPlugin()->mainEntry(kOfxImageEffectActionDescribeInContext, newContext->getHandle(), inarg.getHandle(), 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)ph->getOfxPlugin()<<"->"<"<getOfxPlugin(), kOfxImageEffectActionDescribeInContext); + + if (stat == kOfxStatOK || stat == kOfxStatReplyDefault) { + _contexts[context] = std::move(newContext); + return _contexts[context].get(); + } + return nullptr; + } + + ImageEffect::Instance* ImageEffectPlugin::createInstance(const std::string &context, void *clientData) + { + + /// todo - we need to make sure action:load is called, then action:describe again + /// (not because we are expecting the results to change, but because plugin + /// might get confused otherwise), then a describe_in_context + + PluginHandle *ph = getPluginHandle(); + if (!ph) { + return nullptr; + } + + Descriptor *desc = getContext(context); + + if (desc) { + ImageEffect::Instance *instance = gImageEffectHost->newInstance(clientData, + this, + *desc, + context); + instance->populate(); + return instance; + } + return 0; + } + + void ImageEffectPlugin::unload() { + if (_pluginHandle) { + OfxStatus stat; + try { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)_pluginHandle->getOfxPlugin()<<"->"<mainEntry(kOfxActionUnload, 0, 0, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)_pluginHandle->getOfxPlugin()<<"->"<"<::iterator i=_plugins.begin();i!=_plugins.end();i++) { + ImageEffectPlugin *p = *i; + + if (p->getIdentifier() != identifier) { + continue; + } + + if (vermaj != -1 && p->getVersionMajor() != vermaj) { + continue; + } + + if (vermin != -1 && p->getVersionMinor() != vermin) { + continue; + } + + if (!sofar || p->trumps(sofar)) { + sofar = p; + } + } + + return sofar; + } + + /// whether we support this plugin. + bool PluginCache::pluginSupported(OFX::Host::Plugin *p, std::string &reason) const { + if (!gImageEffectHost) { + reason = "host not initialized"; + return false; + } + auto *plugin = dynamic_cast(p); + if (!plugin) { + reason = "not an image effect plugin"; + return false; + } + return gImageEffectHost->pluginSupported(plugin, reason); + } + + /// get the plugin by label. vermaj and vermin can be specified. if they are not it will + /// pick the highest found version. + ImageEffectPlugin *PluginCache::getPluginByLabel(const std::string &label, int vermaj, int vermin) + { + // return the highest version one, which fits the pattern provided + ImageEffectPlugin *sofar = 0; + + for (std::vector::iterator i=_plugins.begin();i!=_plugins.end();i++) { + ImageEffectPlugin *p = *i; + + if (p->getDescriptor().getProps().getStringProperty(kOfxPropLabel) != label) { + continue; + } + + if (vermaj != -1 && p->getVersionMajor() != vermaj) { + continue; + } + + if (vermin != -1 && p->getVersionMinor() != vermin) { + continue; + } + + if (!sofar || p->trumps(sofar)) { + sofar = p; + } + } + + return sofar; + } + + const std::vector& PluginCache::getPlugins() const + { + return _plugins; + } + + const std::map& PluginCache::getPluginsByID() const + { + return _pluginsByID; + } + + /// handle the case where the info needs filling in from the file. runs the "describe" action on the plugin. + void PluginCache::loadFromPlugin(Plugin *op) const { + std::string msg = "loading "; + msg += op->getRawIdentifier(); + + _host->loadingStatus(msg); + + ImageEffectPlugin *p = dynamic_cast(op); + assert(p); + + PluginHandle plug(p, _host); + + OfxStatus stat; + try { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)plug.getOfxPlugin()<<"->"<mainEntry(kOfxActionLoad, 0, 0, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)plug.getOfxPlugin()<<"->"<"<getIdentifier() << std::endl; + return; + } + + try { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)plug.getOfxPlugin()<<"->"<mainEntry(kOfxActionDescribe, p->getDescriptor().getHandle(), 0, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)plug.getOfxPlugin()<<"->"<"<getIdentifier() << std::endl; + return; + } + + ImageEffect::Descriptor &e = p->getDescriptor(); + Property::Set &eProps = e.getProps(); + + int size = eProps.getDimension(kOfxImageEffectPropSupportedContexts); + + for (int j=0;jaddContext(context); + } + + try { +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)plug.getOfxPlugin()<<"->"<mainEntry(kOfxActionUnload, 0, 0, 0); +# ifdef OFX_DEBUG_ACTIONS + std::cout << "OFX: "<<(void*)plug.getOfxPlugin()<<"->"<"<getIdentifier() << std::endl; + return; + } + } + + + /// handler for preparing to read in a chunk of XML from the cache, set up context to do this + void PluginCache::beginXmlParsing(Plugin *p) { + _currentPlugin = dynamic_cast(p); + } + + /// XML handler : element begins (everything is stored in elements and attributes) + void PluginCache::xmlElementBegin(const std::string &el, std::map map) + { + if (el == "apiproperties") { + return; + } + + if (el == "context") { + std::shared_ptr newContext = gImageEffectHost->makeDescriptor(_currentPlugin->getBinary()->getBundlePath(), _currentPlugin); + _currentContext = newContext.get(); + _currentPlugin->addContext(map["name"], newContext); + return; + } + + if (el == "param" && _currentContext) { + std::string pname = map["name"]; + std::string ptype = map["type"]; + + _currentParam = _currentContext->paramDefine(ptype.c_str(), pname.c_str()); + return; + } + + if (el == "clip" && _currentContext) { + std::string cname = map["name"]; + + _currentClip = new ClipDescriptor(cname); + _currentContext->addClip(cname, _currentClip); + return; + } + + if (_currentContext && _currentParam) { + APICache::propertySetXMLRead(el, map, _currentParam->getProperties(), _currentProp); + return; + } + + if (_currentContext && _currentClip) { + APICache::propertySetXMLRead(el, map, _currentClip->getProps(), _currentProp); + return; + } + + if (!_currentContext && !_currentParam) { + APICache::propertySetXMLRead(el, map, _currentPlugin->getDescriptor().getProps(), _currentProp); + return; + } + + std::cout << "element " << el << "\n"; + assert(false); + } + + void PluginCache::xmlCharacterHandler(const std::string &) { + } + + void PluginCache::xmlElementEnd(const std::string &el) { + if (el == "param") { + _currentParam = 0; + } + + if (el == "context") { + _currentContext = 0; + } + } + + void PluginCache::endXmlParsing() { + _currentPlugin = 0; + } + + void PluginCache::saveXML(Plugin *ip, std::ostream &os) const { + ImageEffectPlugin *p = dynamic_cast(ip); + if (p) { + p->saveXML(os); + } + } + + void PluginCache::confirmPlugin(Plugin *p) { + ImageEffectPlugin *plugin = dynamic_cast(p); + if (!plugin) { + return; + } + _plugins.push_back(plugin); + + if (_pluginsByID.find(plugin->getIdentifier()) != _pluginsByID.end()) { + ImageEffectPlugin *otherPlugin = _pluginsByID[plugin->getIdentifier()]; + if (plugin->trumps(otherPlugin)) { + _pluginsByID[plugin->getIdentifier()] = plugin; + } + } else { + _pluginsByID[plugin->getIdentifier()] = plugin; + } + + MajorPlugin maj(plugin); + + if (_pluginsByIDMajor.find(maj) != _pluginsByIDMajor.end()) { + ImageEffectPlugin *otherPlugin = _pluginsByIDMajor[maj]; + if (plugin->trumps(otherPlugin)) { + _pluginsByIDMajor[maj] = plugin; + } + } else { + _pluginsByIDMajor[maj] = plugin; + } + } + + Plugin *PluginCache::newPlugin(PluginBinary *pb, + int pi, + OfxPlugin *pl) { + ImageEffectPlugin *plugin = new ImageEffectPlugin(*this, pb, pi, pl); + return plugin; + } + + Plugin *PluginCache::newPlugin(PluginBinary *pb, + int pi, + const std::string &api, + int apiVersion, + const std::string &pluginId, + const std::string &rawId, + int pluginMajorVersion, + int pluginMinorVersion) + { + ImageEffectPlugin *plugin = new ImageEffectPlugin(*this, pb, pi, api, apiVersion, pluginId, rawId, pluginMajorVersion, pluginMinorVersion); + return plugin; + } + + void PluginCache::dumpToStdOut() + { + if (_pluginsByID.empty()) + std::cout << "No Plug-ins Found." << std::endl; + + for(std::map::const_iterator it = _pluginsByID.begin(); it != _pluginsByID.end(); ++it) + { + std::cout << "Plug-in:" << it->first << std::endl; + std::cout << "\t" << "Filepath: " << it->second->getBinary()->getFilePath(); + std::cout<< "(" << it->second->getIndex() << ")" << std::endl; + + std::cout << "Contexts:" << std::endl; + const std::set& contexts = it->second->getContexts(); + for (std::set::const_iterator it2 = contexts.begin(); it2 != contexts.end(); ++it2) + std::cout << "\t* " << *it2 << std::endl; + const Descriptor& d = it->second->getDescriptor(); + std::cout << "Inputs:" << std::endl; + const std::map& inputs = d.getClips(); + for (std::map::const_iterator it2 = inputs.begin(); it2 != inputs.end(); ++it2) + std::cout << "\t\t* " << it2->first << std::endl; + } + } + + } // ImageEffect + + } // Host + +} // OFX diff --git a/third_party/openfx/HostSupport/src/ofxhInteract.cpp b/third_party/openfx/HostSupport/src/ofxhInteract.cpp new file mode 100755 index 000000000..d37d2df22 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhInteract.cpp @@ -0,0 +1,443 @@ + + +// ofx +#include "ofxKeySyms.h" +#include "ofxCore.h" +#include "ofxImageEffect.h" + +// ofx host +#include "ofxhBinary.h" +#include "ofxhClip.h" +#include "ofxhParam.h" +#include "ofxhMemory.h" +#include "ofxhImageEffect.h" +#include "ofxhInteract.h" +#include "ofxOld.h" // old plugins may rely on deprecated properties being present + +namespace OFX { + + namespace Host { + + namespace Interact { + + // + // descriptor + // + static const Property::PropSpec interactDescriptorStuffs[] = { + { kOfxInteractPropHasAlpha , Property::eInt, 1, true, "0" }, + { kOfxInteractPropBitDepth , Property::eInt, 1, true, "0" }, + Property::propSpecEnd + }; + + Descriptor::Descriptor() + : _properties(interactDescriptorStuffs) + , _state(eUninitialised) + , _entryPoint(NULL) + { + } + + Descriptor::~Descriptor() + { + } + + /// call describe on this descriptor + bool Descriptor::describe(int bitDepthPerComponent, bool hasAlpha) + { + if(_state == eUninitialised) { + _properties.setIntProperty(kOfxInteractPropBitDepth, bitDepthPerComponent); + _properties.setIntProperty(kOfxInteractPropHasAlpha, (int)(hasAlpha)); + + OfxStatus stat = callEntry(kOfxActionDescribe, getHandle(), NULL, NULL); + if(stat == kOfxStatOK || stat == kOfxStatReplyDefault) { + _state = eDescribed; + } + else { + _state = eFailed; + } + } + return _state == eDescribed; + } + + // call the interactive entry point + OfxStatus Descriptor::callEntry(const char *action, + void *handle, + OfxPropertySetHandle inArgs, + OfxPropertySetHandle outArgs) + { + if(_entryPoint && _state != eFailed) { + return _entryPoint(action, handle, inArgs, outArgs); + } + else + return kOfxStatFailed; + + return kOfxStatOK; + } + + + //////////////////////////////////////////////////////////////////////////////// + static const Property::PropSpec interactInstanceStuffs[] = { + { kOfxPropEffectInstance, Property::ePointer, 1, true, NULL }, + { kOfxPropInstanceData, Property::ePointer, 1, false, NULL }, + { kOfxInteractPropPixelScale, Property::eDouble, 2, true, "1.0f" }, + { kOfxInteractPropBackgroundColour , Property::eDouble, 3, true, "0.0f" }, +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + { kOfxInteractPropViewportSize, Property::eDouble, 2, true, "100.0f" }, +#endif + { kOfxInteractPropSlaveToParam , Property::eString, 0, false, ""}, + { kOfxInteractPropSuggestedColour , Property::eDouble, 3, true, "1.0f" }, + Property::propSpecEnd + }; + + static const Property::PropSpec interactArgsStuffs[] = { + { kOfxPropEffectInstance, Property::ePointer, 1, false, NULL }, + { kOfxPropTime, Property::eDouble, 1, false, "0.0" }, + { kOfxImageEffectPropRenderScale, Property::eDouble, 2, false, "0.0" }, + { kOfxInteractPropBackgroundColour , Property::eDouble, 3, false, "0.0f" }, +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + { kOfxInteractPropViewportSize, Property::eDouble, 2, false, "0.0f" }, +#endif + { kOfxInteractPropPixelScale, Property::eDouble, 2, false, "1.0f" }, + { kOfxInteractPropPenPosition, Property::eDouble, 2, false, "0.0" }, + { kOfxInteractPropPenViewportPosition, Property::eInt, 2, false, "0" }, // new in OFX 1.2 + { kOfxInteractPropPenPressure, Property::eDouble, 1, false, "0.0" }, + { kOfxPropKeyString, Property::eString, 1, false, "" }, + { kOfxPropKeySym, Property::eInt, 1, false, "0" }, + Property::propSpecEnd + }; + + // instance + + Instance::Instance(Descriptor& desc, void *effectInstance) + : _descriptor(desc) + , _properties(interactInstanceStuffs) + , _state(desc.getState()) + , _effectInstance(effectInstance) + , _argProperties(interactArgsStuffs) + { + _properties.setPointerProperty(kOfxPropEffectInstance, effectInstance); + _properties.setChainedSet(&desc.getProperties()); /// chain it into the descriptor props + _properties.setGetHook(kOfxInteractPropPixelScale, this); + _properties.setGetHook(kOfxInteractPropBackgroundColour,this); +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + _properties.setGetHook(kOfxInteractPropViewportSize,this); +#endif + _properties.setGetHook(kOfxInteractPropSuggestedColour,this); + + _argProperties.setGetHook(kOfxInteractPropPixelScale, this); + _argProperties.setGetHook(kOfxInteractPropBackgroundColour,this); +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + _argProperties.setGetHook(kOfxInteractPropViewportSize,this); +#endif + } + + Instance::~Instance() + { + /// call it directly incase CI failed and we should always tidy up after create instance + callEntry(kOfxActionDestroyInstance, NULL); + } + + /// call the entry point in the descriptor with action and the given args + OfxStatus Instance::callEntry(const char *action, Property::Set *inArgs) + { + if(_state != eFailed) { + OfxPropertySetHandle inHandle = inArgs ? inArgs->getHandle() : NULL ; + return _descriptor.callEntry(action, getHandle(), inHandle, NULL); + } + return kOfxStatFailed; + } + + // do nothing + int Instance::getDimension(const std::string &name) const + { + if(name == kOfxInteractPropPixelScale){ + return 2; + } + else if(name == kOfxInteractPropBackgroundColour){ + return 3; + } + else if(name == kOfxInteractPropSuggestedColour + ){ + return 3; + } +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + else if(name == kOfxInteractPropViewportSize){ + return 2; + } +#endif + else + throw Property::Exception(kOfxStatErrValue); + } + + // do nothing function + void Instance::reset(const std::string &/*name*/) + { + // no-op + } + + double Instance::getDoubleProperty(const std::string &name, int index) const + { + if(name == kOfxInteractPropPixelScale){ + if(index>=2) throw Property::Exception(kOfxStatErrBadIndex); + double first[2]; + getPixelScale(first[0],first[1]); + return first[index]; + } + else if(name == kOfxInteractPropBackgroundColour){ + if(index>=3) throw Property::Exception(kOfxStatErrBadIndex); + double first[3]; + getBackgroundColour(first[0],first[1],first[2]); + return first[index]; + } + else if(name == kOfxInteractPropSuggestedColour + ){ + if(index>=3) throw Property::Exception(kOfxStatErrBadIndex); + double first[3]; + bool stat = getSuggestedColour(first[0],first[1],first[2]); + if (!stat) throw Property::Exception(kOfxStatReplyDefault); + return first[index]; + } +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + else if(name == kOfxInteractPropViewportSize){ + if(index>=2) throw Property::Exception(kOfxStatErrBadIndex); + double first[2]; + getViewportSize(first[0],first[1]); + return first[index]; + } +#endif + else + throw Property::Exception(kOfxStatErrUnknown); + } + + void Instance::getDoublePropertyN(const std::string &name, double *first, int n) const + { + if(name == kOfxInteractPropPixelScale){ + if(n>2) throw Property::Exception(kOfxStatErrBadIndex); + getPixelScale(first[0],first[1]); + } + else if(name == kOfxInteractPropBackgroundColour){ + if(n>3) throw Property::Exception(kOfxStatErrBadIndex); + getBackgroundColour(first[0],first[1],first[2]); + } + else if(name == kOfxInteractPropSuggestedColour + ){ + if(n>3) throw Property::Exception(kOfxStatErrBadIndex); + bool stat = getSuggestedColour(first[0],first[1],first[2]); + if (!stat) throw Property::Exception(kOfxStatReplyDefault); + } +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + else if(name == kOfxInteractPropViewportSize){ + if(n>2) throw Property::Exception(kOfxStatErrBadIndex); + getViewportSize(first[0],first[1]); + } +#endif + else + throw Property::Exception(kOfxStatErrUnknown); + } + + void Instance::getSlaveToParam(std::vector& params) const + { + int nSlaveParams = _properties.getDimension(kOfxInteractPropSlaveToParam); + + for (int i=0; i(handle); + if(interactInstance) + return interactInstance->swapBuffers(); + else + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatFailed; + } + } + + static OfxStatus interactRedraw(OfxInteractHandle handle) + { + try { + Interact::Instance *interactInstance = reinterpret_cast(handle); + if(interactInstance) + return interactInstance->redraw(); + else + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatFailed; + } + } + + static OfxStatus interactGetPropertySet(OfxInteractHandle handle, OfxPropertySetHandle *property) + { + try { + Interact::Base *interact = reinterpret_cast(handle); + if (!property) { + return kOfxStatErrBadHandle; + } + + if (interact) { + *property = interact->getPropHandle(); + + return kOfxStatOK; + } + *property = NULL; + + return kOfxStatErrBadHandle; + } catch (...) { + return kOfxStatFailed; + } + } + + /// the interact suite + static const OfxInteractSuiteV1 gSuite = { + interactSwapBuffers, + interactRedraw, + interactGetPropertySet + }; + + /// function to get the sutie + const void *GetSuite(int version) { + if(version == 1) + return (void *) &gSuite; + return NULL; + } + + + } // Interact + + } // Host + +} // OFX diff --git a/third_party/openfx/HostSupport/src/ofxhMemory.cpp b/third_party/openfx/HostSupport/src/ofxhMemory.cpp new file mode 100755 index 000000000..8f69f07b3 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhMemory.cpp @@ -0,0 +1,64 @@ + + +// ofx host + +// ofx +#include "ofxCore.h" +#include "ofxImageEffect.h" + +// ofx host +#include "ofxhMemory.h" + +namespace OFX { + + namespace Host { + + namespace Memory { + + Instance::Instance() : _ptr(0), _locked(0) {} + + Instance::~Instance() { + delete [] _ptr; + } + + bool Instance::alloc(size_t nBytes) { + if(!_locked){ + if(_ptr) + freeMem(); + _ptr = new char[nBytes]; + return true; + } + else + return false; + } + + OfxImageMemoryHandle Instance::getHandle(){ + return (OfxImageMemoryHandle)this; + } + + void Instance::freeMem(){ + delete [] _ptr; + _ptr = 0; + _locked = 0; + } + + void* Instance::getPtr() { + return _ptr; + } + + void Instance::lock() { + ++_locked; + } + + void Instance::unlock() { + if (_locked > 0) { + --_locked; + } + } + + } // Memory + + } // Host + +} // OFX + diff --git a/third_party/openfx/HostSupport/src/ofxhParam.cpp b/third_party/openfx/HostSupport/src/ofxhParam.cpp new file mode 100644 index 000000000..4036b8501 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhParam.cpp @@ -0,0 +1,2300 @@ + + +// ofx +#include "ofxCore.h" +#include "ofxImageEffect.h" +#ifdef OFX_SUPPORTS_PARAMETRIC +#include "ofxParametricParam.h" +#endif + +// ofx host +#include "ofxhBinary.h" +#include "ofxhPropertySuite.h" +#include "ofxhParam.h" +#include "ofxhImageEffect.h" +#include "ofxOld.h" // old plugins may rely on deprecated properties being present + + +#include +#include +#include +#include + +namespace OFX { + + namespace Host { + + namespace Param { + + // + // Base + // + Base::Base(const std::string &name, const std::string& type) : + _paramName(name), + _paramType(type) + { + assert(_paramType.c_str()); + } + + Base::Base(const std::string &name, const std::string &type, const Property::Set &properties) : + _paramName(name), + _paramType(type), + _properties(properties) + { + assert(_paramType.c_str()); + } + + + Base::~Base() {} + + /// grab a handle on the parameter for passing to the C API + OfxParamHandle Base::getHandle() const { + return (OfxParamHandle)this; + } + + /// grab a handle on the properties of this parameter for the C api + OfxPropertySetHandle Base::getPropHandle() const { + return _properties.getHandle(); + } + + Property::Set &Base::getProperties() { + return _properties; + } + + const Property::Set &Base::getProperties() const { + return _properties; + } + + const std::string &Base::getType() const { + return _paramType; + } + + const std::string &Base::getName() const { + return _paramName; + } + + const std::string &Base::getParentName() const { + return _properties.getStringProperty(kOfxParamPropParent); + } + + const std::string &Base::getScriptName() const { + return _properties.getStringProperty(kOfxParamPropScriptName); + } + + const std::string &Base::getLabel() const { + return _properties.getStringProperty(kOfxPropLabel); + } + + const std::string &Base::getLongLabel() const { + return _properties.getStringProperty(kOfxPropLongLabel); + } + + const std::string &Base::getShortLabel() const { + return _properties.getStringProperty(kOfxPropShortLabel); + } + + const std::string &Base::getDoubleType() const { + return _properties.getStringProperty(kOfxParamPropDoubleType, 0); + } + + const std::string &Base::getDefaultCoordinateSystem() const { + return _properties.getStringProperty(kOfxParamPropDefaultCoordinateSystem, 0); + } + + const std::string &Base::getHint() const { + return _properties.getStringProperty(kOfxParamPropHint, 0); + } + + bool Base::getEnabled() const { + return _properties.getIntProperty(kOfxParamPropEnabled, 0) != 0; + } + + bool Base::getSecret() const { + return _properties.getIntProperty(kOfxParamPropSecret, 0) != 0; + } + + bool Base::getIsPersistant() const { + return _properties.getIntProperty(kOfxParamPropPersistant, 0) != 0; + } + + bool Base::getEvaluateOnChange() const { + return _properties.getIntProperty(kOfxParamPropEvaluateOnChange, 0) != 0; + } + + bool Base::getCanUndo() const { + if (_properties.fetchProperty(kOfxParamPropCanUndo)) { + return _properties.getIntProperty(kOfxParamPropCanUndo) != 0; + } + return false; + } + + bool Base::getCanAnimate() const { + if (_properties.fetchProperty(kOfxParamPropAnimates)) { + return _properties.getIntProperty(kOfxParamPropAnimates) != 0; + } + return false; + } + + // + // Descriptor + // + + struct TypeMap { + const char *paramType; + Property::TypeEnum propType; + int propDimension; + }; + + static + bool isDoubleParam(const std::string ¶mType) + { + return paramType == kOfxParamTypeDouble || + paramType == kOfxParamTypeDouble2D || + paramType == kOfxParamTypeDouble3D +#ifdef OFX_SUPPORTS_PARAMETRIC + || paramType == kOfxParamTypeParametric +#endif + ; + } + + bool isColourParam(const std::string ¶mType) + { + return + paramType == kOfxParamTypeRGBA || + paramType == kOfxParamTypeRGB; + } + + bool isIntParam(const std::string ¶mType) + { + return paramType == kOfxParamTypeInteger || + paramType == kOfxParamTypeInteger2D || + paramType == kOfxParamTypeInteger3D; + } + + static const TypeMap typeMap[] = { + { kOfxParamTypeInteger, Property::eInt, 1 }, + { kOfxParamTypeDouble, Property::eDouble, 1 }, + { kOfxParamTypeBoolean, Property::eInt, 1 }, + { kOfxParamTypeChoice, Property::eInt, 1 }, + { kOfxParamTypeRGBA, Property::eDouble, 4 }, + { kOfxParamTypeRGB, Property::eDouble, 3 }, + { kOfxParamTypeDouble2D, Property::eDouble, 2 }, + { kOfxParamTypeInteger2D, Property::eInt, 2 }, + { kOfxParamTypeDouble3D, Property::eDouble, 3 }, + { kOfxParamTypeInteger3D, Property::eInt, 3 }, + { kOfxParamTypeString, Property::eString, 1 }, + { kOfxParamTypeCustom, Property::eString, 1 }, + { kOfxParamTypeGroup, Property::eNone, 0 }, + { kOfxParamTypePage, Property::eNone, 0 }, + { kOfxParamTypePushButton,Property::eNone, 0 }, +#ifdef OFX_SUPPORTS_PARAMETRIC + { kOfxParamTypeParametric,Property::eDouble, 0 }, +#endif + { 0, Property::eNone, 0 } + }; + + /// is this a standard type + bool isStandardType(const std::string &type) + { + const TypeMap *tm = typeMap; + while (tm->paramType) { + if (tm->paramType == type) + return true; + tm++; + } + return false; + } + + static + bool findType(const std::string paramType, Property::TypeEnum &propType, int &propDim) + { + const TypeMap *tm = typeMap; + while (tm->paramType) { + if (tm->paramType == paramType) { + propType = tm->propType; + propDim = tm->propDimension; + return true; + } + tm++; + } + return false; + } + + /// make a parameter, with the given type and name + Descriptor::Descriptor(const std::string &type, + const std::string &name) : Base(name, type) + { + const char *ctype = type.c_str(); + const char *cname = name.c_str(); + + Property::PropSpec universalProps[] = { + { kOfxPropType, Property::eString, 1, true, kOfxTypeParameter }, + { kOfxParamPropSecret, Property::eInt, 1, false, "0"}, + { kOfxParamPropHint, Property::eString, 1, false, ""}, + { kOfxParamPropScriptName, Property::eString, 1, false, cname }, + { kOfxParamPropParent, Property::eString, 1, false, "" }, + { kOfxParamPropEnabled, Property::eInt, 1, false, "1" }, + { kOfxParamPropDataPtr, Property::ePointer, 1, false, 0 }, + { kOfxParamPropType, Property::eString, 1, true, ctype }, + { kOfxPropName, Property::eString, 1, false, cname }, + { kOfxPropLabel, Property::eString, 1, false, cname }, + { kOfxPropShortLabel, Property::eString, 1, false, cname }, + { kOfxPropLongLabel, Property::eString, 1, false, cname }, + { kOfxPropIcon, Property::eString, 2, false, "" }, + Property::propSpecEnd + }; + + _properties.addProperties(universalProps); + } + + /// make a parameter, with the given type and name + void Descriptor::addStandardParamProps(const std::string &type) + { + Property::TypeEnum propType = Property::eString; + int propDim = 1; + findType(type, propType, propDim); + + + static const Property::PropSpec allString[] = { + { kOfxParamPropStringMode, Property::eString, 1, false, kOfxParamStringIsSingleLine }, + { kOfxParamPropStringFilePathExists, Property::eInt, 1, false, "1" }, + Property::propSpecEnd + }; + + static const Property::PropSpec allChoice[] = { + { kOfxParamPropChoiceOption, Property::eString, 0, false, "" }, + Property::propSpecEnd + }; + + static const Property::PropSpec allCustom[] = { + { kOfxParamPropCustomInterpCallbackV1, Property::ePointer, 1, false, 0 }, + Property::propSpecEnd + }; + + static const Property::PropSpec allPage[] = { + { kOfxParamPropPageChild, Property::eString, 0, false, "" }, + Property::propSpecEnd + }; + + static const Property::PropSpec allGroup[] = { + { kOfxParamPropGroupOpen, Property::eInt, 1, false, "1" }, + Property::propSpecEnd + }; + +# ifdef OFX_SUPPORTS_PARAMETRIC + static const Property::PropSpec allParametric[] = { + { kOfxParamPropParametricDimension, Property::eInt, 1, false, "1" }, + { kOfxParamPropParametricUIColour, Property::eDouble, 0, false, "" }, + { kOfxParamPropParametricInteractBackground,Property::ePointer, 1, false, 0 }, + { kOfxParamPropParametricRange, Property::eDouble, 2, false, "0" }, + Property::propSpecEnd + }; +# endif + + if (propType != Property::eNone) { + addValueParamProps(type, propType, propDim); + } + + if (type == kOfxParamTypeString) { + _properties.addProperties(allString); + } + + if (isDoubleParam(type) || isIntParam(type) || isColourParam(type)) { + addNumericParamProps(type, propType, propDim); + } + + if (type != kOfxParamTypeGroup && type != kOfxParamTypePage) { + addInteractParamProps(type); + } + + if (type == kOfxParamTypeChoice) { + _properties.addProperties(allChoice); + } + + if (type == kOfxParamTypeCustom) { + _properties.addProperties(allCustom); + } + + if (type == kOfxParamTypePage) { + _properties.addProperties(allPage); + } + + if (type == kOfxParamTypeGroup) { + _properties.addProperties(allGroup); + } + +# ifdef OFX_SUPPORTS_PARAMETRIC + if (type == kOfxParamTypeParametric) { + _properties.addProperties(allParametric); + _properties.setDoubleProperty(kOfxParamPropParametricRange, 0., 0); + _properties.setDoubleProperty(kOfxParamPropParametricRange, 1., 1); + } +# endif + } + + /// add standard properties to a params that can take an interact + void Descriptor::addInteractParamProps(const std::string &/*type*/) + { + static const Property::PropSpec allButGroupPageProps[] = { + { kOfxParamPropInteractV1, Property::ePointer, 1, false, 0 }, + { kOfxParamPropInteractSize, Property::eDouble, 2, false, "0" }, + { kOfxParamPropInteractSizeAspect, Property::eDouble, 1, false, "1" }, + { kOfxParamPropInteractMinimumSize, Property::eDouble, 2, false, "10" }, + { kOfxParamPropInteractPreferedSize,Property::eInt, 2, false, "10" }, + Property::propSpecEnd + }; + + + _properties.addProperties(allButGroupPageProps); + } + + /// add standard properties to a value holding param + void Descriptor::addValueParamProps(const std::string &type, Property::TypeEnum valueType, int dim) + { + static const Property::PropSpec invariantProps[] = { + { kOfxParamPropIsAnimating, Property::eInt, 1, false, "0" }, + { kOfxParamPropIsAutoKeying,Property::eInt, 1, false, "0" }, + { kOfxParamPropPersistant, Property::eInt, 1, false, "1" }, + { kOfxParamPropEvaluateOnChange, Property::eInt, 1, false, "1" }, +# ifdef kOfxParamPropPluginMayWrite + { kOfxParamPropPluginMayWrite, Property::eInt, 1, false, "0" }, // removed in OFX 1.4 +# endif + { kOfxParamPropCanUndo, Property::eInt, 1, false, "1" }, + { kOfxParamPropCacheInvalidation, Property::eString, 1, false, kOfxParamInvalidateValueChange }, + Property::propSpecEnd + }; + + /// http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#ParametersAnimation + /// The following may animate, depending on the host. + /// Properties exist on the host to check this. If the host does support animation on them, then they do _not_ animate by default. + /// They are... + /// - kOfxParamTypeCustom + /// - kOfxParamTypeString + /// - kOfxParamTypeBoolean + /// - kOfxParamTypeChoice + /// If host doesn't support animation on them, then setting kOfxParamPropIsAnimating to 0 or 1 doesn't matter + /// so just set the kOfxParamPropIsAnimating property to 0 for all those "extra animating" params. + bool animates = type != kOfxParamTypeCustom && type != kOfxParamTypeString && type != kOfxParamTypeBoolean && type != kOfxParamTypeChoice; + + Property::PropSpec variantProps[] = { + { kOfxParamPropAnimates, Property::eInt, 1, false, animates ? "1" : "0" }, + { kOfxParamPropDefault, valueType, dim, false, valueType == Property::eString ? "" : "0" }, + Property::propSpecEnd + }; + + _properties.addProperties(invariantProps); + _properties.addProperties(variantProps); + } + + /// add standard properties to a value holding param + void Descriptor::addNumericParamProps(const std::string &type, Property::TypeEnum valueType, int dim) + { + static std::string dbl_minstr, dbl_maxstr, int_minstr, int_maxstr; + static bool doneOne = false; + + if(!doneOne) { + std::ostringstream dbl_min, dbl_max, int_min, int_max; + doneOne = true; + dbl_min << -DBL_MAX; // not a bug, @see kOfxParamPropDisplayMin + dbl_max << DBL_MAX; + int_min << INT_MIN; + int_max << INT_MAX; + + dbl_minstr = dbl_min.str(); + dbl_maxstr = dbl_max.str(); + int_minstr = int_min.str(); + int_maxstr = int_max.str(); + } + + Property::PropSpec allNumeric[] = { + { kOfxParamPropDisplayMin, valueType, dim, false, isColourParam(type) ? "0" : (valueType == Property::eDouble ? dbl_minstr : int_minstr).c_str() }, + { kOfxParamPropDisplayMax, valueType, dim, false, isColourParam(type) ? "1" : (valueType == Property::eDouble ? dbl_maxstr : int_maxstr).c_str() }, + { kOfxParamPropMin, valueType, dim, false, (valueType == Property::eDouble ? dbl_minstr : int_minstr).c_str() }, + { kOfxParamPropMax, valueType, dim, false, (valueType == Property::eDouble ? dbl_maxstr : int_maxstr).c_str() }, + Property::propSpecEnd + }; + + _properties.addProperties(allNumeric); + + /// if any double or a colour + if (valueType == Property::eDouble) { + static const Property::PropSpec allDouble[] = { + { kOfxParamPropIncrement, Property::eDouble, 1, false, "1" }, + { kOfxParamPropDigits, Property::eInt, 1, false, "2" }, + Property::propSpecEnd + }; + _properties.addProperties(allDouble); + } + + /// if a double param type + if(isDoubleParam(type)) { + static const Property::PropSpec allDouble[] = { + { kOfxParamPropDoubleType, Property::eString, 1, false, kOfxParamDoubleTypePlain }, + { kOfxParamPropDefaultCoordinateSystem, Property::eString, 1, false, kOfxParamCoordinatesCanonical }, + Property::propSpecEnd + }; + _properties.addProperties(allDouble); + + if(dim == 1) { + static const Property::PropSpec allDouble1D[] = { + { kOfxParamPropShowTimeMarker, Property::eInt, 1, false, "0" }, + Property::propSpecEnd + }; + + _properties.addProperties(allDouble1D); + } + } + + /// if a multi dimensional param + if ((isDoubleParam(type) || isIntParam(type)) && (dim == 2 || dim == 3 +#ifdef OFX_SUPPORTS_PARAMETRIC + || dim == 0 +#endif + )) { + static const Property::PropSpec all2D3D[] = { + { kOfxParamPropDimensionLabel, Property::eString, dim, false, "" }, + Property::propSpecEnd + }; + + _properties.addProperties(all2D3D); + _properties.setStringProperty(kOfxParamPropDimensionLabel, "x", 0); + _properties.setStringProperty(kOfxParamPropDimensionLabel, "y", 1); + if (dim == 3) { + _properties.setStringProperty(kOfxParamPropDimensionLabel, "z", 2); + } + } + + /// if a multi dimensional param + if (isColourParam(type)) { + static const Property::PropSpec allColor[] = { + { kOfxParamPropDimensionLabel, Property::eString, dim, false, "" }, + Property::propSpecEnd + }; + + _properties.addProperties(allColor); + _properties.setStringProperty(kOfxParamPropDimensionLabel, "r", 0); + _properties.setStringProperty(kOfxParamPropDimensionLabel, "g", 1); + _properties.setStringProperty(kOfxParamPropDimensionLabel, "b", 2); + if (dim == 4) { + _properties.setStringProperty(kOfxParamPropDimensionLabel, "a", 3); + } + } + } + + BaseSet::~BaseSet() {} + + /// obtain a handle on this set for passing to the C api + SetDescriptor::SetDescriptor() + { + } + + /// obtain a handle on this set for passing to the C api + OfxParamSetHandle BaseSet::getParamSetHandle() const + { + return (OfxParamSetHandle)this; + } + + SetDescriptor::~SetDescriptor() + { + // iterate the params and delete them + std::list::iterator i; + for(i = _paramList.begin(); i != _paramList.end(); ++i) { + if(*i) + delete (*i); + } + } + + const std::map &SetDescriptor::getParams() const + { + return _paramMap; + } + + const std::list &SetDescriptor::getParamList() const + { + return _paramList; + } + + void SetDescriptor::addParam(const std::string &name, Descriptor *p) { + _paramList.push_back(p); + _paramMap[name] = p; + } + + /// define a param on this effect + Descriptor *SetDescriptor::paramDefine(const char *paramType, + const char *name) + { + if(!isStandardType(paramType)) + return NULL; /// << EEK! This is bad. + + Descriptor *desc = new Descriptor(paramType, name); + desc->addStandardParamProps(paramType); + addParam(name, desc); + return desc; + } + + //////////////////////////////////////////////////////////////////////////////// + // + // Instance + // + + /// the description of a plugin parameter + Instance::~Instance() {} + + /// make a parameter, with the given type and name + Instance::Instance(Descriptor& descriptor, Param::SetInstance* paramSet) + : Base(descriptor.getName(), descriptor.getType(), descriptor.getProperties()) + , _paramSetInstance(paramSet) + , _parentInstance(0) + { + _properties.addNotifyHook(kOfxParamPropEnabled, this); + _properties.addNotifyHook(kOfxParamPropSecret, this); + _properties.addNotifyHook(kOfxPropLabel, this); + _properties.addNotifyHook(kOfxParamPropMin, this); + _properties.addNotifyHook(kOfxParamPropMax, this); + _properties.addNotifyHook(kOfxParamPropDisplayMin, this); + _properties.addNotifyHook(kOfxParamPropDisplayMax, this); + _properties.addNotifyHook(kOfxParamPropEvaluateOnChange, this); + } + + // callback which should set enabled state as appropriate + void Instance::setEnabled() + { + } + + // callback which should set secret state as appropriate + void Instance::setSecret() + { + } + + // callback which should update label + void Instance::setLabel() + { + } + + /// callback which should set range + void Instance::setRange() + { + } + + /// callback which should set display range + void Instance::setDisplayRange() + { + } + + /// callback which should set evaluate on change + void Instance::setEvaluateOnChange() + { + } + + /// get a value, implemented by instances to deconstruct var args + OfxStatus Instance::getV(va_list /*arg*/) + { + return kOfxStatErrUnsupported; + } + + /// get a value, implemented by instances to deconstruct var args + OfxStatus Instance::getV(OfxTime /*time*/, va_list /*arg*/) + { + return kOfxStatErrUnsupported; + } + + /// set a value, implemented by instances to deconstruct var args + OfxStatus Instance::setV(va_list /*arg*/) + { + return kOfxStatErrUnsupported; + } + + /// key a value, implemented by instances to deconstruct var args + OfxStatus Instance::setV(OfxTime /*time*/, va_list /*arg*/) + { + return kOfxStatErrUnsupported; + } + + /// derive a value, implemented by instances to deconstruct var args + OfxStatus Instance::deriveV(OfxTime /*time*/, va_list /*arg*/) + { + return kOfxStatErrUnsupported; + } + + /// integrate a value, implemented by instances to deconstruct var args + OfxStatus Instance::integrateV(OfxTime /*time1*/, OfxTime /*time2*/, va_list /*arg*/) + { + return kOfxStatErrUnsupported; + } + + /// overridden from Property::NotifyHook + void Instance::notify(const std::string &name, bool /*single*/, int /*num*/) + { + if (name == kOfxPropLabel) { + setLabel(); + } + if (name == kOfxParamPropEnabled) { + setEnabled(); + } + if (name == kOfxParamPropSecret) { + setSecret(); + } + if (name == kOfxParamPropMin || name == kOfxParamPropMax) { + setRange(); + } + if (name == kOfxParamPropDisplayMin || name == kOfxParamPropDisplayMax) { + setDisplayRange(); + } + if (name == kOfxParamPropEvaluateOnChange) { + setEvaluateOnChange(); + } + } + + // copy one parameter to another, with a range (NULL means to copy all animation) + OfxStatus Instance::copyFrom(const Instance &/*instance*/, OfxTime /*offset*/, const OfxRangeD* /*range*/) { + return kOfxStatErrMissingHostFeature; + } + + void Instance::setParentInstance(Instance* instance){ + _parentInstance = instance; + } + + Instance* Instance::getParentInstance(){ + return _parentInstance; + } + + // + // KeyframeParam + // + + OfxStatus KeyframeParam::getNumKeys(unsigned int &/*nKeys*/) const { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus KeyframeParam::getKeyTime(int /*nth*/, OfxTime& /*time*/) const { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus KeyframeParam::getKeyIndex(OfxTime /*time*/, int /*direction*/, int & /*index*/) const { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus KeyframeParam::deleteKey(OfxTime /*time*/) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus KeyframeParam::deleteAllKeys() { + return kOfxStatErrMissingHostFeature; + } + + void GroupInstance::setChildren(std::vector children) + { + _children = children; + for (std::vector::iterator it=children.begin(); it!=children.end(); ++it) { + if(*it){ + (*it)->setParentInstance(this); + } + } + } + + const std::vector &GroupInstance::getChildren() const + { + return _children; + } + + // + // Page Instance + // + + const std::map &PageInstance::getChildren() const + { + // HACK!!!! this really should be done with a notify hook so we don't force + // _children to be mutable + if(_children.size() == 0 ) + { + int nChildren = _properties.getDimension(kOfxParamPropPageChild); + for(int i=0;igetParam(childName); + if(child) + _children[i]=child; + } + } + return _children; + } + + // + // ChoiceInstance + // + + /// make a parameter, with the given type and name + ChoiceInstance::ChoiceInstance(Descriptor& descriptor, Param::SetInstance* instance) + : Instance(descriptor,instance) + { + _properties.addNotifyHook(kOfxParamPropChoiceOption, this); + } + + // callback which should set option as appropriate + void ChoiceInstance::setOption(int /*num*/) + { + } + + /// implementation of var args function + OfxStatus ChoiceInstance::getV(va_list arg) + { + int *value = va_arg(arg, int*); + OfxStatus stat = get(*value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus ChoiceInstance::getV(OfxTime time, va_list arg) + { + int *value = va_arg(arg, int*); + OfxStatus stat = get(time, *value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus ChoiceInstance::setV(va_list arg) + { + int value = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(value); + } + + /// implementation of var args function + OfxStatus ChoiceInstance::setV(OfxTime time, va_list arg) + { + int value = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(time, value); + } + + /// overridden from Instance + void ChoiceInstance::notify(const std::string &name, bool single, int num) + { + Instance::notify(name, single, num); + if (name == kOfxParamPropChoiceOption) { + setOption(num); + } + } + // + // IntegerInstance + // + OfxStatus IntegerInstance::derive(OfxTime /*time*/, int&) { + return kOfxStatErrUnsupported; + } + + OfxStatus IntegerInstance::integrate(OfxTime /*time1*/, OfxTime /*time2*/, int&) { + return kOfxStatErrUnsupported; + } + + /// implementation of var args function + OfxStatus IntegerInstance::getV(va_list arg) + { + int *value = va_arg(arg, int*); + OfxStatus stat = get(*value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus IntegerInstance::getV(OfxTime time, va_list arg) + { + int *value = va_arg(arg, int*); + OfxStatus stat = get(time, *value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus IntegerInstance::setV(va_list arg) + { + int value = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(value); + } + + /// implementation of var args function + OfxStatus IntegerInstance::setV(OfxTime time, va_list arg) + { + int value = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(time, value); + } + + /// implementation of var args function + OfxStatus IntegerInstance::deriveV(OfxTime time, va_list arg) + { + int *value = va_arg(arg, int*); + OfxStatus stat = derive(time, *value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus IntegerInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + int *value = va_arg(arg, int*); + OfxStatus stat = integrate(time1, time2, *value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + // + // DoubleInstance + // + /// implementation of var args function + OfxStatus DoubleInstance::getV(va_list arg) + { + double *value = va_arg(arg, double*); + OfxStatus stat = get(*value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus DoubleInstance::getV(OfxTime time, va_list arg) + { + double *value = va_arg(arg, double*); + OfxStatus stat = get(time, *value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus DoubleInstance::setV(va_list arg) + { + double value = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(value); + } + + /// implementation of var args function + OfxStatus DoubleInstance::setV(OfxTime time, va_list arg) + { + double value = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(time, value); + } + + /// implementation of var args function + OfxStatus DoubleInstance::deriveV(OfxTime time, va_list arg) + { + double *value = va_arg(arg, double*); + OfxStatus stat = derive(time, *value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus DoubleInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + double *value = va_arg(arg, double*); + OfxStatus stat = integrate(time1, time2, *value); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + // + // BooleanInstance + // + /// implementation of var args function + OfxStatus BooleanInstance::getV(va_list arg) + { + bool v; + OfxStatus stat = get(v); + + int *value = va_arg(arg, int*); + *value = v; +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus BooleanInstance::getV(OfxTime time, va_list arg) + { + bool v; + OfxStatus stat = get(time, v); + + int *value = va_arg(arg, int*); + *value = v; +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus BooleanInstance::setV(va_list arg) + { + bool value = va_arg(arg, int) != 0; +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(value); + } + + /// implementation of var args function + OfxStatus BooleanInstance::setV(OfxTime time, va_list arg) + { + bool value = va_arg(arg, int) != 0; +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(time, value); + } + + + // + // RGBAInstance + // + + OfxStatus RGBAInstance::derive(OfxTime /*time*/, double&, double&, double&, double&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus RGBAInstance::integrate(OfxTime /*time1*/, OfxTime /*time2*/, double&,double&,double&,double&) { + return kOfxStatErrMissingHostFeature; + } + + /// implementation of var args function + OfxStatus RGBAInstance::getV(va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + double *a = va_arg(arg, double*); + OfxStatus stat = get(*r, *g, *b, *a); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b << ' ' << *a; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus RGBAInstance::getV(OfxTime time, va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + double *a = va_arg(arg, double*); + OfxStatus stat = get(time, *r, *g, *b, *a); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b << ' ' << *a; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus RGBAInstance::setV(va_list arg) + { + double r = va_arg(arg, double); + double g = va_arg(arg, double); + double b = va_arg(arg, double); + double a = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << r << ',' << g << ',' << b << ',' << a << ')'; +# endif + return set(r, g, b, a); + } + + /// implementation of var args function + OfxStatus RGBAInstance::setV(OfxTime time, va_list arg) + { + double r = va_arg(arg, double); + double g = va_arg(arg, double); + double b = va_arg(arg, double); + double a = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << r << ',' << g << ',' << b << ',' << a << ')'; +# endif + return set(time, r, g, b, a); + } + + /// implementation of var args function + OfxStatus RGBAInstance::deriveV(OfxTime time, va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + double *a = va_arg(arg, double*); + OfxStatus stat = derive(time, *r, *g, *b, *a); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b << ' ' << *a; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus RGBAInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + double *a = va_arg(arg, double*); + OfxStatus stat = integrate(time1, time2, *r, *g, *b, *a); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b << ' ' << *a; + } +# endif + return stat; + } + + // + // RGBInstance + // + OfxStatus RGBInstance::derive(OfxTime /*time*/, double&,double&,double&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus RGBInstance::integrate(OfxTime /*time1*/, OfxTime /*time2*/, double&,double&,double&) { + return kOfxStatErrMissingHostFeature; + } + + /// implementation of var args function + OfxStatus RGBInstance::getV(va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + OfxStatus stat = get(*r, *g, *b); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus RGBInstance::getV(OfxTime time, va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + OfxStatus stat = get(time, *r, *g, *b); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus RGBInstance::setV(va_list arg) + { + double r = va_arg(arg, double); + double g = va_arg(arg, double); + double b = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << r << ',' << g << ',' << b << ')'; +# endif + return set(r, g, b); + } + + /// implementation of var args function + OfxStatus RGBInstance::setV(OfxTime time, va_list arg) + { + double r = va_arg(arg, double); + double g = va_arg(arg, double); + double b = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << r << ',' << g << ',' << b << ')'; +# endif + return set(time, r, g, b); + } + + /// implementation of var args function + OfxStatus RGBInstance::deriveV(OfxTime time, va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + OfxStatus stat = derive(time, *r, *g, *b); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus RGBInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + double *r = va_arg(arg, double*); + double *g = va_arg(arg, double*); + double *b = va_arg(arg, double*); + OfxStatus stat = integrate(time1, time2, *r, *g, *b); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *r << ' ' << *g << ' ' << *b; + } +# endif + return stat; + } + + // + // Double2DInstance + // + + OfxStatus Double2DInstance::derive(OfxTime /*time*/, double&,double&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Double2DInstance::integrate(OfxTime /*time1*/, OfxTime /*time2*/, double&,double&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Double2DInstance::getV(va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + OfxStatus stat = get(*value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Double2DInstance::getV(OfxTime time, va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + OfxStatus stat = get(time, *value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Double2DInstance::setV(va_list arg) + { + double value1 = va_arg(arg, double); + double value2 = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ')'; +# endif + return set(value1, value2); + } + + /// implementation of var args function + OfxStatus Double2DInstance::setV(OfxTime time, va_list arg) + { + double value1 = va_arg(arg, double); + double value2 = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ')'; +# endif + return set(time, value1, value2); + } + + /// implementation of var args function + OfxStatus Double2DInstance::deriveV(OfxTime time, va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + OfxStatus stat = derive(time, *value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Double2DInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + OfxStatus stat = integrate(time1, time2, *value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + // + // Integer2DInstance + // + + OfxStatus Integer2DInstance::derive(OfxTime /*time*/, int&,int&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Integer2DInstance::integrate(OfxTime /*time1*/, OfxTime /*time2*/, int&,int&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Integer2DInstance::getV(va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + OfxStatus stat = get(*value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Integer2DInstance::getV(OfxTime time, va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + OfxStatus stat = get(time, *value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Integer2DInstance::setV(va_list arg) + { + int value1 = va_arg(arg, int); + int value2 = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ')'; +# endif + return set(value1, value2); + } + + /// implementation of var args function + OfxStatus Integer2DInstance::setV(OfxTime time, va_list arg) + { + int value1 = va_arg(arg, int); + int value2 = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ')'; +# endif + return set(time, value1, value2); + } + + /// implementation of var args function + OfxStatus Integer2DInstance::deriveV(OfxTime time, va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + OfxStatus stat = derive(time, *value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Integer2DInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + OfxStatus stat = integrate(time1, time2, *value1, *value2); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2; + } +# endif + return stat; + } + + // + // Double3DInstance + // + + OfxStatus Double3DInstance::derive(OfxTime /*time*/, double&,double&,double&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Double3DInstance::integrate(OfxTime /*time1*/, OfxTime /*time2*/, double&,double&,double&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Double3DInstance::getV(va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + double *value3 = va_arg(arg, double*); + OfxStatus stat = get(*value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Double3DInstance::getV(OfxTime time, va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + double *value3 = va_arg(arg, double*); + OfxStatus stat = get(time, *value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Double3DInstance::setV(va_list arg) + { + double value1 = va_arg(arg, double); + double value2 = va_arg(arg, double); + double value3 = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ',' << value3 << ')'; +# endif + return set(value1, value2, value3); + } + + /// implementation of var args function + OfxStatus Double3DInstance::setV(OfxTime time, va_list arg) + { + double value1 = va_arg(arg, double); + double value2 = va_arg(arg, double); + double value3 = va_arg(arg, double); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ',' << value3 << ')'; +# endif + return set(time, value1, value2, value3); + } + + /// implementation of var args function + OfxStatus Double3DInstance::deriveV(OfxTime time, va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + double *value3 = va_arg(arg, double*); + OfxStatus stat = derive(time, *value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Double3DInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + double *value1 = va_arg(arg, double*); + double *value2 = va_arg(arg, double*); + double *value3 = va_arg(arg, double*); + OfxStatus stat = integrate(time1, time2, *value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + // + // Integer3DInstance + // + OfxStatus Integer3DInstance::derive(OfxTime /*time*/, int&,int&,int&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Integer3DInstance::integrate(OfxTime /*time1*/, OfxTime /*time2*/, int&,int&,int&) { + return kOfxStatErrMissingHostFeature; + } + + OfxStatus Integer3DInstance::getV(va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + int *value3 = va_arg(arg, int*); + OfxStatus stat = get(*value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Integer3DInstance::getV(OfxTime time, va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + int *value3 = va_arg(arg, int*); + OfxStatus stat = get(time, *value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Integer3DInstance::setV(va_list arg) + { + int value1 = va_arg(arg, int); + int value2 = va_arg(arg, int); + int value3 = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ',' << value3 << ')'; +# endif + return set(value1, value2, value3); + } + + /// implementation of var args function + OfxStatus Integer3DInstance::setV(OfxTime time, va_list arg) + { + int value1 = va_arg(arg, int); + int value2 = va_arg(arg, int); + int value3 = va_arg(arg, int); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << '(' << value1 << ',' << value2 << ',' << value3 << ')'; +# endif + return set(time, value1, value2, value3); + } + + /// implementation of var args function + OfxStatus Integer3DInstance::deriveV(OfxTime time, va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + int *value3 = va_arg(arg, int*); + OfxStatus stat = derive(time, *value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus Integer3DInstance::integrateV(OfxTime time1, OfxTime time2, va_list arg) + { + int *value1 = va_arg(arg, int*); + int *value2 = va_arg(arg, int*); + int *value3 = va_arg(arg, int*); + OfxStatus stat = integrate(time1, time2, *value1, *value2, *value3); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value1 << ' ' << *value2 << ' ' << *value3; + } +# endif + return stat; + } + + //////////////////////////////////////////////////////////////////////////////// + // string param + OfxStatus StringInstance::getV(va_list arg) + { + const char **value = va_arg(arg, const char **); + + OfxStatus stat = get(_returnValue); // I so don't like this, temp storage should be delegated to the implementation + *value = _returnValue.c_str(); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus StringInstance::getV(OfxTime time, va_list arg) + { + const char **value = va_arg(arg, const char **); + + OfxStatus stat = get(time, _returnValue); // I so don't like this, temp storage should be delegated to the implementation + *value = _returnValue.c_str(); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *value; + } +# endif + return stat; + } + + /// implementation of var args function + OfxStatus StringInstance::setV(va_list arg) + { + char *value = va_arg(arg, char*); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(value); + } + + /// implementation of var args function + OfxStatus StringInstance::setV(OfxTime time, va_list arg) + { + char *value = va_arg(arg, char*); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << value; +# endif + return set(time, value); + } + + ////////////////////////////////////////////////////////////////////////////////// + // Param::SetInstance + // + + /// ctor + SetInstance::SetInstance() + {} + + /// dtor. + SetInstance::~SetInstance() + { + // iterate the params and delete them + std::list::iterator i; + for(i = _paramList.begin(); i != _paramList.end(); ++i) { + if(*i) + delete (*i); + } + } + + const std::map &SetInstance::getParams() const + { + return _params; + } + + const std::list &SetInstance::getParamList() const + { + return _paramList; + } + + OfxStatus SetInstance::addParam(const std::string& name, Instance* instance) + { + if(_params.find(name)==_params.end()){ + _params[name] = instance; + _paramList.push_back(instance); + } + else + return kOfxStatErrExists; + + return kOfxStatOK; + } + + //////////////////////////////////////////////////////////////////////////////// + // Suite functions below + + static OfxStatus paramDefine(OfxParamSetHandle paramSet, + const char *paramType, + const char *name, + OfxPropertySetHandle *propertySet) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramDefine - " << paramSet << ' ' << paramType << ' ' << name << ' ' << propertySet << " ..."; +# endif + SetDescriptor *paramSetDescriptor = reinterpret_cast(paramSet); + + if (!paramSetDescriptor) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + Descriptor *desc = paramSetDescriptor->paramDefine(paramType, name); + + if(desc) { + if (propertySet) + *propertySet = desc->getPropHandle(); + // desc is still referenced by _paramList and _paramMap +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } else { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrUnsupported) << std::endl; +# endif + return kOfxStatErrUnsupported; + } + } + + static OfxStatus paramGetHandle(OfxParamSetHandle paramSet, + const char *name, + OfxParamHandle *param, + OfxPropertySetHandle *propertySet) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetHandle - " << paramSet << ' ' << name << ' ' << param << ' ' << propertySet << " ..."; +# endif + BaseSet *baseSet = reinterpret_cast(paramSet); + + if (!baseSet) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + SetInstance *setInstance = dynamic_cast(baseSet); + + if(setInstance){ + const std::map& params = setInstance->getParams(); + std::map::const_iterator it = params.find(name); + + // if we can't find it return an error... + if(it==params.end()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' '<< StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + + // get the param + if (param) { + *param = (it->second)->getHandle(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << *param; +# endif + } + + // get the param property set + if(propertySet) { + *propertySet = (it->second)->getPropHandle(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << *propertySet; +# endif + } + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } + + SetDescriptor *setDescriptor = dynamic_cast(baseSet); + + if(setDescriptor){ + const std::map& params = setDescriptor->getParams(); + std::map::const_iterator it = params.find(name); + + // if we can't find it return an error... + if(it==params.end()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' '<< StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + + // get the param + if (param) { + *param = (it->second)->getHandle(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << *param; +# endif + } + + // get the param property set + if(propertySet) { + *propertySet = (it->second)->getPropHandle(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << *propertySet; +# endif + } + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + static OfxStatus paramSetGetPropertySet(OfxParamSetHandle paramSet, + OfxPropertySetHandle *propHandle) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramSetGetPropertySet - " << paramSet << ' ' << propHandle << " ..."; +# endif + BaseSet *baseSet = reinterpret_cast(paramSet); + + if (baseSet) { + if (propHandle) { + *propHandle = baseSet->getParamSetProps().getHandle(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << *propHandle; +# endif + } +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + static OfxStatus paramGetPropertySet(OfxParamHandle param, + OfxPropertySetHandle *propHandle) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetPropertySet - " << param << ' ' << propHandle << " ..."; +# endif + Param::Instance *paramInstance = reinterpret_cast(param); + + if(paramInstance && paramInstance->verifyMagic()){ + // get the param property set + if (propHandle) { + *propHandle = paramInstance->getPropHandle(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << *propHandle; +# endif + } + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } else { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + } + + /// get the current param value + static OfxStatus paramGetValue(OfxParamHandle paramHandle, + ...) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetValue - " << paramHandle << " ..."; +# endif + Instance *paramInstance = reinterpret_cast(paramHandle); + if(!paramInstance || !paramInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + va_list ap; + va_start(ap,paramHandle); + OfxStatus stat = kOfxStatErrUnsupported; + + try { + stat = paramInstance->getV(ap); + } + catch(...) {} + + va_end(ap); + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + /// get the param value at a time + static OfxStatus paramGetValueAtTime(OfxParamHandle paramHandle, + OfxTime time, + ...) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetValueAtTime - " << paramHandle << ' ' << time << " ..."; +# endif + Instance *paramInstance = reinterpret_cast(paramHandle); + if(!paramInstance || !paramInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + + va_list ap; + va_start(ap, time); + OfxStatus stat = kOfxStatErrUnsupported; + + try { + stat = paramInstance->getV(time, ap); + } + catch(...) {} + + va_end(ap); + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + /// get the param's derivative at the given time + static OfxStatus paramGetDerivative(OfxParamHandle paramHandle, + OfxTime time, + ...) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetDerivative - " << paramHandle << ' ' << time << " ..."; +# endif + Instance *paramInstance = reinterpret_cast(paramHandle); + if(!paramInstance || !paramInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + va_list ap; + va_start(ap, time); + OfxStatus stat = kOfxStatErrUnsupported; + + try { + stat = paramInstance->deriveV(time, ap); + } + catch(...) {} + + va_end(ap); + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramGetIntegral(OfxParamHandle paramHandle, + OfxTime time1, OfxTime time2, + ...) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetIntegral - " << paramHandle << ' ' << time1 << ' ' << time2 << " ..."; +# endif + Instance *paramInstance = reinterpret_cast(paramHandle); + if(!paramInstance || !paramInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + va_list ap; + va_start(ap, time2); + OfxStatus stat = kOfxStatErrUnsupported; + + try { + stat = paramInstance->integrateV(time1, time2, ap); + } + catch(...) {} + + va_end(ap); + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + /// set the param's value at the 'current' time + static OfxStatus paramSetValue(OfxParamHandle paramHandle, + ...) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramSetValue - " << paramHandle << ' '; +# endif + Instance *paramInstance = reinterpret_cast(paramHandle); + if(!paramInstance || !paramInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << " ... " << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + va_list ap; + va_start(ap, paramHandle); + OfxStatus stat = kOfxStatErrUnsupported; + + try { + stat = paramInstance->setV(ap); + } + catch(...) {} + + va_end(ap); + + if (stat == kOfxStatOK) { + paramInstance->getParamSetInstance()->paramChangedByPlugin(paramInstance); + } + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << " ... " << StatStr(stat) << std::endl; +# endif + return stat; + } + + + /// set the param's value at the indicated time, and set a key + static OfxStatus paramSetValueAtTime(OfxParamHandle paramHandle, + OfxTime time, // time in frames + ...) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramSetValueAtTime - " << paramHandle << ' ' << time << ' '; +# endif + Instance *paramInstance = reinterpret_cast(paramHandle); + if(!paramInstance || !paramInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << " ... " << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + va_list ap; + va_start(ap, time); + OfxStatus stat = kOfxStatErrUnsupported; + + try { + stat = paramInstance->setV(time, ap); + } + catch(...) {} + + va_end(ap); + + if (stat == kOfxStatOK) { + paramInstance->getParamSetInstance()->paramChangedByPlugin(paramInstance); + } + +# ifdef OFX_DEBUG_PARAMETERS + std::cout << " ... " << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramGetNumKeys(OfxParamHandle paramHandle, + unsigned int *numberOfKeys) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetNumKeys - " << paramHandle << " ..."; +# endif + Param::Instance *pInstance = reinterpret_cast(paramHandle); + + if (!pInstance || !pInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + KeyframeParam *paramInstance = dynamic_cast(pInstance); + if(!paramInstance) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + OfxStatus stat = paramInstance->getNumKeys(*numberOfKeys); +# ifdef OFX_DEBUG_PARAMETERS + if (stat == kOfxStatOK) { + std::cout << ' ' << *numberOfKeys; + } + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramGetKeyTime(OfxParamHandle paramHandle, + unsigned int nthKey, + OfxTime *time) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetKeyTime - " << paramHandle << " ..."; +# endif + Param::Instance *pInstance = reinterpret_cast(paramHandle); + + if (!pInstance || !pInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + KeyframeParam *paramInstance = dynamic_cast(pInstance); + if(!paramInstance) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + OfxStatus stat = paramInstance->getKeyTime(nthKey,*time); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramGetKeyIndex(OfxParamHandle paramHandle, + OfxTime time, + int direction, + int *index) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramGetKeyIndex - " << paramHandle << " ..."; +# endif + Param::Instance *pInstance = reinterpret_cast(paramHandle); + + if (!pInstance || !pInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + KeyframeParam *paramInstance = dynamic_cast(pInstance); + if(!paramInstance) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + OfxStatus stat = paramInstance->getKeyIndex(time,direction,*index); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramDeleteKey(OfxParamHandle paramHandle, + OfxTime time) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramDeleteKey - " << paramHandle << " ..."; +# endif + Param::Instance *pInstance = reinterpret_cast(paramHandle); + + if (!pInstance || !pInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + KeyframeParam *paramInstance = dynamic_cast(pInstance); + if(!paramInstance) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + OfxStatus stat = paramInstance->deleteKey(time); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramDeleteAllKeys(OfxParamHandle paramHandle) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramDeleteAllKeys - " << paramHandle << " ..."; +# endif + Param::Instance *pInstance = reinterpret_cast(paramHandle); + + if (!pInstance || !pInstance->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + KeyframeParam *paramInstance = dynamic_cast(pInstance); + if(!paramInstance) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + OfxStatus stat = paramInstance->deleteAllKeys(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramCopy(OfxParamHandle paramTo, + OfxParamHandle paramFrom, + OfxTime dstOffset, const OfxRangeD *frameRange) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramCopy - " << paramTo << " ..."; +# endif + Instance *paramInstanceTo = reinterpret_cast(paramTo); + Instance *paramInstanceFrom = reinterpret_cast(paramFrom); + + if(!paramInstanceTo || !paramInstanceTo->verifyMagic() || + !paramInstanceFrom || !paramInstanceFrom->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + + OfxStatus stat = paramInstanceTo->copyFrom(*paramInstanceFrom,dstOffset,frameRange); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static OfxStatus paramEditBegin(OfxParamSetHandle paramSet, const char *name) + { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramEditBegin - " << paramSet << ' ' << name << " ..."; +# endif + SetInstance *setInstance = reinterpret_cast(paramSet); + if(!setInstance) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + OfxStatus stat = setInstance->editBegin(std::string(name)); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + + static OfxStatus paramEditEnd(OfxParamSetHandle paramSet) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << "OFX: paramEditEnd - " << paramSet << " ..."; +# endif + SetInstance *setInstance = reinterpret_cast(paramSet); + if(!setInstance) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + OfxStatus stat = setInstance->editEnd(); +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(stat) << std::endl; +# endif + return stat; + } + + static const OfxParameterSuiteV1 gParamSuiteV1 = { + paramDefine, + paramGetHandle, + paramSetGetPropertySet, + paramGetPropertySet, + paramGetValue, + paramGetValueAtTime, + paramGetDerivative, + paramGetIntegral, + paramSetValue, + paramSetValueAtTime, + paramGetNumKeys, + paramGetKeyTime, + paramGetKeyIndex, + paramDeleteKey, + paramDeleteAllKeys, + paramCopy, + paramEditBegin, + paramEditEnd + }; + + + const void *GetSuite(int version) { + if(version ==1) + return &gParamSuiteV1; + return NULL; + } + + } // Param + + } // Host + +} // OFX diff --git a/third_party/openfx/HostSupport/src/ofxhPluginAPICache.cpp b/third_party/openfx/HostSupport/src/ofxhPluginAPICache.cpp new file mode 100644 index 000000000..68d3b51f7 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhPluginAPICache.cpp @@ -0,0 +1,135 @@ + + +#include + +#include +#include + +// ofx +#include "ofxCore.h" +#include "ofxImageEffect.h" + +// ofx host +#include "ofxhBinary.h" +#include "ofxhPropertySuite.h" +#include "ofxhClip.h" +#include "ofxhParam.h" +#include "ofxhMemory.h" +#include "ofxhImageEffect.h" +#include "ofxhPluginAPICache.h" +#include "ofxhPluginCache.h" +#include "ofxhHost.h" +#include "ofxhImageEffectAPI.h" +#include "ofxhXml.h" + +namespace OFX +{ + namespace Host + { + namespace APICache + { + void PluginAPICacheI::registerInCache(OFX::Host::PluginCache &pluginCache) { + pluginCache.registerAPICache(_apiName, _apiVersionMin, _apiVersionMax, this); + } + + void propertySetXMLRead(const std::string &el, + std::map map, + Property::Set &set, + Property::Property *¤tProp) { + if (el == "property") { + std::string propName = map["name"]; + std::string propType = map["type"]; + int dimension = atoi(map["dimension"].c_str()); + + currentProp = set.fetchProperty(propName, false); + + if(!currentProp) { + if (propType == "int") { + currentProp = new Property::Int(propName, dimension, false, 0); + } else if (propType == "string") { + currentProp = new Property::String(propName, dimension, false, ""); + } else if (propType == "double") { + currentProp = new Property::Double(propName, dimension, false, 0); + } else if (propType == "pointer") { + currentProp = new Property::Pointer(propName, dimension, false, 0); + } + set.addProperty(currentProp); + } + return; + } + + if (el == "value" && currentProp) { + int index = atoi(map["index"].c_str()); + std::string value = map["value"]; + + switch (currentProp->getType()) { + case Property::eInt: + set.setIntProperty(currentProp->getName(), atoi(value.c_str()), index); + break; + case Property::eString: + set.setStringProperty(currentProp->getName(), value, index); + break; + case Property::eDouble: + set.setDoubleProperty(currentProp->getName(), atof(value.c_str()), index); + break; + case Property::ePointer: + break; + default: + break; + } + + return; + } + + std::cout << "got unrecognised key " << el << "\n"; + + assert(false); + } + + static void propertyXMLWrite(std::ostream &o, Property::Property *prop, const std::string &indent="") + { + if (prop->getType() != Property::ePointer) { + + o << indent << "getName()) + << XML::attribute("type", Property::gTypeNames[prop->getType()]) + << XML::attribute("dimension", prop->getFixedDimension()) + << ">\n"; + + for (int i=0;igetDimension();i++) { + o << indent << " getStringValue(i)) + << "/>\n"; + } + + o << indent << "\n"; + } + } + + void propertyXMLWrite(std::ostream &o, const Property::Set &set, const std::string &name, int indent) + { + Property::Property *prop = set.fetchProperty(name); + + if(prop) { + std::string indent_prefix(indent, ' '); + propertyXMLWrite(o, prop, indent_prefix); + } + } + + void propertySetXMLWrite(std::ostream &o, const Property::Set &set, int indent) + { + std::string indent_prefix(indent, ' '); + + for (Property::PropertyMap::const_iterator i = set.getProperties().begin(); + i != set.getProperties().end(); + i++) + { + Property::Property *prop = i->second; + propertyXMLWrite(o, prop, indent_prefix); + } + } + + } + } +} diff --git a/third_party/openfx/HostSupport/src/ofxhPluginCache.cpp b/third_party/openfx/HostSupport/src/ofxhPluginCache.cpp new file mode 100644 index 000000000..5769639d1 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhPluginCache.cpp @@ -0,0 +1,694 @@ + + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "expat.h" + +// ofx +#include "ofxCore.h" +#include "ofxImageEffect.h" + +// ofx host +#include "ofxhBinary.h" +#include "ofxhPropertySuite.h" +#include "ofxhMemory.h" +#include "ofxhPluginAPICache.h" +#include "ofxhPluginCache.h" +#include "ofxhHost.h" +#include "ofxhXml.h" + +#if defined (__linux__) || defined (__FreeBSD__) + +#define DIRLIST_SEP_CHARS ":;" +#define DIRSEP "/" +#include + +static const char *getArchStr() +{ + if(sizeof(void *) == 4) { +#if defined(__linux__) + return "Linux-x86"; +#else + return "FreeBSD-x86"; +#endif + } + else { +#if defined(__linux__) + return "Linux-x86-64"; +#else + return "FreeBSD-x86-64"; +#endif + } +} + +#define ARCHSTR getArchStr() + +#elif defined (__APPLE__) + +#define DIRLIST_SEP_CHARS ";:" +#if defined(__x86_64) || defined(__x86_64__) +#define ARCHSTR "MacOS-x86-64" +#else +#define ARCHSTR "MacOS" +#endif +#define DIRSEP "/" +#include + +#elif defined (WINDOWS) +#define DIRLIST_SEP_CHARS ";" +#ifdef _WIN64 +#define ARCHSTR "win64" +#else +#define ARCHSTR "win32" +#endif +#define DIRSEP "\\" + +#include "shlobj.h" +#include "tchar.h" +#endif + +OFX::Host::PluginCache* OFX::Host::PluginCache::gPluginCachePtr = 0; + +// Define this to enable ofx plugin cache debug messages. +//#define CACHE_DEBUG + +using namespace OFX::Host; + + +/// try to open the plugin bundle object and query it for plugins +void PluginBinary::loadPluginInfo(PluginCache *cache) { + if (isInvalid()) { + return; + } + _fileModificationTime = _binary.getTime(); + _fileSize = _binary.getSize(); + _binaryChanged = false; + + // Take a reference to load the binary only once per session. It will + // eventually be unloaded in the destructor (see below). + // This avoid lots of useless calls to dlopen()/dlclose(). + if (!_binary.isLoaded()) { + _binary.ref(); + } + + int (*getNo)(void) = (int(*)()) _binary.findSymbol("OfxGetNumberOfPlugins"); + OfxPlugin* (*getPlug)(int) = (OfxPlugin*(*)(int)) _binary.findSymbol("OfxGetPlugin"); + + if (getNo == 0 || getPlug == 0) { + + _binary.setInvalid(true); + + } else { + int pluginCount = (*getNo)(); + + _plugins.reserve(pluginCount); + + for (int i=0;ifindApiHandler(plug->pluginApi, plug->apiVersion); + assert(api); + + _plugins.push_back(api->newPlugin(this, i, plug)); + } + } +} + +PluginBinary::~PluginBinary() { + std::vector::iterator i = _plugins.begin(); + while (i != _plugins.end()) { + delete *i; + i++; + } + // release the last reference to the binary, which should unload it + // if this reference was taken by loadPluginInfo(). + if (_binary.isLoaded()) { + _binary.unref(); + } + assert(!_binary.isLoaded()); +} + +PluginHandle::PluginHandle(Plugin *p, OFX::Host::Host *host) +{ + _b = p->getBinary(); + _b->_binary.ref(); + _op = 0; + OfxPlugin* (*getPlug)(int) = (OfxPlugin*(*)(int)) _b->_binary.findSymbol("OfxGetPlugin"); + if (getPlug) { + _op = getPlug(p->getIndex()); + if (_op) { + _op->setHost(host->getHandle()); + } + } +} + +PluginHandle::~PluginHandle() { + _b->_binary.unref(); +} + + +#if defined (WINDOWS) +const TCHAR *getStdOFXPluginPath(const std::string &hostId = "Plugins") +{ + static TCHAR buffer[MAX_PATH]; + static int gotIt = 0; + if(!gotIt) { + gotIt = 1; + SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_CURRENT, buffer); + strcat_s(buffer, MAX_PATH, __T("\\OFX\\Plugins")); + } + return buffer; +} +#endif + +static +std::string OFXGetEnv(const char* e) +{ +#if defined(WINDOWS) && !defined(__MINGW32__) + size_t requiredSize; + getenv_s(&requiredSize, 0, 0, e); + std::vector buffer(requiredSize); + if(requiredSize >0) + { + getenv_s(&requiredSize, &buffer.front(), requiredSize, e); + return &buffer.front(); + } + return ""; +#else + if(getenv(e)) + return getenv(e); +#endif + return ""; +} + +PluginCache* PluginCache::getPluginCache() +{ + if(!gPluginCachePtr) + gPluginCachePtr = new PluginCache(); + return gPluginCachePtr; +} + +void PluginCache::clearPluginCache() +{ + delete gPluginCachePtr; + gPluginCachePtr = 0; +} + +PluginCache::~PluginCache() +{ + for(std::list::iterator it=_binaries.begin(); it != _binaries.end(); ++it) { + delete (*it); + } + _binaries.clear(); +} + +PluginCache::PluginCache() : _hostSpec(0), _xmlCurrentBinary(0), _xmlCurrentPlugin(0) { + + _cacheVersion = ""; + _ignoreCache = false; + _dirty = false; + _enablePluginSeek = true; + + std::string s = OFXGetEnv("OFX_PLUGIN_PATH"); + + + while (s.length()) { + + int spos = int(s.find_first_of(DIRLIST_SEP_CHARS)); + + std::string path; + + if (spos != -1) { + path = s.substr(0, spos); + s = s.substr(spos+1); + } + else { + path = s; + s = ""; + } + + _pluginPath.push_back(path); + } + +#if defined(WINDOWS) + _pluginPath.push_back(getStdOFXPluginPath()); + _pluginPath.push_back("C:\\Program Files\\Common Files\\OFX\\Plugins"); +#endif +#if defined(__linux__) || defined(__FreeBSD__) + _pluginPath.push_back("/usr/OFX/Plugins"); +#endif +#if defined(__APPLE__) + _pluginPath.push_back("/Library/OFX/Plugins"); +#endif +} + +void PluginCache::setPluginHostPath(const std::string &hostId) { +#if defined(WINDOWS) + _pluginPath.push_back(getStdOFXPluginPath(hostId)); + _pluginPath.push_back("C:\\Program Files\\Common Files\\OFX\\" + hostId); +#endif +#if defined(__linux__) || defined(__FreeBSD__) + _pluginPath.push_back("/usr/OFX/" + hostId); +#endif +#if defined(__APPLE__) + _pluginPath.push_back("/Library/OFX/" + hostId); +#endif +} + +void PluginCache::scanDirectory(std::set &foundBinFiles, const std::string &dir, bool recurse) +{ +#ifdef CACHE_DEBUG + printf("looking in %s for plugins\n", dir.c_str()); +#endif + +#if defined (WINDOWS) + WIN32_FIND_DATA findData; + HANDLE findHandle; +#else + DIR *d = opendir(dir.c_str()); + if (!d) { + return; + } +#endif + + _pluginDirs.push_back(dir.c_str()); + +#if defined (UNIX) + while (dirent *de = readdir(d)) +#elif defined (WINDOWS) + findHandle = FindFirstFile((dir + "\\*").c_str(), &findData); + + if (findHandle == INVALID_HANDLE_VALUE) + { + return; + } + + while (1) +#endif + { +#if defined (UNIX) + std::string name = de->d_name; + bool isdir = true; +#else + std::string name = findData.cFileName; + bool isdir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; +#endif + if (name.find(".ofx.bundle") != std::string::npos) { + std::string barename = name.substr(0, name.length() - strlen(".bundle")); + std::string bundlename = dir + DIRSEP + name; + std::string binpath = dir + DIRSEP + name + DIRSEP "Contents" DIRSEP + ARCHSTR + DIRSEP + barename; + + // don't insert binpath yet, do it later because of Mac OS X Universal stuff + //foundBinFiles.insert(binpath); + +#if defined(__APPLE__) && (defined(__x86_64) || defined(__x86_64__)) + /* From the OpenFX specification: + + MacOS-x86-64 - for Apple Macintosh OS X, specifically on + intel x86 CPUs running AMD's 64 bit extensions. 64 bit host + applications should check this first, and if it doesn't + exist or is empty, fall back to "MacOS" looking for a + universal binary. + */ + + std::string binpath_universal = dir + DIRSEP + name + DIRSEP "Contents" DIRSEP + "MacOS" + DIRSEP + barename; + if (_knownBinFiles.find(binpath_universal) != _knownBinFiles.end()) { + binpath = binpath_universal; + } +#endif + if (_knownBinFiles.find(binpath) == _knownBinFiles.end()) { +#ifdef CACHE_DEBUG + printf("found non-cached binary %s\n", binpath.c_str()); +#endif + _dirty = true; + + // the binary was not in the cache + + PluginBinary *pb = 0; +#if defined(__x86_64) || defined(__x86_64__) + pb = new PluginBinary(binpath, bundlename, this); +# if defined(__APPLE__) + if (pb->isInvalid()) { + // fallback to "MacOS" + delete pb; + binpath = binpath_universal; + pb = new PluginBinary(binpath, bundlename, this); + } +# endif +#else + pb = new PluginBinary(binpath, bundlename, this); +#endif + _binaries.push_back(pb); + _knownBinFiles.insert(binpath); + foundBinFiles.insert(binpath); + + for (int j=0;jgetNPlugins();j++) { + Plugin *plug = &pb->getPlugin(j); + const APICache::PluginAPICacheI &api = plug->getApiHandler(); + api.loadFromPlugin(plug); + } + } else { +#ifdef CACHE_DEBUG + printf("found cached binary %s\n", binpath.c_str()); +#endif + } + // insert final path (universal or not) in the list of found files + foundBinFiles.insert(binpath); + } else { + if (isdir && (recurse && name[0] != '@' && name != "." && name != "..")) { + scanDirectory(foundBinFiles, dir + DIRSEP + name, recurse); + } + } +#if defined(WINDOWS) + int rval = FindNextFile(findHandle, &findData); + + if (rval == 0) { + break; + } +#endif + } + +#if defined(UNIX) + closedir(d); +#else + FindClose(findHandle); +#endif +} + +std::string PluginCache::seekPluginFile(const std::string &baseName) const { + // Exit early if disabled + if (!_enablePluginSeek) + return ""; + + for (std::list::const_iterator paths= _pluginDirs.begin(); + paths != _pluginDirs.end(); + paths++) { + std::string candidate = *paths + DIRSEP + baseName; + FILE *f = fopen(candidate.c_str(), "r"); + if (f) { + fclose(f); + return candidate; + } + } + return ""; +} + +void PluginCache::scanPluginFiles() +{ + std::set foundBinFiles; + + for (std::list::iterator paths= _pluginPath.begin(); + paths != _pluginPath.end(); + paths++) { + scanDirectory(foundBinFiles, *paths, _nonrecursePath.find(*paths) == _nonrecursePath.end()); + } + + std::list::iterator i=_binaries.begin(); + while (i!=_binaries.end()) { + PluginBinary *pb = *i; + + if (foundBinFiles.find(pb->getFilePath()) == foundBinFiles.end()) { + + // the binary was in the cache, but was not on the path + + _dirty = true; + i = _binaries.erase(i); + delete pb; + + } else { + + bool binChanged = pb->hasBinaryChanged(); + + // the binary was in the cache, but the binary has changed and thus we need to reload + if (binChanged) { + pb->loadPluginInfo(this); + _dirty = true; + } + + for (int j=0;jgetNPlugins();j++) { + Plugin *plug = &pb->getPlugin(j); + APICache::PluginAPICacheI &api = plug->getApiHandler(); + + if (binChanged) { + api.loadFromPlugin(plug); + } + + std::string reason; + + if (api.pluginSupported(plug, reason)) { + _plugins.push_back(plug); + api.confirmPlugin(plug); + } else { + std::cerr << "ignoring plugin " << plug->getIdentifier() << + " as unsupported (" << reason << ")" << std::endl; + } + } + + i++; + } + } +} + + +/// callback for XML parser +static void elementBeginHandler(void *userData, const XML_Char *name, const XML_Char **atts) { + PluginCache::getPluginCache()->elementBeginCallback(userData, name, atts); +} + +/// callback for XML parser +static void elementCharHandler(void *userData, const XML_Char *data, int len) { + PluginCache::getPluginCache()->elementCharCallback(userData, data, len); +} + +/// callback for XML parser +static void elementEndHandler(void *userData, const XML_Char *name) { + PluginCache::getPluginCache()->elementEndCallback(userData, name); +} + +static bool mapHasAll(const std::map &attmap, const char **atts) { + while (*atts) { + if (attmap.find(*atts) == attmap.end()) { + return false; + } + atts++; + } + return true; +} + +void PluginCache::elementBeginCallback(void */*userData*/, const XML_Char *name, const XML_Char **atts) { + if (_ignoreCache) { + return; + } + + std::string ename = name; + std::map attmap; + + while (*atts) { + attmap[atts[0]] = atts[1]; + atts += 2; + } + + /// XXX: validate in general + + if (ename == "cache") { + std::string cacheversion = attmap["version"]; + if (cacheversion != _cacheVersion) { +#ifdef CACHE_DEBUG + printf("mismatched version, ignoring cache (got '%s', wanted '%s')\n", + cacheversion.c_str(), + _cacheVersion.c_str()); +#endif + _ignoreCache = true; + } + } + + if (ename == "binary") { + const char *binAtts[] = {"path", "bundle_path", "mtime", "size", NULL}; + + if (!mapHasAll(attmap, binAtts)) { + // no path: bad XML + } + + std::string fname = attmap["path"]; + std::string bname = attmap["bundle_path"]; + time_t mtime = OFX::Host::Property::stringToInt(attmap["mtime"]); + size_t size = OFX::Host::Property::stringToInt(attmap["size"]); + + _xmlCurrentBinary = new PluginBinary(fname, bname, mtime, size); + _binaries.push_back(_xmlCurrentBinary); + _knownBinFiles.insert(fname); + return; + } + + if (ename == "plugin" && _xmlCurrentBinary && !_xmlCurrentBinary->hasBinaryChanged()) { + const char *plugAtts[] = {"api", "name", "index", "api_version", "major_version", "minor_version", NULL}; + + if (!mapHasAll(attmap, plugAtts)) { + // no path: bad XML + } + + std::string api = attmap["api"]; + std::string rawIdentifier = attmap["name"]; + + std::string identifier = rawIdentifier; + + // Who says the pluginIdentifier is case-insensitive? OFX 1.3 spec doesn't mention this. + // http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#id472588 + //for (size_t i=0;inewPlugin(_xmlCurrentBinary, idx, api, api_version, identifier, rawIdentifier, major_version, minor_version); + _xmlCurrentBinary->addPlugin(pe); + _xmlCurrentPlugin = pe; + apiCache->beginXmlParsing(pe); + } + + return; + } + + if (_xmlCurrentPlugin) { + APICache::PluginAPICacheI &api = _xmlCurrentPlugin->getApiHandler(); + api.xmlElementBegin(name, attmap); + } + +} + +void PluginCache::elementCharCallback(void */*userData*/, const XML_Char *data, int size) +{ + if (_ignoreCache) { + return; + } + + std::string s(data, size); + if (_xmlCurrentPlugin) { + APICache::PluginAPICacheI &api = _xmlCurrentPlugin->getApiHandler(); + api.xmlCharacterHandler(s); + } else { + /// XXX: we only want whitespace + } +} + +void PluginCache::elementEndCallback(void */*userData*/, const XML_Char *name) { + if (_ignoreCache) { + return; + } + + std::string ename = name; + + /// XXX: validation? + + if (ename == "plugin") { + if (_xmlCurrentPlugin) { + APICache::PluginAPICacheI &api = _xmlCurrentPlugin->getApiHandler(); + api.endXmlParsing(); + } + _xmlCurrentPlugin = 0; + return; + } + + if (ename == "bundle") { + _xmlCurrentBinary = 0; + return; + } + + if (_xmlCurrentPlugin) { + APICache::PluginAPICacheI &api = _xmlCurrentPlugin->getApiHandler(); + api.xmlElementEnd(name); + } +} + +void PluginCache::readCache(std::istream &ifs) { + XML_Parser xP = XML_ParserCreate(NULL); + XML_SetElementHandler(xP, elementBeginHandler, elementEndHandler); + XML_SetCharacterDataHandler(xP, elementCharHandler); + + while (ifs.good()) { + char buf[1001] = {0}; + ifs.read(buf, 1000); + + if (buf[0] == 0) { + XML_Parse(xP, "", 0, XML_TRUE); + break; + } + + int p = XML_Parse(xP, buf, int(strlen(buf)), XML_FALSE); + + if (p == XML_STATUS_ERROR) { + std::cout << "xml error : " << XML_GetErrorCode(xP) << std::endl; + /// XXX: do something here + break; + } + } + + XML_ParserFree(xP); +} + +void PluginCache::writePluginCache(std::ostream &os) const { +#ifdef CACHE_DEBUG + printf("writing pluginCache with version = %s\n", _cacheVersion.c_str()); +#endif + + os << "\n"; + for (std::list::const_iterator i=_binaries.begin();i!=_binaries.end();i++) { + PluginBinary *b = *i; + os << "\n"; + os << " getBundlePath()) + << XML::attribute("path", b->getFilePath()) + << XML::attribute("mtime", int(b->getFileModificationTime())) + << XML::attribute("size", int(b->getFileSize())) << "/>\n"; + + for (int j=0;jgetNPlugins();j++) { + Plugin *p = &b->getPlugin(j); + + + os << " getRawIdentifier()) + << XML::attribute("index", p->getIndex()) + << XML::attribute("api", p->getPluginApi()) + << XML::attribute("api_version", p->getApiVersion()) + << XML::attribute("major_version", p->getVersionMajor()) + << XML::attribute("minor_version", p->getVersionMinor()) + << ">\n"; + + const APICache::PluginAPICacheI &api = p->getApiHandler(); + os << " \n"; + api.saveXML(p, os); + os << " \n"; + + os << " \n"; + } + os << "\n"; + } + os << "\n"; +} + + +APICache::PluginAPICacheI *PluginCache::findApiHandler(const std::string &api, int version) { + std::list::iterator i = _apiHandlers.begin(); + while (i != _apiHandlers.end()) { + if (i->matches(api, version)) { + return i->handler; + } + i++; + } + return 0; +} diff --git a/third_party/openfx/HostSupport/src/ofxhPropertySuite.cpp b/third_party/openfx/HostSupport/src/ofxhPropertySuite.cpp new file mode 100644 index 000000000..e707206a4 --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhPropertySuite.cpp @@ -0,0 +1,1046 @@ + + +// ofx +#include "ofxCore.h" +#include "ofxImageEffect.h" + +// ofx host +#include "ofxhBinary.h" +#include "ofxhPropertySuite.h" +#include "ofxhUtilities.h" + +#include +#include + +namespace OFX { + namespace Host { + namespace Property { + + /// type holder, for integers + int IntValue::kEmpty = 0; + double DoubleValue::kEmpty = 0; + void *PointerValue::kEmpty = 0; + std::string StringValue::kEmpty; + const char *gTypeNames[] = {"int", "double", "string", "pointer" }; + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> int GetHook::getProperty(const std::string &name, int index) const + { + return getIntProperty(name, index); + } + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> double GetHook::getProperty(const std::string &name, int index) const + { + return getDoubleProperty(name, index); + } + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> void *GetHook::getProperty(const std::string &name, int index) const + { + return getPointerProperty(name, index); + } + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> const std::string &GetHook::getProperty(const std::string &name, int index) const + { + return getStringProperty(name, index); + } + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> void GetHook::getPropertyN(const std::string &name, int *values, int count) const + { + getIntPropertyN(name, values, count); + } + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> void GetHook::getPropertyN(const std::string &name, double *values, int count) const + { + getDoublePropertyN(name, values, count); + } + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> void GetHook::getPropertyN(const std::string &name, void **values, int count) const + { + getPointerPropertyN(name, values, count); + } + + /// this does some magic so that it calls get string/int/double/pointer appropriately + template<> void GetHook::getPropertyN(const std::string &name, const char **values, int count) const + { + getStringPropertyN(name, values, count); + } + + + /// override this to get a single value at the given index. + const std::string &GetHook::getStringProperty(const std::string &/*name*/, int /*index*/) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getStringProperty!!!! " << std::endl; +# endif + return StringValue::kEmpty; + } + + /// override this function to optimize multiple-string properties fetching + void GetHook::getStringPropertyN(const std::string &name, const char** values, int count) const + { + for (int i = 0; i < count; ++i) { + values[i] = getStringProperty(name, i).c_str(); + } + } + + /// override this to fetch a single value at the given index. + int GetHook::getIntProperty(const std::string &/*name*/, int /*index*/) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getIntProperty!!!! " << std::endl; +# endif + return 0; + } + + /// override this to fetch a single value at the given index. + double GetHook::getDoubleProperty(const std::string &/*name*/, int /*index*/) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getDoubleProperty!!!! " << std::endl; +# endif + return 0; + } + + /// override this to fetch a single value at the given index. + void *GetHook::getPointerProperty(const std::string &/*name*/, int /*index*/) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getPointerProperty!!!! " << std::endl; +# endif + return NULL; + } + + /// override this to fetch a multiple values in a multi-dimension property + void GetHook::getDoublePropertyN(const std::string &/*name*/, double *values, int count) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getDoublePropertyN!!!! " << std::endl; +# endif + memset(values, 0, sizeof(double) * count); + } + + /// override this to fetch a multiple values in a multi-dimension property + void GetHook::getIntPropertyN(const std::string &/*name*/, int *values, int count) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getIntPropertyN!!!! " << std::endl; +# endif + memset(values, 0, sizeof(int) * count); + } + + /// override this to fetch a multiple values in a multi-dimension property + void GetHook::getPointerPropertyN(const std::string &/*name*/, void **values, int count) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getPointerPropertyN!!!! " << std::endl; +# endif + memset(values, 0, sizeof(void *) * count); + } + + + /// override this to fetch the dimension size. + int GetHook::getDimension(const std::string &/*name*/) const + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::getDimension!!!! " << std::endl; +# endif + return 0; + } + + /// override this to handle a reset(). + void GetHook::reset(const std::string &/*name*/) + { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Calling un-overriden GetHook::reset!!!! " << std::endl; +# endif + } + + Property::Property(const std::string &name, + TypeEnum type, + int dimension, + bool pluginReadOnly) + : _name(name) + , _type(type) + , _dimension(dimension) + , _pluginReadOnly(pluginReadOnly) + , _getHook(0) + { + } + + Property::Property(const Property &other) + : _name(other._name) + , _type(other._type) + , _dimension(other._dimension) + , _pluginReadOnly(other._pluginReadOnly) + , _getHook(0) + { + } + + /// call notify on the contained notify hooks + void Property::notify(bool single, int indexOrN) + { + std::vector::iterator i; + for(i = _notifyHooks.begin(); i != _notifyHooks.end(); ++i) { + (*i)->notify(_name, single, indexOrN); + } + } + + inline int castToAPIType(int i) { return i; } + inline void *castToAPIType(void *v) { return v; } + inline double castToAPIType(double d) { return d; } + inline const char *castToAPIType(const std::string &s) { return s.c_str(); } + + template PropertyTemplate::PropertyTemplate(const std::string &name, + int dimension, + bool /*pluginReadOnly*/, + APIType defaultValue) + : Property(name, T::typeCode, dimension) + { + + if (dimension) { + _value.resize(dimension); + _defaultValue.resize(dimension); + } + + if (dimension) { + for (int i=0;i PropertyTemplate::PropertyTemplate(const PropertyTemplate &pt) + : Property(pt) + , _value(pt._value) + , _defaultValue(pt._defaultValue) + { + } + +#ifdef WINDOWS +#pragma warning( disable : 4181 ) +#endif + /// get one value + template + const typename T::ReturnType PropertyTemplate::getValue(int index) const + { + if (_getHook) { + return _getHook->getProperty(_name, index); + } + else { + return getValueRaw(index); + } + } +#ifdef WINDOWS +#pragma warning( default : 4181 ) +#endif + // get multiple values + template + void PropertyTemplate::getValueN(typename T::APIType *values, int count) const { + if (_getHook) { + _getHook->getPropertyN(_name, values, count); + } + else { + getValueNRaw(values, count); + } + } + +#ifdef WINDOWS +#pragma warning( disable : 4181 ) +#endif + /// get one value, without going through the getHook + template + const typename T::ReturnType PropertyTemplate::getValueRaw(int index) const + { + if (index < 0 || ((size_t)index >= _value.size())) { + throw Exception(kOfxStatErrBadIndex); + } + return _value[index]; + } +#ifdef WINDOWS +#pragma warning( default : 4181 ) +#endif + // get multiple values, without going through the getHook + template + void PropertyTemplate::getValueNRaw(APIType *value, int count) const + { + size_t size = count; + if (size > _value.size()) { + size = _value.size(); + } + + for (size_t i=0;i void PropertyTemplate::setValue(const typename T::Type &value, int index) + { + if (index < 0 || ((size_t)index > _value.size() && _dimension)) { + throw Exception(kOfxStatErrBadIndex); + } + + if (_value.size() <= (size_t)index) { + _value.resize(index+1); + } + _value[index] = value; + + notify(true, index); + } + + /// set multiple values + template void PropertyTemplate::setValueN(const typename T::APIType *value, int count) + { + if (_dimension && ((size_t)count > _value.size())) { + throw Exception(kOfxStatErrBadIndex); + } + if (_value.size() != (size_t)count) { + _value.resize(count); + } + for (int i=0;i int PropertyTemplate::getDimension() const { + if (_dimension != 0) { + return _dimension; + } + else { + // code to get it from the hook + if (_getHook) { + return _getHook->getDimension(_name); + } + else { + return (int)_value.size(); + } + } + } + + template void PropertyTemplate::reset() + { + if (_getHook) { + _getHook->reset(_name); + int dim = getDimension(); + + if(!isFixedSize()) { + _value.resize(dim); + } + for(int i = 0; i < dim; ++i) { + _value[i] = _getHook->getProperty(_name, i); + } + } + else { + if(isFixedSize()) { + _value = _defaultValue; + } + else { + _value.resize(0); + } + + // now notify on a reset + notify(false, _dimension); + } + } + + // explicit instanciations (required by ofxhPluginAPICache.cpp) + template class PropertyTemplate; + template class PropertyTemplate; + template class PropertyTemplate; + template class PropertyTemplate; + + inline int castAwayConst(int i) { return i; } + inline double castAwayConst(double d) { return d; } + inline void *castAwayConst(void *v) { return v; } + inline char *castAwayConst(const char *s) { return const_cast(s); } + + inline int *castToConst(int *i) { return i; } + inline double *castToConst(double *d) { return d; } + inline const char **castToConst(char **s) { return const_cast(s); } + inline void **castToConst(void **v) { return v; } + + + void Set::setGetHook(const std::string &s, GetHook *ghook) const + { + Property *prop = fetchProperty(s); + + if(prop) { + prop->setGetHook(ghook); + } + } + + + /// add a notify hook for a particular property. users may need to call particular + /// specialised versions of this. + void Set::addNotifyHook(const std::string &s, NotifyHook *hook) const + { + Property *prop = fetchProperty(s); + + if(prop) { + prop->addNotifyHook(hook); + } + } + + Property *Set::fetchProperty(const std::string&name, bool followChain) const + { + PropertyMap::const_iterator i = _props.find(name); + if (i == _props.end()) { + if(followChain && _chainedSet) { + return _chainedSet->fetchProperty(name, true); + } + return NULL; + } + return i->second; + } + + template bool Set::fetchTypedProperty(const std::string&name, T *&prop, bool followChain) const + { + Property *myprop = fetchProperty(name, followChain); + + if(!myprop) + return false; + + prop = dynamic_cast(myprop); + if (prop == 0) { + return false; + } + return true; + } + + String *Set::fetchStringProperty(const std::string &name, bool followChain) const { + String *p; + if (fetchTypedProperty(name, p, followChain)) { + return p; + } + return NULL; + } + + Int *Set::fetchIntProperty(const std::string &name, bool followChain) const { + Int *p; + if (fetchTypedProperty(name, p, followChain)) { + return p; + } + return NULL; + } + + Pointer *Set::fetchPointerProperty(const std::string &name, bool followChain) const { + Pointer *p; + if (fetchTypedProperty(name, p, followChain)) { + return p; + } + return NULL; + } + + Double *Set::fetchDoubleProperty(const std::string &name, bool followChain) const { + Double *p; + if (fetchTypedProperty(name, p, followChain)) { + return p; + } + return NULL; + } + + /// add one new property + void Set::createProperty(const PropSpec &spec) + { + if (_props.find(spec.name) != _props.end()) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: Tried to add a duplicate property to a Property::Set: " << spec.name << std::endl; +# endif + return; + } + + switch (spec.type) { + case eInt: + _props[spec.name] = new Int(spec.name, spec.dimension, spec.readonly, spec.defaultValue?atoi(spec.defaultValue):0); + break; + case eDouble: + _props[spec.name] = new Double(spec.name, spec.dimension, spec.readonly, spec.defaultValue?atof(spec.defaultValue):0); + break; + case eString: + _props[spec.name] = new String(spec.name, spec.dimension, spec.readonly, spec.defaultValue?spec.defaultValue:""); + break; + case ePointer: + _props[spec.name] = new Pointer(spec.name, spec.dimension, spec.readonly, (void*)spec.defaultValue); + break; + default: // XXX error - unrecognised type + break; + } + } + + void Set::addProperties(const PropSpec spec[]) + { + while (spec->name) { + createProperty(*spec); + spec++; + } + } + + /// add one new property + void Set::addProperty(Property *prop) + { + PropertyMap::iterator t = _props.find(prop->getName()); + if(t != _props.end()) + delete t->second; + _props[prop->getName()] = prop; + } + + /// empty ctor + Set::Set() + : _magic(kMagic) + , _chainedSet(NULL) + { + } + + Set::Set(const PropSpec spec[]) + : _magic(kMagic) + , _chainedSet(NULL) + { + addProperties(spec); + } + + Set::Set(const Set &other) + : _magic(kMagic) + , _chainedSet(NULL) + { + bool failed = false; + + for (std::map::const_iterator i = other._props.begin(); + i != other._props.end(); + i++) + { + Property *copyProp = i->second->deepCopy(); + if (!copyProp) { + failed = true; + break; + } + _props[i->first] = copyProp; + } + + if (failed) + + for (std::map::iterator j = _props.begin(); + j != _props.end(); + j++) { + delete j->second; + } + + } + + Set::~Set() + { + std::map::iterator i = _props.begin(); + while (i != _props.end()) { + delete i->second; + i++; + } + } + + /// set a particular property + template void Set::setProperty(const std::string &property, int index, const typename T::Type &value) + { + try { + PropertyTemplate *prop = 0; + if(fetchTypedProperty(property, prop)) { + prop->setValue(value, index); + } + else { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: setProperty " << property << "[" << index << "] ignored because host property not defined" << std::endl; +# endif + } + } + catch(...) {} + } + + /// set a particular property + template void Set::setPropertyN(const std::string &property, int count, const typename T::APIType *value) + { + try { + PropertyTemplate *prop = 0; + if(fetchTypedProperty(property, prop)) { + prop->setValueN(value, count); + } + else { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: setPropertyN " << property << " ignored because host property not defined" << std::endl; +# endif + } + } + catch(...) {} + } + + /// get a particular property + template typename T::ReturnType Set::getProperty(const std::string &property, int index) const + { + try { + PropertyTemplate *prop; + if(fetchTypedProperty(property, prop, true)) { + return prop->getValue(index); + } + } + catch(...) {} + return T::kEmpty; + } + + /// get a particular property + template void Set::getPropertyN(const std::string &property, int count, typename T::APIType *value) const + { + try { + PropertyTemplate *prop; + if(fetchTypedProperty(property, prop, true)) { + return prop->getValueN(value, count); + } + } + catch(...) {} + } + + /// get a particular property + template typename T::ReturnType Set::getPropertyRaw(const std::string &property, int index) const + { + try { + PropertyTemplate *prop; + if(fetchTypedProperty(property, prop, true)) { + return prop->getValueRaw(index); + } + } + catch(...) {} + return T::kEmpty; + } + + /// get a particular property + template void Set::getPropertyRawN(const std::string &property, int count, typename T::APIType *value) const + { + try { + PropertyTemplate *prop; + if(fetchTypedProperty(property, prop, true)) { + return prop->getValueNRaw(value, count); + } + } + catch(...) {} + } + + /// get a particular int property + int Set::getIntPropertyRaw(const std::string &property, int index) const + { + return getPropertyRaw(property, index); + } + + /// get a particular double property + double Set::getDoublePropertyRaw(const std::string &property, int index) const + { + return getPropertyRaw(property, index); + } + + /// get a particular double property + void *Set::getPointerPropertyRaw(const std::string &property, int index) const + { + return getPropertyRaw(property, index); + } + + /// get a particular double property + const std::string &Set::getStringPropertyRaw(const std::string &property, int index) const + { + String *prop; + if(fetchTypedProperty(property, prop, true)) { + return prop->getValueRaw(index); + } + return StringValue::kEmpty; + } + + /// get a particular int property + int Set::getIntProperty(const std::string &property, int index) const + { + return getProperty(property, index); + } + + /// get the value of a particular double property + void Set::getIntPropertyN(const std::string &property, int *v, int N) const + { + return getPropertyN(property, N, v); + } + + /// get a particular double property + double Set::getDoubleProperty(const std::string &property, int index) const + { + return getProperty(property, index); + } + + /// get the value of a particular double property + void Set::getDoublePropertyN(const std::string &property, double *v, int N) const + { + return getPropertyN(property, N, v); + } + + /// get a particular double property + void *Set::getPointerProperty(const std::string &property, int index) const + { + return getProperty(property, index); + } + + /// get a particular double property + const std::string &Set::getStringProperty(const std::string &property, int index) const + { + return getProperty(property, index); + } + + /// set a particular string property + void Set::setStringProperty(const std::string &property, const std::string &value, int index) + { + setProperty(property, index, value); + } + + /// get a particular int property + void Set::setIntProperty(const std::string &property, int v, int index) + { + setProperty(property, index, v); + } + + /// get a particular double property + void Set::setIntPropertyN(const std::string &property, const int *v, int N) + { + setPropertyN(property, N, v); + } + + /// get a particular double property + void Set::setDoubleProperty(const std::string &property, double v, int index) + { + setProperty(property, index, v); + } + + /// get a particular double property + void Set::setDoublePropertyN(const std::string &property, const double *v, int N) + { + setPropertyN(property, N, v); + } + + /// get a particular double property + void Set::setPointerProperty(const std::string &property, void *v, int index) + { + setProperty(property, index, v); + } + + /// get the dimension of a particular property + int Set::getDimension(const std::string &property) const + { + Property *prop = 0; + if(fetchTypedProperty(property, prop, true)) { + return prop->getDimension(); + } + return 0; + } + + /// is the given string one of the values of a multi-dimensional string prop + /// this returns a non negative index if it is found, otherwise, -1 + int Set::findStringPropValueIndex(const std::string &propName, + const std::string &propValue) const + { + String *prop = fetchStringProperty(propName, true); + + if(prop) { + const std::vector &values = prop->getValues(); + std::vector::const_iterator i = find(values.begin(), values.end(), propValue); + if(i != values.end()) { + return int(i - values.begin()); + } + } + return -1; + } + + /// static functions for the suite + template static OfxStatus propSet(OfxPropertySetHandle properties, + const char *property, + int index, + typename T::APIType value) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propSet - " << properties << ' ' << property << "[" << index << "] = " << value << " ..."; +# endif + try { + Set *thisSet = reinterpret_cast(properties); + if(!thisSet || !thisSet->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + PropertyTemplate *prop = 0; + if(!thisSet->fetchTypedProperty(property, prop, false)) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propSet " << property << "[" << index << "] ignored because effect property not defined" << std::endl; + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + prop->setValue(value, index); + } catch (const Exception& e) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(e.getStatus()) << std::endl; +# endif + return e.getStatus(); + } catch (...) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } + + /// static functions for the suite + template static OfxStatus propSetN(OfxPropertySetHandle properties, + const char *property, + int count, + const typename T::APIType *values) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propSetN - " << properties << ' ' << property << "[0.." << count-1 << "] = "; + for (int i = 0; i < count; ++i) { + if (i != 0) { + std::cout << ','; + } + std::cout << values[i]; + } +# endif + try { + Set *thisSet = reinterpret_cast(properties); + if(!thisSet || !thisSet->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + PropertyTemplate *prop = 0; + if(!thisSet->fetchTypedProperty(property, prop, false)) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propSetN " << property << " ignored because effect property not defined" << std::endl; + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + prop->setValueN(values, count); + } catch (const Exception& e) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(e.getStatus()) << std::endl; +# endif + return e.getStatus(); + } catch (...) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } + + /// static functions for the suite + template static OfxStatus propGet(OfxPropertySetHandle properties, + const char *property, + int index, + typename T::APITypeConstless *value) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propGet - " << properties << ' ' << property << "[" << index << "] = ..."; +# endif + try { + Set *thisSet = reinterpret_cast(properties); + if(!thisSet || !thisSet->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + PropertyTemplate *prop = 0; + if(!thisSet->fetchTypedProperty(property, prop, true)) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + *value = castAwayConst(castToAPIType(prop->getValue(index))); + +# ifdef OFX_DEBUG_PROPERTIES + std::cout << *value << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + } catch (const Exception& e) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(e.getStatus()) << std::endl; +# endif + return e.getStatus(); + } catch (...) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + return kOfxStatOK; + } + + /// static functions for the suite + template static OfxStatus propGetN(OfxPropertySetHandle properties, + const char *property, + int count, + typename T::APITypeConstless *values) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propGetN - " << properties << ' ' << property << "[0.." << count-1 << "] = ..."; +# endif + try { + Set *thisSet = reinterpret_cast(properties); + if(!thisSet || !thisSet->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + PropertyTemplate *prop = 0; + if(!thisSet->fetchTypedProperty(property, prop, true)) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + prop->getValueN(castToConst(values), count); +# ifdef OFX_DEBUG_PROPERTIES + for (int i = 0; i < count; ++i) { + if (i != 0) { + std::cout << ','; + } + std::cout << values[i]; + } + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + } catch (const Exception& e) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(e.getStatus()) << std::endl; +# endif + return e.getStatus(); + } catch (...) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + return kOfxStatOK; + } + + /// static functions for the suite + static OfxStatus propReset(OfxPropertySetHandle properties, const char *property) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propReset - " << properties << ' ' << property << " ..."; +# endif + try { + Set *thisSet = reinterpret_cast(properties); + if(!thisSet || !thisSet->verifyMagic()) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + Property *prop = thisSet->fetchProperty(property, false); + if(!prop) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + prop->reset(); +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + } catch (const Exception& e) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(e.getStatus()) << std::endl; +# endif + return e.getStatus(); + } catch (...) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + return kOfxStatOK; + } + + /// static functions for the suite + static OfxStatus propGetDimension(OfxPropertySetHandle properties, const char *property, int *count) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "OFX: propGetDimension - " << properties << ' ' << property << " ..."; +# endif + if (!properties) { +# ifdef OFX_DEBUG_PARAMETERS + std::cout << ' ' << StatStr(kOfxStatErrBadHandle) << std::endl; +# endif + return kOfxStatErrBadHandle; + } + try { + Set *thisSet = reinterpret_cast(properties); + Property *prop = thisSet->fetchProperty(property, true); + if(!prop) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << "unknown property\n"; +# endif + return kOfxStatErrUnknown; + } + *count = prop->getDimension(); +# ifdef OFX_DEBUG_PROPERTIES + std::cout << *count << ' ' << StatStr(kOfxStatOK) << std::endl; +# endif + return kOfxStatOK; + } catch (const Exception& e) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(e.getStatus()) << std::endl; +# endif + return e.getStatus(); + } catch (...) { +# ifdef OFX_DEBUG_PROPERTIES + std::cout << ' ' << StatStr(kOfxStatErrUnknown) << std::endl; +# endif + return kOfxStatErrUnknown; + } + } + + /// the actual suite that is passed across the API to manage properties + struct OfxPropertySuiteV1 gSuite = { + propSet, + propSet, + propSet, + propSet, + propSetN, + propSetN, + propSetN, + propSetN, + propGet, + propGet, + propGet, + propGet, + propGetN, + propGetN, + propGetN, + propGetN, + propReset, + propGetDimension + }; + + /// return the OFX function suite that manages properties + const void *GetSuite(int version) + { + if(version == 1) + return (void *)(&gSuite); + return NULL; + } + + } + } +} diff --git a/third_party/openfx/HostSupport/src/ofxhUtilities.cpp b/third_party/openfx/HostSupport/src/ofxhUtilities.cpp new file mode 100644 index 000000000..e3d33ba7c --- /dev/null +++ b/third_party/openfx/HostSupport/src/ofxhUtilities.cpp @@ -0,0 +1,37 @@ + + +#include "ofxCore.h" +#include "ofxhUtilities.h" + +namespace OFX { + + /// get me deepest bit depth + std::string FindDeepestBitDepth(const std::string &s1, const std::string &s2) + { + if(s1 == kOfxBitDepthNone) { + return s2; + } + else if(s1 == kOfxBitDepthByte) { + if(s2 == kOfxBitDepthShort || s2 == kOfxBitDepthFloat) + return s2; + return s1; + } + else if(s1 == kOfxBitDepthShort) { + if(s2 == kOfxBitDepthFloat) + return s2; + return s1; + } + else if(s1 == kOfxBitDepthHalf) { + if(s2 == kOfxBitDepthFloat) + return s2; + return s1; + } + else if(s1 == kOfxBitDepthFloat) { + return s1; + } + else { + return s2; // oooh this might be bad dad. + } + } + +} diff --git a/third_party/openfx/Support/CMakeLists.txt b/third_party/openfx/Support/CMakeLists.txt new file mode 100644 index 000000000..4c09b1897 --- /dev/null +++ b/third_party/openfx/Support/CMakeLists.txt @@ -0,0 +1,8 @@ +set(OFX_SUPPORT_HEADER_DIR "include") +file(GLOB_RECURSE OFX_SUPPORT_HEADER_FILES "${OFX_SUPPORT_HEADER_DIR}/*.h") + +add_subdirectory(Library) +if(BUILD_EXAMPLE_PLUGINS) + add_subdirectory(Plugins) + add_subdirectory(PropTester) +endif() diff --git a/third_party/openfx/Support/LICENSE b/third_party/openfx/Support/LICENSE new file mode 100644 index 000000000..6f3b8f093 --- /dev/null +++ b/third_party/openfx/Support/LICENSE @@ -0,0 +1,32 @@ +Software License : + +Copyright OpenFX and contributors to the OpenFX project. +SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder 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 +HOLDER 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. diff --git a/third_party/openfx/Support/Library/.gdb_history b/third_party/openfx/Support/Library/.gdb_history new file mode 100644 index 000000000..b98ddf17a --- /dev/null +++ b/third_party/openfx/Support/Library/.gdb_history @@ -0,0 +1,57 @@ +run tmpPlugin.bundle +where +l +q +run tmpPlugin.bundle +where +l +l +p myBundle +up +p myBundle +q +run blah.bundle +up +w +where +ls +w +down +down +up +l +p myBundle +q +break main +run blah +n +n +p myBundle +n +q +q +l +l +break 17 +run +n +p bundleURL +n +p myBundle +n +where +p myBundle +up +w +l +p myBundle +q +break main +run +n +n +p myBundle +n +n +p nPluginsFunc +q diff --git a/third_party/openfx/Support/Library/CMakeLists.txt b/third_party/openfx/Support/Library/CMakeLists.txt new file mode 100644 index 000000000..7f3dcbcf2 --- /dev/null +++ b/third_party/openfx/Support/Library/CMakeLists.txt @@ -0,0 +1,16 @@ +set(OFX_SUPPORT_LIBRARY_DIR ".") +file(GLOB_RECURSE OFX_SUPPORT_LIBRARY_FILES "${OFX_SUPPORT_LIBRARY_DIR}/*.cpp") + +add_library(OfxSupport STATIC + ${OFX_HEADER_FILES} + ${OFX_SUPPORT_HEADER_FILES} + ${OFX_SUPPORT_LIBRARY_FILES}) + +set_target_properties(OfxSupport PROPERTIES LINKER_LANGUAGE CXX) +if(NOT MSVC) + set_target_properties(OfxSupport PROPERTIES COMPILE_FLAGS "-fPIC") +endif() + +target_include_directories(OfxSupport PUBLIC + ${OFX_HEADER_DIR} + ${OFX_SUPPORT_HEADER_DIR}) diff --git a/third_party/openfx/Support/Library/ofxSupport.dsp b/third_party/openfx/Support/Library/ofxSupport.dsp new file mode 100755 index 000000000..4f8b3b9dc --- /dev/null +++ b/third_party/openfx/Support/Library/ofxSupport.dsp @@ -0,0 +1,128 @@ +# Microsoft Developer Studio Project File - Name="ofxsupport" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=ofxsupport - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ofxsupport.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ofxsupport.mak" CFG="ofxsupport - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ofxsupport - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "ofxsupport - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ofxsupport - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"ofxSupport.lib" + +!ELSEIF "$(CFG)" == "ofxsupport - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"ofxSupport.lib" + +!ENDIF + +# Begin Target + +# Name "ofxsupport - Win32 Release" +# Name "ofxsupport - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ofxsCore.cpp +# End Source File +# Begin Source File + +SOURCE=.\ofxsImageEffect.cpp +# End Source File +# Begin Source File + +SOURCE=.\ofxsInteract.cpp +# End Source File +# Begin Source File + +SOURCE=.\ofxsLog.cpp +# End Source File +# Begin Source File + +SOURCE=.\ofxsMultiThread.cpp +# End Source File +# Begin Source File + +SOURCE=.\ofxsParams.cpp +# End Source File +# Begin Source File + +SOURCE=.\ofxsProperty.cpp +# End Source File +# Begin Source File + +SOURCE=.\ofxsPropertyValidation.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ofxsSupportPrivate.h +# End Source File +# End Group +# End Target +# End Project diff --git a/third_party/openfx/Support/Library/ofxsCore.cpp b/third_party/openfx/Support/Library/ofxsCore.cpp new file mode 100644 index 000000000..65da7050d --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsCore.cpp @@ -0,0 +1,113 @@ + + +#include "ofxsSupportPrivate.h" +#ifdef DEBUG +#include +#if defined(__APPLE__) || defined(linux) +#include +#include +#endif +#endif + +#include "ofxsMemory.h" + +namespace OFX { + /** @brief Throws an @ref OFX::Exception depending on the status flag passed in */ + void throwSuiteStatusException(OfxStatus stat) + { + switch (stat) + { + case kOfxStatOK : + case kOfxStatReplyYes : + case kOfxStatReplyNo : + case kOfxStatReplyDefault : + break; + + case kOfxStatErrMemory : + throw std::bad_alloc(); + + default : +# ifdef DEBUG + std::cout << "Threw suite exception!" << std::endl; +# if defined(__APPLE__) || defined(linux) + void* callstack[128]; + int i, frames = backtrace(callstack, 128); + char** strs = backtrace_symbols(callstack, frames); + for (i = 0; i < frames; ++i) { + std::cout << strs[i] << std::endl; + } + free(strs); +# endif +# endif + throw OFX::Exception::Suite(stat); + } + } + + void throwHostMissingSuiteException(std::string name) + { +# ifdef DEBUG + std::cout << "Threw suite exception! Host missing '" << name << "' suite." << std::endl; +# if defined(__APPLE__) || defined(linux) + void* callstack[128]; + int i, frames = backtrace(callstack, 128); + char** strs = backtrace_symbols(callstack, frames); + for (i = 0; i < frames; ++i) { + std::cout << strs[i] << std::endl; + } + free(strs); +# endif +# endif + throw OFX::Exception::Suite(kOfxStatErrUnsupported); + } + + + /** @brief maps status to a string */ + const char* mapStatusToString(OfxStatus stat) + { + switch(stat) + { + case kOfxStatOK : return "kOfxStatOK"; + case kOfxStatFailed : return "kOfxStatFailed"; + case kOfxStatErrFatal : return "kOfxStatErrFatal"; + case kOfxStatErrUnknown : return "kOfxStatErrUnknown"; + case kOfxStatErrMissingHostFeature : return "kOfxStatErrMissingHostFeature"; + case kOfxStatErrUnsupported : return "kOfxStatErrUnsupported"; + case kOfxStatErrExists : return "kOfxStatErrExists"; + case kOfxStatErrFormat : return "kOfxStatErrFormat"; + case kOfxStatErrMemory : return "kOfxStatErrMemory"; + case kOfxStatErrBadHandle : return "kOfxStatErrBadHandle"; + case kOfxStatErrBadIndex : return "kOfxStatErrBadIndex"; + case kOfxStatErrValue : return "kOfxStatErrValue"; + case kOfxStatReplyYes : return "kOfxStatReplyYes"; + case kOfxStatReplyNo : return "kOfxStatReplyNo"; + case kOfxStatReplyDefault : return "kOfxStatReplyDefault"; + case kOfxStatErrImageFormat : return "kOfxStatErrImageFormat"; + } + return "UNKNOWN STATUS CODE"; + } + + + /** @brief namespace for memory allocation that is done via wrapping the ofx memory suite */ + namespace Memory { + /** @brief allocate n bytes, returns a pointer to it */ + void *allocate(size_t nBytes, ImageEffect *effect) + { + void *data = 0; + OfxStatus stat = OFX::Private::gMemorySuite->memoryAlloc((void *)(effect ? effect->getHandle() : 0), nBytes, &data); + if(stat != kOfxStatOK) + throw std::bad_alloc(); + return data; + } + + /** @brief free n previously allocated memory */ + void free(void *ptr) throw() + { + if(ptr) + // note we are ignore errors, this could be bad, but we don't throw on a destruction + OFX::Private::gMemorySuite->memoryFree(ptr); + } + + }; + +}; // namespace OFX + diff --git a/third_party/openfx/Support/Library/ofxsImageEffect.cpp b/third_party/openfx/Support/Library/ofxsImageEffect.cpp new file mode 100644 index 000000000..62599800e --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsImageEffect.cpp @@ -0,0 +1,3078 @@ + + +/** @brief This file contains code that skins the ofx effect suite */ + +#include "ofxsSupportPrivate.h" +#include // for find +#include // for strlen +#ifdef DEBUG +#include +#endif +#include +#include "ofxGPURender.h" +#include "ofxsCore.h" + +#if defined __APPLE__ || defined __linux__ || defined __FreeBSD__ +# if __GNUC__ >= 4 +# define EXPORT __attribute__((visibility("default"))) +# define LOCAL __attribute__((visibility("hidden"))) +# else +# define EXPORT +# define LOCAL +# endif +#elif defined _WIN32 +# define EXPORT OfxExport +# define LOCAL +#else +# error Not building on your operating system quite yet +#endif + +// string utility functions +static bool ends_with(std::string const & value, std::string const & ending) +{ + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +static bool starts_with(std::string const & value, std::string const & beginning) +{ + if (beginning.size() > value.size()) return false; + return std::equal(beginning.begin(), beginning.end(), value.begin()); +} + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. */ +namespace OFX { + + // globals to keep consistent data structures around. + OFX::PluginFactoryArray plugIDs; + //Put it all into a map, so we know when to delete what! + struct OfxPlugInfo + { + OfxPlugInfo() = default; + OfxPlugInfo(OFX::PluginFactory* f, std::unique_ptr p):_factory(f), _plug(std::move(p)){} + OFX::PluginFactory* _factory = nullptr; + std::unique_ptr _plug; + }; + typedef std::map OfxPlugInfoMap; + OfxPlugInfoMap plugInfoMap; + + typedef std::vector OfxPluginArray; + OfxPluginArray ofxPlugs; + + /** @brief the global host description */ + ImageEffectHostDescription gHostDescription; + bool gHostDescriptionHasInit = false; + + bool ImageEffectHostDescription::supportsPixelComponent(const PixelComponentEnum component) const + { + return std::find(_supportedComponents.begin(), _supportedComponents.end(), component) != _supportedComponents.end(); + } + bool ImageEffectHostDescription::supportsBitDepth( const BitDepthEnum bitDepth) const + { + return std::find(_supportedPixelDepths.begin(), _supportedPixelDepths.end(), bitDepth) != _supportedPixelDepths.end(); + } + bool ImageEffectHostDescription::supportsContext(const ContextEnum context) const + { + return std::find(_supportedContexts.begin(), _supportedContexts.end(), context) != _supportedContexts.end(); + } + + /** @return default pixel depth supported by host application. */ + BitDepthEnum ImageEffectHostDescription::getDefaultPixelDepth() const + { + if(!_supportedPixelDepths.empty()) { + return _supportedPixelDepths[0]; + } else { + OFX::Log::warning(true, "The host doesn't define supported pixel depth. (size: %d)", (int)_supportedPixelDepths.size()); + return eBitDepthFloat; + } + } + + /** @return default pixel component supported by host application. */ + PixelComponentEnum ImageEffectHostDescription::getDefaultPixelComponent() const + { + if(! _supportedComponents.empty()) { + return _supportedComponents[0]; + } else { + OFX::Log::warning(true, "The host doesn't define supported pixel component. (size: %d)", _supportedComponents.size()); + return ePixelComponentRGBA; + } + } + + ImageEffectHostDescription* getImageEffectHostDescription() + { + if(gHostDescriptionHasInit) + return &gHostDescription; + return NULL; + } + + namespace Private { + // Suite and host pointers + OfxHost *gHost = 0; + OfxImageEffectSuiteV1 *gEffectSuite = 0; + OfxPropertySuiteV1 *gPropSuite = 0; + OfxInteractSuiteV1 *gInteractSuite = 0; + OfxParameterSuiteV1 *gParamSuite = 0; + OfxMemorySuiteV1 *gMemorySuite = 0; + OfxMultiThreadSuiteV1 *gThreadSuite = 0; + OfxMessageSuiteV1 *gMessageSuite = 0; + OfxMessageSuiteV2 *gMessageSuiteV2 = 0; + OfxProgressSuiteV1 *gProgressSuiteV1 = 0; + OfxProgressSuiteV2 *gProgressSuiteV2 = 0; + OfxTimeLineSuiteV1 *gTimeLineSuite = 0; + OfxParametricParameterSuiteV1 *gParametricParameterSuite = 0; +#ifdef OFX_SUPPORTS_OPENGLRENDER + OfxImageEffectOpenGLRenderSuiteV1 *gOpenGLRenderSuite = 0; +#endif + + // @brief the set of descriptors, one per context used by kOfxActionDescribeInContext, + //'eContextNone' is the one used by the kOfxActionDescribe + EffectDescriptorMap gEffectDescriptors; + }; + + /** @brief map a std::string to a context */ + ContextEnum mapToContextEnum(const std::string &s) + { + if(s == kOfxImageEffectContextGenerator) return eContextGenerator; + if(s == kOfxImageEffectContextFilter) return eContextFilter; + if(s == kOfxImageEffectContextTransition) return eContextTransition; + if(s == kOfxImageEffectContextPaint) return eContextPaint; + if(s == kOfxImageEffectContextGeneral) return eContextGeneral; + if(s == kOfxImageEffectContextRetimer) return eContextRetimer; + OFX::Log::error(true, "Unknown image effect context '%s'", s.c_str()); + throw std::invalid_argument(s); + } + + const char* mapContextEnumToStr(ContextEnum context) + { + switch (context) { + case eContextGenerator: + return kOfxImageEffectContextGenerator; + case eContextFilter: + return kOfxImageEffectContextFilter; + case eContextTransition: + return kOfxImageEffectContextTransition; + case eContextPaint: + return kOfxImageEffectContextPaint; + case eContextGeneral: + return kOfxImageEffectContextGeneral; + case eContextRetimer: + return kOfxImageEffectContextRetimer; + default: + OFX::Log::error(true, "Unknown context enum '%d'", (int)context); + throw std::invalid_argument("unknown ContextEnum"); + } + } + + const char* mapMessageTypeEnumToStr(OFX::Message::MessageTypeEnum type) + { + if(type == OFX::Message::eMessageFatal) + return kOfxMessageFatal; + else if(type == OFX::Message::eMessageError) + return kOfxMessageError; + else if(type == OFX::Message::eMessageMessage) + return kOfxMessageMessage; + else if(type == OFX::Message::eMessageWarning) + return kOfxMessageWarning; + else if(type == OFX::Message::eMessageLog) + return kOfxMessageLog; + else if(type == OFX::Message::eMessageQuestion) + return kOfxMessageQuestion; + OFX::Log::error(true, "Unknown message type enum '%d'", type); + return 0; + } + + OFX::Message::MessageReplyEnum mapToMessageReplyEnum(OfxStatus stat) + { + if(stat == kOfxStatOK) + return OFX::Message::eMessageReplyOK; + else if(stat == kOfxStatReplyYes) + return OFX::Message::eMessageReplyYes; + else if(stat == kOfxStatReplyNo) + return OFX::Message::eMessageReplyNo; + else if(stat == kOfxStatFailed) + return OFX::Message::eMessageReplyFailed; + OFX::Log::error(true, "Unknown message reply status enum '%d'", stat); + return OFX::Message::eMessageReplyFailed; + } + + /** @brief map a std::string to a context */ + InstanceChangeReason mapToInstanceChangedReason(const std::string &s) + { + if(s == kOfxChangePluginEdited) return eChangePluginEdit; + if(s == kOfxChangeUserEdited) return eChangeUserEdit; + if(s == kOfxChangeTime) return eChangeTime; + OFX::Log::error(true, "Unknown instance changed reason '%s'", s.c_str()); + throw std::invalid_argument(s); + } + + /** @brief turns a bit depth string into and enum */ + BitDepthEnum mapStrToBitDepthEnum(const std::string &str) + { + if(str == kOfxBitDepthByte) { + return eBitDepthUByte; + } + else if(str == kOfxBitDepthShort) { + return eBitDepthUShort; + } + else if(str == kOfxBitDepthHalf) { + return eBitDepthHalf; + } + else if(str == kOfxBitDepthFloat) { + return eBitDepthFloat; + } + else if(str == kOfxBitDepthNone) { + return eBitDepthNone; + } + else { + return eBitDepthCustom; + } + } + + /** @brief turns a bit depth string into and enum */ + const char* mapBitDepthEnumToStr(BitDepthEnum bitDepth) + { + switch (bitDepth) { + case eBitDepthUByte: + return kOfxBitDepthByte; + case eBitDepthUShort: + return kOfxBitDepthShort; + case eBitDepthHalf: + return kOfxBitDepthHalf; + case eBitDepthFloat: + return kOfxBitDepthFloat; + case eBitDepthNone: + return kOfxBitDepthNone; + case eBitDepthCustom: + return "OfxBitDepthCustom"; + default: + OFX::Log::error(true, "Unknown bit depth enum '%d'", (int)bitDepth); + throw std::invalid_argument("unknown BitDepthEnum"); + } + } + + /** @brief turns a pixel component string into and enum */ + PixelComponentEnum mapStrToPixelComponentEnum(const std::string &str) + { + if(str == kOfxImageComponentRGBA) { + return ePixelComponentRGBA; + } + else if(str == kOfxImageComponentRGB) { + return ePixelComponentRGB; + } + else if(str == kOfxImageComponentAlpha) { + return ePixelComponentAlpha; + } + else if(str == kOfxImageComponentNone) { + return ePixelComponentNone; + } + else { + return ePixelComponentCustom; + } + } + + /** @brief turns a pixel component string into and enum */ + const char* mapPixelComponentEnumToStr(PixelComponentEnum pixelComponent) + { + switch (pixelComponent) { + case ePixelComponentRGBA: + return kOfxImageComponentRGBA; + case ePixelComponentRGB: + return kOfxImageComponentRGB; + case ePixelComponentAlpha: + return kOfxImageComponentAlpha; + case ePixelComponentCustom: + return "OfxImageComponentCustom"; + default: + OFX::Log::error(true, "Unknown pixel component enum '%d'", (int)pixelComponent); + throw std::invalid_argument("unknown PixelComponentEnum"); + } + } + + /** @brief turns a premultiplication string into and enum */ + static PreMultiplicationEnum mapStrToPreMultiplicationEnum(const std::string &str) + { + if(str == kOfxImageOpaque) { + return eImageOpaque; + } + else if(str == kOfxImagePreMultiplied) { + return eImagePreMultiplied; + } + else if(str == kOfxImageUnPreMultiplied) { + return eImageUnPreMultiplied; + } + else { + throw std::invalid_argument(""); + } + } + + /** @brief turns a field string into and enum */ + FieldEnum mapStrToFieldEnum(const std::string &str) + { + if(str == kOfxImageFieldNone) { + return eFieldNone; + } + else if(str == kOfxImageFieldBoth) { + return eFieldBoth; + } + else if(str == kOfxImageFieldLower) { + return eFieldLower; + } + else if(str == kOfxImageFieldUpper) { + return eFieldUpper; + } + else { + throw std::invalid_argument(""); + } + } + + + //////////////////////////////////////////////////////////////////////////////// + // clip descriptor + + /** @brief hidden constructor */ + ClipDescriptor::ClipDescriptor(const std::string &name, OfxPropertySetHandle props) + : _clipName(name) + , _clipProps(props) + { + OFX::Validation::validateClipDescriptorProperties(props); + } + + /** @brief set the label properties */ + void ClipDescriptor::setLabel(const std::string &label) + { + _clipProps.propSetString(kOfxPropLabel, label); + } + + /** @brief set the label properties */ + void ClipDescriptor::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel) + { + setLabel(label); + _clipProps.propSetString(kOfxPropShortLabel, shortLabel, false); + _clipProps.propSetString(kOfxPropLongLabel, longLabel, false); + } + + /** @brief set how fielded images are extracted from the clip defaults to eFieldExtractDoubled */ + void ClipDescriptor::setFieldExtraction(FieldExtractionEnum v) + { + switch(v) + { + case eFieldExtractBoth : + _clipProps.propSetString(kOfxImageClipPropFieldExtraction, kOfxImageFieldBoth); + break; + + case eFieldExtractSingle : + _clipProps.propSetString(kOfxImageClipPropFieldExtraction, kOfxImageFieldSingle); + break; + + case eFieldExtractDoubled : + _clipProps.propSetString(kOfxImageClipPropFieldExtraction, kOfxImageFieldDoubled); + break; + } + } + + /** @brief set which components are supported, defaults to none set, this must be called at least once! */ + void ClipDescriptor::addSupportedComponent(PixelComponentEnum v) + { + int n = _clipProps.propGetDimension(kOfxImageEffectPropSupportedComponents); + switch(v) + { + case ePixelComponentNone : + _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentNone, n); + break; + + case ePixelComponentRGBA : + _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentRGBA, n); + break; + + case ePixelComponentRGB : + _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentRGB, n); + break; + + case ePixelComponentAlpha : + _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, kOfxImageComponentAlpha, n); + break; + case ePixelComponentCustom : + break; + } + } + + /** @brief set which components are supported, defaults to none set, this must be called at least once! */ + void ClipDescriptor::addSupportedComponent(const std::string &comp) + { + int n = _clipProps.propGetDimension(kOfxImageEffectPropSupportedComponents); + _clipProps.propSetString(kOfxImageEffectPropSupportedComponents, comp, n); + + } + + /** @brief say whether we are going to do random temporal access on this clip, defaults to false */ + void ClipDescriptor::setTemporalClipAccess(bool v) + { + _clipProps.propSetInt(kOfxImageEffectPropTemporalClipAccess, int(v)); + } + + /** @brief say whether if the clip is optional, defaults to false */ + void ClipDescriptor::setOptional(bool v) + { + _clipProps.propSetInt(kOfxImageClipPropOptional, int(v)); + } + + /** @brief say whether this clip supports tiling, defaults to true */ + void ClipDescriptor::setSupportsTiles(bool v) + { + _clipProps.propSetInt(kOfxImageEffectPropSupportsTiles, int(v)); + } + + /** @brief say whether this clip is a 'mask', so the host can know to replace with a roto or similar, defaults to false */ + void ClipDescriptor::setIsMask(bool v) + { + _clipProps.propSetInt(kOfxImageClipPropIsMask, int(v)); + } + + //////////////////////////////////////////////////////////////////////////////// + // image effect descriptor + + /** @brief effect descriptor ctor */ + ImageEffectDescriptor::ImageEffectDescriptor(OfxImageEffectHandle handle) + : _effectHandle(handle) + { + // fetch the property set handle of the effect + OfxPropertySetHandle props; + OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet(handle, &props); + throwSuiteStatusException(stat); + _effectProps.propSetHandle(props); + + OFX::Validation::validatePluginDescriptorProperties(props); + + // fetch the param set handle and set it in our ParamSetDescriptor base + OfxParamSetHandle paramSetHandle; + stat = OFX::Private::gEffectSuite->getParamSet(handle, ¶mSetHandle); + throwSuiteStatusException(stat); + setParamSetHandle(paramSetHandle); + } + + + /** @brief dtor */ + ImageEffectDescriptor::~ImageEffectDescriptor() + { + // delete any clip descriptors we may have constructed + std::map::iterator iter; + for(iter = _definedClips.begin(); iter != _definedClips.end(); ++iter) { + if(iter->second) { + delete iter->second; + iter->second = NULL; + } + } + } + + /** @brief, set the label properties in a plugin */ + void ImageEffectDescriptor::setLabel(const std::string &label) + { + _effectProps.propSetString(kOfxPropLabel, label); + } + + /** @brief, set the label properties in a plugin */ + void ImageEffectDescriptor::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel) + { + setLabel(label); + _effectProps.propSetString(kOfxPropShortLabel, shortLabel, false); + _effectProps.propSetString(kOfxPropLongLabel, longLabel, false); + } + + + /** @brief, set the version properties in a plugin */ + void ImageEffectDescriptor::setVersion(int major, int minor, int micro, int build, const std::string &versionLabel) + { + _effectProps.propSetInt(kOfxPropVersion, major, 0, false); // introduced in OFX 1.2 + if (minor || micro || build) { + _effectProps.propSetInt(kOfxPropVersion, minor, 1, false); // introduced in OFX 1.2 + if (micro || build) { + _effectProps.propSetInt(kOfxPropVersion, micro, 2, false); // introduced in OFX 1.2 + if (build) { + _effectProps.propSetInt(kOfxPropVersion, build, 3, false); // introduced in OFX 1.2 + } + } + } + if (!versionLabel.empty()) { + _effectProps.propSetString(kOfxPropVersionLabel, versionLabel, false); + } + } + + /** @brief Set the plugin grouping */ + void ImageEffectDescriptor::setPluginGrouping(const std::string &group) + { + _effectProps.propSetString(kOfxImageEffectPluginPropGrouping, group); + } + + /** @brief Set the plugin description, defaults to "" */ + void ImageEffectDescriptor::setPluginDescription(const std::string &description) + { + _effectProps.propSetString(kOfxPropPluginDescription, description, false); // introduced in OFX 1.2 + } + + /** @brief Add a context to those supported */ + void ImageEffectDescriptor::addSupportedContext(ContextEnum v) + { + int n = _effectProps.propGetDimension(kOfxImageEffectPropSupportedContexts); + switch (v) + { + case eContextNone : + break; + case eContextGenerator : + _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGenerator, n); + break; + case eContextFilter : + _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextFilter, n); + break; + case eContextTransition : + _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextTransition, n); + break; + case eContextPaint : + _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextPaint, n); + break; + case eContextGeneral : + _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGeneral, n); + break; + case eContextRetimer : + _effectProps.propSetString(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextRetimer, n); + break; + } + } + + void ImageEffectDescriptor::setOverlayInteractDescriptor(EffectOverlayDescriptor* desc) + { + _overlayDescriptor.reset(desc); + if(OFX::gHostDescription.supportsOverlays && desc->getMainEntry()) + _effectProps.propSetPointer(kOfxImageEffectPluginPropOverlayInteractV1, (void*)desc->getMainEntry()); + } + + /** @brief Add a pixel depth to those supported */ + void ImageEffectDescriptor::addSupportedBitDepth(BitDepthEnum v) + { + int n = _effectProps.propGetDimension(kOfxImageEffectPropSupportedPixelDepths); + switch(v) + { + case eBitDepthNone : + _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthNone , n); + break; + case eBitDepthUByte : + _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthByte , n); + break; + case eBitDepthUShort : + _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthShort , n); + break; + case eBitDepthHalf : + _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthHalf , n); + break; + case eBitDepthFloat : + _effectProps.propSetString(kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthFloat , n); + break; + case eBitDepthCustom : + break; + } + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief Add a pixel depth to those supported */ + void ImageEffectDescriptor::addSupportedOpenGLBitDepth(BitDepthEnum v) + { + int n = _effectProps.propGetDimension(kOfxOpenGLPropPixelDepth); + switch(v) + { + case eBitDepthNone : + _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthNone , n); + break; + case eBitDepthUByte : + _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthByte , n); + break; + case eBitDepthUShort : + _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthShort , n); + break; + case eBitDepthHalf : + _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthHalf , n); + break; + case eBitDepthFloat : + _effectProps.propSetString(kOfxOpenGLPropPixelDepth, kOfxBitDepthFloat , n); + break; + default: + break; + } + } +#endif + + /** @brief Is the plugin single instance only ? */ + void ImageEffectDescriptor::setSingleInstance(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPluginPropSingleInstance, int(v)); + } + + /** @brief Does the plugin expect the host to perform per frame SMP threading */ + void ImageEffectDescriptor::setHostFrameThreading(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPluginPropHostFrameThreading, int(v)); + } + + /** @brief Does the plugin support multi resolution images */ + void ImageEffectDescriptor::setSupportsMultiResolution(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPropSupportsMultiResolution, int(v)); + } + + /** @brief Does the plugin support image tiling */ + void ImageEffectDescriptor::setSupportsTiles(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPropSupportsTiles, int(v)); + } + + /** @brief Does the plugin perform temporal clip access */ + void ImageEffectDescriptor::setTemporalClipAccess(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPropTemporalClipAccess, int(v)); + } + + /** @brief Does the plugin want to have render called twice per frame in all circumanstances for fielded images ? */ + void ImageEffectDescriptor::setRenderTwiceAlways(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPluginPropFieldRenderTwiceAlways, int(v)); + } + + /** @brief Does the plugin support inputs and output clips of differing depths */ + void ImageEffectDescriptor::setSupportsMultipleClipDepths(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPropSupportsMultipleClipDepths, int(v)); + } + + /** @brief Does the plugin support inputs and output clips of pixel aspect ratios */ + void ImageEffectDescriptor::setSupportsMultipleClipPARs(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPropSupportsMultipleClipPARs, int(v)); + } + + /** @brief What kind of thread safety does the plugin have */ + void ImageEffectDescriptor::setRenderThreadSafety(RenderSafetyEnum v) + { + switch(v) + { + case eRenderUnsafe : + _effectProps.propSetString(kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderUnsafe); + break; + case eRenderInstanceSafe : + _effectProps.propSetString(kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderInstanceSafe); + break; + case eRenderFullySafe : + _effectProps.propSetString(kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderFullySafe); + break; + } + } + + /** @brief Does the plugin support OpenCL Buffers Render */ + void ImageEffectDescriptor::setSupportsOpenCLBuffersRender(bool v) + { + try { + + _effectProps.propSetString(kOfxImageEffectPropOpenCLRenderSupported, (v ? "true" : "false")); + } catch(OFX::Exception::PropertyUnknownToHost) { + OFX::Log::warning(true, "Host does not have kOfxImageEffectPropOpenCLRenderSupported property"); + } + } + + /** @brief Does the plugin support OpenCL Images Render */ + void ImageEffectDescriptor::setSupportsOpenCLImagesRender(bool v) + { + try { + + _effectProps.propSetString(kOfxImageEffectPropOpenCLSupported, (v ? "true" : "false")); + } catch(OFX::Exception::PropertyUnknownToHost) { + OFX::Log::warning(true, "Host does not have kOfxImageEffectPropOpenCLSupported property"); + } + } + + /** @brief Does the plugin support CUDA Render */ + void ImageEffectDescriptor::setSupportsCudaRender(bool v) + { + try { + + _effectProps.propSetString(kOfxImageEffectPropCudaRenderSupported, (v ? "true" : "false")); + } catch(OFX::Exception::PropertyUnknownToHost) { + OFX::Log::warning(true, "Host does not have kOfxImageEffectPropCudaRenderSupported property"); + } + } + + /** @brief Does the plugin support CUDA Stream */ + void ImageEffectDescriptor::setSupportsCudaStream(bool v) + { + try { + _effectProps.propSetString(kOfxImageEffectPropCudaStreamSupported, (v ? "true" : "false")); + } catch(OFX::Exception::PropertyUnknownToHost) { + OFX::Log::warning(true, "Host does not have kOfxImageEffectPropCudaStreamSupported property"); + } + } + + /** @brief Does the plugin support Metal Render */ + void ImageEffectDescriptor::setSupportsMetalRender(bool v) + { + try { + _effectProps.propSetString(kOfxImageEffectPropMetalRenderSupported, (v ? "true" : "false")); + } catch(OFX::Exception::PropertyUnknownToHost) { + OFX::Log::warning(true, "Host does not have kOfxImageEffectPropMetalRenderSupported property"); + } + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief Does the plugin support OpenGL accelerated rendering (but is also capable of CPU rendering) ? */ + void ImageEffectDescriptor::setSupportsOpenGLRender(bool v) { + if (gHostDescription.supportsOpenGLRender) { + _effectProps.propSetString(kOfxImageEffectPropOpenGLRenderSupported, (v ? "true" : "false")); + } + } + + /** @brief Does the plugin require OpenGL accelerated rendering ? */ + void ImageEffectDescriptor::setNeedsOpenGLRender(bool v) { + if (gHostDescription.supportsOpenGLRender) { + _effectProps.propSetString(kOfxImageEffectPropOpenGLRenderSupported, (v ? "needed" : "false")); + } + } + + void ImageEffectDescriptor::addOpenGLBitDepth(BitDepthEnum v) { + int n = _effectProps.propGetDimension(kOfxImageEffectPropSupportedPixelDepths); + std::string value = mapBitDepthEnumToStr(v); + if (!value.empty()) { + _effectProps.propSetString(kOfxOpenGLPropPixelDepth, value, n); + } + } +#endif + + /** @brief If the slave param changes the clip preferences need to be re-evaluated */ + void ImageEffectDescriptor::addClipPreferencesSlaveParam(ParamDescriptor &p) + { + int n = _effectProps.propGetDimension(kOfxImageEffectPropClipPreferencesSlaveParam); + _effectProps.propSetString(kOfxImageEffectPropClipPreferencesSlaveParam, p.getName(), n); + } + + /** @brief Create a clip, only callable from describe in context */ + ClipDescriptor *ImageEffectDescriptor::defineClip(const std::string &name) + { + // do we have the clip already + std::map::const_iterator search; + search = _definedClips.find(name); + if(search != _definedClips.end()) + return search->second; + + // no, so make it + OfxPropertySetHandle propSet; + OfxStatus stat = OFX::Private::gEffectSuite->clipDefine(_effectHandle, name.c_str(), &propSet); + (void)stat; + + ClipDescriptor *clip = new ClipDescriptor(name, propSet); + + _definedClips[name] = clip; + _clipComponentsPropNames[name] = std::string("OfxImageClipPropComponents_") + name; + _clipDepthPropNames[name] = std::string("OfxImageClipPropDepth_") + name; + _clipPARPropNames[name] = std::string("OfxImageClipPropPAR_") + name; + _clipROIPropNames[name] = std::string("OfxImageClipPropRoI_") + name; + _clipFrameRangePropNames[name] = std::string("OfxImageClipPropFrameRange_") + name; + return clip; + } + + //////////////////////////////////////////////////////////////////////////////// + // wraps up an image + ImageBase::ImageBase(OfxPropertySetHandle props) + : _imageProps(props) + { + OFX::Validation::validateImageBaseProperties(props); + + // and fetch all the properties + _rowBytes = _imageProps.propGetInt(kOfxImagePropRowBytes, /*throwOnFailure*/false); // not required for OpenCL Images + _pixelAspectRatio = _imageProps.propGetDouble(kOfxImagePropPixelAspectRatio);; + + std::string str = _imageProps.propGetString(kOfxImageEffectPropComponents); + _pixelComponents = mapStrToPixelComponentEnum(str); + + switch (_pixelComponents) { + case ePixelComponentAlpha: + _pixelComponentCount = 1; + break; + case ePixelComponentNone: + _pixelComponentCount = 0; + break; + case ePixelComponentRGB: + _pixelComponentCount = 3; + break; + case ePixelComponentRGBA: + _pixelComponentCount = 4; + break; + case ePixelComponentCustom: + default: + _pixelComponentCount = 0; + break; + } + + str = _imageProps.propGetString(kOfxImageEffectPropPixelDepth); + _pixelDepth = mapStrToBitDepthEnum(str); + + // compute bytes per pixel + _pixelBytes = _pixelComponentCount; + + switch(_pixelDepth) + { + case eBitDepthNone : _pixelBytes *= 0; break; + case eBitDepthUByte : _pixelBytes *= 1; break; + case eBitDepthUShort : _pixelBytes *= 2; break; + case eBitDepthHalf : _pixelBytes *= 2; break; + case eBitDepthFloat : _pixelBytes *= 4; break; + case eBitDepthCustom : _pixelBytes *= 0; break; + } + + str = _imageProps.propGetString(kOfxImageEffectPropPreMultiplication); + _preMultiplication = mapStrToPreMultiplicationEnum(str); + + _regionOfDefinition.x1 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 0); + _regionOfDefinition.y1 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 1); + _regionOfDefinition.x2 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 2); + _regionOfDefinition.y2 = _imageProps.propGetInt(kOfxImagePropRegionOfDefinition, 3); + + _bounds.x1 = _imageProps.propGetInt(kOfxImagePropBounds, 0); + _bounds.y1 = _imageProps.propGetInt(kOfxImagePropBounds, 1); + _bounds.x2 = _imageProps.propGetInt(kOfxImagePropBounds, 2); + _bounds.y2 = _imageProps.propGetInt(kOfxImagePropBounds, 3); + + str = _imageProps.propGetString(kOfxImagePropField); + if(str == kOfxImageFieldNone) { + _field = eFieldNone; + } + else if(str == kOfxImageFieldBoth) { + _field = eFieldBoth; + } + else if(str == kOfxImageFieldLower) { + _field = eFieldLower; + } + else if(str == kOfxImageFieldUpper) { + _field = eFieldLower; + } + else { + OFX::Log::error(true, "Unknown field state '%s' reported on an image", str.c_str()); + _field = eFieldNone; + } + + _uniqueID = _imageProps.propGetString(kOfxImagePropUniqueIdentifier); + + _renderScale.x = _imageProps.propGetDouble(kOfxImageEffectPropRenderScale, 0); + _renderScale.y = _imageProps.propGetDouble(kOfxImageEffectPropRenderScale, 1); + } + + ImageBase::~ImageBase() + { + } + + //////////////////////////////////////////////////////////////////////////////// + // wraps up an image + Image::Image(OfxPropertySetHandle props) + : ImageBase(props) + { + OFX::Validation::validateImageProperties(props); + + // and fetch all the properties + _OpenCLImage = nullptr; + _OpenCLImage = _imageProps.propGetPointer(kOfxImageEffectPropOpenCLImage, /*throwOnFailure*/false); + // should throw if it is not an image + _pixelData = _imageProps.propGetPointer(kOfxImagePropData, /*throwOnFailure*/!_OpenCLImage); + } + + Image::~Image() + { + OFX::Private::gEffectSuite->clipReleaseImage(_imageProps.propSetHandle()); + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + //////////////////////////////////////////////////////////////////////////////// + // wraps up an OpenGL texture + Texture::Texture(OfxPropertySetHandle props) + : ImageBase(props) + { + OFX::Validation::validateTextureProperties(props); + + // should throw if it is not a texture + _index = _imageProps.propGetInt(kOfxImageEffectPropOpenGLTextureIndex); + _target = _imageProps.propGetInt(kOfxImageEffectPropOpenGLTextureTarget); + } + + Texture::~Texture() + { + OfxStatus stat = OFX::Private::gOpenGLRenderSuite->clipFreeTexture(_imageProps.propSetHandle()); + if (stat != kOfxStatOK) { + throwSuiteStatusException(stat); + } + } +#endif + + /** @brief return a pixel pointer + + No attempt made to be uber efficient here. + */ + void *Image::getPixelAddress(int x, int y) + { + // are we in the image bounds + if(x < _bounds.x1 || x >= _bounds.x2 || y < _bounds.y1 || y >= _bounds.y2 || _pixelBytes == 0) + return 0; + + char *pix = ((char *) _pixelData) + (size_t)(y - _bounds.y1) * _rowBytes; + pix += (x - _bounds.x1) * _pixelBytes; + return (void *) pix; + } + + const void *Image::getPixelAddress(int x, int y) const + { + // are we in the image bounds + if(x < _bounds.x1 || x >= _bounds.x2 || y < _bounds.y1 || y >= _bounds.y2 || _pixelBytes == 0) + return 0; + + const char *pix = ((const char *) _pixelData) + (size_t)(y - _bounds.y1) * _rowBytes; + pix += (x - _bounds.x1) * _pixelBytes; + return (const void *) pix; + } + + //////////////////////////////////////////////////////////////////////////////// + // clip instance + + /** @brief hidden constructor */ + Clip::Clip(ImageEffect *effect, const std::string &name, OfxImageClipHandle handle, OfxPropertySetHandle props) + : _clipName(name) + , _clipProps(props) + , _clipHandle(handle) + , _effect(effect) + { + OFX::Validation::validateClipInstanceProperties(_clipProps); + } + + /** @brief fetch the label */ + void Clip::getLabel(std::string &label) const + { + label = _clipProps.propGetString(kOfxPropLabel); + } + + /** @brief fetch the labels */ + void Clip::getLabels(std::string &label, std::string &shortLabel, std::string &longLabel) const + { + getLabel(label); + shortLabel = _clipProps.propGetString(kOfxPropShortLabel, false); + longLabel = _clipProps.propGetString(kOfxPropLongLabel, false); + } + + /** @brief get the pixel depth */ + BitDepthEnum Clip::getPixelDepth(void) const + { + std::string str = _clipProps.propGetString(kOfxImageEffectPropPixelDepth); + BitDepthEnum e; + try { + e = mapStrToBitDepthEnum(str); + if(e == eBitDepthNone && isConnected()) { + OFX::Log::error(true, "Clip %s is connected and has no pixel depth.", _clipName.c_str()); + } + } + // gone wrong ? + catch(std::invalid_argument&) { + OFX::Log::error(true, "Unknown pixel depth property '%s' reported on clip '%s'", str.c_str(), _clipName.c_str()); + e = eBitDepthNone; + } + return e; + } + + /** @brief get the components in the image */ + PixelComponentEnum Clip::getPixelComponents(void) const + { + std::string str = _clipProps.propGetString(kOfxImageEffectPropComponents); + PixelComponentEnum e; + try { + e = mapStrToPixelComponentEnum(str); + if(e == ePixelComponentNone && isConnected()) { + OFX::Log::error(true, "Clip %s is connected and has no pixel component type!", _clipName.c_str()); + } + } + // gone wrong ? + catch(std::invalid_argument&) { + OFX::Log::error(true, "Unknown pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str()); + e = ePixelComponentNone; + } + return e; + } + + /** @brief get the number of components in the image */ + int Clip::getPixelComponentCount(void) const + { + std::string str = _clipProps.propGetString(kOfxImageEffectPropComponents); + PixelComponentEnum e; + try { + e = mapStrToPixelComponentEnum(str); + if(e == ePixelComponentNone && isConnected()) { + OFX::Log::error(true, "Clip %s is connected and has no pixel component type!", _clipName.c_str()); + } + } + // gone wrong ? + catch(std::invalid_argument&) { + OFX::Log::error(true, "Unknown pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str()); + e = ePixelComponentNone; + } + + switch (e) { + case ePixelComponentAlpha: + return 1; + case ePixelComponentNone: + return 0; + case ePixelComponentRGB: + return 3; + case ePixelComponentRGBA: + return 4; + case ePixelComponentCustom: + default: + return 0; + } + } + + /** @brief what is the actual pixel depth of the clip */ + BitDepthEnum Clip::getUnmappedPixelDepth(void) const + { + std::string str = _clipProps.propGetString(kOfxImageClipPropUnmappedPixelDepth); + BitDepthEnum e; + try { + e = mapStrToBitDepthEnum(str); + if(e == eBitDepthNone && !isConnected()) { + OFX::Log::error(true, "Clip %s is connected and has no unmapped pixel depth.", _clipName.c_str()); + } + } + // gone wrong ? + catch(std::invalid_argument&) { + OFX::Log::error(true, "Unknown unmapped pixel depth property '%s' reported on clip '%s'", str.c_str(), _clipName.c_str()); + e = eBitDepthNone; + } + return e; + } + + /** @brief what is the component type of the clip */ + PixelComponentEnum Clip::getUnmappedPixelComponents(void) const + { + std::string str = _clipProps.propGetString(kOfxImageClipPropUnmappedComponents); + PixelComponentEnum e; + try { + e = mapStrToPixelComponentEnum(str); + if(e == ePixelComponentNone && !isConnected()) { + OFX::Log::error(true, "Clip %s is connected and has no unmapped pixel component type!", _clipName.c_str()); + } + } + // gone wrong ? + catch(std::invalid_argument&) { + OFX::Log::error(true, "Unknown unmapped pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str()); + e = ePixelComponentNone; + } + return e; + } + + /** @brief get the components in the image */ + PreMultiplicationEnum Clip::getPreMultiplication(void) const + { + std::string str = _clipProps.propGetString(kOfxImageEffectPropPreMultiplication); + PreMultiplicationEnum e; + try { + e = mapStrToPreMultiplicationEnum(str); + } + // gone wrong ? + catch(std::invalid_argument&) { + OFX::Log::error(true, "Unknown premultiplication type '%s' reported on clip %s!", str.c_str(), _clipName.c_str()); + e = eImageOpaque; + } + return e; + } + + /** @brief which spatial field comes first temporally */ + FieldEnum Clip::getFieldOrder(void) const + { + std::string str = _clipProps.propGetString(kOfxImageClipPropFieldOrder); + FieldEnum e; + try { + e = mapStrToFieldEnum(str); + OFX::Log::error(e != eFieldNone && e != eFieldLower && e != eFieldUpper, + "Field order '%s' reported on a clip %s is invalid, it must be none, lower or upper.", str.c_str(), _clipName.c_str()); + } + // gone wrong ? + catch(std::invalid_argument&) { + OFX::Log::error(true, "Unknown field order '%s' reported on a clip %s.", str.c_str(), _clipName.c_str()); + e = eFieldNone; + } + return e; + } + + /** @brief is the clip connected */ + bool Clip::isConnected(void) const + { + return _clipProps.propGetInt(kOfxImageClipPropConnected) != 0; + } + + /** @brief can the clip be continuously sampled */ + bool Clip::hasContinuousSamples(void) const + { + return _clipProps.propGetInt(kOfxImageClipPropContinuousSamples) != 0; + } + + /** @brief get the scale factor that has been applied to this clip */ + double Clip::getPixelAspectRatio(void) const + { + try { + return _clipProps.propGetDouble(kOfxImagePropPixelAspectRatio); + } catch(...) { + return 1.0; // This error could happen in Eyeon Fusion. + } + } + + /** @brief get the frame rate, in frames per second on this clip, after any clip preferences have been applied */ + double Clip::getFrameRate(void) const + { + return _clipProps.propGetDouble(kOfxImageEffectPropFrameRate); + } + + /** @brief return the range of frames over which this clip has images, after any clip preferences have been applied */ + OfxRangeD Clip::getFrameRange(void) const + { + OfxRangeD v; + v.min = _clipProps.propGetDouble(kOfxImageEffectPropFrameRange, 0); + v.max = _clipProps.propGetDouble(kOfxImageEffectPropFrameRange, 1); + return v; + } + + /** @brief get the frame rate, in frames per second on this clip, before any clip preferences have been applied */ + double Clip::getUnmappedFrameRate(void) const + { + return _clipProps.propGetDouble(kOfxImageEffectPropUnmappedFrameRate); + } + + /** @brief return the range of frames over which this clip has images, before any clip preferences have been applied */ + OfxRangeD Clip::getUnmappedFrameRange(void) const + { + OfxRangeD v; + v.min = _clipProps.propGetDouble(kOfxImageEffectPropUnmappedFrameRange, 0); + v.max = _clipProps.propGetDouble(kOfxImageEffectPropUnmappedFrameRange, 1); + return v; + } + + /** @brief get the RoD for this clip in the cannonical coordinate system */ + OfxRectD Clip::getRegionOfDefinition(double t) + { + OfxRectD bounds; + OfxStatus stat = OFX::Private::gEffectSuite->clipGetRegionOfDefinition(_clipHandle, t, &bounds); + if(stat == kOfxStatFailed) { + bounds.x1 = bounds.x2 = bounds.y1 = bounds.y2 = 0; + } + throwSuiteStatusException(stat); + return bounds; + } + + /** @brief fetch an image */ + Image *Clip::fetchImage(double t) + { + OfxPropertySetHandle imageHandle; + OfxStatus stat = OFX::Private::gEffectSuite->clipGetImage(_clipHandle, t, NULL, &imageHandle); + if(stat == kOfxStatFailed) { + return NULL; // not an error, fetched images out of range/region, assume black and transparent + } + else + throwSuiteStatusException(stat); + + return new Image(imageHandle); + } + + /** @brief fetch an image, with a specific region in cannonical coordinates */ + Image *Clip::fetchImage(double t, const OfxRectD &bounds) + { + OfxPropertySetHandle imageHandle; + OfxStatus stat = OFX::Private::gEffectSuite->clipGetImage(_clipHandle, t, &bounds, &imageHandle); + if(stat == kOfxStatFailed) { + return NULL; // not an error, fetched images out of range/region, assume black and transparent + } + else + throwSuiteStatusException(stat); + + return new Image(imageHandle); + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + Texture *Clip::loadTexture(double t, BitDepthEnum format, const OfxRectD *region) + { + if (!gHostDescription.supportsOpenGLRender) { + throwHostMissingSuiteException("loadTexture"); + } + OfxPropertySetHandle hTex; + OfxStatus stat = Private::gOpenGLRenderSuite->clipLoadTexture(_clipHandle, t, format == eBitDepthNone ? NULL : mapBitDepthEnumToStr(format), region, &hTex); + if (stat != kOfxStatOK) { + throwSuiteStatusException(stat); + } + return new Texture(hTex); + } +#endif + //////////////////////////////////////////////////////////////////////////////// + /// image effect + + /** @brief ctor */ + ImageEffect::ImageEffect(OfxImageEffectHandle handle) + : _effectHandle(handle) + , _effectProps(0) + , _context(eContextNone) + , _progressStartSuccess(false) + { + // get the property handle + _effectProps = OFX::Private::fetchEffectProps(handle); + + // Set this as the instance data pointer on the effect handle + _effectProps.propSetPointer(kOfxPropInstanceData, this); + + // validate the plugin instance + OFX::Validation::validatePluginInstanceProperties(_effectProps); + + // fetch the context + std::string ctxt = _effectProps.propGetString(kOfxImageEffectPropContext); + _context = mapToContextEnum(ctxt); + + // the param set daddy-oh + OfxParamSetHandle paramSet; + OfxStatus stat = OFX::Private::gEffectSuite->getParamSet(handle, ¶mSet); + throwSuiteStatusException(stat); + setParamSetHandle(paramSet); + + } + + /** @brief dtor */ + ImageEffect::~ImageEffect() + { + // clobber the instance data property on the effect handle + _effectProps.propSetPointer(kOfxPropInstanceData, 0); + + // delete any clip instances we may have constructed + std::map::iterator iter; + for(iter = _fetchedClips.begin(); iter != _fetchedClips.end(); ++iter) { + if(iter->second) { + delete iter->second; + iter->second = NULL; + } + } + } + + /** @brief the context this effect was instantiate in */ + ContextEnum ImageEffect::getContext(void) const + { + return _context; + } + + /** @brief size of the project */ + OfxPointD ImageEffect::getProjectSize(void) const + { + OfxPointD v; + v.x = _effectProps.propGetDouble(kOfxImageEffectPropProjectSize, 0); + v.y = _effectProps.propGetDouble(kOfxImageEffectPropProjectSize, 1); + return v; + } + + /** @brief origin of the project */ + OfxPointD ImageEffect::getProjectOffset(void) const + { + OfxPointD v; + v.x = _effectProps.propGetDouble(kOfxImageEffectPropProjectOffset, 0); + v.y = _effectProps.propGetDouble(kOfxImageEffectPropProjectOffset, 1); + return v; + } + + /** @brief extent of the project */ + OfxPointD ImageEffect::getProjectExtent(void) const + { + OfxPointD v; + v.x = _effectProps.propGetDouble(kOfxImageEffectPropProjectExtent, 0); + v.y = _effectProps.propGetDouble(kOfxImageEffectPropProjectExtent, 1); + return v; + } + + /** @brief pixel aspect ratio of the project */ + double ImageEffect::getProjectPixelAspectRatio(void) const + { + return _effectProps.propGetDouble(kOfxImageEffectPropProjectPixelAspectRatio, 0); + } + + /** @brief how long does the effect last */ + double ImageEffect::getEffectDuration(void) const + { + return _effectProps.propGetDouble(kOfxImageEffectInstancePropEffectDuration, 0); + } + + /** @brief the frame rate of the project */ + double ImageEffect::getFrameRate(void) const + { + return _effectProps.propGetDouble(kOfxImageEffectPropFrameRate, 0); + } + + /** @brief is the instance currently being interacted with */ + bool ImageEffect::isInteractive(void) const + { + return _effectProps.propGetInt(kOfxPropIsInteractive) != 0; + } + + /** @brief set the instance to be sequentially renderred, this should have been part of clip preferences! */ + void ImageEffect::setSequentialRender(bool v) + { + _effectProps.propSetInt(kOfxImageEffectInstancePropSequentialRender, int(v)); + } + + /** @brief Have we informed the host we want to be seqentially renderred ? */ + bool ImageEffect::getSequentialRender(void) const + { + return _effectProps.propGetInt(kOfxImageEffectInstancePropSequentialRender) != 0; + } + + /** @brief Does the plugin support image tiling ? Can only be called from changedParam or changedClip. */ + void ImageEffect::setSupportsTiles(bool v) + { + _effectProps.propSetInt(kOfxImageEffectPropSupportsTiles, int(v), false); // read/write from OFX 1.4 + } + + /** @brief Have we informed the host we support image tiling ? */ + bool ImageEffect::getSupportsTiles(void) const + { + return _effectProps.propGetInt(kOfxImageEffectPropSupportsTiles) != 0; + } + + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief Does the plugin support OpenGL accelerated rendering (but is also capable of CPU rendering) ? Can only be called from changedParam or changedClip. */ + void ImageEffect::setSupportsOpenGLRender(bool v) { + if (gHostDescription.supportsOpenGLRender) { + _effectProps.propSetString(kOfxImageEffectPropOpenGLRenderSupported, (v ? "true" : "false"), false); // read/write from OFX 1.4 + } + } + + /** @brief Does the plugin require OpenGL accelerated rendering ? Can only be called from changedParam or changedClip. */ + void ImageEffect::setNeedsOpenGLRender(bool v) { + if (gHostDescription.supportsOpenGLRender) { + _effectProps.propSetString(kOfxImageEffectPropOpenGLRenderSupported, (v ? "needed" : "false"), false); // read/write from OFX 1.4 + } + } +#endif + + /** @brief notify host that the internal data structures need syncing back to parameters for persistance and so on. This is reset by the host after calling SyncPrivateData. */ + void ImageEffect::setParamSetNeedsSyncing() + { + _effectProps.propSetInt(kOfxPropParamSetNeedsSyncing, 1, false); // introduced in OFX 1.2 + } + + OFX::Message::MessageReplyEnum ImageEffect::sendMessage(OFX::Message::MessageTypeEnum type, const std::string& id, const std::string& msg) + { + if(!OFX::Private::gMessageSuite){ throwHostMissingSuiteException("message"); } + if(!OFX::Private::gMessageSuite->message){ throwHostMissingSuiteException("message"); } + OfxStatus stat = OFX::Private::gMessageSuite->message(_effectHandle, mapMessageTypeEnumToStr(type), id.c_str(), msg.c_str()); + return mapToMessageReplyEnum(stat); + } + + OFX::Message::MessageReplyEnum ImageEffect::setPersistentMessage(OFX::Message::MessageTypeEnum type, const std::string& id, const std::string& msg) + { + if(!OFX::Private::gMessageSuiteV2){ throwHostMissingSuiteException("setPersistentMessage"); } + if(!OFX::Private::gMessageSuiteV2->setPersistentMessage){ throwHostMissingSuiteException("setPersistentMessage"); } + OfxStatus stat = OFX::Private::gMessageSuiteV2->setPersistentMessage(_effectHandle, mapMessageTypeEnumToStr(type), id.c_str(), msg.c_str()); + return mapToMessageReplyEnum(stat); + } + + OFX::Message::MessageReplyEnum ImageEffect::clearPersistentMessage() + { + if(!OFX::Private::gMessageSuiteV2){ throwHostMissingSuiteException("clearPersistentMessage"); } + if(!OFX::Private::gMessageSuiteV2->clearPersistentMessage){ throwHostMissingSuiteException("clearPersistentMessage"); } + OfxStatus stat = OFX::Private::gMessageSuiteV2->clearPersistentMessage(_effectHandle); + return mapToMessageReplyEnum(stat); + } + + /** @brief Fetch the named clip from this instance */ + Clip *ImageEffect::fetchClip(const std::string &name) + { + // do we have the clip already + std::map::const_iterator search; + search = _fetchedClips.find(name); + if(search != _fetchedClips.end()) + return search->second; + + // fetch the property set handle of the effect + OfxImageClipHandle clipHandle = 0; + OfxPropertySetHandle propHandle = 0; + OfxStatus stat = OFX::Private::gEffectSuite->clipGetHandle(_effectHandle, name.c_str(), &clipHandle, &propHandle); + throwSuiteStatusException(stat); + + // and make one + Clip *newClip = new Clip(this, name, clipHandle, propHandle); + + // add it in + _fetchedClips[name] = newClip; + + // return it + return newClip; + } + + /** @brief does the host want us to abort rendering? */ + bool ImageEffect::abort(void) const + { + return OFX::Private::gEffectSuite->abort(_effectHandle) != 0; + } + + /** @brief adds a new interact to the set of interacts open on this effect */ + void ImageEffect::addOverlayInteract(OverlayInteract *interact) + { + // do we have it already ? + std::list::iterator i; + i = std::find(_overlayInteracts.begin(), _overlayInteracts.end(), interact); + + // we don't, put it in there + if(i == _overlayInteracts.end()) { + // we have a new one to add in here + _overlayInteracts.push_back(interact); + } + } + + /** @brief removes an interact to the set of interacts open on this effect */ + void ImageEffect::removeOverlayInteract(OverlayInteract *interact) + { + // find it + std::list::iterator i; + i = std::find(_overlayInteracts.begin(), _overlayInteracts.end(), interact); + + // and remove it + if(i != _overlayInteracts.end()) { + _overlayInteracts.erase(i); + } + } + + /** @brief force all overlays on this interact to be redrawn */ + void ImageEffect::redrawOverlays(void) + { + // find it + std::list::iterator i; + for(i = _overlayInteracts.begin(); i != _overlayInteracts.end(); ++i) { + (*i)->requestRedraw(); + } + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + bool ImageEffect::flushOpenGLResources(void) + { + if (!gHostDescription.supportsOpenGLRender) { + return false; + } + return Private::gOpenGLRenderSuite->flushResources() == kOfxStatOK; + } +#endif + + //////////////////////////////////////////////////////////////////////////////// + // below are the default members for the base image effect + + + /** @brief client is identity function, returns the clip and time for the identity function + */ + bool ImageEffect::isIdentity(const IsIdentityArguments &/*args*/, Clip * &/*identityClip*/, double &/*identityTime*/) + { + return false; // by default, we are not an identity operation + } + + /** @brief The get RoD action */ + bool ImageEffect::getRegionOfDefinition(const RegionOfDefinitionArguments &/*args*/, OfxRectD &/*rod*/) + { + return false; // by default, we are not setting the RoD + } + + /** @brief the get RoI action */ + void ImageEffect::getRegionsOfInterest(const RegionsOfInterestArguments &/*args*/, RegionOfInterestSetter &/*rois*/) + { + // fa niente + } + + /** @brief the get frames needed action */ + void ImageEffect::getFramesNeeded(const FramesNeededArguments &/*args*/, FramesNeededSetter &/*frames*/) + { + // fa niente + } + + /** @brief client begin sequence render function */ + void ImageEffect::beginSequenceRender(const BeginSequenceRenderArguments &/*args*/) + { + // fa niente + } + + /** @brief client end sequence render function, this is one of the few that must be set */ + void ImageEffect::endSequenceRender(const EndSequenceRenderArguments &/*args*/) + { + // fa niente + } + + /** @brief The purge caches action, a request for an instance to free up as much memory as possible in low memory situations */ + void ImageEffect::purgeCaches(void) + { + // fa niente + } + + /** @brief The sync private data action, called when the effect needs to sync any private data to persistant parameters */ + void ImageEffect::syncPrivateData(void) + { + // fa niente + } + + /** @brief get the clip preferences */ + void ImageEffect::getClipPreferences(ClipPreferencesSetter &/*clipPreferences*/) + { + // fa niente + } + + /** @brief the effect is about to be actively edited by a user, called when the first user interface is opened on an instance */ + void ImageEffect::beginEdit(void) + { + // fa niente + } + + /** @brief the effect is no longer being edited by a user, called when the last user interface is closed on an instance */ + void ImageEffect::endEdit(void) + { + // fa niente + } + + /** @brief the effect is about to have some values changed */ + void ImageEffect::beginChanged(InstanceChangeReason /*reason*/) + { + } + + /** @brief called when a param has just had its value changed */ + void ImageEffect::changedParam(const InstanceChangedArgs &/*args*/, const std::string &/*paramName*/) + { + } + + /** @brief called when a clip has just been changed in some way (a rewire maybe) */ + void ImageEffect::changedClip(const InstanceChangedArgs &/*args*/, const std::string &/*clipName*/) + { + } + + /** @brief the effect has just had some values changed */ + void ImageEffect::endChanged(InstanceChangeReason /*reason*/) + { + } + + /** @brief get the time domain */ + bool ImageEffect::getTimeDomain(OfxRangeD &/*range*/) + { + // by default, do the default + return false; + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief OpenGL context attached */ + void ImageEffect::contextAttached(void) + { + // fa niente + } + + /** @brief OpenGL context detached */ + void ImageEffect::contextDetached(void) + { + // fa niente + } +#endif + + /** @brief called when a custom param needs to be interpolated */ + std::string ImageEffect::interpolateCustomParam(const InterpolateCustomArgs &args, const std::string &/*paramName*/) + { + return args.value1; + } + + /// Start doing progress. + void ImageEffect::progressStart(const std::string &message, const std::string &messageid) + { + if(OFX::Private::gProgressSuiteV2) { + OfxStatus stat = OFX::Private::gProgressSuiteV2->progressStart((void *) _effectHandle, message.c_str(), messageid.c_str()); + _progressStartSuccess = ( stat == kOfxStatOK ); + } else if(OFX::Private::gProgressSuiteV1) { + OfxStatus stat = OFX::Private::gProgressSuiteV1->progressStart((void *) _effectHandle, message.c_str()); + _progressStartSuccess = ( stat == kOfxStatOK ); + } + + } + + /// finish yer progress + void ImageEffect::progressEnd() + { + if(_progressStartSuccess) { + if(OFX::Private::gProgressSuiteV2) { + OFX::Private::gProgressSuiteV2->progressEnd((void *) _effectHandle); + } else if(OFX::Private::gProgressSuiteV1) { + OFX::Private::gProgressSuiteV1->progressEnd((void *) _effectHandle); + } + } + } + + /// set the progress to some level of completion, returns + /// false if you should abandon processing, true to continue + bool ImageEffect::progressUpdate(double t) + { + if(_progressStartSuccess) { + if(OFX::Private::gProgressSuiteV2) { + OfxStatus stat = OFX::Private::gProgressSuiteV2->progressUpdate((void *) _effectHandle, t); + if(stat == kOfxStatReplyNo) + return false; + } else if(OFX::Private::gProgressSuiteV1) { + OfxStatus stat = OFX::Private::gProgressSuiteV1->progressUpdate((void *) _effectHandle, t); + if(stat == kOfxStatReplyNo) + return false; + } + } + return true; + } + + /// get the current time on the timeline. This is not necessarily the same + /// time as being passed to an action (eg render) + double ImageEffect::timeLineGetTime() + { + if(OFX::Private::gTimeLineSuite) { + double time; + if(OFX::Private::gTimeLineSuite->getTime((void *) _effectHandle, &time) == kOfxStatOK) + return time; + } + return 0; + } + + /// set the timeline to a specific time + void ImageEffect::timeLineGotoTime(double t) + { + if(OFX::Private::gTimeLineSuite) { + OFX::Private::gTimeLineSuite->gotoTime((void *) _effectHandle, t); + } + } + + /// get the first and last times available on the effect's timeline + void ImageEffect:: timeLineGetBounds(double &t1, double &t2) + { + if(OFX::Private::gTimeLineSuite) { + OFX::Private::gTimeLineSuite->getTimeBounds((void *) _effectHandle, &t1, &t2); + return; + } + t1 = t2 = 0; + } + + //////////////////////////////////////////////////////////////////////////////// + // Class used to set the clip preferences of the effect. */ + + const std::string& ClipPreferencesSetter::extractValueForName(const StringStringMap& m, const std::string& name) + { + StringStringMap::const_iterator it = m.find(name); + if(it==m.end()) + throw(Exception::PropertyUnknownToHost(name.c_str())); + return it->second; + } + + /** @brief, force the host to set a clip's mapped component type to be \em comps. */ + void ClipPreferencesSetter::setClipComponents(Clip &clip, PixelComponentEnum comps) + { + doneSomething_ = true; + const std::string& propName = extractValueForName(clipComponentPropNames_, clip.name()); + + switch(comps) + { + case ePixelComponentNone : + outArgs_.propSetString(propName.c_str(), kOfxImageComponentNone); + break; + case ePixelComponentRGBA : + outArgs_.propSetString(propName.c_str(), kOfxImageComponentRGBA); + break; + case ePixelComponentRGB : + outArgs_.propSetString(propName.c_str(), kOfxImageComponentRGB); + break; + case ePixelComponentAlpha : + outArgs_.propSetString(propName.c_str(), kOfxImageComponentAlpha); + break; + case ePixelComponentCustom : + break; + } + } + + /** @brief, force the host to set a clip's mapped bit depth be \em bitDepth */ + void ClipPreferencesSetter::setClipBitDepth(Clip &clip, BitDepthEnum bitDepth) + { + doneSomething_ = true; + const std::string& propName = extractValueForName(clipDepthPropNames_, clip.name()); + + switch(bitDepth) + { + case eBitDepthNone : + outArgs_.propSetString(propName.c_str(), kOfxBitDepthNone); + break; + case eBitDepthUByte : + outArgs_.propSetString(propName.c_str(), kOfxBitDepthByte); + break; + case eBitDepthUShort : + outArgs_.propSetString(propName.c_str(), kOfxBitDepthShort); + break; + case eBitDepthHalf : + outArgs_.propSetString(propName.c_str(), kOfxBitDepthHalf); + break; + case eBitDepthFloat : + outArgs_.propSetString(propName.c_str(), kOfxBitDepthFloat); + break; + case eBitDepthCustom : + break; + } + } + + /** @brief, force the host to set a clip's mapped Pixel Aspect Ratio to be \em PAR */ + void ClipPreferencesSetter::setPixelAspectRatio(Clip &clip, double PAR) + { + doneSomething_ = true; + const std::string& propName = extractValueForName(clipPARPropNames_, clip.name()); + outArgs_.propSetDouble(propName.c_str(), PAR); + } + + /** @brief Allows an effect to change the output frame rate */ + void ClipPreferencesSetter::setOutputFrameRate(double v) + { + doneSomething_ = true; + outArgs_.propSetDouble(kOfxImageEffectPropFrameRate, v); + } + + /** @brief Set the premultiplication state of the output clip. */ + void ClipPreferencesSetter::setOutputPremultiplication(PreMultiplicationEnum v) + { + doneSomething_ = true; + switch(v) + { + case eImageOpaque : + outArgs_.propSetString(kOfxImageEffectPropPreMultiplication, kOfxImageOpaque); + break; + case eImagePreMultiplied: + outArgs_.propSetString(kOfxImageEffectPropPreMultiplication, kOfxImagePreMultiplied); + break; + case eImageUnPreMultiplied: + outArgs_.propSetString(kOfxImageEffectPropPreMultiplication, kOfxImageUnPreMultiplied); + break; + } + } + + /** @brief Set whether the effect can be continously sampled. */ + void ClipPreferencesSetter::setOutputHasContinousSamples(bool v) + { + doneSomething_ = true; + outArgs_.propSetInt(kOfxImageClipPropContinuousSamples, int(v)); + } + + /** @brief Sets whether the effect will produce different images in all frames, even if the no params or input images are varying (eg: a noise generator). */ + void ClipPreferencesSetter::setOutputFrameVarying(bool v) + { + doneSomething_ = true; + outArgs_.propSetInt(kOfxImageEffectFrameVarying, int(v)); + } + + + void ClipPreferencesSetter::setOutputFielding(FieldEnum v) + { + doneSomething_ = true; + switch(v) + { + case eFieldNone : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldNone, 0, false); break; + case eFieldLower : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldLower, 0, false); break; + case eFieldUpper : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldUpper, 0, false); break; + case eFieldBoth : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldBoth, 0, false); break; + case eFieldSingle : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldSingle, 0, false); break; + case eFieldDoubled : outArgs_.propSetString(kOfxImageClipPropFieldOrder, kOfxImageFieldDoubled, 0, false); break; + } + } + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Class that skins image memory allocation */ + + /** @brief ctor */ + ImageMemory::ImageMemory(size_t nBytes, ImageEffect *associatedEffect) + : _handle(0) + { + OfxImageEffectHandle effectHandle = 0; + if(associatedEffect != 0) { + effectHandle = associatedEffect->_effectHandle; + } + + OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryAlloc(effectHandle, nBytes, &_handle); + if(stat == kOfxStatErrMemory) + throw std::bad_alloc(); + throwSuiteStatusException(stat); + } + + /** @brief dtor */ + ImageMemory::~ImageMemory() + { + OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryFree(_handle); + // ignore status code for exception purposes + (void)stat; + } + + /** @brief lock the memory and return a pointer to it */ + void *ImageMemory::lock(void) + { + void *ptr; + OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryLock(_handle, &ptr); + if(stat == kOfxStatErrMemory) + throw std::bad_alloc(); + throwSuiteStatusException(stat); + return ptr; + } + + /** @brief unlock the memory */ + void ImageMemory::unlock(void) + { + OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryUnlock(_handle); + (void)stat; + } + + + + /** @brief OFX::Private namespace, for things private to the support library code here generally calls image effect class members */ + namespace Private { + + /** @brief Creates the global host description and sets its properties */ + static + void + fetchHostDescription(OfxHost *host) + { + OFX::Log::error(OFX::gHostDescriptionHasInit, "Tried to create host description when we already have one."); + if(!OFX::gHostDescriptionHasInit) { + OFX::gHostDescriptionHasInit = true; + // wrap the property handle up with a property set + PropertySet hostProps(host->host); + + // and get some properties + gHostDescription.APIVersionMajor = hostProps.propGetInt(kOfxPropAPIVersion, 0, false); // OFX 1.2 + if (gHostDescription.APIVersionMajor == 0) { + // assume OFX 1.0 + gHostDescription.APIVersionMajor = 1; + } + gHostDescription.APIVersionMinor = hostProps.propGetInt(kOfxPropAPIVersion, 1, false); // OFX 1.2 + gHostDescription.hostName = hostProps.propGetString(kOfxPropName); + gHostDescription.hostLabel = hostProps.propGetString(kOfxPropLabel); + gHostDescription.versionMajor = hostProps.propGetInt(kOfxPropVersion, 0, false); // OFX 1.2 + gHostDescription.versionMinor = hostProps.propGetInt(kOfxPropVersion, 1, false); // OFX 1.2 + gHostDescription.versionMicro = hostProps.propGetInt(kOfxPropVersion, 2, false); // OFX 1.2 + gHostDescription.versionLabel = hostProps.propGetString(kOfxPropVersionLabel, false); // OFX 1.2 + gHostDescription.hostIsBackground = hostProps.propGetInt(kOfxImageEffectHostPropIsBackground) != 0; + gHostDescription.supportsOverlays = hostProps.propGetInt(kOfxImageEffectPropSupportsOverlays) != 0; + gHostDescription.supportsMultiResolution = hostProps.propGetInt(kOfxImageEffectPropSupportsMultiResolution) != 0; + gHostDescription.supportsTiles = hostProps.propGetInt(kOfxImageEffectPropSupportsTiles) != 0; + gHostDescription.temporalClipAccess = hostProps.propGetInt(kOfxImageEffectPropTemporalClipAccess) != 0; + gHostDescription.supportsMultipleClipDepths = hostProps.propGetInt(kOfxImageEffectPropSupportsMultipleClipDepths) != 0; + gHostDescription.supportsMultipleClipPARs = hostProps.propGetInt(kOfxImageEffectPropSupportsMultipleClipPARs) != 0; + gHostDescription.supportsSetableFrameRate = hostProps.propGetInt(kOfxImageEffectPropSetableFrameRate) != 0; + gHostDescription.supportsSetableFielding = hostProps.propGetInt(kOfxImageEffectPropSetableFielding) != 0; + gHostDescription.sequentialRender = hostProps.propGetInt(kOfxImageEffectInstancePropSequentialRender, false); // appeared in OFX 1.2 + gHostDescription.supportsStringAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsStringAnimation) != 0; + gHostDescription.supportsCustomInteract = hostProps.propGetInt(kOfxParamHostPropSupportsCustomInteract) != 0; + gHostDescription.supportsChoiceAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsChoiceAnimation) != 0; + // As of 1.5 + gHostDescription.supportsStrChoice = hostProps.propGetInt(kOfxParamHostPropSupportsStrChoice, false) != 0; + // As of 1.5 + gHostDescription.supportsStrChoiceAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsStrChoiceAnimation, false) != 0; + gHostDescription.supportsBooleanAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsBooleanAnimation) != 0; + gHostDescription.supportsCustomAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsCustomAnimation) != 0; + gHostDescription.osHandle = hostProps.propGetPointer(kOfxPropHostOSHandle, false); + gHostDescription.supportsParametricParameter = gParametricParameterSuite != 0; + gHostDescription.supportsParametricAnimation = hostProps.propGetInt(kOfxParamHostPropSupportsParametricAnimation, false) != 0; + gHostDescription.supportsOpenCLRender = hostProps.propGetString(kOfxImageEffectPropOpenCLRenderSupported, 0, false) == "true"; + gHostDescription.supportsCudaRender = hostProps.propGetString(kOfxImageEffectPropCudaRenderSupported, 0, false) == "true"; + gHostDescription.supportsCudaStream = hostProps.propGetString(kOfxImageEffectPropCudaStreamSupported, 0, false) == "true"; + gHostDescription.supportsMetalRender = hostProps.propGetString(kOfxImageEffectPropMetalRenderSupported, 0, false) == "true"; + gHostDescription.supportsRenderQualityDraft = hostProps.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0; // appeared in OFX 1.4 + { + std::string originStr = hostProps.propGetString(kOfxImageEffectHostPropNativeOrigin, false); // appeared in OFX 1.4 + if (originStr.empty()) { + // from http://openeffects.org/standard_changes/host-origin-hints : + // "All this hint does is tell plugin that the host world is different + // than OFX. Historically the first two hosts that exhibited this issue + // could be Fusion (upper left is 0,0 natively) and Toxic (Center is 0,0)." + if (gHostDescription.hostName == "com.eyeonline.Fusion" || + ends_with(gHostDescription.hostName, "Fusion")) { + // if host is Fusion, set to TopLeft + gHostDescription.nativeOrigin = eNativeOriginTopLeft; + } else if (starts_with(gHostDescription.hostName, "Autodesk Toxik") || + ends_with(gHostDescription.hostName, "Toxik")) { + // if host is Toxic, set to Center + gHostDescription.nativeOrigin = eNativeOriginCenter; + } else { + gHostDescription.nativeOrigin = eNativeOriginBottomLeft; + } + } else if (originStr == kOfxHostNativeOriginBottomLeft) { + gHostDescription.nativeOrigin = eNativeOriginBottomLeft; + } else if (originStr == kOfxHostNativeOriginTopLeft) { + gHostDescription.nativeOrigin = eNativeOriginTopLeft; + } else if (originStr == kOfxHostNativeOriginCenter) { + gHostDescription.nativeOrigin = eNativeOriginCenter; + } + } +#ifdef OFX_SUPPORTS_OPENGLRENDER + gHostDescription.supportsOpenGLRender = gOpenGLRenderSuite != 0 && hostProps.propGetString(kOfxImageEffectPropOpenGLRenderSupported, 0, false) == "true"; +#endif + gHostDescription.maxParameters = hostProps.propGetInt(kOfxParamHostPropMaxParameters); + gHostDescription.maxPages = hostProps.propGetInt(kOfxParamHostPropMaxPages); + gHostDescription.pageRowCount = hostProps.propGetInt(kOfxParamHostPropPageRowColumnCount, 0); + gHostDescription.pageColumnCount = hostProps.propGetInt(kOfxParamHostPropPageRowColumnCount, 1); + + int numComponents = hostProps.propGetDimension(kOfxImageEffectPropSupportedComponents); + for(int i=0; igetPropertySet(handle, &propHandle); + throwSuiteStatusException(stat); + return OFX::PropertySet(propHandle); + } + + /** @brief Keeps count of how many times load/unload have been called */ + int gLoadCount = 0; + + /** @brief Library side load action, this fetches all the suite pointers */ + void loadAction(void) + { + gLoadCount++; + + //OfxStatus status = kOfxStatOK; + + // fetch the suites + OFX::Log::error(gHost == 0, "Host pointer has not been set."); + if(!gHost) throw OFX::Exception::Suite(kOfxStatErrBadHandle); + + if(gLoadCount == 1) { + gEffectSuite = (OfxImageEffectSuiteV1 *) fetchSuite(kOfxImageEffectSuite, 1); + gPropSuite = (OfxPropertySuiteV1 *) fetchSuite(kOfxPropertySuite, 1); + gParamSuite = (OfxParameterSuiteV1 *) fetchSuite(kOfxParameterSuite, 1); + gMemorySuite = (OfxMemorySuiteV1 *) fetchSuite(kOfxMemorySuite, 1); + gThreadSuite = (OfxMultiThreadSuiteV1 *) fetchSuite(kOfxMultiThreadSuite, 1); + gMessageSuite = (OfxMessageSuiteV1 *) fetchSuite(kOfxMessageSuite, 1); + gMessageSuiteV2 = (OfxMessageSuiteV2 *) fetchSuite(kOfxMessageSuite, 2, true); + gProgressSuiteV1 = (OfxProgressSuiteV1 *) fetchSuite(kOfxProgressSuite, 1, true); + gProgressSuiteV2 = (OfxProgressSuiteV2 *) fetchSuite(kOfxProgressSuite, 2, true); + gTimeLineSuite = (OfxTimeLineSuiteV1 *) fetchSuite(kOfxTimeLineSuite, 1, true); + gParametricParameterSuite = (OfxParametricParameterSuiteV1*) fetchSuite(kOfxParametricParameterSuite, 1, true); +#ifdef OFX_SUPPORTS_OPENGLRENDER + gOpenGLRenderSuite = (OfxImageEffectOpenGLRenderSuiteV1*) fetchSuite(kOfxOpenGLRenderSuite, 1, true); +#endif + + // OK check and fetch host information + fetchHostDescription(gHost); + + /// and set some dendent flags + OFX::gHostDescription.supportsMessageSuiteV2 = gMessageSuiteV2 != NULL; + OFX::gHostDescription.supportsProgressSuite = (gProgressSuiteV1 != NULL || gProgressSuiteV2 != NULL); + OFX::gHostDescription.supportsTimeLineSuite = gTimeLineSuite != NULL; + + // fetch the interact suite if the host supports interaction + if(OFX::gHostDescription.supportsOverlays || OFX::gHostDescription.supportsCustomInteract) + gInteractSuite = (OfxInteractSuiteV1 *) fetchSuite(kOfxInteractSuite, 1); + } + + // initialise the validation code + OFX::Validation::initialise(); + + // validate the host + OFX::Validation::validateHostProperties(gHost); + + } + + /** @brief Library side unload action, this fetches all the suite pointers */ + static + void unloadAction(const char* id) + { + gLoadCount--; + if (gLoadCount<0) { + OFX::Log::warning(true, "OFX Plugin '%s' is already unloaded.", id); + return; + } + + if(gLoadCount==0) + { + // force these to null + gEffectSuite = 0; + gPropSuite = 0; + gParamSuite = 0; + gMemorySuite = 0; + gThreadSuite = 0; + gMessageSuite = 0; + gMessageSuiteV2 = 0; + gInteractSuite = 0; + gParametricParameterSuite = 0; + } + + { + EffectDescriptorMap::iterator it = gEffectDescriptors.find(id); + EffectContextMap& toBeDeleted = it->second; + for(EffectContextMap::iterator it2 = toBeDeleted.begin(); it2 != toBeDeleted.end(); ++it2) + { + OFX::ImageEffectDescriptor* desc = it2->second; + delete desc; + } + toBeDeleted.clear(); + } + { + OFX::OfxPlugInfoMap::iterator it = OFX::plugInfoMap.find(id); + OFX::OfxPluginArray::iterator it2 = std::find(ofxPlugs.begin(), ofxPlugs.end(), it->second._plug.get()); + if (it2 != ofxPlugs.end()) { + (*it2) = nullptr; + } + OFX::plugInfoMap.erase(it); + } + } + + + /** @brief fetches our pointer out of the props on the handle */ + ImageEffect *retrieveImageEffectPointer(OfxImageEffectHandle handle) + { + ImageEffect *instance; + + // get the prop set on the handle + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet(handle, &propHandle); + throwSuiteStatusException(stat); + + // make our wrapper object + PropertySet props(propHandle); + + // fetch the instance data out of the properties + instance = (ImageEffect *) props.propGetPointer(kOfxPropInstanceData); + + OFX::Log::error(instance == 0, "Instance data handle in effect instance properties is NULL!"); + + // need to throw something here + + // and dance to the music + return instance; + } + + /** @brief Checks the handles passed into the plugin's main entry point */ + static + void + checkMainHandles(const std::string &action, const void *handle, + OfxPropertySetHandle inArgsHandle, OfxPropertySetHandle outArgsHandle, + bool handleCanBeNull, bool inArgsCanBeNull, bool outArgsCanBeNull) + { + if(handleCanBeNull) + OFX::Log::warning(handle != 0, "Handle passed to '%s' is not null.", action.c_str()); + else + OFX::Log::error(handle == 0, "'Handle passed to '%s' is null.", action.c_str()); + + if(inArgsCanBeNull) + OFX::Log::warning(inArgsHandle != 0, "'inArgs' Handle passed to '%s' is not null.", action.c_str()); + else + OFX::Log::error(inArgsHandle == 0, "'inArgs' handle passed to '%s' is null.", action.c_str()); + + if(outArgsCanBeNull) + OFX::Log::warning(outArgsHandle != 0, "'outArgs' Handle passed to '%s' is not null.", action.c_str()); + else + OFX::Log::error(outArgsHandle == 0, "'outArgs' handle passed to '%s' is null.", action.c_str()); + + // validate the property sets on the arguments + OFX::Validation::validateActionArgumentsProperties(action, inArgsHandle, outArgsHandle); + + // throw exceptions if null when not meant to be null + if(!handleCanBeNull && !handle) throwSuiteStatusException(kOfxStatErrBadHandle); + if(!inArgsCanBeNull && !inArgsHandle) throwSuiteStatusException(kOfxStatErrBadHandle); + if(!outArgsCanBeNull && !outArgsHandle) throwSuiteStatusException(kOfxStatErrBadHandle); + } + + + /** @brief Fetches the arguments used in a render action 'inargs' property set into a POD struct */ + static void + getRenderActionArguments(RenderArguments &args, OFX::PropertySet inArgs) + { + args.time = inArgs.propGetDouble(kOfxPropTime); + + args.renderScale.x = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 0); + args.renderScale.y = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 1); + + args.renderWindow.x1 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 0); + args.renderWindow.y1 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 1); + args.renderWindow.x2 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 2); + args.renderWindow.y2 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 3); + + args.isEnabledOpenCLRender = inArgs.propGetInt(kOfxImageEffectPropOpenCLEnabled, false) != 0; + args.isEnabledCudaRender = inArgs.propGetInt(kOfxImageEffectPropCudaEnabled, false) != 0; + args.isEnabledMetalRender = inArgs.propGetInt(kOfxImageEffectPropMetalEnabled, false) != 0; + args.pOpenCLCmdQ = inArgs.propGetPointer(kOfxImageEffectPropOpenCLCommandQueue, false); + args.pCudaStream = inArgs.propGetPointer(kOfxImageEffectPropCudaStream, false); + args.pMetalCmdQ = inArgs.propGetPointer(kOfxImageEffectPropMetalCommandQueue, false); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + // Don't throw an exception if the following inArgs are not present. + // OpenGL rendering appeared in OFX 1.3 + args.openGLEnabled = inArgs.propGetInt(kOfxImageEffectPropOpenGLEnabled, false) != 0; +#endif + + // Don't throw an exception if the following inArgs are not present: + // They appeared in OFX 1.2. + args.sequentialRenderStatus = inArgs.propGetInt(kOfxImageEffectPropSequentialRenderStatus, false) != 0; + args.interactiveRenderStatus = inArgs.propGetInt(kOfxImageEffectPropInteractiveRenderStatus, false) != 0; + + // kOfxImageEffectPropRenderQualityDraft appeared in OFX 1.4 + args.renderQualityDraft = inArgs.propGetInt(kOfxImageEffectPropRenderQualityDraft, false) != 0; + + args.fieldToRender = eFieldNone; + std::string str = inArgs.propGetString(kOfxImageEffectPropFieldToRender); + try { + args.fieldToRender = mapStrToFieldEnum(str); + } + catch (std::invalid_argument&) { + // dud field? + OFX::Log::error(true, "Unknown field to render '%s'", str.c_str()); + + // HACK need to throw something to cause a failure + } + } + + /** @brief Library side render action, fetches relevant properties and calls the client code */ + static + void + renderAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + RenderArguments args; + + // get the arguments + getRenderActionArguments(args, inArgs); + + // and call the plugin client render code + effectInstance->render(args); + } + + /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */ + static + void + beginSequenceRenderAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + BeginSequenceRenderArguments args; + + args.frameRange.min = inArgs.propGetDouble(kOfxImageEffectPropFrameRange, 0); + args.frameRange.max = inArgs.propGetDouble(kOfxImageEffectPropFrameRange, 1); + + args.frameStep = inArgs.propGetDouble(kOfxImageEffectPropFrameStep, 0); + + args.renderScale.x = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 0); + args.renderScale.y = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 1); + + args.isEnabledOpenCLRender = inArgs.propGetInt(kOfxImageEffectPropOpenCLEnabled, false) != 0; + args.isEnabledCudaRender = inArgs.propGetInt(kOfxImageEffectPropCudaEnabled, false) != 0; + args.isEnabledMetalRender = inArgs.propGetInt(kOfxImageEffectPropMetalEnabled, false) != 0; + args.pOpenCLCmdQ = inArgs.propGetPointer(kOfxImageEffectPropOpenCLCommandQueue, false); + args.pCudaStream = inArgs.propGetPointer(kOfxImageEffectPropCudaStream, false); + args.pMetalCmdQ = inArgs.propGetPointer(kOfxImageEffectPropMetalCommandQueue, false); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + // Don't throw an exception if the following inArgs are not present. + // OpenGL rendering appeared in OFX 1.3 + args.openGLEnabled = inArgs.propGetInt(kOfxImageEffectPropOpenGLEnabled, false) != 0; +#endif + args.isInteractive = inArgs.propGetInt(kOfxPropIsInteractive) != 0; + // Don't throw an exception if the following inArgs are not present: + // They appeared in OFX 1.2 + args.sequentialRenderStatus = inArgs.propGetInt(kOfxImageEffectPropSequentialRenderStatus, false) != 0; + args.interactiveRenderStatus = inArgs.propGetInt(kOfxImageEffectPropInteractiveRenderStatus, false) != 0; + + // and call the plugin client render code + effectInstance->beginSequenceRender(args); + } + + /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */ + static + void + endSequenceRenderAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + EndSequenceRenderArguments args; + + args.renderScale.x = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 0); + args.renderScale.y = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 1); + + args.isEnabledOpenCLRender = inArgs.propGetInt(kOfxImageEffectPropOpenCLEnabled, false) != 0; + args.isEnabledCudaRender = inArgs.propGetInt(kOfxImageEffectPropCudaEnabled, false) != 0; + args.isEnabledMetalRender = inArgs.propGetInt(kOfxImageEffectPropMetalEnabled, false) != 0; + args.pOpenCLCmdQ = inArgs.propGetPointer(kOfxImageEffectPropOpenCLCommandQueue, false); + args.pCudaStream = inArgs.propGetPointer(kOfxImageEffectPropCudaStream, false); + args.pMetalCmdQ = inArgs.propGetPointer(kOfxImageEffectPropMetalCommandQueue, false); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + // Don't throw an exception if the following inArgs are not present. + // OpenGL rendering appeared in OFX 1.3 + args.openGLEnabled = inArgs.propGetInt(kOfxImageEffectPropOpenGLEnabled, false) != 0; +#endif + args.isInteractive = inArgs.propGetInt(kOfxPropIsInteractive) != 0; + // Don't throw an exception if the following inArgs are not present: + // They appeared in OFX 1.2 + args.sequentialRenderStatus = inArgs.propGetInt(kOfxImageEffectPropSequentialRenderStatus, false) != 0; + args.interactiveRenderStatus = inArgs.propGetInt(kOfxImageEffectPropInteractiveRenderStatus, false) != 0; + + // and call the plugin client render code + effectInstance->endSequenceRender(args); + } + + + /** @brief Fetches the arguments used in a isIdentity action 'inargs' property set into a POD struct */ + static void + getIsIdentityActionArguments(IsIdentityArguments &args, OFX::PropertySet inArgs) + { + args.time = inArgs.propGetDouble(kOfxPropTime); + + args.renderScale.x = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 0); + args.renderScale.y = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 1); + + args.renderWindow.x1 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 0); + args.renderWindow.y1 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 1); + args.renderWindow.x2 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 2); + args.renderWindow.y2 = inArgs.propGetInt(kOfxImageEffectPropRenderWindow, 3); + + std::string str = inArgs.propGetString(kOfxImageEffectPropFieldToRender); + try { + args.fieldToRender = mapStrToFieldEnum(str); + } + catch (std::invalid_argument&) { + // dud field? + OFX::Log::error(true, "Unknown field to render '%s'", str.c_str()); + + // HACK need to throw something to cause a failure + } + } + + /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */ + static + bool + isIdentityAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + IsIdentityArguments args; + + // get the arguments + getIsIdentityActionArguments(args, inArgs); + + // and call the plugin client isIdentity code + Clip *identityClip = 0; + double identityTime = args.time; + bool v = effectInstance->isIdentity(args, identityClip, identityTime); + + if(v && identityClip) { + outArgs.propSetString(kOfxPropName, identityClip->name()); + outArgs.propSetDouble(kOfxPropTime, identityTime); + return true; + } + return false; + } + + /** @brief Library side get region of definition function */ + static + bool + regionOfDefinitionAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + RegionOfDefinitionArguments args; + + args.renderScale.x = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 0); + args.renderScale.y = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 1); + + args.time = inArgs.propGetDouble(kOfxPropTime); + + // and call the plugin client code + OfxRectD rod; + bool v = effectInstance->getRegionOfDefinition(args, rod); + + if(v) { + outArgs.propSetDouble(kOfxImageEffectPropRegionOfDefinition, rod.x1, 0); + outArgs.propSetDouble(kOfxImageEffectPropRegionOfDefinition, rod.y1, 1); + outArgs.propSetDouble(kOfxImageEffectPropRegionOfDefinition, rod.x2, 2); + outArgs.propSetDouble(kOfxImageEffectPropRegionOfDefinition, rod.y2, 3); + return true; + } + return false; + } + + /** @brief Library side get regions of interest function */ + static + bool + regionsOfInterestAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs, const char* plugname) + { + /** @brief local class to set the roi of a clip */ + class LOCAL ActualROISetter : public OFX::RegionOfInterestSetter { + OFX::PropertySet &outArgs_; + bool doneSomething_; + const std::map& clipROIPropNames_; + public : + /** @brief ctor */ + ActualROISetter(OFX::PropertySet &args, const std::map& clipROIPropNames) + : outArgs_(args) + , doneSomething_(false) + , clipROIPropNames_(clipROIPropNames) + { } + + /** @brief did we set something ? */ + bool didSomething(void) const {return doneSomething_;} + + /** @brief set the RoI of the clip */ + virtual void setRegionOfInterest(const Clip &clip, const OfxRectD &roi) + { + std::map::const_iterator it = clipROIPropNames_.find(clip.name()); + if(it==clipROIPropNames_.end()) + throw(Exception::PropertyUnknownToHost(clip.name().c_str())); + + // construct the name of the property + const std::string& propName = it->second; + + // and set it + outArgs_.propSetDouble(propName.c_str(), roi.x1, 0); + outArgs_.propSetDouble(propName.c_str(), roi.y1, 1); + outArgs_.propSetDouble(propName.c_str(), roi.x2, 2); + outArgs_.propSetDouble(propName.c_str(), roi.y2, 3); + + // and record the face we have done something + doneSomething_ = true; + } + }; // end of local class + + // fetch our effect pointer + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + RegionsOfInterestArguments args; + + // fetch in arguments from the prop handle + args.renderScale.x = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 0); + args.renderScale.y = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 1); + + args.regionOfInterest.x1 = inArgs.propGetDouble(kOfxImageEffectPropRegionOfInterest, 0); + args.regionOfInterest.y1 = inArgs.propGetDouble(kOfxImageEffectPropRegionOfInterest, 1); + args.regionOfInterest.x2 = inArgs.propGetDouble(kOfxImageEffectPropRegionOfInterest, 2); + args.regionOfInterest.y2 = inArgs.propGetDouble(kOfxImageEffectPropRegionOfInterest, 3); + + args.time = inArgs.propGetDouble(kOfxPropTime); + + // make a roi setter object + ActualROISetter setRoIs(outArgs, gEffectDescriptors[plugname][effectInstance->getContext()]->getClipROIPropNames()); + + // and call the plugin client code + effectInstance->getRegionsOfInterest(args, setRoIs); + + // did we do anything ? + if(setRoIs.didSomething()) + return true; + return false; + } + + /** @brief Library side frames needed action */ + static + bool + framesNeededAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet &outArgs, const char* plugname) + { + /** @brief local class to set the frames needed from a clip */ + class LOCAL ActualSetter : public OFX::FramesNeededSetter { + OFX::PropertySet &outArgs_; /**< @brief property set to set values in */ + std::map > frameRanges_; /**< @brief map holding a bunch of frame ranges, one for each clip */ + const std::map& _clipFrameRangePropNames; + public : + /** @brief ctor */ + ActualSetter(OFX::PropertySet &args, const std::map& clipFrameRangePropNames) + : outArgs_(args), _clipFrameRangePropNames(clipFrameRangePropNames) + { } + + /** @brief set the RoI of the clip */ + virtual void setFramesNeeded(const Clip &clip, const OfxRangeD &range) + { + // insert this into the vector which is in the map + frameRanges_[clip.name()].push_back(range); + } + + /** @brief write frameRanges_ back to the property set */ + bool setOutProperties(void) + { + bool didSomething = false; + + std::map >::iterator i; + + for(i = frameRanges_.begin(); i != frameRanges_.end(); ++i) { + if(i->first != kOfxImageEffectOutputClipName) { + didSomething = true; + + // Make the property name we are setting + const std::map::const_iterator it = _clipFrameRangePropNames.find(i->first); + if(it==_clipFrameRangePropNames.end()) + throw(Exception::PropertyUnknownToHost(i->first.c_str())); + + const std::string& propName = it->second; + + // fetch the list of frame ranges + std::vector &clipRange = i->second; + std::vector::iterator j; + int n = 0; + + // and set 'em + for(j = clipRange.begin(); j < clipRange.end(); ++j) { + outArgs_.propSetDouble(propName.c_str(), j->min, n++); + outArgs_.propSetDouble(propName.c_str(), j->max, n++); + } + } + } + + return didSomething; + } + + }; // end of local class + + // fetch our effect pointer + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + FramesNeededArguments args; + + // fetch in arguments from the prop handle + args.time = inArgs.propGetDouble(kOfxPropTime); + + // make a roi setter object + ActualSetter setFrames(outArgs, gEffectDescriptors[plugname][effectInstance->getContext()]->getClipFrameRangePropNames()); + + // and call the plugin client code + effectInstance->getFramesNeeded(args, setFrames); + + // Write it back to the properties and see if we set anything + if(setFrames.setOutProperties()) + return true; + return false; + } + + /** @brief Library side get regions of interest function */ + static + bool + getTimeDomainAction(OfxImageEffectHandle handle, OFX::PropertySet &outArgs) + { + // fetch our effect pointer + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + // we can only be a general context effect, so check that this is true + OFX::Log::error(effectInstance->getContext() != eContextGeneral, "Calling kOfxImageEffectActionGetTimeDomain on an effect that is not a general context effect."); + + OfxRangeD timeDomain; + + // and call the plugin client code + bool v = effectInstance->getTimeDomain(timeDomain); + + if(v) { + outArgs.propSetDouble(kOfxImageEffectPropFrameRange, timeDomain.min, 0); + outArgs.propSetDouble(kOfxImageEffectPropFrameRange, timeDomain.max, 1); + } + + return v; + } + + /** @brief Library side get regions of interest function */ + static + bool + clipPreferencesAction(OfxImageEffectHandle handle, OFX::PropertySet &outArgs, const char* plugname) + { + // fetch our effect pointer + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + // set up our clip preferences setter + ImageEffectDescriptor* desc = gEffectDescriptors[plugname][effectInstance->getContext()]; + ClipPreferencesSetter prefs(outArgs, desc->getClipDepthPropNames(), desc->getClipComponentPropNames(), desc->getClipPARPropNames()); + + // and call the plug-in client code + effectInstance->getClipPreferences(prefs); + + // did we do anything ? + if(prefs.didSomething()) + return true; + return false; + } + + /** @brief Library side begin instance changed action */ + static + void + beginInstanceChangedAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + std::string reasonStr = inArgs.propGetString(kOfxPropChangeReason); + InstanceChangeReason reason = mapToInstanceChangedReason(reasonStr); + + // and call the plugin client code + effectInstance->beginChanged(reason); + } + + /** @brief Library side instance changed action */ + static + void + instanceChangedAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + InstanceChangedArgs args; + + // why did it change + std::string reasonStr = inArgs.propGetString(kOfxPropChangeReason); + args.reason = mapToInstanceChangedReason(reasonStr); + args.time = inArgs.propGetDouble(kOfxPropTime); + args.renderScale.x = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 0); + args.renderScale.y = inArgs.propGetDouble(kOfxImageEffectPropRenderScale, 1); + + // what changed + std::string changedType = inArgs.propGetString(kOfxPropType); + std::string changedName = inArgs.propGetString(kOfxPropName); + + if(changedType == kOfxTypeParameter) { + // and call the plugin client code + effectInstance->changedParam(args, changedName); + } + else if(changedType == kOfxTypeClip) { + // and call the plugin client code + effectInstance->changedClip(args, changedName); + } + else { + OFX::Log::error(true, "Instance Changed called with unknown type '%s' of object '%s'", changedType.c_str(), changedName.c_str()); + } + } + + /** @brief Library side end instance changed action */ + static + void + endInstanceChangedAction(OfxImageEffectHandle handle, OFX::PropertySet inArgs) + { + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + std::string reasonStr = inArgs.propGetString(kOfxPropChangeReason); + InstanceChangeReason reason = mapToInstanceChangedReason(reasonStr); + + // and call the plugin client code + effectInstance->endChanged(reason); + } + + + /** @brief The main entry point for the plugin + */ + OfxStatus mainEntryStr(const char *actionRaw, + const void *handleRaw, + OfxPropertySetHandle inArgsRaw, + OfxPropertySetHandle outArgsRaw, + const char* plugname) + { + OFX::Log::print("********************************************************************************"); + OFX::Log::print("START mainEntry (%s for %s)", actionRaw, plugname); + OFX::Log::indent(); + OfxStatus stat = kOfxStatReplyDefault; + try { + + OfxPlugInfoMap::iterator it = plugInfoMap.find(plugname); + if(it==plugInfoMap.end()) + throw; + + OFX::PluginFactory* factory = it->second._factory; + + // Cast the raw handle to be an image effect handle, because that is what it is + OfxImageEffectHandle handle = (OfxImageEffectHandle) handleRaw; + + // Turn the arguments into wrapper objects to make our lives easier + OFX::PropertySet inArgs(inArgsRaw); + OFX::PropertySet outArgs(outArgsRaw); + + // turn the action into a std::string + std::string action(actionRaw); + + // figure the actions + if (action == kOfxActionLoad) { + // call the support load function, param-less + OFX::Private::loadAction(); + + // call the plugin side load action, param-less + factory->load(); + + // got here, must be good + stat = kOfxStatOK; + } + + // figure the actions + else if (action == kOfxActionUnload) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, true, true, true); + + // call the plugin side unload action, param-less, should be called, eve if the stat above failed! + factory->unload(); + + // call the support unload function, param-less + OFX::Private::unloadAction(plugname); + + // got here, must be good + stat = kOfxStatOK; + } + + else if(action == kOfxActionDescribe) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // make the plugin descriptor + ImageEffectDescriptor *desc = new ImageEffectDescriptor(handle); + + // validate the host + OFX::Validation::validatePluginDescriptorProperties(fetchEffectProps(handle)); + + // and pass it to the plugin to do something with it + + factory->describe(*desc); + + // add it to our map + gEffectDescriptors[plugname][eContextNone] = desc; + + // got here, must be good + stat = kOfxStatOK; + } + else if(action == kOfxImageEffectActionDescribeInContext) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true); + + // make the plugin descriptor and pass it to the plugin to do something with it + ImageEffectDescriptor *desc = new ImageEffectDescriptor(handle); + + // figure the context and map it to an enum + std::string contextStr = inArgs.propGetString(kOfxImageEffectPropContext); + ContextEnum context = mapToContextEnum(contextStr); + + // validate the host + OFX::Validation::validatePluginDescriptorProperties(fetchEffectProps(handle)); + + // call plugin describe in context + factory->describeInContext(*desc, context); + + // add it to our map + gEffectDescriptors[plugname][context] = desc; + + // got here, must be good + stat = kOfxStatOK; + } + else if(action == kOfxActionCreateInstance) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch the effect props to figure the context + PropertySet effectProps = fetchEffectProps(handle); + + // get the context and turn it into an enum + std::string str = effectProps.propGetString(kOfxImageEffectPropContext); + ContextEnum context = mapToContextEnum(str); + + // make the image effect instance for this context + ImageEffect *instance = factory->createInstance(handle, context); + (void)instance; + + // validate the plugin handle's properties + OFX::Validation::validatePluginInstanceProperties(fetchEffectProps(handle)); + + // got here, must be good + stat = kOfxStatOK; + } + else if(action == kOfxActionDestroyInstance) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch our pointer out of the props on the handle + ImageEffect *instance = retrieveImageEffectPointer(handle); + + // kill it + delete instance; + + // got here, must be good + stat = kOfxStatOK; + } + else if(action == kOfxImageEffectActionRender) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true); + + // call the render action skin + renderAction(handle, inArgs); + + // got here, must be good + stat = kOfxStatOK; + } + else if(action == kOfxImageEffectActionBeginSequenceRender) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true); + + // call the begin render action skin + beginSequenceRenderAction(handle, inArgs); + } + else if(action == kOfxImageEffectActionEndSequenceRender) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true); + + // call the begin render action skin + endSequenceRenderAction(handle, inArgs); + } + else if(action == kOfxImageEffectActionIsIdentity) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false); + + // call the identity action, if it is, return OK + if(isIdentityAction(handle, inArgs, outArgs)) + stat = kOfxStatOK; + } + else if(action == kOfxImageEffectActionGetRegionOfDefinition) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false); + + // call the rod action, return OK if it does something + if(regionOfDefinitionAction(handle, inArgs, outArgs)) + stat = kOfxStatOK; + } + else if(action == kOfxImageEffectActionGetRegionsOfInterest) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false); + + // call the RoI action, return OK if it does something + if(regionsOfInterestAction(handle, inArgs, outArgs, plugname)) + stat = kOfxStatOK; + } + else if(action == kOfxImageEffectActionGetFramesNeeded) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false); + + // call the frames needed action, return OK if it does something + if(framesNeededAction(handle, inArgs, outArgs, plugname)) + stat = kOfxStatOK; + } + else if(action == kOfxImageEffectActionGetClipPreferences) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, false); + + // call the frames needed action, return OK if it does something + if(clipPreferencesAction(handle, outArgs, plugname)) + stat = kOfxStatOK; + } + else if(action == kOfxActionPurgeCaches) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch our pointer out of the props on the handle + ImageEffect *instance = retrieveImageEffectPointer(handle); + + // purge 'em + instance->purgeCaches(); + } + else if(action == kOfxActionSyncPrivateData) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch our pointer out of the props on the handle + ImageEffect *instance = retrieveImageEffectPointer(handle); + + // and sync it + instance->syncPrivateData(); + } + else if(action == kOfxImageEffectActionGetTimeDomain) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, false); + + // call the instance changed action + if(getTimeDomainAction(handle, outArgs)) + stat = kOfxStatOK; + } + else if(action == kOfxActionBeginInstanceChanged) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true); + + // call the instance changed action + beginInstanceChangedAction(handle, inArgs); + } + else if(action == kOfxActionInstanceChanged) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true); + + // call the instance changed action + instanceChangedAction(handle, inArgs); + } + else if(action == kOfxActionEndInstanceChanged) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true); + + // call the instance changed action + endInstanceChangedAction(handle, inArgs); + } + else if(action == kOfxActionBeginInstanceEdit) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch our pointer out of the props on the handle + ImageEffect *instance = retrieveImageEffectPointer(handle); + + // call the begin edit function + instance->beginEdit(); + } + else if(action == kOfxActionEndInstanceEdit) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch our pointer out of the props on the handle + ImageEffect *instance = retrieveImageEffectPointer(handle); + + // call the end edit function + instance->endEdit(); + } +#ifdef OFX_SUPPORTS_OPENGLRENDER + else if(action == kOfxActionOpenGLContextAttached) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch our pointer out of the props on the handle + ImageEffect *instance = retrieveImageEffectPointer(handle); + + // call the context attached function + instance->contextAttached(); + } + else if(action == kOfxActionOpenGLContextDetached) { + checkMainHandles(actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true); + + // fetch our pointer out of the props on the handle + ImageEffect *instance = retrieveImageEffectPointer(handle); + + // call the context detached function + instance->contextDetached(); + } +#endif + else if(actionRaw) { + OFX::Log::error(true, "Unknown action '%s'.", actionRaw); + } + else { + OFX::Log::error(true, "Requested action was a null pointer."); + } + } + + // catch suite exceptions + catch (const OFX::Exception::Suite &ex) + { + OFX::Log::error(true, "Caught OFX::Exception::Suite: %s", ex.what()); +# ifdef DEBUG + std::cout << "Caught OFX::Exception::Suite: " << ex.what() << std::endl; +# endif + stat = ex.status(); + } + + // catch host inadequate exceptions + catch (const OFX::Exception::HostInadequate &e) + { + OFX::Log::error(true, "Caught OFX::Exception::HostInadequate: %s", e.what()); +# ifdef DEBUG + std::cout << "Caught OFX::Exception::HostInadequate: " << e.what() << std::endl; +# endif + stat = kOfxStatErrMissingHostFeature; + } + + // catch exception due to a property being unknown to the host, implies something wrong with host if not caught further down + catch (const OFX::Exception::PropertyUnknownToHost &e) + { + OFX::Log::error(true, "Caught OFX::Exception::PropertyUnknownToHost: %s", e.what()); +# ifdef DEBUG + std::cout << "Caught OFX::Exception::PropertyUnknownToHost: " << e.what() << std::endl; +# endif + stat = kOfxStatErrMissingHostFeature; + } + + // catch memory + catch (std::bad_alloc&) + { + stat = kOfxStatErrMemory; + } + + // catch a custom client exception, if defined +#ifdef OFX_CLIENT_EXCEPTION_TYPE + catch (OFX_CLIENT_EXCEPTION_TYPE &ex) + { + stat = OFX_CLIENT_EXCEPTION_HANDLER(ex, plugname); + } +#endif + // Catch anything else, unknown + catch (const std::exception &e) + { + OFX::Log::error(true, "Caught std::exception: %s", e.what()); +# ifdef DEBUG + std::cout << "Caught std::exception: " << e.what() << std::endl; +# endif + stat = kOfxStatFailed; + } + catch (...) + { + OFX::Log::error(true, "Caught unknown exception"); +# ifdef DEBUG + std::cout << "Caught Unknown exception" << std::endl; +# endif + stat = kOfxStatFailed; + } + + OFX::Log::outdent(); + OFX::Log::print("STOP mainEntry (%s for %s, returning %d=%s)\n", actionRaw, plugname, + stat, mapStatusToString(stat)); + return stat; + } + + + OfxStatus customParamInterpolationV1Entry( + const void* handleRaw, + OfxPropertySetHandle inArgsRaw, + OfxPropertySetHandle outArgsRaw) + { + OFX::Log::print("********************************************************************************"); + OFX::Log::print("START customParamInterpolationV1Entry"); + OFX::Log::indent(); + OfxStatus stat = kOfxStatReplyDefault; + try { + // Cast the raw handle to be an image effect handle, because that is what it is + OfxImageEffectHandle handle = (OfxImageEffectHandle) handleRaw; + + // Turn the arguments into wrapper objects to make our lives easier + OFX::PropertySet inArgs(inArgsRaw); + OFX::PropertySet outArgs(outArgsRaw); + + ImageEffect *effectInstance = retrieveImageEffectPointer(handle); + + InterpolateCustomArgs interpArgs; + + interpArgs.time = inArgs.propGetDouble(kOfxPropTime); + interpArgs.value1 = inArgs.propGetString(kOfxParamPropCustomValue, 0); + interpArgs.value2 = inArgs.propGetString(kOfxParamPropCustomValue, 1); + interpArgs.keytime1 = inArgs.propGetDouble(kOfxParamPropInterpolationTime, 0); + interpArgs.keytime2 = inArgs.propGetDouble(kOfxParamPropInterpolationTime, 1); + interpArgs.amount = inArgs.propGetDouble(kOfxParamPropInterpolationAmount); + + std::string paramName = inArgs.propGetString(kOfxPropName); + + // and call the plugin client code + std::string output = effectInstance->interpolateCustomParam(interpArgs, paramName); + + outArgs.propSetString(kOfxParamPropCustomValue, output); + } + + // catch suite exceptions + catch (OFX::Exception::Suite &ex) + { +# ifdef DEBUG + std::cout << "Caught OFX::Exception::Suite" << std::endl; +# endif + stat = ex.status(); + } + + // catch host inadequate exceptions + catch (OFX::Exception::HostInadequate&) + { +# ifdef DEBUG + std::cout << "Caught OFX::Exception::HostInadequate" << std::endl; +# endif + stat = kOfxStatErrMissingHostFeature; + } + + // catch exception due to a property being unknown to the host, implies something wrong with host if not caught further down + catch (OFX::Exception::PropertyUnknownToHost&) + { +# ifdef DEBUG + std::cout << "Caught OFX::Exception::PropertyUnknownToHost" << std::endl; +# endif + stat = kOfxStatErrMissingHostFeature; + } + + // catch memory + catch (std::bad_alloc&) + { + stat = kOfxStatErrMemory; + } + + // catch a custom client exception, if defined +#ifdef OFX_CLIENT_EXCEPTION_TYPE + catch (OFX_CLIENT_EXCEPTION_TYPE &ex) + { + stat = OFX_CLIENT_EXCEPTION_HANDLER(ex, plugname); + } +#endif + // Catch anything else, unknown + catch (...) + { +# ifdef DEBUG + std::cout << "Caught Unknown exception" << std::endl; +# endif + stat = kOfxStatFailed; + } + + OFX::Log::outdent(); + OFX::Log::print("STOP customParamInterpolationV1Entry\n"); + return stat; + } + + /** @brief The plugin function that gets passed the host structure. */ + void setHost(OfxHost *host) + { + gHost = host; + } + + }; // namespace Private + + /** @brief Fetch's a suite from the host and logs errors */ + const void * fetchSuite(const char *suiteName, int suiteVersion, bool optional) + { + const void *suite = Private::gHost->fetchSuite(Private::gHost->host, suiteName, suiteVersion); + if(suite==0) + { + if(optional) + OFX::Log::warning(suite == 0, "Could not fetch the optional suite '%s' version %d.", suiteName, suiteVersion); + else + OFX::Log::error(suite == 0, "Could not fetch the mandatory suite '%s' version %d.", suiteName, suiteVersion); + } + if(!optional && suite == 0) throw OFX::Exception::HostInadequate(suiteName); + return suite; + } + +}; // namespace OFX + +static +OFX::OfxPlugInfo generatePlugInfo(OFX::PluginFactory* factory, std::string& newID) +{ + newID = factory->getUID(); + std::unique_ptr ofxPlugin(new OfxPlugin()); + ofxPlugin->pluginApi = kOfxImageEffectPluginApi; + ofxPlugin->apiVersion = 1; + ofxPlugin->pluginIdentifier = factory->getID().c_str(); + ofxPlugin->pluginVersionMajor = factory->getMajorVersion(); + ofxPlugin->pluginVersionMinor = factory->getMinorVersion(); + ofxPlugin->setHost = OFX::Private::setHost; + ofxPlugin->mainEntry = factory->getMainEntry(); + return OFX::OfxPlugInfo(factory, std::move(ofxPlugin)); +} + +bool gHasInit = false; + +static +void init() +{ + if(gHasInit) + return; + + OFX::Plugin::getPluginIDs(OFX::plugIDs); + if(OFX::ofxPlugs.empty()) + OFX::ofxPlugs.resize(OFX::plugIDs.size()); + + int counter = 0; + for (OFX::PluginFactoryArray::const_iterator it = OFX::plugIDs.begin(); it != OFX::plugIDs.end(); ++it, ++counter) + { + std::string newID; + OFX::OfxPlugInfo info = generatePlugInfo(*it, newID); + OFX::ofxPlugs[counter] = info._plug.get(); + OFX::plugInfoMap[newID] = std::move(info); + } + gHasInit = true; +} + +/** @brief, mandated function returning the number of plugins, which is always 1 */ +EXPORT int OfxGetNumberOfPlugins(void) +{ + init(); + return (int)OFX::plugIDs.size(); +} + +/** @brief, mandated function returning the nth plugin + +We call the plugin side defined OFX::Plugin::getPluginIDs function to find out what to set. +*/ + +EXPORT OfxPlugin* OfxGetPlugin(int nth) +{ + init(); + int numPlugs = (int)OFX::plugInfoMap.size(); + OFX::Log::error(nth >= numPlugs, "Host attempted to get plugin %d, when there is only %d plugin(s), so it should have asked for 0.", nth, numPlugs); + if(OFX::ofxPlugs[nth] == nullptr) + { + std::string newID; + OFX::OfxPlugInfo info = generatePlugInfo(OFX::plugIDs[nth], newID); + OFX::ofxPlugs[nth] = info._plug.get(); + OFX::plugInfoMap[newID] = std::move(info); + } + return OFX::ofxPlugs[nth]; +} diff --git a/third_party/openfx/Support/Library/ofxsInteract.cpp b/third_party/openfx/Support/Library/ofxsInteract.cpp new file mode 100644 index 000000000..784a9d093 --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsInteract.cpp @@ -0,0 +1,546 @@ + + +/** @brief This file contains code that skins the ofx interact suite (for image effects) */ + + +#include "ofxsSupportPrivate.h" +#include // for find + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. +*/ +namespace OFX { + + /** @brief fetch a pixel scale out of the property set */ + static OfxPointD getPixelScale(const PropertySet &props) + { + OfxPointD pixelScale; + pixelScale.x = props.propGetDouble(kOfxInteractPropPixelScale, 0); + pixelScale.y = props.propGetDouble(kOfxInteractPropPixelScale, 1); + return pixelScale; + } + + /** @brief fetch a render scale out of the property set */ + static OfxPointD getRenderScale(const PropertySet &props) + { + OfxPointD v; + v.x = props.propGetDouble(kOfxImageEffectPropRenderScale, 0); + v.y = props.propGetDouble(kOfxImageEffectPropRenderScale, 1); + return v; + } + + /** @brief fetch a background colour out of the property set */ + static OfxRGBColourD getBackgroundColour(const PropertySet &props) + { + OfxRGBColourD backGroundColour; + backGroundColour.r = props.propGetDouble(kOfxInteractPropBackgroundColour, 0); + backGroundColour.g = props.propGetDouble(kOfxInteractPropBackgroundColour, 1); + backGroundColour.b = props.propGetDouble(kOfxInteractPropBackgroundColour, 2); + return backGroundColour; + } + + /** @brief retrieves the image effect pointer from the interact handle */ + static ImageEffect *retrieveEffectFromInteractHandle(OfxInteractHandle handle) + { + // get the properties set on this handle + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet(handle, &propHandle); + throwSuiteStatusException(stat); + PropertySet interactProperties(propHandle); + + // get the effect handle from this handle + OfxImageEffectHandle effectHandle = (OfxImageEffectHandle) interactProperties.propGetPointer(kOfxPropEffectInstance); + + // get the effect properties + return OFX::Private::retrieveImageEffectPointer(effectHandle); + } + + /** @brief ctor */ + Interact::Interact(OfxInteractHandle handle) + : _interactHandle(handle) + , _effect(0) + { + // get the properties set on this handle + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet(handle, &propHandle); + throwSuiteStatusException(stat); + _interactProperties.propSetHandle(propHandle); + + // set othe instance data on the property handle to point to this interact + _interactProperties.propSetPointer(kOfxPropInstanceData, (void *)this); + + // get the effect handle from this handle + _effect = retrieveEffectFromInteractHandle(handle); + } + + /** @brief ctor */ + Interact::~Interact() + { + } + + /** @brief The bitdepth of each component in the openGL frame buffer */ + int + Interact::getBitDepth(void) const + { + return _interactProperties.propGetInt(kOfxInteractPropBitDepth); + } + + /** @brief Does the openGL frame buffer have an alpha */ + bool + Interact::hasAlpha(void) const + { + return _interactProperties.propGetInt(kOfxInteractPropHasAlpha) != 0; + } + + /** @brief Returns the size of a real screen pixel under the interact's cannonical projection */ + OfxPointD + Interact::getPixelScale(void) const + { + OfxPointD v; + v.x = _interactProperties.propGetDouble(kOfxInteractPropPixelScale, 0); + v.y = _interactProperties.propGetDouble(kOfxInteractPropPixelScale, 1); + return v; + } + + /** @brief The suggested colour to draw a widget in an interact */ + bool + Interact::getSuggestedColour(OfxRGBColourD &c) const + { + // OFX 1.2/1.3 specs say that the host should return kOfxStatReplyDefault if there is no suggested color + OfxStatus stat = OFX::Private::gPropSuite->propGetDouble(_interactProperties.propSetHandle(), kOfxInteractPropSuggestedColour, 0, &c.r); + if (stat != kOfxStatOK) { + return false; // host gave no suggestion (replied kOfxStatReplyDefault or property is unknown to host) + } + stat = OFX::Private::gPropSuite->propGetDouble(_interactProperties.propSetHandle(), kOfxInteractPropSuggestedColour, 1, &c.g); + if (stat != kOfxStatOK) { + return false; // host gave no suggestion (replied kOfxStatReplyDefault or property is unknown to host) + } + stat = OFX::Private::gPropSuite->propGetDouble(_interactProperties.propSetHandle(), kOfxInteractPropSuggestedColour, 2, &c.b); + if (stat != kOfxStatOK) { + return false; // host gave no suggestion (replied kOfxStatReplyDefault or property is unknown to host) + } + return true; + } + + /** @brief Request a redraw */ + void + Interact::requestRedraw(void) const + { + OfxStatus stat = OFX::Private::gInteractSuite->interactRedraw(_interactHandle); + throwSuiteStatusException(stat); + } + + /** @brief Swap a buffer in the case of a double bufferred interact, this is possibly a silly one */ + void + Interact::swapBuffers(void) const + { + OfxStatus stat = OFX::Private::gInteractSuite->interactSwapBuffers(_interactHandle); + throwSuiteStatusException(stat); + } + + /** @brief Set a param that the interact should be redrawn on if its value changes */ + void + Interact::addParamToSlaveTo(Param *p) + { + // do we have it already ? + std::list::iterator i; + i = std::find(_slaveParams.begin(), _slaveParams.end(), p); + if(i == _slaveParams.end()) { + // we have a new one to add in here + _slaveParams.push_back(p); + + // and set the property + int n = _interactProperties.propGetDimension(kOfxInteractPropSlaveToParam); + _interactProperties.propSetString(kOfxInteractPropSlaveToParam, p->getName(), n); + } + + } + + /** @brief Remova a param that the interact should be redrawn on if its value changes */ + void + Interact::removeParamToSlaveTo(Param *p) + { + // do we have it already ? + std::list::iterator i; + i = std::find(_slaveParams.begin(), _slaveParams.end(), p); + if(i != _slaveParams.end()) { + // clobber it from the list + _slaveParams.erase(i); + + // reset the property to remove our dead one + _interactProperties.propReset(kOfxInteractPropSlaveToParam); + + // and add them all in again + int n = 0; + for(i = _slaveParams.begin(); i != _slaveParams.end(); ++i, ++n) { + _interactProperties.propSetString(kOfxInteractPropSlaveToParam, (*i)->getName(), n); + } + } + } + + /** @brief the background colour */ + OfxRGBColourD Interact::getBackgroundColour(void) const + { + return OFX::getBackgroundColour(_interactProperties); + } + + /** @brief the function called to draw in the interact */ + bool + Interact::draw(const DrawArgs &/*args*/) + { + return false; + } + + /** @brief the function called to handle pen motion in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + bool + Interact::penMotion(const PenArgs &/*args*/) + { + return false; + } + + /** @brief the function called to handle pen down events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + bool + Interact::penDown(const PenArgs &/*args*/) + { + return false; + } + + /** @brief the function called to handle pen up events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + bool + Interact::penUp(const PenArgs &/*args*/) + { + return false; + } + + /** @brief the function called to handle key down events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + bool + Interact::keyDown(const KeyArgs &/*args*/) + { + return false; + } + + /** @brief the function called to handle key up events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + bool + Interact::keyUp(const KeyArgs &/*args*/) + { + return false; + } + + /** @brief the function called to handle key down repeat events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + bool + Interact::keyRepeat(const KeyArgs &/*args*/) + { + return false; + } + + /** @brief Called when the interact is given input focus */ + void + Interact::gainFocus(const FocusArgs &/*args*/) + { + } + + /** @brief Called when the interact is loses input focus */ + void + Interact::loseFocus(const FocusArgs &/*args*/) + { + } + + //////////////////////////////////////////////////////////////////////////////// + // overlay interact guff + + /** @brief ctor */ + OverlayInteract::OverlayInteract(OfxInteractHandle handle) + : Interact(handle) + { + // add this interact into the list of overlays that the effect knows about + if(_effect) + _effect->addOverlayInteract(this); + } + + /** @brief ctor */ + OverlayInteract::~OverlayInteract() + { + // add this interact into the list of overlays that the effect knows about + if(_effect) + _effect->removeOverlayInteract(this); + } + + //////////////////////////////////////////////////////////////////////////////// + /** @brief ctor */ + InteractArgs::InteractArgs(const PropertySet &props) + { + time = props.propGetDouble(kOfxPropTime); + renderScale = getRenderScale(props); + } + + /** @brief ctor */ + DrawArgs::DrawArgs(const PropertySet &props) + : InteractArgs(props) + { +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + viewportSize.x = props.propGetDouble(kOfxInteractPropViewportSize, 0, false); + viewportSize.y = props.propGetDouble(kOfxInteractPropViewportSize, 1, false); +#endif + backGroundColour = getBackgroundColour(props); + pixelScale = getPixelScale(props); + } + + /** @brief ctor */ + PenArgs::PenArgs(const PropertySet &props) + : InteractArgs(props) + { +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + viewportSize.x = props.propGetDouble(kOfxInteractPropViewportSize, 0, false); + viewportSize.y = props.propGetDouble(kOfxInteractPropViewportSize, 1, false); +#endif + pixelScale = getPixelScale(props); + backGroundColour = getBackgroundColour(props); + penPosition.x = props.propGetDouble(kOfxInteractPropPenPosition, 0); + penPosition.y = props.propGetDouble(kOfxInteractPropPenPosition, 1); + try { + penViewportPosition.x = props.propGetInt(kOfxInteractPropPenViewportPosition, 0); + penViewportPosition.y = props.propGetInt(kOfxInteractPropPenViewportPosition, 1); + } catch (OFX::Exception::PropertyUnknownToHost&) { + // Introduced in OFX 1.2. Return (-1,-1) if not available + penViewportPosition.x = penViewportPosition.y = -1.; + } + penPressure = props.propGetDouble(kOfxInteractPropPenPressure); + } + + /** @brief ctor */ + KeyArgs::KeyArgs(const PropertySet &props) + : InteractArgs(props) + { + time = props.propGetDouble(kOfxPropTime); + renderScale = getRenderScale(props); + keyString = props.propGetString(kOfxPropKeyString); + keySymbol = props.propGetInt(kOfxPropKeySym); + } + + /** @brief ctor */ + FocusArgs::FocusArgs(const PropertySet &props) + : InteractArgs(props) + { +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + viewportSize.x = props.propGetDouble(kOfxInteractPropViewportSize, 0, false); + viewportSize.y = props.propGetDouble(kOfxInteractPropViewportSize, 1, false); +#endif + pixelScale = getPixelScale(props); + backGroundColour = getBackgroundColour(props); + } + + + void ParamInteractDescriptor::setInteractSizeAspect(double asp) + { + _props->propSetDouble(kOfxParamPropInteractSizeAspect , asp); + } + + void ParamInteractDescriptor::setInteractMinimumSize(int x, int y) + { + _props->propSetInt(kOfxParamPropInteractMinimumSize, x, 0); + _props->propSetInt(kOfxParamPropInteractMinimumSize, y, 1); + } + + void ParamInteractDescriptor::setInteractPreferredSize(int x, int y) + { + _props->propSetInt(kOfxParamPropInteractPreferedSize, x, 0); + _props->propSetInt(kOfxParamPropInteractPreferedSize, y, 1); + } + + ParamInteract::ParamInteract(OfxInteractHandle handle, ImageEffect* effect):Interact(handle), _effect(effect) + {} + + OfxPointI ParamInteract::getInteractSize() const + { + OfxPointI ret; + ret.x = _interactProperties.propGetInt(kOfxParamPropInteractSize, 0); + ret.y = _interactProperties.propGetInt(kOfxParamPropInteractSize, 1); + return ret; + } + + namespace Private { + /** @brief fetches our pointer out of the props on the handle */ + static + Interact *retrieveInteractPointer(OfxInteractHandle handle) + { + Interact *instance; + + // get the prop set on the handle + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet(handle, &propHandle); + throwSuiteStatusException(stat); + + // make our wrapper object + PropertySet props(propHandle); + + // fetch the instance data out of the properties + instance = (Interact *) props.propGetPointer(kOfxPropInstanceData); + + OFX::Log::error(instance == 0, "Instance data handle in effect instance properties is NULL!"); + + // need to throw something here + + // and dance to the music + return instance; + } + + /** @brief The common entry point used by all interacts */ + static + OfxStatus + interactMainEntry(const std::string &action, + OfxInteractHandle handle, + PropertySet inArgs, + PropertySet /*outArgs*/) + { + OfxStatus stat = kOfxStatReplyDefault; + + // get the interact pointer + Interact *interact = retrieveInteractPointer(handle); + + // if one was not made, return and do nothing + if(!interact) + return stat; + + if(action == kOfxActionDestroyInstance) { + delete interact; + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionDraw) { + // make the draw args + DrawArgs drawArgs(inArgs); + if(interact->draw(drawArgs)) + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionPenMotion) { + + // make the draw args + PenArgs args(inArgs); + if(interact->penMotion(args)) + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionPenDown) { + // make the draw args + PenArgs args(inArgs); + if(interact->penDown(args)) + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionPenUp) { + // make the draw args + PenArgs args(inArgs); + if(interact->penUp(args)) + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionKeyDown) { + // make the draw args + KeyArgs args(inArgs); + if(interact->keyDown(args)) + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionKeyUp) { + // make the draw args + KeyArgs args(inArgs); + if(interact->keyUp(args)) + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionKeyRepeat) { + // make the draw args + KeyArgs args(inArgs); + if(interact->keyRepeat(args)) + stat = kOfxStatOK; + } + else if(action == kOfxInteractActionGainFocus) { + // make the draw args + FocusArgs args(inArgs); + interact->gainFocus(args); + } + else if(action == kOfxInteractActionLoseFocus) { + // make the draw args + FocusArgs args(inArgs); + interact->loseFocus(args); + } + + return stat; + } + + /** @brief The main entry for image effect overlays */ + OfxStatus interactMainEntry(const char *actionRaw, + const void *handleRaw, + OfxPropertySetHandle inArgsRaw, + OfxPropertySetHandle outArgsRaw, + InteractDescriptor& desc) + { + OFX::Log::print("********************************************************************************"); + OFX::Log::print("START overlayInteractMainEntry (%s)", actionRaw); + OFX::Log::indent(); + OfxStatus stat = kOfxStatReplyDefault; + + try { + // Cast the raw handle to be an image effect handle, because that is what it is + OfxInteractHandle handle = (OfxInteractHandle) handleRaw; + + // Turn the arguments into wrapper objects to make our lives easier + OFX::PropertySet inArgs(inArgsRaw); + OFX::PropertySet outArgs(outArgsRaw); + + // turn the action into a std::string + std::string action(actionRaw); + + // figure the actions + if (action == kOfxActionDescribe) { + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gInteractSuite->interactGetPropertySet(handle, &propHandle); + throwSuiteStatusException(stat); + PropertySet interactProperties(propHandle); + desc.setPropertySet(&interactProperties); + desc.describe(); + } + else if (action == kOfxActionCreateInstance) + { + // fetch the image effect we are being made for out of the interact's property handle + ImageEffect *effect = retrieveEffectFromInteractHandle(handle); + OFX::Interact* interact = desc.createInstance(handle, effect); + (void)interact; + // and all was well + stat = kOfxStatOK; + } + else { + stat = interactMainEntry(action, handle, inArgs, outArgs); + } + + } + catch(...) + { + stat = kOfxStatFailed; + } + + OFX::Log::outdent(); + OFX::Log::print("STOP overlayInteractMainEntry (%s)", actionRaw); + return stat; + } + + }; // end namespace private + +}; // end of namespace diff --git a/third_party/openfx/Support/Library/ofxsLog.cpp b/third_party/openfx/Support/Library/ofxsLog.cpp new file mode 100644 index 000000000..5444a78c4 --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsLog.cpp @@ -0,0 +1,129 @@ + + +/** @file This file contains the body of functions used for logging ofx problems etc... + +The log file is written to using printf style functions, rather than via c++ iostreams. + +*/ + +#include +#include +#include +#include +#include + +#include "ofxsLog.h" + +namespace OFX { + namespace Log { + + /** @brief log file */ + static FILE *gLogFP = 0; + + /// environment variable for the log file +#define kLogFileEnvVar "OFX_PLUGIN_LOGFILE" + + /** @brief the global logfile name */ + static std::string gLogFileName(getenv(kLogFileEnvVar) ? getenv(kLogFileEnvVar) : "ofxPluginLog.txt"); + + /** @brief global indent level, not MP sane */ + static int gIndent = 0; + + /** @brief Sets the name of the log file. */ + void setFileName(const std::string &value) + { + gLogFileName = value; + } + + /** @brief Opens the log file, returns whether this was sucessful or not. */ + bool open(void) + { +#ifdef DEBUG + if(!gLogFP) { + gLogFP = fopen(gLogFileName.c_str(), "a"); + return gLogFP != 0; + } +#endif + return gLogFP != 0; + } + + /** @brief Closes the log file. */ + void close(void) + { + if(gLogFP) { + fclose(gLogFP); + } + gLogFP = 0; + } + + /** @brief Indent it, not MP sane at the moment */ + void indent(void) + { + ++gIndent; + } + + /** @brief Outdent it, not MP sane at the moment */ + void outdent(void) + { + --gIndent; + } + + /** @brief do the indenting */ + static void doIndent(void) + { + if(open()) { + for(int i = 0; i < gIndent; i++) { + fputs(" ", gLogFP); + } + } + } + + /** @brief Prints to the log file. */ + void print(const char *format, ...) + { + if(open()) { + doIndent(); + va_list args; + va_start(args, format); + vfprintf(gLogFP, format, args); + fputc('\n', gLogFP); + fflush(gLogFP); + va_end(args); + } + } + + /** @brief Prints to the log file only if the condition is true and prepends a warning notice. */ + void warning(bool condition, const char *format, ...) + { + if(condition && open()) { + doIndent(); + fputs("WARNING : ", gLogFP); + + va_list args; + va_start(args, format); + vfprintf(gLogFP, format, args); + fputc('\n', gLogFP); + va_end(args); + + fflush(gLogFP); + } + } + + /** @brief Prints to the log file only if the condition is true and prepends an error notice. */ + void error(bool condition, const char *format, ...) + { + if(condition && open()) { + doIndent(); + fputs("ERROR : ", gLogFP); + + va_list args; + va_start(args, format); + vfprintf(gLogFP, format, args); + fputc('\n', gLogFP); + va_end(args); + + fflush(gLogFP); + } + } + }; +}; diff --git a/third_party/openfx/Support/Library/ofxsMultiThread.cpp b/third_party/openfx/Support/Library/ofxsMultiThread.cpp new file mode 100644 index 000000000..ced3592fe --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsMultiThread.cpp @@ -0,0 +1,128 @@ + + +#include "ofxsSupportPrivate.h" + +namespace OFX { + + namespace MultiThread { + + //////////////////////////////////////////////////////////////////////////////// + // SMP class + + /** @brief ctor */ + Processor::Processor(void) + { + } + + /** @brief dtor */ + Processor::~Processor() + { + } + + /** @brief Function to pass to the multi thread suite */ + void Processor::staticMultiThreadFunction(unsigned int threadIndex, unsigned int threadMax, void *customArg) + { + // cast the custom arg to one of me + Processor *me = (Processor *) customArg; + + // and call my thread function + me->multiThreadFunction(threadIndex, threadMax); + } + + /** @brief Function to pass to the multi thread suite */ + void Processor::multiThread(unsigned int nCPUs) + { + // if 0, use all the CPUs we can + if(nCPUs == 0) + nCPUs = OFX::MultiThread::getNumCPUs(); + + // if 1 cpu, don't bother with the threading + if(nCPUs == 1) { + multiThreadFunction(0, 1); + } + else { + // OK do it + OfxStatus stat = kOfxStatFailed; + if(OFX::Private::gThreadSuite){ + stat = OFX::Private::gThreadSuite->multiThread(staticMultiThreadFunction, nCPUs, (void *)this); + } + + // did we do it? + throwSuiteStatusException(stat); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // futility functions + + /** @brief Has the current thread been spawned from an MP */ + bool isSpawnedThread(void) + { + if(OFX::Private::gThreadSuite){ + int v = OFX::Private::gThreadSuite->multiThreadIsSpawnedThread(); + return v != 0; + }else{ + return false; + } + } + + /** @brief The number of CPUs that can be used for MP-ing */ + unsigned int getNumCPUs(void) + { + unsigned int n = 1; + OfxStatus stat = OFX::Private::gThreadSuite ? OFX::Private::gThreadSuite->multiThreadNumCPUs(&n) : kOfxStatFailed; + + if(stat != kOfxStatOK) n = 1; + return n; + } + + /** @brief The index of the current thread. From 0 to numCPUs() - 1 */ + unsigned int getThreadIndex(void) + { + unsigned int n = 0; + OfxStatus stat = OFX::Private::gThreadSuite ? OFX::Private::gThreadSuite->multiThreadIndex(&n) : kOfxStatFailed; + if(stat != kOfxStatOK) n = 0; + return n; + } + + //////////////////////////////////////////////////////////////////////////////// + // MUTEX class + + /** @brief ctor */ + Mutex::Mutex(int lockCount) + : _handle(0) + { + OfxStatus stat = OFX::Private::gThreadSuite ? OFX::Private::gThreadSuite->mutexCreate(&_handle, lockCount) : kOfxStatReplyDefault; + throwSuiteStatusException(stat); + } + + /** @brief dtor */ + Mutex::~Mutex(void) + { + OfxStatus stat = OFX::Private::gThreadSuite ? OFX::Private::gThreadSuite->mutexDestroy(_handle) : kOfxStatReplyDefault; + (void)stat; + } + + /** @brief lock it, blocks until lock is gained */ + void Mutex::lock() + { + OfxStatus stat = OFX::Private::gThreadSuite ? OFX::Private::gThreadSuite->mutexLock(_handle) : kOfxStatReplyDefault; + throwSuiteStatusException(stat); + } + + /** @brief unlock it */ + void Mutex::unlock() + { + OfxStatus stat = OFX::Private::gThreadSuite ? OFX::Private::gThreadSuite->mutexUnLock(_handle) : kOfxStatReplyDefault; + throwSuiteStatusException(stat); + } + + /** @brief attempt to lock, non-blocking */ + bool Mutex::tryLock() + { + OfxStatus stat = OFX::Private::gThreadSuite ? OFX::Private::gThreadSuite->mutexTryLock(_handle) : kOfxStatReplyDefault; + return stat == kOfxStatOK; + } + + }; +}; diff --git a/third_party/openfx/Support/Library/ofxsParams.cpp b/third_party/openfx/Support/Library/ofxsParams.cpp new file mode 100644 index 000000000..0af7d1c40 --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsParams.cpp @@ -0,0 +1,3226 @@ + + +/** @brief This file contains code that skins the ofx param suite */ + +#include +#include +#include "ofxsSupportPrivate.h" +#include "ofxParametricParam.h" + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. */ +namespace OFX { + + /** @brief dummy page positioning parameter to be passed to @ref OFX::PageParamDescriptor::addChild */ + DummyParamDescriptor PageParamDescriptor::gSkipRow(kOfxParamPageSkipRow); + + /** @brief dummy page positioning parameter to be passed to @ref OFX::PageParamDescriptor::addChild */ + DummyParamDescriptor PageParamDescriptor::gSkipColumn(kOfxParamPageSkipColumn); + + /** @brief turns a ParamTypeEnum into the char * that raw OFX uses */ + const char * mapParamTypeEnumToString(ParamTypeEnum v) + { + switch(v) + { + case eStringParam : return kOfxParamTypeString ; + case eIntParam : return kOfxParamTypeInteger ; + case eInt2DParam : return kOfxParamTypeInteger2D ; + case eInt3DParam : return kOfxParamTypeInteger3D ; + case eDoubleParam : return kOfxParamTypeDouble ; + case eDouble2DParam : return kOfxParamTypeDouble2D ; + case eDouble3DParam : return kOfxParamTypeDouble3D ; + case eRGBParam : return kOfxParamTypeRGB ; + case eRGBAParam : return kOfxParamTypeRGBA ; + case eBooleanParam : return kOfxParamTypeBoolean ; + case eChoiceParam : return kOfxParamTypeChoice ; + case eStrChoiceParam : return kOfxParamTypeStrChoice; + case eCustomParam : return kOfxParamTypeCustom ; + case eGroupParam : return kOfxParamTypeGroup ; + case ePageParam : return kOfxParamTypePage ; + case ePushButtonParam : return kOfxParamTypePushButton ; + case eParametricParam : return kOfxParamTypeParametric ; + default: assert(false); + } + return kOfxParamTypeInteger; + } + + static + bool isEqual(const char* t1, const char* t2) + { + return strcmp(t1, t2)==0; + } + + static + ParamTypeEnum mapParamTypeStringToEnum(const char * v) + { + if(isEqual(kOfxParamTypeString,v)) + return eStringParam ; + else if(isEqual(kOfxParamTypeInteger,v)) + return eIntParam ; + else if(isEqual(kOfxParamTypeInteger2D,v)) + return eInt2DParam ; + else if(isEqual(kOfxParamTypeInteger3D,v)) + return eInt3DParam ; + else if(isEqual(kOfxParamTypeDouble,v)) + return eDoubleParam ; + else if(isEqual(kOfxParamTypeDouble2D,v)) + return eDouble2DParam ; + else if(isEqual(kOfxParamTypeDouble3D,v)) + return eDouble3DParam ; + else if(isEqual(kOfxParamTypeRGB,v)) + return eRGBParam ; + else if(isEqual(kOfxParamTypeRGBA,v)) + return eRGBAParam ; + else if(isEqual(kOfxParamTypeBoolean,v)) + return eBooleanParam ; + else if(isEqual(kOfxParamTypeChoice,v)) + return eChoiceParam ; + else if (isEqual(kOfxParamTypeStrChoice, v)) + return eStrChoiceParam; + else if(isEqual(kOfxParamTypeCustom ,v)) + return eCustomParam ; + else if(isEqual(kOfxParamTypeGroup,v)) + return eGroupParam ; + else if(isEqual(kOfxParamTypePage,v)) + return ePageParam ; + else if(isEqual(kOfxParamTypePushButton,v)) + return ePushButtonParam ; + else if(isEqual(kOfxParamTypeParametric,v)) + return eParametricParam ; + else + assert(false); + return ePushButtonParam ; + } + + //////////////////////////////////////////////////////////////////////////////// + // the base class for all param descriptors + + /** @brief ctor */ + ParamDescriptor::ParamDescriptor(const std::string &name, ParamTypeEnum type, OfxPropertySetHandle props) + : _paramName(name) + , _paramType(type) + , _paramProps(props) + { + // validate the properities on this descriptor + if(type != eDummyParam) + OFX::Validation::validateParameterProperties(type, props, true); + } + + ParamDescriptor::~ParamDescriptor() + { + } + + /** @brief set the label property */ + void + ParamDescriptor::setLabel(const std::string &label) + { + _paramProps.propSetString(kOfxPropLabel, label); + } + + /** @brief set the label properties */ + void + ParamDescriptor::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel) + { + setLabel(label); + _paramProps.propSetString(kOfxPropShortLabel, shortLabel, false); + _paramProps.propSetString(kOfxPropLongLabel, longLabel, false); + } + + /** @brief set the param hint */ + void + ParamDescriptor::setHint(const std::string &v) + { + _paramProps.propSetString(kOfxParamPropHint, v, false); + } + + /** @brief set the script name, default is the name it was defined with */ + void + ParamDescriptor::setScriptName(const std::string &v) + { + _paramProps.propSetString(kOfxParamPropScriptName, v, false); + } + + /** @brief set the secretness of the param, defaults to false */ + void + ParamDescriptor::setIsSecret(bool v) + { + _paramProps.propSetInt(kOfxParamPropSecret, v); + } + + /** @brief set the if the param is enabled, defaults to true */ + void + ParamDescriptor::setEnabled(bool v) + { + _paramProps.propSetInt(kOfxParamPropEnabled, v); + } + + /** @brief set the group param that is the parent of this one, default is to be ungrouped at the root level */ + void + ParamDescriptor::setParent(const GroupParamDescriptor &v) + { + _paramProps.propSetString(kOfxParamPropParent, v.getName()); + } + + /** @brief set the icon file name (SVG or PNG) */ + void + ParamDescriptor::setIcon(const std::string &v, bool pngFormat) + { + _paramProps.propSetString(kOfxPropIcon, v, (int)pngFormat, false); // introduced in OFX 1.2 + } + + bool + ParamDescriptor::getHostHasNativeOverlayHandle() const + { + bool v = _paramProps.propGetInt(kOfxParamPropHasHostOverlayHandle, 0, false) != 0; // OFX 1.2 + return v; + } + + void + ParamDescriptor::setUseHostNativeOverlayHandle(bool use) + { + _paramProps.propSetInt(kOfxParamPropUseHostOverlayHandle, use, 0, false); // OFX 1.2 + } + + //////////////////////////////////////////////////////////////////////////////// + // the base class for all params that can hold a value + + /** @brief ctor */ + ValueParamDescriptor::ValueParamDescriptor(const std::string &name, ParamTypeEnum type, OfxPropertySetHandle props) + : ParamDescriptor(name, type, props) + { + } + + /** @brief dtor */ + ValueParamDescriptor::~ValueParamDescriptor() + { + } + + /** @brief set whether the param can animate, defaults to true in most cases */ + void ValueParamDescriptor::setAnimates(bool v) + { + _paramProps.propSetInt(kOfxParamPropAnimates, v); + } + + /** @brief set whether the param is persistant, defaults to true */ + void ValueParamDescriptor::setIsPersistant(bool v) + { + _paramProps.propSetInt(kOfxParamPropPersistant, v); + } + + /** @brief Set's whether the value of the param is significant (ie: affects the rendered image), defaults to true */ + void ValueParamDescriptor::setEvaluateOnChange(bool v) + { + _paramProps.propSetInt(kOfxParamPropEvaluateOnChange, v); + } + + /** @brief Set's whether the value of the param is significant (ie: affects the rendered image), defaults to true */ + void ValueParamDescriptor::setCanUndo(bool v) + { + _paramProps.propSetInt(kOfxParamPropCanUndo, v, 0, false); + } + + /** @brief Set's how any cache should be invalidated if the parameter is changed, defaults to eCacheInvalidateValueChange */ + void ValueParamDescriptor::setCacheInvalidation(CacheInvalidationEnum v) + { + switch(v) + { + case eCacheInvalidateValueChange : + _paramProps.propSetString(kOfxParamPropCacheInvalidation, kOfxParamInvalidateValueChange); + break; + + case eCacheInvalidateValueChangeToEnd : + _paramProps.propSetString(kOfxParamPropCacheInvalidation, kOfxParamInvalidateValueChangeToEnd); + break; + + case eCacheInvalidateValueAll : + _paramProps.propSetString(kOfxParamPropCacheInvalidation, kOfxParamInvalidateAll); + break; + } + } + + void ValueParamDescriptor::setInteractDescriptor(ParamInteractDescriptor* desc) + { + _interact.reset(desc); + _paramProps.propSetPointer(kOfxParamPropInteractV1, (void*)desc->getMainEntry()); + desc->setParamName(getName()); + } + + //////////////////////////////////////////////////////////////////////////////// + // int param descriptor + + /** @brief ctor */ + IntParamDescriptor::IntParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eIntParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void + IntParamDescriptor::setDefault(int v) + { + _paramProps.propSetInt(kOfxParamPropDefault, v); + } + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void + IntParamDescriptor::setRange(int min, int max) + { + _paramProps.propSetInt(kOfxParamPropMin, min); + _paramProps.propSetInt(kOfxParamPropMax, max); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + IntParamDescriptor::setDisplayRange(int min, int max) + { + _paramProps.propSetInt(kOfxParamPropDisplayMin, min); + _paramProps.propSetInt(kOfxParamPropDisplayMax, max); + } + + //////////////////////////////////////////////////////////////////////////////// + // 2D int param descriptor + + /** @brief ctor */ + Int2DParamDescriptor::Int2DParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eInt2DParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void + Int2DParamDescriptor::setDefault(int x, int y) + { + _paramProps.propSetInt(kOfxParamPropDefault, x, 0); + _paramProps.propSetInt(kOfxParamPropDefault, y, 1); + } + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void + Int2DParamDescriptor::setRange(int xmin, int ymin, + int xmax, int ymax) + { + _paramProps.propSetInt(kOfxParamPropMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropMax, ymax, 1); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Int2DParamDescriptor::setDisplayRange(int xmin, int ymin, + int xmax, int ymax) + { + _paramProps.propSetInt(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMax, ymax, 1); + } + + void Int2DParamDescriptor::setDimensionLabels(const std::string& x, const std::string& y) + { + _paramProps.propSetString(kOfxParamPropDimensionLabel, x, 0, false); + _paramProps.propSetString(kOfxParamPropDimensionLabel, y, 1, false); + } + + //////////////////////////////////////////////////////////////////////////////// + // 3D int param descriptor + + /** @brief ctor */ + Int3DParamDescriptor::Int3DParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eInt3DParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void + Int3DParamDescriptor::setDefault(int x, int y, int z) + { + _paramProps.propSetInt(kOfxParamPropDefault, x, 0); + _paramProps.propSetInt(kOfxParamPropDefault, y, 1); + _paramProps.propSetInt(kOfxParamPropDefault, z, 2); + } + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void + Int3DParamDescriptor::setRange(int xmin, int ymin, int zmin, + int xmax, int ymax, int zmax) + { + _paramProps.propSetInt(kOfxParamPropMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropMin, zmin, 2); + _paramProps.propSetInt(kOfxParamPropMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropMax, ymax, 1); + _paramProps.propSetInt(kOfxParamPropMax, zmax, 2); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Int3DParamDescriptor::setDisplayRange(int xmin, int ymin, int zmin, + int xmax, int ymax, int zmax) + { + _paramProps.propSetInt(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropDisplayMin, zmin, 2); + _paramProps.propSetInt(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMax, ymax, 1); + _paramProps.propSetInt(kOfxParamPropDisplayMax, zmax, 2); + } + + void Int3DParamDescriptor::setDimensionLabels(const std::string& x, const std::string& y, const std::string& z) + { + _paramProps.propSetString(kOfxParamPropDimensionLabel, x, 0, false); + _paramProps.propSetString(kOfxParamPropDimensionLabel, y, 1, false); + _paramProps.propSetString(kOfxParamPropDimensionLabel, z, 2, false); + } + + //////////////////////////////////////////////////////////////////////////////// + // base class for all double param descriptors + + /** @brief hidden constructor */ + BaseDoubleParamDescriptor::BaseDoubleParamDescriptor(const std::string &name, ParamTypeEnum type, OfxPropertySetHandle props) + : ValueParamDescriptor(name, type, props) + { + } + + /** @brief set the type of the double param, defaults to eDoubleTypePlain */ + void BaseDoubleParamDescriptor::setDoubleType(DoubleTypeEnum v) + { + switch(v) + { + case eDoubleTypePlain : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypePlain); + break; + case eDoubleTypeAngle : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeAngle); + break; + case eDoubleTypeScale : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeScale); + break; + case eDoubleTypeTime : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeTime); + break; + case eDoubleTypeAbsoluteTime : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeAbsoluteTime); + break; + case eDoubleTypeX : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeX); + break; + case eDoubleTypeXAbsolute : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeXAbsolute); + break; + case eDoubleTypeY : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeY); + break; + case eDoubleTypeYAbsolute : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeYAbsolute); + break; + case eDoubleTypeXY : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeXY); + break; + case eDoubleTypeXYAbsolute : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeXYAbsolute); + break; +#ifdef kOfxParamDoubleTypeNormalisedX + case eDoubleTypeNormalisedX : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeNormalisedX); + break; + case eDoubleTypeNormalisedY : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeNormalisedY); + break; + case eDoubleTypeNormalisedXAbsolute : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeNormalisedXAbsolute); + break; + case eDoubleTypeNormalisedYAbsolute : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeNormalisedYAbsolute); + break; + case eDoubleTypeNormalisedXY : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeNormalisedXY); + break; + case eDoubleTypeNormalisedXYAbsolute : + _paramProps.propSetString(kOfxParamPropDoubleType, kOfxParamDoubleTypeNormalisedXYAbsolute); + break; +#endif + } + } + + /** @brief set the type of coordinate system for default values */ + void BaseDoubleParamDescriptor::setDefaultCoordinateSystem(DefaultCoordinateSystemEnum v) + { + try { + // this property was introduced with OpenFX 1.2 + switch(v) + { + case eCoordinatesCanonical : + _paramProps.propSetString(kOfxParamPropDefaultCoordinateSystem, kOfxParamCoordinatesCanonical); + break; + case eCoordinatesNormalised : + _paramProps.propSetString(kOfxParamPropDefaultCoordinateSystem, kOfxParamCoordinatesNormalised); + break; + } + } catch (std::exception&) { + } + } + + /** @brief set the sensitivity of any gui slider */ + void BaseDoubleParamDescriptor::setIncrement(double v) + { + _paramProps.propSetDouble(kOfxParamPropIncrement, v); + } + + /** @brief set the number of digits printed after a decimal point in any gui */ + void BaseDoubleParamDescriptor::setDigits(int v) + { + _paramProps.propSetInt(kOfxParamPropDigits, v); + } + + //////////////////////////////////////////////////////////////////////////////// + // double param descriptor + + /** @brief ctor */ + DoubleParamDescriptor::DoubleParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : BaseDoubleParamDescriptor(name, eDoubleParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void + DoubleParamDescriptor::setDefault(double v) + { + _paramProps.propSetDouble(kOfxParamPropDefault, v); + } + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void + DoubleParamDescriptor::setRange(double min, double max) + { + _paramProps.propSetDouble(kOfxParamPropMin, min); + _paramProps.propSetDouble(kOfxParamPropMax, max); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + DoubleParamDescriptor::setDisplayRange(double min, double max) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, min); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, max); + } + + //////////////////////////////////////////////////////////////////////////////// + // 2D double param descriptor + + /** @brief ctor */ + Double2DParamDescriptor::Double2DParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : BaseDoubleParamDescriptor(name, eDouble2DParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void + Double2DParamDescriptor::setDefault(double x, double y) + { + _paramProps.propSetDouble(kOfxParamPropDefault, x, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, y, 1); + } + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void + Double2DParamDescriptor::setRange(double xmin, double ymin, + double xmax, double ymax) + { + _paramProps.propSetDouble(kOfxParamPropMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropMax, ymax, 1); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Double2DParamDescriptor::setDisplayRange(double xmin, double ymin, + double xmax, double ymax) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, ymax, 1); + } + + void Double2DParamDescriptor::setDimensionLabels(const std::string& x, const std::string& y) + { + _paramProps.propSetString(kOfxParamPropDimensionLabel, x, 0); + _paramProps.propSetString(kOfxParamPropDimensionLabel, y, 1); + } + + /** @brief set kOfxParamPropUseHostOverlayHandle */ + void Double2DParamDescriptor::setUseHostOverlayHandle(bool v) + { + _paramProps.propSetInt(kOfxParamPropUseHostOverlayHandle, v); + } + + //////////////////////////////////////////////////////////////////////////////// + // 3D double param descriptor + + /** @brief ctor */ + Double3DParamDescriptor::Double3DParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : BaseDoubleParamDescriptor(name, eDouble3DParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void + Double3DParamDescriptor::setDefault(double x, double y, double z) + { + _paramProps.propSetDouble(kOfxParamPropDefault, x, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, y, 1); + _paramProps.propSetDouble(kOfxParamPropDefault, z, 2); + } + + /** @brief set the hard min/max range, default is -DBL_MAX, DBL_MAX */ + void + Double3DParamDescriptor::setRange(double xmin, double ymin, double zmin, + double xmax, double ymax, double zmax) + { + _paramProps.propSetDouble(kOfxParamPropMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropMin, zmin, 2); + _paramProps.propSetDouble(kOfxParamPropMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropMax, ymax, 1); + _paramProps.propSetDouble(kOfxParamPropMax, zmax, 2); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Double3DParamDescriptor::setDisplayRange(double xmin, double ymin, double zmin, + double xmax, double ymax, double zmax) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, zmin, 2); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, ymax, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, zmax, 2); + } + + void Double3DParamDescriptor::setDimensionLabels(const std::string& x, const std::string& y, const std::string& z) + { + _paramProps.propSetString(kOfxParamPropDimensionLabel, x, 0); + _paramProps.propSetString(kOfxParamPropDimensionLabel, y, 1); + _paramProps.propSetString(kOfxParamPropDimensionLabel, z, 2); + } + + //////////////////////////////////////////////////////////////////////////////// + // RGB param descriptor + + /** @brief hidden constructor */ + RGBParamDescriptor::RGBParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eRGBParam, props) + { + } + + /** @brief set the default value */ + void RGBParamDescriptor::setDefault(double r, double g, double b) + { + _paramProps.propSetDouble(kOfxParamPropDefault, r, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, g, 1); + _paramProps.propSetDouble(kOfxParamPropDefault, b, 2); + } + + /** @brief set the hard min/max range, default is 0., 1. */ + void + RGBParamDescriptor::setRange(double rmin, double gmin, double bmin, + double rmax, double gmax, double bmax) + { + _paramProps.propSetDouble(kOfxParamPropMin, rmin, 0); + _paramProps.propSetDouble(kOfxParamPropMin, gmin, 1); + _paramProps.propSetDouble(kOfxParamPropMin, bmin, 2); + _paramProps.propSetDouble(kOfxParamPropMax, rmax, 0); + _paramProps.propSetDouble(kOfxParamPropMax, gmax, 1); + _paramProps.propSetDouble(kOfxParamPropMax, bmax, 2); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + RGBParamDescriptor::setDisplayRange(double rmin, double gmin, double bmin, + double rmax, double gmax, double bmax) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, rmin, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, gmin, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, bmin, 2); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, rmax, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, gmax, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, bmax, 2); + } + + void RGBParamDescriptor::setDimensionLabels(const std::string& r, const std::string& g, const std::string& b) + { + _paramProps.propSetString(kOfxParamPropDimensionLabel, r, 0); + _paramProps.propSetString(kOfxParamPropDimensionLabel, g, 1); + _paramProps.propSetString(kOfxParamPropDimensionLabel, b, 2); + } + + //////////////////////////////////////////////////////////////////////////////// + // RGBA param descriptor + + /** @brief hidden constructor */ + RGBAParamDescriptor::RGBAParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eRGBAParam, props) + { + } + + /** @brief set the default value */ + void RGBAParamDescriptor::setDefault(double r, double g, double b, double a) + { + _paramProps.propSetDouble(kOfxParamPropDefault, r, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, g, 1); + _paramProps.propSetDouble(kOfxParamPropDefault, b, 2); + _paramProps.propSetDouble(kOfxParamPropDefault, a, 3); + } + + + /** @brief set the hard min/max range, default is 0., 1. */ + void + RGBAParamDescriptor::setRange(double rmin, double gmin, double bmin, double amin, + double rmax, double gmax, double bmax, double amax) + { + _paramProps.propSetDouble(kOfxParamPropMin, rmin, 0); + _paramProps.propSetDouble(kOfxParamPropMin, gmin, 1); + _paramProps.propSetDouble(kOfxParamPropMin, bmin, 2); + _paramProps.propSetDouble(kOfxParamPropMin, amin, 3); + _paramProps.propSetDouble(kOfxParamPropMax, rmax, 0); + _paramProps.propSetDouble(kOfxParamPropMax, gmax, 1); + _paramProps.propSetDouble(kOfxParamPropMax, bmax, 2); + _paramProps.propSetDouble(kOfxParamPropMax, amax, 3); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + RGBAParamDescriptor::setDisplayRange(double rmin, double gmin, double bmin, double amin, + double rmax, double gmax, double bmax, double amax) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, rmin, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, gmin, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, bmin, 2); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, amin, 3); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, rmax, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, gmax, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, bmax, 2); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, amax, 3); + } + + void RGBAParamDescriptor::setDimensionLabels(const std::string& r, const std::string& g, const std::string& b, const std::string& a) + { + _paramProps.propSetString(kOfxParamPropDimensionLabel, r, 0); + _paramProps.propSetString(kOfxParamPropDimensionLabel, g, 1); + _paramProps.propSetString(kOfxParamPropDimensionLabel, b, 2); + _paramProps.propSetString(kOfxParamPropDimensionLabel, a, 3); + } + + //////////////////////////////////////////////////////////////////////////////// + // bool param descriptor + + /** @brief hidden constructor */ + BooleanParamDescriptor::BooleanParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eBooleanParam, props) + { + } + + /** @brief set the default value */ + void BooleanParamDescriptor::setDefault(bool v) + { + _paramProps.propSetInt(kOfxParamPropDefault, int(v)); + } + + //////////////////////////////////////////////////////////////////////////////// + // choice param descriptor + + /** @brief hidden constructor */ + ChoiceParamDescriptor::ChoiceParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eChoiceParam, props) + { + } + + /** @brief set the default value */ + void ChoiceParamDescriptor::setDefault(int v) + { + _paramProps.propSetInt(kOfxParamPropDefault, v); + } + + /** @brief how many options do we have */ + int ChoiceParamDescriptor::getNOptions(void) + { + int nCurrentValues = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + return nCurrentValues; + } + + /** @brief append an option to the choice param */ + void ChoiceParamDescriptor::appendOption(const std::string &v, const std::string& label, const int order) + { + int nCurrentValues = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + _paramProps.propSetString(kOfxParamPropChoiceOption, v, nCurrentValues); + if(!label.empty()) { + { + // If the kOfxParamPropChoiceLabelOption doesn't exist, we put that information into the Hint. + // It's better than nothing... + std::string hint = _paramProps.propGetString(kOfxParamPropHint); + if(!hint.empty()) { + hint += "\n"; + if( nCurrentValues == 0 ) { + hint += "\n"; + } + } + hint += v + ": " + label; + _paramProps.propSetString(kOfxParamPropHint, hint); + } + } + if (order != INT_MIN) { + // Host may not support this prop (added in 1.5); continue without it. + _paramProps.propSetInt(kOfxParamPropChoiceOrder, order, nCurrentValues, false); + } + } + + /** @brief reset all options */ + void ChoiceParamDescriptor::resetOptions(void) + { + _paramProps.propReset(kOfxParamPropChoiceOption); + } + + //////////////////////////////////////////////////////////////////////////////// + // string choice param descriptor + + /** @brief hidden constructor */ + StrChoiceParamDescriptor::StrChoiceParamDescriptor(const std::string& p_Name, OfxPropertySetHandle p_Props) + : ValueParamDescriptor(p_Name, eStrChoiceParam, p_Props) + { + } + + /** @brief set the default value */ + void StrChoiceParamDescriptor::setDefault(const std::string& p_DefaultValue) + { + _paramProps.propSetString(kOfxParamPropDefault, p_DefaultValue); + } + + /** @brief append an option */ + void StrChoiceParamDescriptor::appendOption(const std::string& p_Enum, const std::string& p_Option, int order) + { + const int numOptions = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + assert(numOptions == _paramProps.propGetDimension(kOfxParamPropChoiceEnum)); + + _paramProps.propSetString(kOfxParamPropChoiceEnum, p_Enum, numOptions); + _paramProps.propSetString(kOfxParamPropChoiceOption, p_Option, numOptions); + + if (order != INT_MIN) { + // Host may not support this prop (added in 1.5); continue without it. + _paramProps.propSetInt(kOfxParamPropChoiceOrder, order, numOptions, false); + } + } + + /** @brief how many options do we have */ + int StrChoiceParamDescriptor::getNOptions() + { + const int numOptions = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + assert(numOptions == _paramProps.propGetDimension(kOfxParamPropChoiceEnum)); + + return numOptions; + } + + /** @brief clear all the options so as to add some new ones in */ + void StrChoiceParamDescriptor::resetOptions(void) + { + _paramProps.propReset(kOfxParamPropChoiceEnum); + _paramProps.propReset(kOfxParamPropChoiceOption); + } + + //////////////////////////////////////////////////////////////////////////////// + // string param descriptor + + /** @brief hidden ctor */ + StringParamDescriptor::StringParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eStringParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void StringParamDescriptor::setDefault(const std::string &v) + { + _paramProps.propSetString(kOfxParamPropDefault, v); + } + + /** @brief sets the kind of the string param, defaults to eStringSingleLine */ + void StringParamDescriptor::setStringType(StringTypeEnum v) + { + switch (v) + { + case eStringTypeSingleLine : + _paramProps.propSetString(kOfxParamPropStringMode, kOfxParamStringIsSingleLine); + break; + case eStringTypeMultiLine : + _paramProps.propSetString(kOfxParamPropStringMode, kOfxParamStringIsMultiLine); + break; + case eStringTypeFilePath : + _paramProps.propSetString(kOfxParamPropStringMode, kOfxParamStringIsFilePath); + break; + case eStringTypeDirectoryPath : + _paramProps.propSetString(kOfxParamPropStringMode, kOfxParamStringIsDirectoryPath); + break; + case eStringTypeLabel : + _paramProps.propSetString(kOfxParamPropStringMode, kOfxParamStringIsLabel); + break; + case eStringTypeRichTextFormat : + _paramProps.propSetString(kOfxParamPropStringMode, kOfxParamStringIsRichTextFormat); + break; + } + } + + /** @brief if the string param is a file path, say that we are picking an existing file, defaults to true */ + void StringParamDescriptor::setFilePathExists(bool v) + { + _paramProps.propSetInt(kOfxParamPropStringFilePathExists, int(v)); + } + + //////////////////////////////////////////////////////////////////////////////// + // custom param descriptor + + /** @brief hidden ctor */ + CustomParamDescriptor::CustomParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ValueParamDescriptor(name, eCustomParam, props) + { + } + + /** @brief set the default value, default is 0 */ + void CustomParamDescriptor::setDefault(const std::string &v) + { + _paramProps.propSetString(kOfxParamPropDefault, v); + } + + void CustomParamDescriptor::setCustomInterpolation(bool v) + { + _paramProps.propSetPointer(kOfxParamPropCustomInterpCallbackV1, v ? (void*)OFX::Private::customParamInterpolationV1Entry : NULL); + } + + //////////////////////////////////////////////////////////////////////////////// + // group param descriptor + + /** @brief hidden constructor */ + GroupParamDescriptor::GroupParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ParamDescriptor(name, eGroupParam, props) + { + } + + /** @brief whether the initial state of a group is open or closed in a hierarchical layout, defaults to true */ + void GroupParamDescriptor::setOpen(const bool v) + { + _paramProps.propSetInt(kOfxParamPropGroupOpen, v, false); // introduced in OFX 1.2 + } + + //////////////////////////////////////////////////////////////////////////////// + // page param descriptor + + /** @brief hidden constructor */ + PageParamDescriptor::PageParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ParamDescriptor(name, ePageParam, props) + { + } + + /** @brief adds a child parameter. Note the two existing pseudo params, gColumnSkip and gRowSkip */ + void PageParamDescriptor::addChild(const ParamDescriptor &p) + { + int nKids = _paramProps.propGetDimension(kOfxParamPropPageChild); + _paramProps.propSetString(kOfxParamPropPageChild, p.getName(), nKids); + } + + //////////////////////////////////////////////////////////////////////////////// + // pushbutton param descriptor + + /** @brief hidden constructor */ + PushButtonParamDescriptor::PushButtonParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ParamDescriptor(name, ePushButtonParam, props) + { + } + + //////////////////////////////////////////////////////////////////////////////// + // parametric param descriptor + + /** @brief hidden constructor */ + ParametricParamDescriptor::ParametricParamDescriptor(const std::string &name, OfxPropertySetHandle props) + : ParamDescriptor(name, eParametricParam, props) + , _ofxParamHandle(0) + , _paramSet(0) + { + } + + void ParametricParamDescriptor::setParamSet(ParamSetDescriptor& paramSet) + { + _paramSet = ¶mSet; + OFX::Private::gParamSuite->paramGetHandle(_paramSet->getParamSetHandle(), getName().c_str(), &_ofxParamHandle, 0); + } + + void ParametricParamDescriptor::setRange(const double min, const double max) + { + _paramProps.propSetDouble(kOfxParamPropParametricRange, min, 0); + _paramProps.propSetDouble(kOfxParamPropParametricRange, max, 1); + } + + void ParametricParamDescriptor::setDimension(const int dimension) + { + _paramProps.propSetInt(kOfxParamPropParametricDimension, dimension); + } + + void ParametricParamDescriptor::setDimensionLabel(const std::string& label, const int id) + { + _paramProps.propSetString(kOfxParamPropDimensionLabel, label, id); + } + + void ParametricParamDescriptor::setUIColour(const int id, const OfxRGBColourD& color) + { + _paramProps.propSetDouble(kOfxParamPropParametricUIColour, color.r, id*3 + 0); + _paramProps.propSetDouble(kOfxParamPropParametricUIColour, color.g, id*3 + 1); + _paramProps.propSetDouble(kOfxParamPropParametricUIColour, color.b, id*3 + 2); + } + + void ParametricParamDescriptor::addControlPoint(const int id, const OfxTime time, const double x, const double y, const bool addKey) + { + OFX::Private::gParametricParameterSuite->parametricParamAddControlPoint(_ofxParamHandle, id, time, x, y, addKey); + } + + void ParametricParamDescriptor::setIdentity(const int id) + { + addControlPoint(id, 0, 0, 0, false); + addControlPoint(id, 0, 1, 1, false); + } + + void ParametricParamDescriptor::setIdentity() + { + const int nbCurves = _paramProps.propGetInt(kOfxParamPropParametricDimension); + for(int i = 0; i < nbCurves; ++i) { + setIdentity(i); + } + } + + void ParametricParamDescriptor::setInteractDescriptor(ParamInteractDescriptor* desc) + { + _interact.reset(desc); + _paramProps.propSetPointer(kOfxParamPropParametricInteractBackground, (void*)desc->getMainEntry()); + desc->setParamName(getName()); + } + + //////////////////////////////////////////////////////////////////////////////// + // Descriptor for a set of parameters + /** @brief hidden ctor */ + ParamSetDescriptor::ParamSetDescriptor(void) + : _paramSetHandle(0) + { + } + + ParamDescriptor* ParamSetDescriptor::getParamDescriptor(const std::string& name) const + { + std::map::const_iterator it = _definedParams.find(name); + if(it!=_definedParams.end()) + return it->second; + return 0; + } + + /** @brief set the param set handle */ + void + ParamSetDescriptor::setParamSetHandle(OfxParamSetHandle h) + { + // set me handle + _paramSetHandle = h; + + if(h) { + // fetch me props + OfxPropertySetHandle props; + OfxStatus stat = OFX::Private::gParamSuite->paramSetGetPropertySet(h, &props); + _paramSetProps.propSetHandle(props); + throwSuiteStatusException(stat); + } + else { + _paramSetProps.propSetHandle(0); + } + } + + /** @brief dtor */ + ParamSetDescriptor::~ParamSetDescriptor() + { + // delete any descriptor we may have constructed + std::map::iterator iter; + for(iter = _definedParams.begin(); iter != _definedParams.end(); ++iter) { + if(iter->second) { + delete iter->second; + iter->second = NULL; + } + } + } + + /** @brief estabilishes the order of page params. Do it by calling it in turn for each page */ + void + ParamSetDescriptor::setPageParamOrder(PageParamDescriptor &p) + { + int nPages = _paramSetProps.propGetDimension(kOfxPluginPropParamPageOrder); + _paramSetProps.propSetString(kOfxPluginPropParamPageOrder, p.getName().c_str(), nPages); + } + + + /** @brief calls the raw OFX routine to define a param */ + void ParamSetDescriptor::defineRawParam(const std::string &name, ParamTypeEnum paramType, OfxPropertySetHandle &props) + { + OfxStatus stat = OFX::Private::gParamSuite->paramDefine(_paramSetHandle, mapParamTypeEnumToString(paramType), name.c_str(), &props); + throwSuiteStatusException(stat); + } + + /** @brief if a param has been defined in this set, go find it */ + ParamDescriptor * + ParamSetDescriptor::findPreviouslyDefinedParam(const std::string &name) + { + // search + std::map::const_iterator search; + search = _definedParams.find(name); + if(search == _definedParams.end()) + return NULL; + return search->second; + } + + /** @brief Define an integer param, only callable from describe in context */ + IntParamDescriptor * + ParamSetDescriptor::defineIntParam(const std::string &name) + { + IntParamDescriptor *param = NULL; + defineParamDescriptor(name, eIntParam, param); + return param; + } + + /** @brief Define a 2D integer param */ + Int2DParamDescriptor *ParamSetDescriptor::defineInt2DParam(const std::string &name) + { + Int2DParamDescriptor *param = NULL; + defineParamDescriptor(name, eInt2DParam, param); + return param; + } + + /** @brief Define a 3D integer param */ + Int3DParamDescriptor *ParamSetDescriptor::defineInt3DParam(const std::string &name) + { + Int3DParamDescriptor *param = NULL; + defineParamDescriptor(name, eInt3DParam, param); + return param; + } + + /** @brief Define an double param, only callable from describe in context */ + DoubleParamDescriptor * + ParamSetDescriptor::defineDoubleParam(const std::string &name) + { + DoubleParamDescriptor *param = NULL; + defineParamDescriptor(name, eDoubleParam, param); + return param; + } + + /** @brief Define a 2D double param */ + Double2DParamDescriptor *ParamSetDescriptor::defineDouble2DParam(const std::string &name) + { + Double2DParamDescriptor *param = NULL; + defineParamDescriptor(name, eDouble2DParam, param); + return param; + } + + /** @brief Define a 3D double param */ + Double3DParamDescriptor *ParamSetDescriptor::defineDouble3DParam(const std::string &name) + { + Double3DParamDescriptor *param = NULL; + defineParamDescriptor(name, eDouble3DParam, param); + return param; + } + + /** @brief Define a string param */ + StringParamDescriptor *ParamSetDescriptor::defineStringParam(const std::string &name) + { + StringParamDescriptor *param = NULL; + defineParamDescriptor(name, eStringParam, param); + return param; + } + + /** @brief Define a RGBA param */ + RGBAParamDescriptor *ParamSetDescriptor::defineRGBAParam(const std::string &name) + { + RGBAParamDescriptor *param = NULL; + defineParamDescriptor(name, eRGBAParam, param); + return param; + } + + /** @brief Define an RGB param */ + RGBParamDescriptor *ParamSetDescriptor::defineRGBParam(const std::string &name) + { + RGBParamDescriptor *param = NULL; + defineParamDescriptor(name, eRGBParam, param); + return param; + } + + /** @brief Define a Boolean param */ + BooleanParamDescriptor *ParamSetDescriptor::defineBooleanParam(const std::string &name) + { + BooleanParamDescriptor *param = NULL; + defineParamDescriptor(name, eBooleanParam, param); + return param; + } + + /** @brief Define a Choice param */ + ChoiceParamDescriptor *ParamSetDescriptor::defineChoiceParam(const std::string &name) + { + ChoiceParamDescriptor *param = NULL; + defineParamDescriptor(name, eChoiceParam, param); + return param; + } + + /** @brief Define a String Choice param */ + StrChoiceParamDescriptor* ParamSetDescriptor::defineStrChoiceParam(const std::string& p_Name) + { + StrChoiceParamDescriptor* param = NULL; + defineParamDescriptor(p_Name, eStrChoiceParam, param); + return param; + } + + /** @brief Define a group param */ + GroupParamDescriptor *ParamSetDescriptor::defineGroupParam(const std::string &name) + { + GroupParamDescriptor *param = NULL; + defineParamDescriptor(name, eGroupParam, param); + return param; + } + + /** @brief Define a Page param */ + PageParamDescriptor *ParamSetDescriptor::definePageParam(const std::string &name) + { + PageParamDescriptor *param = NULL; + defineParamDescriptor(name, ePageParam, param); + return param; + } + + /** @brief Define a push button param */ + PushButtonParamDescriptor *ParamSetDescriptor::definePushButtonParam(const std::string &name) + { + PushButtonParamDescriptor *param = NULL; + defineParamDescriptor(name, ePushButtonParam, param); + return param; + } + + /** @brief Define a parametric param */ + ParametricParamDescriptor* ParamSetDescriptor::defineParametricParam(const std::string &name) + { + ParametricParamDescriptor* param = NULL; + if (defineParamDescriptor(name, eParametricParam, param)) { + // Parametric parameters need the ParamSet ! + param->setParamSet(*this); + } + return param; + } + + /** @brief Define a custom param */ + CustomParamDescriptor *ParamSetDescriptor::defineCustomParam(const std::string &name) + { + CustomParamDescriptor *param = NULL; + defineParamDescriptor(name, eCustomParam, param); + return param; + } + + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Base class for all param instances */ + Param::Param(const ParamSet *paramSet, const std::string &name, ParamTypeEnum type, OfxParamHandle handle) + : _paramSet(paramSet) + , _paramName(name) + , _paramType(type) + , _paramHandle(handle) + { + // fetch our property handle + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gParamSuite->paramGetPropertySet(handle, &propHandle); + throwSuiteStatusException(stat); + _paramProps.propSetHandle(propHandle); + + // and validate the properties + OFX::Validation::validateParameterProperties(type, _paramProps, false); + } + + /** @brief dtor */ + Param::~Param() + { + } + + /** @brief get name */ + const std::string &Param::getName(void) const + { + return _paramName; + } + + /** @brief, set the label properties in a param */ + void Param::setLabel(const std::string &label) + { + _paramProps.propSetString(kOfxPropLabel, label); + } + + /** @brief, set the label properties in a param */ + void Param::setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel) + { + setLabel(label); + _paramProps.propSetString(kOfxPropShortLabel, shortLabel, false); + _paramProps.propSetString(kOfxPropLongLabel, longLabel, false); + } + + /** @brief set the secretness of the param, defaults to false */ + void Param::setIsSecret(bool v) + { + _paramProps.propSetInt(kOfxParamPropSecret, v); + } + + /** @brief set the param hint */ + void Param::setHint(const std::string &v) + { + _paramProps.propSetString(kOfxParamPropHint, v, false); + } + + /** @brief whether the param is enabled */ + void Param::setEnabled(bool v) + { + _paramProps.propSetInt(kOfxParamPropEnabled, v); + } + + /** @brief set the private data pointer */ + void Param::setDataPtr(void* ptr) + { + _paramProps.propSetPointer(kOfxParamPropDataPtr, ptr); + } + + /** @brief fetch the label */ + void Param::getLabel(std::string &label) const + { + label = _paramProps.propGetString(kOfxPropLabel); + } + + /** @brief fetch the labels */ + void Param::getLabels(std::string &label, std::string &shortLabel, std::string &longLabel) const + { + getLabel(label); + shortLabel = _paramProps.propGetString(kOfxPropShortLabel, false); + longLabel = _paramProps.propGetString(kOfxPropLongLabel, false); + } + + /** @brief get whether the param is secret */ + bool Param::getIsSecret(void) const + { + bool v = _paramProps.propGetInt(kOfxParamPropSecret) != 0; + return v; + } + + /** @brief whether the param is enabled */ + bool Param::getIsEnable(void) const + { + bool v = _paramProps.propGetInt(kOfxParamPropEnabled) != 0; + return v; + } + + /** @brief get the private data pointer */ + void* Param::getDataPtr(void) const + { + return _paramProps.propGetPointer(kOfxParamPropDataPtr); + } + + /** @brief get the param hint */ + std::string Param::getHint(void) const + { + std::string v = _paramProps.propGetString(kOfxParamPropHint, false); + return v; + } + + /** @brief get the script name */ + std::string Param::getScriptName(void) const + { + std::string v = _paramProps.propGetString(kOfxParamPropScriptName, false); + return v; + } + + /** @brief get the group param that is the parent of this one */ + GroupParam *Param::getParent(void) const + { + std::string v = _paramProps.propGetString(kOfxParamPropParent); + if(v == "") return NULL; + return _paramSet->fetchGroupParam(v); + } + + /** @brief get the icon file name (SVG or PNG) */ + std::string Param::getIcon(bool pngFormat) const + { + std::string v = _paramProps.propGetString(kOfxPropIcon, (int)pngFormat, false); // OFX 1.2 + return v; + } + + bool Param::getHostHasNativeOverlayHandle() const + { + bool v = _paramProps.propGetInt(kOfxParamPropHasHostOverlayHandle, 0, false) != 0; // OFX 1.2 + return v; + } + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a value holding param */ + + /** @brief hidden constructor */ + ValueParam::ValueParam(const ParamSet *paramSet, const std::string &name, ParamTypeEnum type, OfxParamHandle handle) + : Param(paramSet, name, type, handle) + { + } + + /** @brief dtor */ + ValueParam::~ValueParam() + { + } + + /** @brief Set's whether the value of the param is significant (ie: affects the rendered image) */ + void + ValueParam::setEvaluateOnChange(bool v) + { + _paramProps.propSetInt(kOfxParamPropEvaluateOnChange, v); + } + + /** @brief is the param animating */ + bool + ValueParam::getIsAnimating(void) const + { + return _paramProps.propGetInt(kOfxParamPropIsAnimating) != 0; + } + + /** @brief is the param auto keing */ + bool + ValueParam::getIsAutoKeying(void) const + { + return _paramProps.propGetInt(kOfxParamPropIsAutoKeying) != 0; + } + + /** @brief is the param persistant */ + bool + ValueParam::getIsPersistant(void) const + { + return _paramProps.propGetInt(kOfxParamPropPersistant) != 0; + } + + /** @brief Get's whether the value of the param is significant (ie: affects the rendered image) */ + bool + ValueParam::getEvaluateOnChange(void) const + { + return _paramProps.propGetInt(kOfxParamPropEvaluateOnChange) != 0; + } + + /** @brief Get's whether the value of the param is significant (ie: affects the rendered image) */ + CacheInvalidationEnum + ValueParam::getCacheInvalidation(void) const + { + std::string v = _paramProps.propGetString(kOfxParamPropCacheInvalidation); + if(v == kOfxParamInvalidateValueChange) + return eCacheInvalidateValueChange; + else if(v == kOfxParamInvalidateValueChangeToEnd) + return eCacheInvalidateValueChangeToEnd; + else // if(v == kOfxParamInvalidateAll) + return eCacheInvalidateValueAll; + } + + /** @brief if the param is animating, the number of keys in it, otherwise 0 */ + unsigned int + ValueParam::getNumKeys(void) + { + if(!OFX::Private::gParamSuite->paramGetNumKeys) throwHostMissingSuiteException("paramGetNumKeys"); + unsigned int v = 0; + OfxStatus stat = OFX::Private::gParamSuite->paramGetNumKeys(_paramHandle, &v); + throwSuiteStatusException(stat); + return v; + } + + /** @brief get the time of the nth key, nth must be between 0 and getNumKeys-1 */ + double + ValueParam::getKeyTime(int nthKey) + { + if(!OFX::Private::gParamSuite->paramGetKeyTime) throwHostMissingSuiteException("paramGetKeyTime"); + double v = 0; + OfxStatus stat = OFX::Private::gParamSuite->paramGetKeyTime(_paramHandle, nthKey, &v); + + // oops? + if(stat == kOfxStatFailed) throw std::out_of_range("ValueParam::getKeyTime key index out of range"); + throwSuiteStatusException(stat); + return v; + } + + /** @brief find the index of a key by a time */ + int + ValueParam::getKeyIndex(double time, + KeySearchEnum searchDir) + { + if(!OFX::Private::gParamSuite->paramGetKeyIndex) throwHostMissingSuiteException("paramGetKeyIndex"); + int v = 0; + + // turn enum into -1,0,1 + int dir = searchDir == eKeySearchBackwards ? -1 : (searchDir == eKeySearchNear ? 0 : 1); + + // call raw param function + OfxStatus stat = OFX::Private::gParamSuite->paramGetKeyIndex(_paramHandle, time, dir, &v); + + // oops? + if(stat == kOfxStatFailed) return -1; // if search failed, return -1 + throwSuiteStatusException(stat); + return v; + } + + /** @brief deletes a key at the given time */ + void + ValueParam::deleteKeyAtTime(double time) + { + if(!OFX::Private::gParamSuite->paramDeleteKey) throwHostMissingSuiteException("paramDeleteKey"); + OfxStatus stat = OFX::Private::gParamSuite->paramDeleteKey(_paramHandle, time); + if(stat == kOfxStatFailed) return; // if no key at time, fail quietly + throwSuiteStatusException(stat); + } + + /** @brief delete all the keys */ + void + ValueParam::deleteAllKeys(void) + { + if(!OFX::Private::gParamSuite->paramDeleteAllKeys) throwHostMissingSuiteException("paramDeleteAllKeys"); + OfxStatus stat = OFX::Private::gParamSuite->paramDeleteAllKeys(_paramHandle); + throwSuiteStatusException(stat); + } + + /** @brief copy parameter from another, including any animation etc... */ + void ValueParam::copyFrom(const ValueParam& from, OfxTime dstOffset, const OfxRangeD *frameRange) + { + if(!OFX::Private::gParamSuite->paramCopy) throwHostMissingSuiteException("paramCopy"); + OfxStatus stat = OFX::Private::gParamSuite->paramCopy(_paramHandle, from._paramHandle, dstOffset, frameRange); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up an integer param */ + + /** @brief hidden constructor */ + IntParam::IntParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eIntParam, handle) + { + } + + /** @brief set the default value */ + void IntParam::setDefault(int v) + { + _paramProps.propSetInt(kOfxParamPropDefault, v); + } + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void IntParam::setRange(int min, int max) + { + _paramProps.propSetInt(kOfxParamPropMin, min); + _paramProps.propSetInt(kOfxParamPropMax, max); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void IntParam::setDisplayRange(int min, int max) + { + _paramProps.propSetInt(kOfxParamPropDisplayMin, min); + _paramProps.propSetInt(kOfxParamPropDisplayMax, max); + } + + /** @brief get the default value */ + void IntParam::getDefault(int &v) + { + v = _paramProps.propGetInt(kOfxParamPropDefault); + } + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void IntParam::getRange(int &min, int &max) + { + min = _paramProps.propGetInt(kOfxParamPropMin); + max = _paramProps.propGetInt(kOfxParamPropMax); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void IntParam::getDisplayRange(int &min, int &max) + { + min = _paramProps.propGetInt(kOfxParamPropDisplayMin); + max = _paramProps.propGetInt(kOfxParamPropDisplayMax); + } + + /** @brief get value */ + void IntParam::getValue(int &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &v); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void IntParam::getValueAtTime(double t, int &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &v); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void IntParam::setValue(int v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, v); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void IntParam::setValueAtTime(double t, int v) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, v); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // 2D Int params + + /** @brief hidden constructor */ + Int2DParam::Int2DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eInt2DParam, handle) + { + } + + /** @brief set the default value */ + void Int2DParam::setDefault(int x, int y) + { + _paramProps.propSetInt(kOfxParamPropDefault, x, 0); + _paramProps.propSetInt(kOfxParamPropDefault, y, 1); + } + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void + Int2DParam::setRange(int xmin, int ymin, + int xmax, int ymax) + { + _paramProps.propSetInt(kOfxParamPropMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropMax, ymax, 1); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Int2DParam::setDisplayRange(int xmin, int ymin, + int xmax, int ymax) + { + _paramProps.propSetInt(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMax, ymax, 1); + } + + /** @brief het the default value */ + void Int2DParam::getDefault(int &x, int &y) + { + x = _paramProps.propGetInt(kOfxParamPropDefault, 0); + y = _paramProps.propGetInt(kOfxParamPropDefault, 1); + } + + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void + Int2DParam::getRange(int &xmin, int &ymin, + int &xmax, int &ymax) + { + xmin = _paramProps.propGetInt(kOfxParamPropMin, 0); + ymin = _paramProps.propGetInt(kOfxParamPropMin, 1); + xmax = _paramProps.propGetInt(kOfxParamPropMax, 0); + ymax = _paramProps.propGetInt(kOfxParamPropMax, 1); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Int2DParam::getDisplayRange(int &xmin, int &ymin, + int &xmax, int &ymax) + { + xmin = _paramProps.propGetInt(kOfxParamPropDisplayMin, 0); + ymin = _paramProps.propGetInt(kOfxParamPropDisplayMin, 1); + xmax = _paramProps.propGetInt(kOfxParamPropDisplayMax, 0); + ymax = _paramProps.propGetInt(kOfxParamPropDisplayMax, 1); + } + + /** @brief get value */ + void Int2DParam::getValue(int &x, int &y) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &x, &y); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Int2DParam::getValueAtTime(double t, int &x, int &y) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &x, &y); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void Int2DParam::setValue(int x, int y) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, x, y); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void Int2DParam::setValueAtTime(double t, int x, int y) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, x, y); + throwSuiteStatusException(stat); + } + + + //////////////////////////////////////////////////////////////////////////////// + // 3D Int params + + /** @brief hidden constructor */ + Int3DParam::Int3DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eInt3DParam, handle) + { + } + + /** @brief set the default value */ + void Int3DParam::setDefault(int x, int y, int z) + { + _paramProps.propSetInt(kOfxParamPropDefault, x, 0); + _paramProps.propSetInt(kOfxParamPropDefault, y, 1); + _paramProps.propSetInt(kOfxParamPropDefault, z, 2); + } + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void + Int3DParam::setRange(int xmin, int ymin, int zmin, + int xmax, int ymax, int zmax) + { + _paramProps.propSetInt(kOfxParamPropMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropMin, zmin, 2); + _paramProps.propSetInt(kOfxParamPropMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropMax, ymax, 1); + _paramProps.propSetInt(kOfxParamPropMax, zmax, 2); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Int3DParam::setDisplayRange(int xmin, int ymin, int zmin, + int xmax, int ymax, int zmax) + { + _paramProps.propSetInt(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetInt(kOfxParamPropDisplayMin, zmin, 2); + _paramProps.propSetInt(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetInt(kOfxParamPropDisplayMax, ymax, 1); + _paramProps.propSetInt(kOfxParamPropDisplayMax, zmax, 2); + } + + /** @brief get the default value */ + void Int3DParam::getDefault(int &x, int &y, int &z) + { + x = _paramProps.propGetInt(kOfxParamPropDefault, 0); + y = _paramProps.propGetInt(kOfxParamPropDefault, 1); + z = _paramProps.propGetInt(kOfxParamPropDefault, 2); + } + + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void + Int3DParam::getRange(int &xmin, int &ymin, int &zmin, + int &xmax, int &ymax, int &zmax) + { + xmin = _paramProps.propGetInt(kOfxParamPropMin, 0); + ymin = _paramProps.propGetInt(kOfxParamPropMin, 1); + zmin = _paramProps.propGetInt(kOfxParamPropMin, 2); + xmax = _paramProps.propGetInt(kOfxParamPropMax, 0); + ymax = _paramProps.propGetInt(kOfxParamPropMax, 1); + zmax = _paramProps.propGetInt(kOfxParamPropMax, 2); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Int3DParam::getDisplayRange(int &xmin, int &ymin, int &zmin, + int &xmax, int &ymax, int &zmax) + { + xmin = _paramProps.propGetInt(kOfxParamPropDisplayMin, 0); + ymin = _paramProps.propGetInt(kOfxParamPropDisplayMin, 1); + zmin = _paramProps.propGetInt(kOfxParamPropDisplayMin, 2); + xmax = _paramProps.propGetInt(kOfxParamPropDisplayMax, 0); + ymax = _paramProps.propGetInt(kOfxParamPropDisplayMax, 1); + zmax = _paramProps.propGetInt(kOfxParamPropDisplayMax, 2); + } + + /** @brief get value */ + void Int3DParam::getValue(int &x, int &y, int &z) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &x, &y, &z); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Int3DParam::getValueAtTime(double t, int &x, int &y, int &z) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &x, &y, &z); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void Int3DParam::setValue(int x, int y, int z) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, x, y, z); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void Int3DParam::setValueAtTime(double t, int x, int y, int z) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, x, y, z); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // common base to all double params + + /** @brief hidden constructor */ + BaseDoubleParam::BaseDoubleParam(const ParamSet *paramSet, const std::string &name, ParamTypeEnum type, OfxParamHandle handle) + : ValueParam(paramSet, name, type, handle) + { + } + + /** @brief set the sensitivity of any gui slider */ + void BaseDoubleParam::setIncrement(double v) + { + _paramProps.propSetDouble(kOfxParamPropIncrement, v); + } + + /** @brief set the number of digits printed after a decimal point in any gui */ + void BaseDoubleParam::setDigits(int v) + { + _paramProps.propSetInt(kOfxParamPropDigits, v); + } + + /** @brief get the sensitivity of any gui slider */ + void BaseDoubleParam::getIncrement(double &v) + { + v = _paramProps.propGetDouble(kOfxParamPropIncrement); + } + + /** @brief get the number of digits printed after a decimal point in any gui */ + void BaseDoubleParam::getDigits(int &v) + { + v = _paramProps.propGetInt(kOfxParamPropDigits); + } + + /** @brief get the type of the double param, defaults to eDoubleTypePlain */ + void BaseDoubleParam::getDoubleType(DoubleTypeEnum &v) + { + std::string str = _paramProps.propGetString(kOfxParamPropDoubleType); + + if(str == kOfxParamDoubleTypePlain) + v = eDoubleTypePlain; + else if(str == kOfxParamDoubleTypeAngle) + v = eDoubleTypeAngle; + else if(str == kOfxParamDoubleTypeScale) + v = eDoubleTypeScale; + else if(str == kOfxParamDoubleTypeTime) + v = eDoubleTypeTime; + else if(str == kOfxParamDoubleTypeAbsoluteTime) + v = eDoubleTypeAbsoluteTime; + else if(str == kOfxParamDoubleTypeX) + v = eDoubleTypeX; + else if(str == kOfxParamDoubleTypeXAbsolute) + v = eDoubleTypeXAbsolute; + else if(str == kOfxParamDoubleTypeY) + v = eDoubleTypeY; + else if(str == kOfxParamDoubleTypeYAbsolute) + v = eDoubleTypeYAbsolute; + else if(str == kOfxParamDoubleTypeXY) + v = eDoubleTypeXY; + else if(str == kOfxParamDoubleTypeXYAbsolute) + v = eDoubleTypeXYAbsolute; +#ifdef kOfxParamDoubleTypeNormalisedX + else if(str == kOfxParamDoubleTypeNormalisedX) + v = eDoubleTypeNormalisedX; + else if(str == kOfxParamDoubleTypeNormalisedY) + v = eDoubleTypeNormalisedY; + else if(str == kOfxParamDoubleTypeNormalisedXAbsolute) + v = eDoubleTypeNormalisedXAbsolute; + else if(str == kOfxParamDoubleTypeNormalisedYAbsolute) + v = eDoubleTypeNormalisedYAbsolute; + else if(str == kOfxParamDoubleTypeNormalisedXY) + v = eDoubleTypeNormalisedXY; + else if(str == kOfxParamDoubleTypeNormalisedXYAbsolute) + v = eDoubleTypeNormalisedXYAbsolute; +#endif + else + v = eDoubleTypePlain; + } + + /** @brief get the type of coordinate system for default values */ + void BaseDoubleParam::getDefaultCoordinateSystem(DefaultCoordinateSystemEnum &v) + { + std::string str = _paramProps.propGetString(kOfxParamPropDefaultCoordinateSystem); + + if(str == kOfxParamCoordinatesNormalised) + v = eCoordinatesNormalised; + else + v = eCoordinatesCanonical; + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up an double param */ + + /** @brief hidden constructor */ + DoubleParam::DoubleParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : BaseDoubleParam(paramSet, name, eDoubleParam, handle) + { + } + + /** @brief set the default value */ + void DoubleParam::setDefault(double v) + { + _paramProps.propSetDouble(kOfxParamPropDefault, v); + } + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void DoubleParam::setRange(double min, double max) + { + _paramProps.propSetDouble(kOfxParamPropMin, min); + _paramProps.propSetDouble(kOfxParamPropMax, max); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void DoubleParam::setDisplayRange(double min, double max) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, min); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, max); + } + + /** @brief get the default value */ + void DoubleParam::getDefault(double &v) + { + v = _paramProps.propGetDouble(kOfxParamPropDefault); + } + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void DoubleParam::getRange(double &min, double &max) + { + min = _paramProps.propGetDouble(kOfxParamPropMin); + max = _paramProps.propGetDouble(kOfxParamPropMax); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void DoubleParam::getDisplayRange(double &min, double &max) + { + min = _paramProps.propGetDouble(kOfxParamPropDisplayMin); + max = _paramProps.propGetDouble(kOfxParamPropDisplayMax); + } + + /** @brief get value */ + void DoubleParam::getValue(double &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &v); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void DoubleParam::getValueAtTime(double t, double &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &v); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void DoubleParam::setValue(double v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, v); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void DoubleParam::setValueAtTime(double t, double v) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, v); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void DoubleParam::differentiate(double t, double &v) + { + if(!OFX::Private::gParamSuite->paramGetDerivative) throwHostMissingSuiteException("paramGetDerivative"); + OfxStatus stat = OFX::Private::gParamSuite->paramGetDerivative(_paramHandle, t, &v); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void DoubleParam::integrate(double t1, double t2, double &v) + { + if(!OFX::Private::gParamSuite->paramGetIntegral) throwHostMissingSuiteException("paramGetIntegral"); + OfxStatus stat = OFX::Private::gParamSuite->paramGetIntegral(_paramHandle, t1, t2, &v); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // 2D Double params + + /** @brief hidden constructor */ + Double2DParam::Double2DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : BaseDoubleParam(paramSet, name, eDouble2DParam, handle) + { + } + + /** @brief set the default value */ + void Double2DParam::setDefault(double x, double y) + { + _paramProps.propSetDouble(kOfxParamPropDefault, x, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, y, 1); + } + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void + Double2DParam::setRange(double xmin, double ymin, + double xmax, double ymax) + { + _paramProps.propSetDouble(kOfxParamPropMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropMax, ymax, 1); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Double2DParam::setDisplayRange(double xmin, double ymin, + double xmax, double ymax) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, ymax, 1); + } + + /** @brief get the default value */ + void Double2DParam::getDefault(double &x, double &y) + { + x = _paramProps.propGetDouble(kOfxParamPropDefault, 0); + y = _paramProps.propGetDouble(kOfxParamPropDefault, 1); + } + + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void + Double2DParam::getRange(double &xmin, double &ymin, + double &xmax, double &ymax) + { + xmin = _paramProps.propGetDouble(kOfxParamPropMin, 0); + ymin = _paramProps.propGetDouble(kOfxParamPropMin, 1); + xmax = _paramProps.propGetDouble(kOfxParamPropMax, 0); + ymax = _paramProps.propGetDouble(kOfxParamPropMax, 1); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Double2DParam::getDisplayRange(double &xmin, double &ymin, + double &xmax, double &ymax) + { + xmin = _paramProps.propGetDouble(kOfxParamPropDisplayMin, 0); + ymin = _paramProps.propGetDouble(kOfxParamPropDisplayMin, 1); + xmax = _paramProps.propGetDouble(kOfxParamPropDisplayMax, 0); + ymax = _paramProps.propGetDouble(kOfxParamPropDisplayMax, 1); + } + + /** @brief get value */ + void Double2DParam::getValue(double &x, double &y) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &x, &y); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Double2DParam::getValueAtTime(double t, double &x, double &y) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &x, &y); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void Double2DParam::setValue(double x, double y) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, x, y); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void Double2DParam::setValueAtTime(double t, double x, double y) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, x, y); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Double2DParam::differentiate(double t, double &x, double &y) + { + if(!OFX::Private::gParamSuite->paramGetDerivative) throwHostMissingSuiteException("paramGetDerivative"); + OfxStatus stat = OFX::Private::gParamSuite->paramGetDerivative(_paramHandle, t, &x, &y); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Double2DParam::integrate(double t1, double t2, double &x, double &y) + { + if(!OFX::Private::gParamSuite->paramGetIntegral) throwHostMissingSuiteException("paramGetIntegral"); + OfxStatus stat = OFX::Private::gParamSuite->paramGetIntegral(_paramHandle, t1, t2, &x, &y); + throwSuiteStatusException(stat); + } + + + //////////////////////////////////////////////////////////////////////////////// + // 3D Double params + + /** @brief hidden constructor */ + Double3DParam::Double3DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : BaseDoubleParam(paramSet, name, eDouble3DParam, handle) + { + } + + /** @brief set the default value */ + void Double3DParam::setDefault(double x, double y, double z) + { + _paramProps.propSetDouble(kOfxParamPropDefault, x, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, y, 1); + _paramProps.propSetDouble(kOfxParamPropDefault, z, 2); + } + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void + Double3DParam::setRange(double xmin, double ymin, double zmin, + double xmax, double ymax, double zmax) + { + _paramProps.propSetDouble(kOfxParamPropMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropMin, zmin, 2); + _paramProps.propSetDouble(kOfxParamPropMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropMax, ymax, 1); + _paramProps.propSetDouble(kOfxParamPropMax, zmax, 2); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Double3DParam::setDisplayRange(double xmin, double ymin, double zmin, + double xmax, double ymax, double zmax) + { + _paramProps.propSetDouble(kOfxParamPropDisplayMin, xmin, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, ymin, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMin, zmin, 2); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, xmax, 0); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, ymax, 1); + _paramProps.propSetDouble(kOfxParamPropDisplayMax, zmax, 2); + } + + /** @brief get the default value */ + void Double3DParam::getDefault(double &x, double &y, double &z) + { + x = _paramProps.propGetDouble(kOfxParamPropDefault, 0); + y = _paramProps.propGetDouble(kOfxParamPropDefault, 1); + z = _paramProps.propGetDouble(kOfxParamPropDefault, 2); + } + + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void + Double3DParam::getRange(double &xmin, double &ymin, double &zmin, + double &xmax, double &ymax, double &zmax) + { + xmin = _paramProps.propGetDouble(kOfxParamPropMin, 0); + ymin = _paramProps.propGetDouble(kOfxParamPropMin, 1); + zmin = _paramProps.propGetDouble(kOfxParamPropMin, 2); + xmax = _paramProps.propGetDouble(kOfxParamPropMax, 0); + ymax = _paramProps.propGetDouble(kOfxParamPropMax, 1); + zmax = _paramProps.propGetDouble(kOfxParamPropMax, 2); + } + + /** @brief set the display min and max, default is to be the same as the range param */ + void + Double3DParam::getDisplayRange(double &xmin, double &ymin, double &zmin, + double &xmax, double &ymax, double &zmax) + { + xmin = _paramProps.propGetDouble(kOfxParamPropDisplayMin, 0); + ymin = _paramProps.propGetDouble(kOfxParamPropDisplayMin, 1); + zmin = _paramProps.propGetDouble(kOfxParamPropDisplayMin, 2); + xmax = _paramProps.propGetDouble(kOfxParamPropDisplayMax, 0); + ymax = _paramProps.propGetDouble(kOfxParamPropDisplayMax, 1); + zmax = _paramProps.propGetDouble(kOfxParamPropDisplayMax, 2); + } + + /** @brief get value */ + void Double3DParam::getValue(double &x, double &y, double &z) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &x, &y, &z); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Double3DParam::getValueAtTime(double t, double &x, double &y, double &z) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &x, &y, &z); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void Double3DParam::setValue(double x, double y, double z) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, x, y, z); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void Double3DParam::setValueAtTime(double t, double x, double y, double z) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, x, y, z); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Double3DParam::differentiate(double t, double &x, double &y, double &z) + { + if(!OFX::Private::gParamSuite->paramGetDerivative) throwHostMissingSuiteException("paramGetDerivative"); + OfxStatus stat = OFX::Private::gParamSuite->paramGetDerivative(_paramHandle, t, &x, &y, &z); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void Double3DParam::integrate(double t1, double t2, double &x, double &y, double &z) + { + if(!OFX::Private::gParamSuite->paramGetIntegral) throwHostMissingSuiteException("paramGetIntegral"); + OfxStatus stat = OFX::Private::gParamSuite->paramGetIntegral(_paramHandle, t1, t2, &x, &y, &z); + throwSuiteStatusException(stat); + } + //////////////////////////////////////////////////////////////////////////////// + // RGB colour param + /** @brief hidden constructor */ + RGBParam::RGBParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eRGBParam, handle) + { + } + + /** @brief set the default value */ + void RGBParam::setDefault(double r, double g, double b) + { + _paramProps.propSetDouble(kOfxParamPropDefault, r, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, g, 1); + _paramProps.propSetDouble(kOfxParamPropDefault, b, 2); + } + + + /** @brief get the default value */ + void RGBParam::getDefault(double &r, double &g, double &b) + { + r = _paramProps.propGetDouble(kOfxParamPropDefault, 0); + g = _paramProps.propGetDouble(kOfxParamPropDefault, 1); + b = _paramProps.propGetDouble(kOfxParamPropDefault, 2); + } + + /** @brief get value */ + void RGBParam::getValue(double &r, double &g, double &b) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &r, &g, &b); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void RGBParam::getValueAtTime(double t, double &r, double &g, double &b) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &r, &g, &b); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void RGBParam::setValue(double r, double g, double b) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, r, g, b); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void RGBParam::setValueAtTime(double t, double r, double g, double b) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, r, g, b); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // RGBA colour param + /** @brief hidden constructor */ + RGBAParam::RGBAParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eRGBAParam, handle) + { + } + + /** @brief set the default value */ + void RGBAParam::setDefault(double r, double g, double b, double a) + { + _paramProps.propSetDouble(kOfxParamPropDefault, r, 0); + _paramProps.propSetDouble(kOfxParamPropDefault, g, 1); + _paramProps.propSetDouble(kOfxParamPropDefault, b, 2); + _paramProps.propSetDouble(kOfxParamPropDefault, a, 3); + } + + + /** @brief get the default value */ + void RGBAParam::getDefault(double &r, double &g, double &b, double &a) + { + r = _paramProps.propGetDouble(kOfxParamPropDefault, 0); + g = _paramProps.propGetDouble(kOfxParamPropDefault, 1); + b = _paramProps.propGetDouble(kOfxParamPropDefault, 2); + a = _paramProps.propGetDouble(kOfxParamPropDefault, 3); + } + + /** @brief get value */ + void RGBAParam::getValue(double &r, double &g, double &b, double &a) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &r, &g, &b, &a); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void RGBAParam::getValueAtTime(double t, double &r, double &g, double &b, double &a) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &r, &g, &b, &a); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void RGBAParam::setValue(double r, double g, double b, double a) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, r, g, b, a); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void RGBAParam::setValueAtTime(double t, double r, double g, double b, double a) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, r, g, b, a); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a string param */ + + /** @brief hidden constructor */ + StringParam::StringParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eStringParam, handle) + { + } + + /** @brief set the default value */ + void StringParam::setDefault(const std::string &v) + { + _paramProps.propSetString(kOfxParamPropDefault, v); + } + + /** @brief get the default value */ + void StringParam::getDefault(std::string &v) + { + v = _paramProps.propGetString(kOfxParamPropDefault); + } + + /** @brief get value */ + void StringParam::getValue(std::string &v) + { + char *cStr; + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &cStr); + throwSuiteStatusException(stat); + v = cStr; + } + + /** @brief get the value at a time */ + void StringParam::getValueAtTime(double t, std::string &v) + { + char *cStr; + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &cStr); + throwSuiteStatusException(stat); + v = cStr; + } + + /** @brief set value */ + void StringParam::setValue(const std::string &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, v.c_str()); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void StringParam::setValueAtTime(double t, const std::string &v) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, v.c_str()); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a Boolean integer param */ + + /** @brief hidden constructor */ + BooleanParam::BooleanParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eBooleanParam, handle) + { + } + + /** @brief set the default value */ + void BooleanParam::setDefault(bool v) + { + _paramProps.propSetInt(kOfxParamPropDefault, v); + } + + /** @brief get the default value */ + void BooleanParam::getDefault(bool &v) + { + v = _paramProps.propGetInt(kOfxParamPropDefault) != 0; + } + + /** @brief get value */ + void BooleanParam::getValue(bool &v) + { + int iVal; + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &iVal); + throwSuiteStatusException(stat); + v = iVal != 0; + } + + /** @brief get the value at a time */ + void BooleanParam::getValueAtTime(double t, bool &v) + { + int iVal; + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &iVal); + throwSuiteStatusException(stat); + v = iVal != 0; + } + + /** @brief set value */ + void BooleanParam::setValue(bool v) + { + int iVal = v; + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, iVal); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void BooleanParam::setValueAtTime(double t, bool v) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + int iVal = v; + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, iVal); + throwSuiteStatusException(stat); + } + + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a choice integer param */ + + /** @brief hidden constructor */ + ChoiceParam::ChoiceParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eChoiceParam, handle) + { + } + + /** @brief set the default value */ + void ChoiceParam::setDefault(int v) + { + _paramProps.propSetInt(kOfxParamPropDefault, v); + } + + /** @brief get the default value */ + void ChoiceParam::getDefault(int &v) + { + v = _paramProps.propGetInt(kOfxParamPropDefault); + } + + /** @brief get value */ + void ChoiceParam::getValue(int &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &v); + throwSuiteStatusException(stat); + } + + /** @brief get the value at a time */ + void ChoiceParam::getValueAtTime(double t, int &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &v); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void ChoiceParam::setValue(int v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, v); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void ChoiceParam::setValueAtTime(double t, int v) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, v); + throwSuiteStatusException(stat); + } + + /** @brief how many options do we have */ + int ChoiceParam::getNOptions(void) + { + int nCurrentValues = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + return nCurrentValues; + } + + /** @brief get the option value */ + void ChoiceParam::getOption(int ix, std::string &v) + { + v = _paramProps.propGetString(kOfxParamPropChoiceOption, ix); + } + + /** @brief add another option */ + void ChoiceParam::appendOption(const std::string &v, const std::string& label, const int order) + { + int nCurrentValues = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + _paramProps.propSetString(kOfxParamPropChoiceOption, v, nCurrentValues); + if(!label.empty()) { + { + // If the kOfxParamPropChoiceLabelOption doesn't exist, we put that information into the Hint. + // It's better than nothing... + std::string hint = _paramProps.propGetString(kOfxParamPropHint); + if(!hint.empty()) { + hint += "\n"; + if( nCurrentValues == 0 ) { + hint += "\n"; + } + } + hint += v + ": " + label; + _paramProps.propSetString(kOfxParamPropHint, hint); + } + } + if (order >= 0) { + // Host may not support this prop (added in 1.5); continue without it. + _paramProps.propSetInt(kOfxParamPropChoiceOrder, order, false); + } + } + + /** @brief set the string of a specific option */ + void ChoiceParam::setOption(int item, const std::string &str) + { + _paramProps.propSetString(kOfxParamPropChoiceOption, str, item); + } + + /** @brief set to the default value */ + void ChoiceParam::resetOptions(void) + { + _paramProps.propReset(kOfxParamPropChoiceOption); + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a string choice param */ + + /** @brief hidden constructor */ + StrChoiceParam::StrChoiceParam(const ParamSet* p_ParamSet, const std::string& p_Name, OfxParamHandle p_Handle) + : StringParam(p_ParamSet, p_Name, p_Handle) + { + _paramType = eStrChoiceParam; + } + + /** @brief how many options do we have */ + int StrChoiceParam::getNOptions() + { + const int numOptions = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + assert(numOptions == _paramProps.propGetDimension(kOfxParamPropChoiceEnum)); + + return numOptions; + } + + /** @brief add another option */ + void StrChoiceParam::appendOption(const std::string& p_Enum, const std::string& p_Option, int order) + { + const int numOptions = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + assert(numOptions == _paramProps.propGetDimension(kOfxParamPropChoiceEnum)); + + _paramProps.propSetString(kOfxParamPropChoiceEnum, p_Enum, numOptions); + _paramProps.propSetString(kOfxParamPropChoiceOption, p_Option, numOptions); + + if (order != INT_MIN) { + // Host may not support this prop (added in 1.5); continue without it. + _paramProps.propSetInt(kOfxParamPropChoiceOrder, order, numOptions, false); + } + } + + /** @brief set the string of a specific option */ + void StrChoiceParam::setOption(const std::string& p_Index, const std::string& p_Option) + { + const int numOptions = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + assert(numOptions == _paramProps.propGetDimension(kOfxParamPropChoiceEnum)); + + for (int i = 0; i < numOptions; ++i) + { + const std::string& enumStr = _paramProps.propGetString(kOfxParamPropChoiceEnum, i); + if (enumStr == p_Index) + { + _paramProps.propSetString(kOfxParamPropChoiceOption, p_Option, i); + + return; + } + } + + throwSuiteStatusException(kOfxStatErrBadIndex); + } + + /** @brief get the option value */ + void StrChoiceParam::getOption(const std::string& p_Index, std::string& p_Option) + { + const int numOptions = _paramProps.propGetDimension(kOfxParamPropChoiceOption); + assert(numOptions == _paramProps.propGetDimension(kOfxParamPropChoiceEnum)); + + for (int i = 0; i < numOptions; ++i) + { + const std::string& enumStr = _paramProps.propGetString(kOfxParamPropChoiceEnum, i); + if (enumStr == p_Index) + { + p_Option = _paramProps.propGetString(kOfxParamPropChoiceOption, i); + + return; + } + } + + throwSuiteStatusException(kOfxStatErrBadIndex); + } + + /** @brief set to the default value */ + void StrChoiceParam::resetOptions() + { + _paramProps.propReset(kOfxParamPropChoiceEnum); + _paramProps.propReset(kOfxParamPropChoiceOption); + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a custom param */ + + /** @brief hidden constructor */ + CustomParam::CustomParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : ValueParam(paramSet, name, eCustomParam, handle) + { + } + + /** @brief set the default value */ + void CustomParam::setDefault(const std::string &v) + { + _paramProps.propSetString(kOfxParamPropDefault, v); + } + + /** @brief get the default value */ + void CustomParam::getDefault(std::string &v) + { + v = _paramProps.propGetString(kOfxParamPropDefault); + } + + /** @brief get value */ + void CustomParam::getValue(std::string &v) + { + char *cStr; + OfxStatus stat = OFX::Private::gParamSuite->paramGetValue(_paramHandle, &cStr); + throwSuiteStatusException(stat); + v = cStr; + } + + /** @brief get the value at a time */ + void CustomParam::getValueAtTime(double t, std::string &v) + { + char *cStr; + OfxStatus stat = OFX::Private::gParamSuite->paramGetValueAtTime(_paramHandle, t, &cStr); + throwSuiteStatusException(stat); + v = cStr; + } + + /** @brief set value */ + void CustomParam::setValue(const std::string &v) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, v.c_str()); + throwSuiteStatusException(stat); + } + + /** @brief set value */ + void CustomParam::setValue(const char* str) + { + OfxStatus stat = OFX::Private::gParamSuite->paramSetValue(_paramHandle, str); + throwSuiteStatusException(stat); + } + + /** @brief set the value at a time, implicitly adds a keyframe */ + void CustomParam::setValueAtTime(double t, const std::string &v) + { + if(!OFX::Private::gParamSuite->paramSetValueAtTime) throwHostMissingSuiteException("paramSetValueAtTime"); + OfxStatus stat = OFX::Private::gParamSuite->paramSetValueAtTime(_paramHandle, t, v.c_str()); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a group param + /** @brief hidden constructor */ + GroupParam::GroupParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : Param(paramSet, name, eGroupParam, handle) + { + } + + /** @brief whether the initial state of a group is open or closed in a hierarchical layout, defaults to true */ + bool GroupParam::getIsOpen() + { + bool v = _paramProps.propGetInt(kOfxParamPropGroupOpen) != 0; + return v; + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a page param + + /** @brief hidden constructor */ + PageParam::PageParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : Param(paramSet, name, ePageParam, handle) + { + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a PushButton param + + /** @brief hidden constructor */ + PushButtonParam::PushButtonParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle) + : Param(paramSet, name, ePushButtonParam, handle) + { + } + + //////////////////////////////////////////////////////////////////////////////// + // Wraps up a Parametric param + + /** @brief hidden constructor */ + ParametricParam::ParametricParam(const ParamSet* paramSet, const std::string &name, OfxParamHandle handle) + : Param(paramSet, name, eParametricParam, handle) + {} + + /** @brief Evaluates a parametric parameter + + \arg curveIndex which dimension to evaluate + \arg time the time to evaluate to the parametric param at + \arg parametricPosition the position to evaluate the parametric param at + + @returns the double value is returned + */ + double ParametricParam::getValue(const int curveIndex, + const OfxTime time, + const double parametricPosition) + { + double returnValue = 0.0; + OfxStatus stat = OFX::Private::gParametricParameterSuite->parametricParamGetValue(_paramHandle, + curveIndex, + time, + parametricPosition, + &returnValue); + throwSuiteStatusException(stat); + return returnValue; + } + + /** @brief Returns the number of control points in the parametric param. + + \arg curveIndex which dimension to check + \arg time the time to check + + @returns the integer value is returned + */ + int ParametricParam::getNControlPoints(const int curveIndex, + const OfxTime time) + { + int returnValue = 0; + OfxStatus stat = OFX::Private::gParametricParameterSuite->parametricParamGetNControlPoints(_paramHandle, + curveIndex, + time, + &returnValue); + throwSuiteStatusException(stat); + return returnValue; + } + + /** @brief Returns the key/value pair of the nth control point. + + \arg curveIndex which dimension to check + \arg time the time to check + \arg nthCtl the nth control point to get the value of + + @returns a pair with key and value + */ + std::pair ParametricParam::getNthControlPoint(const int curveIndex, + const OfxTime time, + const int nthCtl) + { + std::pair returnValue; + OfxStatus stat = OFX::Private::gParametricParameterSuite->parametricParamGetNthControlPoint(_paramHandle, + curveIndex, + time, + nthCtl, + &returnValue.first, + &returnValue.second); + throwSuiteStatusException(stat); + return returnValue; + } + + /** @brief Modifies an existing control point on a curve + + \arg curveIndex which dimension to set + \arg time the time to set the value at + \arg nthCtl the control point to modify + \arg key key of the control point + \arg value value of the control point + \arg addAnimationKey if the param is an animatable, setting this to true will + force an animation keyframe to be set as well as a curve key, + otherwise if false, a key will only be added if the curve is already + animating. + + @returns + - ::kOfxStatOK - all was fine + - ::kOfxStatErrBadHandle - if the paramter handle was invalid + - ::kOfxStatErrUnknown - if the type is unknown + + This modifies an existing control point. Note that by changing key, the order of the + control point may be modified (as you may move it before or after anther point). So be + careful when iterating over a curves control points and you change a key. + */ + void ParametricParam::setNthControlPoints(const int curveIndex, + const OfxTime time, + const int nthCtl, + const double key, + const double value, + const bool addAnimationKey) + { + OfxStatus stat = OFX::Private::gParametricParameterSuite->parametricParamSetNthControlPoint(_paramHandle, + curveIndex, + time, + nthCtl, + key, + value, + addAnimationKey); + throwSuiteStatusException(stat); + } + + void ParametricParam::setNthControlPoints(const int curveIndex, + const OfxTime time, + const int nthCtl, + const std::pair ctrlPoint, + const bool addAnimationKey) + { + setNthControlPoints(curveIndex, + time, + nthCtl, + ctrlPoint.first, + ctrlPoint.second, + addAnimationKey); + } + + /** @brief Adds a control point to the curve. + + \arg curveIndex which dimension to set + \arg time the time to set the value at + \arg key key of the control point + \arg value value of the control point + \arg addAnimationKey if the param is an animatable, setting this to true will + force an animation keyframe to be set as well as a curve key, + otherwise if false, a key will only be added if the curve is already + animating. + + This will add a new control point to the given dimension of a parametric parameter. If a key exists + sufficiently close to 'key', then it will be set to the indicated control point. + */ + void ParametricParam::addControlPoint(const int curveIndex, + const OfxTime time, + const double key, + const double value, + const bool addAnimationKey) + { + OfxStatus stat = OFX::Private::gParametricParameterSuite->parametricParamAddControlPoint(_paramHandle, curveIndex, time, key, value, addAnimationKey); + throwSuiteStatusException(stat); + } + + /** @brief Deletes the nth control point from a parametric param. + + \arg curveIndex which dimension to delete + \arg nthCtl the control point to delete + */ + void ParametricParam::deleteControlPoint(const int curveIndex, + const int nthCtl) + { + OfxStatus stat = OFX::Private::gParametricParameterSuite->parametricParamDeleteControlPoint(_paramHandle, curveIndex, nthCtl); + throwSuiteStatusException(stat); + } + + /** @brief Delete all curve control points on the given param. + + \arg curveIndex which dimension to clear + */ + void ParametricParam::deleteControlPoint(const int curveIndex) + { + OfxStatus stat = OFX::Private::gParametricParameterSuite->parametricParamDeleteAllControlPoints(_paramHandle, curveIndex); + throwSuiteStatusException(stat); + } + + //////////////////////////////////////////////////////////////////////////////// + // for a set of parameters + /** @brief hidden ctor */ + ParamSet::ParamSet(void) + : _paramSetHandle(0) + { + } + + /** @brief set the param set handle */ + void + ParamSet::setParamSetHandle(OfxParamSetHandle h) + { + // set me handle + _paramSetHandle = h; + + if(h) { + // fetch me props + OfxPropertySetHandle props; + OfxStatus stat = OFX::Private::gParamSuite->paramSetGetPropertySet(h, &props); + _paramSetProps.propSetHandle(props); + throwSuiteStatusException(stat); + } + else { + _paramSetProps.propSetHandle(0); + } + } + + /** @brief dtor */ + ParamSet::~ParamSet() + { + // delete any descriptor we may have constructed + std::map::iterator iter; + for(iter = _fetchedParams.begin(); iter != _fetchedParams.end(); ++iter) { + if(iter->second) { + delete iter->second; + iter->second = NULL; + } + } + } + + /** @brief calls the raw OFX routine to fetch a param */ + void ParamSet::fetchRawParam(const std::string &name, ParamTypeEnum paramType, OfxParamHandle &handle) const + { + OfxPropertySetHandle propHandle; + + OfxStatus stat = OFX::Private::gParamSuite->paramGetHandle(_paramSetHandle, name.c_str(), &handle, &propHandle); + throwSuiteStatusException(stat); + + PropertySet props(propHandle); + + // make sure it is of our type + std::string paramTypeStr = props.propGetString(kOfxParamPropType); + if(paramTypeStr != mapParamTypeEnumToString(paramType)) { + throw OFX::Exception::TypeRequest("Parameter exists but is of the wrong type"); + } + } + + ParamTypeEnum ParamSet::getParamType(const std::string& name) const + { + OfxPropertySetHandle propHandle; + OfxParamHandle handle; + OfxStatus stat = OFX::Private::gParamSuite->paramGetHandle(_paramSetHandle, name.c_str(), &handle, &propHandle); + throwSuiteStatusException(stat); + PropertySet props(propHandle); + // make sure it is of our type + std::string paramTypeStr = props.propGetString(kOfxParamPropType); + return mapParamTypeStringToEnum(paramTypeStr.c_str()); + } + + bool ParamSet::paramExists(const std::string& name) const + { + OfxParamHandle handle; + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gParamSuite->paramGetHandle(_paramSetHandle, name.c_str(), &handle, &propHandle); + if(stat!=kOfxStatOK) + return false; + return true; + } + + Param* ParamSet::getParam(const std::string& name) const + { + OfxParamHandle handle; + OfxPropertySetHandle propHandle; + OfxStatus stat = OFX::Private::gParamSuite->paramGetHandle(_paramSetHandle, name.c_str(), &handle, &propHandle); + throwSuiteStatusException(stat); + + PropertySet props(propHandle); + + // make sure it is of our type + std::string paramTypeStr = props.propGetString(kOfxParamPropType); + ParamTypeEnum t = mapParamTypeStringToEnum(paramTypeStr.c_str()); + switch(t) + { + case eStringParam : + { + StringParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eIntParam : + { + IntParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eInt2DParam : + { + Int2DParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eInt3DParam : + { + Int3DParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eDoubleParam : + { + DoubleParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eDouble2DParam : + { + Double2DParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eDouble3DParam : + { + Double3DParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eRGBParam : + { + RGBParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eRGBAParam : + { + RGBAParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eBooleanParam : + { + BooleanParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eChoiceParam : + { + ChoiceParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eStrChoiceParam : + { + StrChoiceParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eCustomParam : + { + CustomParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eGroupParam : + { + GroupParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case ePageParam : + { + PageParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case ePushButtonParam : + { + PushButtonParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + case eParametricParam : + { + ParametricParam* ptr = 0; + fetchParam(name, t, ptr); + return ptr; + } + default: + assert(false); + } + return 0; + } + + /** @brief if a param has been fetched in this set, go find it */ + Param * + ParamSet::findPreviouslyFetchedParam(const std::string &name) const + { + // search + std::map::const_iterator search; + search = _fetchedParams.find(name); + if(search == _fetchedParams.end()) + return NULL; + return search->second; + } + + /** @brief Fetch an integer param, only callable from describe in context */ + IntParam * + ParamSet::fetchIntParam(const std::string &name) const + { + IntParam *param = NULL; + fetchParam(name, eIntParam, param); + return param; + } + + /** @brief Fetch a 2D integer param */ + Int2DParam *ParamSet::fetchInt2DParam(const std::string &name) const + { + Int2DParam *param = NULL; + fetchParam(name, eInt2DParam, param); + return param; + } + + /** @brief Fetch a 3D integer param */ + Int3DParam *ParamSet::fetchInt3DParam(const std::string &name) const + { + Int3DParam *param = NULL; + fetchParam(name, eInt3DParam, param); + return param; + } + + /** @brief Fetch an double param, only callable from describe in context */ + DoubleParam * + ParamSet::fetchDoubleParam(const std::string &name) const + { + DoubleParam *param = NULL; + fetchParam(name, eDoubleParam, param); + return param; + } + + /** @brief Fetch a 2D double param */ + Double2DParam *ParamSet::fetchDouble2DParam(const std::string &name) const + { + Double2DParam *param = NULL; + fetchParam(name, eDouble2DParam, param); + return param; + } + + /** @brief Fetch a 3D double param */ + Double3DParam *ParamSet::fetchDouble3DParam(const std::string &name) const + { + Double3DParam *param = NULL; + fetchParam(name, eDouble3DParam, param); + return param; + } + + /** @brief Fetch a string param */ + StringParam *ParamSet::fetchStringParam(const std::string &name) const + { + StringParam *param = NULL; + fetchParam(name, eStringParam, param); + return param; + } + + /** @brief Fetch a RGBA param */ + RGBAParam *ParamSet::fetchRGBAParam(const std::string &name) const + { + RGBAParam *param = NULL; + fetchParam(name, eRGBAParam, param); + return param; + } + + /** @brief Fetch an RGB param */ + RGBParam *ParamSet::fetchRGBParam(const std::string &name) const + { + RGBParam *param = NULL; + fetchParam(name, eRGBParam, param); + return param; + } + + /** @brief Fetch a Boolean param */ + BooleanParam *ParamSet::fetchBooleanParam(const std::string &name) const + { + BooleanParam *param = NULL; + fetchParam(name, eBooleanParam, param); + return param; + } + + /** @brief Fetch a Choice param */ + ChoiceParam *ParamSet::fetchChoiceParam(const std::string &name) const + { + ChoiceParam *param = NULL; + fetchParam(name, eChoiceParam, param); + return param; + } + + /** @brief Fetch a StrChoice param */ + StrChoiceParam* ParamSet::fetchStrChoiceParam(const std::string& p_Name) const + { + StrChoiceParam* param = NULL; + fetchParam(p_Name, eStrChoiceParam, param); + return param; + } + + /** @brief Fetch a group param */ + GroupParam *ParamSet::fetchGroupParam(const std::string &name) const + { + GroupParam *param = NULL; + fetchParam(name, eGroupParam, param); + return param; + } + + /** @brief Fetch a Page param */ + PageParam *ParamSet::fetchPageParam(const std::string &name) const + { + PageParam *param = NULL; + fetchParam(name, ePageParam, param); + return param; + } + + /** @brief Fetch a push button param */ + PushButtonParam *ParamSet::fetchPushButtonParam(const std::string &name) const + { + PushButtonParam *param = NULL; + fetchParam(name, ePushButtonParam, param); + return param; + } + + /** @brief Fetch a custom param */ + CustomParam *ParamSet::fetchCustomParam(const std::string &name) const + { + CustomParam *param = NULL; + fetchParam(name, eCustomParam, param); + return param; + } + + /** @brief Fetch a parametric param */ + ParametricParam *ParamSet::fetchParametricParam(const std::string &name) const + { + ParametricParam *param = NULL; + fetchParam(name, eParametricParam, param); + return param; + } + + /// open an undoblock + void ParamSet::beginEditBlock(const std::string &name) + { + OfxStatus stat = OFX::Private::gParamSuite->paramEditBegin(_paramSetHandle, name.c_str()); + (void)stat; + } + + /// close an undoblock + void ParamSet::endEditBlock() + { + OfxStatus stat = OFX::Private::gParamSuite->paramEditEnd(_paramSetHandle); + (void)stat; + } + +}; diff --git a/third_party/openfx/Support/Library/ofxsProperty.cpp b/third_party/openfx/Support/Library/ofxsProperty.cpp new file mode 100644 index 000000000..e3afee5ee --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsProperty.cpp @@ -0,0 +1,230 @@ + + +#include "ofxsSupportPrivate.h" + +using namespace OFX::Private; + +namespace OFX { + + static + void throwPropertyException(OfxStatus stat, + const std::string &propName) + { + switch (stat) + { + case kOfxStatOK : + case kOfxStatReplyYes : + case kOfxStatReplyNo : + case kOfxStatReplyDefault : + // Throw nothing! + break; + + case kOfxStatErrUnknown : + case kOfxStatErrUnsupported : // unsupported implies unknow here + if(OFX::PropertySet::getThrowOnUnsupportedProperties()) // are we suppressing this? + throw OFX::Exception::PropertyUnknownToHost(propName.c_str()); + break; + + case kOfxStatErrMemory : + throw std::bad_alloc(); + break; + + case kOfxStatErrValue : + throw OFX::Exception::PropertyValueIllegalToHost(propName.c_str()); + break; + + case kOfxStatErrBadHandle : + case kOfxStatErrBadIndex : + default : + throwSuiteStatusException(stat); + break; + } + } + + /** @brief are we logging property get/set */ + int PropertySet::_gPropLogging = 1; + + /** @brief Do we throw an exception if a host returns 'unsupported' when setting a property */ + bool PropertySet::_gThrowOnUnsupported = true; + + /** @brief Virtual destructor */ + PropertySet::~PropertySet() {} + + /** @brief, returns the dimension of the given property from this property set */ + int PropertySet::propGetDimension(const char* property, bool throwOnFailure) const + { + assert(_propHandle != 0); + int dimension = 0; + OfxStatus stat = gPropSuite->propGetDimension(_propHandle, property, &dimension); + Log::error(stat != kOfxStatOK, "Failed on fetching dimension for property %s, host returned status %s.", property, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) + Log::print("Fetched dimension of property %s, returned %d.", property, dimension); + + return dimension; + } + + /** @brief, resets the property to it's default value */ + void PropertySet::propReset(const char* property) + { + assert(_propHandle != 0); + OfxStatus stat = gPropSuite->propReset(_propHandle, property); + Log::error(stat != kOfxStatOK, "Failed on reseting property %s to its defaults, host returned status %s.", property, mapStatusToString(stat)); + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Reset property %s.", property); + } + + /** @brief, Set a single dimension pointer property */ + void PropertySet::propSetPointer(const char* property, void *value, int idx, bool throwOnFailure) + { + assert(_propHandle != 0); + OfxStatus stat = gPropSuite->propSetPointer(_propHandle, property, idx, value); + OFX::Log::error(stat != kOfxStatOK, "Failed on setting pointer property %s[%d] to %p, host returned status %s;", + property, idx, value, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Set pointer property %s[%d] to be %p.", property, idx, value); + } + + /** @brief, Set a single dimension string property */ + void PropertySet::propSetString(const char* property, const std::string &value, int idx, bool throwOnFailure) + { + assert(_propHandle != 0); + OfxStatus stat = gPropSuite->propSetString(_propHandle, property, idx, value.c_str()); + OFX::Log::error(stat != kOfxStatOK, "Failed on setting string property %s[%d] to %s, host returned status %s;", + property, idx, value.c_str(), mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Set string property %s[%d] to be %s.", property, idx, value.c_str()); + } + + /** @brief, Set a single dimension double property */ + void PropertySet::propSetDouble(const char* property, double value, int idx, bool throwOnFailure) + { + assert(_propHandle != 0); + OfxStatus stat = gPropSuite->propSetDouble(_propHandle, property, idx, value); + OFX::Log::error(stat != kOfxStatOK, "Failed on setting double property %s[%d] to %lf, host returned status %s;", + property, idx, value, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Set double property %s[%d] to be %lf.", property, idx, value); + } + + /** @brief, Set a single dimension int property */ + void PropertySet::propSetInt(const char* property, int value, int idx, bool throwOnFailure) + { + assert(_propHandle != 0); + OfxStatus stat = gPropSuite->propSetInt(_propHandle, property, idx, value); + OFX::Log::error(stat != kOfxStatOK, "Failed on setting int property %s[%d] to %d, host returned status %s (%d);", + property, idx, value, mapStatusToString(stat), stat); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Set int property %s[%d] to be %d.", property, idx, value); + } + + /** @brief, Set a multiple dimension double property */ + void PropertySet::propSetDoubleN(const char* property, const double* values, int count, bool throwOnFailure) + { + assert(_propHandle != 0); + OfxStatus stat = gPropSuite->propSetDoubleN(_propHandle, property, count, values); + OFX::Log::error(stat != kOfxStatOK, "Failed on setting double property %s[0..%d], host returned status %s;", + property, count-1, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Set double property %s[0..%d].", property, count-1); + } + + /** @brief Get single pointer property */ + void* PropertySet::propGetPointer(const char* property, int idx, bool throwOnFailure) const + { + assert(_propHandle != 0); + void *value = 0; + OfxStatus stat = gPropSuite->propGetPointer(_propHandle, property, idx, &value); + OFX::Log::error(stat != kOfxStatOK, "Failed on getting pointer property %s[%d], host returned status %s;", + property, idx, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Retrieved pointer property %s[%d], was given %p.", property, idx, value); + + return value; + } + + /** @brief Get single string property */ + std::string PropertySet::propGetString(const char* property, int idx, bool throwOnFailure) const + { + assert(_propHandle != 0); + char *value = NULL; + OfxStatus stat = gPropSuite->propGetString(_propHandle, property, idx, &value); + OFX::Log::error(stat != kOfxStatOK, "Failed on getting string property %s[%d], host returned status %s;", + property, idx, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Retrieved string property %s[%d], was given %s.", property, idx, value); + return value != NULL ? std::string(value) : std::string(); + } + + /** @brief Get single double property */ + double PropertySet::propGetDouble(const char* property, int idx, bool throwOnFailure) const + { + assert(_propHandle != 0); + double value = 0; + OfxStatus stat = gPropSuite->propGetDouble(_propHandle, property, idx, &value); + OFX::Log::error(stat != kOfxStatOK, "Failed on getting double property %s[%d], host returned status %s;", + property, idx, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Retrieved double property %s[%d], was given %lf.", property, idx, value); + return value; + } + + /** @brief Get single int property */ + int PropertySet::propGetInt(const char* property, int idx, bool throwOnFailure) const + { + assert(_propHandle != 0); + int value = 0; + OfxStatus stat = gPropSuite->propGetInt(_propHandle, property, idx, &value); + OFX::Log::error(stat != kOfxStatOK, "Failed on getting int property %s[%d], host returned status %s;", + property, idx, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Retrieved int property %s[%d], was given %d.", property, idx, value); + return value; + } + + std::list PropertySet::propGetNString(const char* property, bool throwOnFailure) const + { + assert(_propHandle != 0); + std::list ret; + int dimension = propGetDimension(property,throwOnFailure); + if (dimension <= 0) { + return ret; + } + std::vector rawValue(dimension); + OfxStatus stat = gPropSuite->propGetStringN(_propHandle, property, dimension, rawValue.data()); + OFX::Log::error(stat != kOfxStatOK, "Failed on getting string property %s, host returned status %s;", + property, mapStatusToString(stat)); + if(throwOnFailure) + throwPropertyException(stat, property); + + if(_gPropLogging > 0) Log::print("Retrieved string property %s, was given %s.", property,rawValue.data()); + + for (int i = 0; i < dimension; ++i) { + ret.push_back(std::string(rawValue[i])); + } + return ret; + + } + +}; diff --git a/third_party/openfx/Support/Library/ofxsPropertyValidation.cpp b/third_party/openfx/Support/Library/ofxsPropertyValidation.cpp new file mode 100644 index 000000000..356253106 --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsPropertyValidation.cpp @@ -0,0 +1,1313 @@ + + +/** @file + +This file contains headers for classes that are used to validate property sets and make sure they have the right members and default values. + +*/ + +#include "ofxsSupportPrivate.h" +#include +#ifdef OFX_SUPPORTS_OPENGLRENDER +#include "ofxGPURender.h" +#endif + +/** @brief Null pointer definition */ +#define NULLPTR ((void *)(0)) + +// #define kOfxsDisableValidation + +// disable validation if not a debug build +#ifndef DEBUG +#define kOfxsDisableValidation +#endif + +//#define kOfxsDisableValidation +/** @brief OFX namespace +*/ +namespace OFX { + + /** @brief The validation code has its own namespace */ + namespace Validation { + +#ifndef kOfxsDisableValidation + /** @brief Set the vector by getting dimension things specified by ilk from the argp list, used by PropertyDescription ctor */ + static void + setVectorFromVarArgs(OFX::PropertyTypeEnum ilk, + int dimension, + va_list &argp, + std::vector &vec) + { + char *vS; + int vI; + double vD; + void *vP; + for(int i = 0; i < dimension; i++) { + switch (ilk) + { + case eString : + vS = va_arg(argp, char *); + vec.push_back(vS); + break; + + case eInt : + vI = va_arg(argp, int); + vec.push_back(vI); + break; + + case ePointer : + vP = va_arg(argp, void *); + vec.push_back(vP); + break; + + case eDouble : + vD = va_arg(argp, double); + vec.push_back(vD); + break; + } + } + } + + + /** @brief PropertyDescription var-args constructor */ + PropertyDescription::PropertyDescription(const char *name, OFX::PropertyTypeEnum ilk, int dimension, ...) + : _name(name) + , _exists(false) // only set when we have validated it + , _dimension(dimension) + , _ilk(ilk) + { + // go through the var args to extract defaults to check against and values to set to + va_list argp; + va_start(argp, dimension); + + bool going = true; + while(going) { + // what is being set ? + DescriptionTag tag = DescriptionTag(va_arg(argp, int)); + + switch (tag) + { + case eDescDefault : // we are setting default values to check against + setVectorFromVarArgs(ilk, dimension, argp, _defaultValue); + break; + + case eDescFinished : // we are finished + default : + going = false; + break; + } + } + + va_end(argp); + } + + + /** @brief See if the property exists in the containing property set and has the correct dimension */ + void + PropertyDescription::validate(bool checkDefaults, + PropertySet &propSet) + { + // see if it exists by fetching the dimension, + + try { + int hostDimension = propSet.propGetDimension(_name.c_str()); + _exists = true; + + if(_dimension != -1) // -1 implies variable dimension + OFX::Log::error(hostDimension != _dimension, "Host reports property '%s' has dimension %d, it should be %d;", _name.c_str(), hostDimension, _dimension); + // check type by getting the first element, the property getting will print any failure messages to the log + if(hostDimension > 0) { + switch(_ilk) + { + case OFX::ePointer : { void *vP = propSet.propGetPointer(_name.c_str()); (void)vP; }break; + case OFX::eInt : { int vI = propSet.propGetInt(_name.c_str()); (void)vI; } break; + case OFX::eString : { std::string vS = propSet.propGetString(_name.c_str()); (void)vS; } break; + case OFX::eDouble : { double vD = propSet.propGetDouble(_name.c_str()); (void)vD; } break; + } + } + + // check the defaults are OK, if there are any + int nDefs = (int)_defaultValue.size(); + if(checkDefaults && nDefs > 0) { + OFX::Log::error(hostDimension != nDefs, "Host reports default dimension of '%s' as %d, which is different to the default dimension size of %d;", + _name.c_str(), hostDimension, nDefs); + + int N = hostDimension < nDefs ? hostDimension : nDefs; + + for(int i = 0; i < N; i++) { + switch(_ilk) + { + case OFX::ePointer : { + void *vP = propSet.propGetPointer(_name.c_str(), i); + OFX::Log::error(vP != (void *) _defaultValue[i], "Default value of %s[%d] = %p, it should be %p;", + _name.c_str(), i, vP, (void *) _defaultValue[i]); + } + break; + case OFX::eInt : { + int vI = propSet.propGetInt(_name.c_str(), i); + OFX::Log::error(vI != (int) _defaultValue[i], "Default value of %s[%d] = %d, it should be %d;", + _name.c_str(), i, vI, (int) _defaultValue[i]); + } + break; + case OFX::eString : { + std::string vS = propSet.propGetString(_name.c_str(), i); + OFX::Log::error(vS != _defaultValue[i].vString, "Default value of %s[%d] = '%s', it should be '%s';", + _name.c_str(), i, vS.c_str(), _defaultValue[i].vString.c_str()); + } + break; + case OFX::eDouble : { + double vD = propSet.propGetDouble(_name.c_str(), i); + OFX::Log::error(vD != (double) _defaultValue[i], "Default value of %s[%d] = %g, it should be %g;", + _name.c_str(), i, vD, (double) _defaultValue[i]); + } + break; + } + } + } + } + catch (OFX::Exception::Suite &e) + { + // just catch it, the error will be reported + _exists = false; + } + catch (OFX::Exception::PropertyUnknownToHost &e) + { + // just catch it, the error will be reported + _exists = false; + } + catch (OFX::Exception::PropertyValueIllegalToHost &e) + { + // just catch it, the error will be reported + _exists = false; + } + } + + + /** @brief This macro is used to short hand passing the var args to @ref OFX::Validation::PropertySetDescription::PropertySetDescription */ +#define mPropDescriptionArg(descs) descs, sizeof(descs)/sizeof(PropertyDescription) + + /** @brief A set of property descriptions, constructor + + Passed in as a zero terminated pairs of (PropertyDescription *descArray, int nDescriptions) + + */ + PropertySetDescription::PropertySetDescription(const char *setName, ...) // PropertyDescription *v, int nV) + : _setName(setName) + { + + // go through the var args to extract defaults to check against and values to set to + va_list argp; + va_start(argp, setName); + + while(1) { + // get a pointer + PropertyDescription *descs = (PropertyDescription *) va_arg(argp, PropertyDescription *); + + // have we finished + if(!descs) break; + + // get the count + int nDescs = (int) va_arg(argp, int); + + // and set it up + for(int i = 0; i < nDescs; i++) { + _descriptions.push_back(descs + i); + } + + } + + va_end(argp); + } + + /** @brief destructor */ + PropertySetDescription::~PropertySetDescription() + { + int nToDelete = (int)_deleteThese.size(); + for(int i = 0; i < nToDelete; i++) { + delete _deleteThese[i]; + } + } + + /** @brief Add more properties into the property vector */ + void + PropertySetDescription::addProperty(PropertyDescription *desc, + bool deleteOnDestruction) + { + _descriptions.push_back(desc); + if(deleteOnDestruction) + _deleteThese.push_back(desc); + } + + /** @brief Validate all the properties in the set */ + void + PropertySetDescription::validate(PropertySet &propSet, + bool checkDefaults, + bool logOrdinaryMessages) + { + OFX::Log::print("START validating properties of %s.", _setName.c_str()); + OFX::Log::indent(); + + // don't print ordinary messages whilst we are checking them + if(!logOrdinaryMessages) PropertySet::propDisableLogging(); + + // check each property in the description + int n = (int)_descriptions.size(); + for(int i = 0; i < n; i++) + _descriptions[i]->validate(checkDefaults, propSet); + + if(!logOrdinaryMessages) PropertySet::propEnableLogging(); + + OFX::Log::outdent(); + OFX::Log::print("STOP property validation of %s.", _setName.c_str()); + } + + + /** @brief A list of properties that all hosts must have, and will be validated against. None of these has a default, but they must exist. */ + static PropertyDescription gHostProps[ ] = + { + // single dimensional string properties + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropName, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLabel, OFX::eString, 1, eDescFinished), + + // single dimensional int properties + PropertyDescription(kOfxImageEffectHostPropIsBackground, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsOverlays, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsMultiResolution, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsTiles, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropTemporalClipAccess, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsMultipleClipDepths, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsMultipleClipPARs, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSetableFrameRate, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSetableFielding, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropSupportsStringAnimation, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropSupportsCustomInteract, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropSupportsChoiceAnimation, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropSupportsStrChoiceAnimation, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropSupportsBooleanAnimation, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropSupportsCustomAnimation, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropMaxParameters, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamHostPropMaxPages, OFX::eInt, 1, eDescFinished), + + // variable multi dimensional string properties + PropertyDescription(kOfxImageEffectPropSupportedComponents, OFX::eString, -1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportedContexts, OFX::eString, -1, eDescFinished), + + // multi dimensional int properities + PropertyDescription(kOfxParamHostPropPageRowColumnCount, OFX::eInt, 2, eDescFinished), + }; + + /** @brief the property set for the global host pointer */ + static PropertySetDescription gHostPropSet("Host Property", + gHostProps, sizeof(gHostProps)/sizeof(PropertyDescription), + NULLPTR); + + + /** @brief A list of properties to validate the effect descriptor against */ + static PropertyDescription gPluginDescriptorProps[ ] = + { + // string props that have no defaults that can be checked against + PropertyDescription(kOfxPropLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropShortLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLongLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPluginPropGrouping, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPluginPropFilePath, OFX::eString, 1, eDescFinished), + + // string props with defaults that can be checked against + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescDefault, kOfxTypeImageEffect, eDescFinished), + PropertyDescription(kOfxImageEffectPluginRenderThreadSafety, OFX::eString, 1, eDescDefault, kOfxImageEffectRenderFullySafe, eDescFinished), + + // int props with defaults that can be checked against + PropertyDescription(kOfxImageEffectPluginPropSingleInstance, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageEffectPluginPropHostFrameThreading, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsMultiResolution, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsTiles, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropTemporalClipAccess, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageEffectPluginPropFieldRenderTwiceAlways, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsMultipleClipDepths, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsMultipleClipPARs, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + + // Pointer props with defaults that can be checked against + PropertyDescription(kOfxImageEffectPluginPropOverlayInteractV1, OFX::ePointer, 1, eDescDefault, (void *)(0), eDescFinished), + + // string props that have variable dimension, and can't be checked against for defaults + PropertyDescription(kOfxImageEffectPropSupportedContexts, OFX::eString, -1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportedPixelDepths, OFX::eString, -1, eDescFinished), + PropertyDescription(kOfxImageEffectPropClipPreferencesSlaveParam, OFX::eString, -1, eDescFinished), + }; + + /** @brief the property set for the global plugin descriptor */ + static PropertySetDescription gPluginDescriptorPropSet("Plugin Descriptor", + gPluginDescriptorProps, sizeof(gPluginDescriptorProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief A list of properties to validate the plugin instance */ + static PropertyDescription gPluginInstanceProps[ ] = + { + // string props with defaults that can be checked against + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescDefault, kOfxTypeImageEffectInstance, eDescFinished), + + // int props with defaults that can be checked against + PropertyDescription(kOfxImageEffectInstancePropSequentialRender, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + + // Pointer props with defaults that can be checked against + PropertyDescription(kOfxPropInstanceData, OFX::ePointer, 1, eDescDefault, (void *)(0), eDescFinished), + PropertyDescription(kOfxImageEffectPropPluginHandle, OFX::ePointer, 1, eDescFinished), + + // string props that have no defaults that can be checked against + PropertyDescription(kOfxImageEffectPropContext, OFX::eString, 1, eDescFinished), + + // int props with not defaults that can be checked against + PropertyDescription(kOfxPropIsInteractive, OFX::eInt, 1, eDescFinished), + + // double props that can't be checked against for defaults + PropertyDescription(kOfxImageEffectPropProjectSize, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropProjectExtent, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropProjectOffset, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropProjectPixelAspectRatio, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectInstancePropEffectDuration, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropFrameRate, OFX::eDouble, 1, eDescFinished), + }; + + /** @brief the property set for a plugin instance */ + static PropertySetDescription gPluginInstancePropSet("Plugin Instance", + gPluginInstanceProps, sizeof(gPluginInstanceProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief A list of properties to validate a clip descriptor */ + static PropertyDescription gClipDescriptorProps[ ] = + { + // string props with checkable defaults + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescDefault, kOfxTypeClip, eDescFinished), + PropertyDescription(kOfxImageClipPropFieldExtraction, OFX::eString, 1, eDescDefault, kOfxImageFieldDoubled, eDescFinished), + + // string props with no checkable defaults + PropertyDescription(kOfxImageEffectPropSupportedComponents, OFX::eString,-1, eDescFinished), + PropertyDescription(kOfxPropName, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropShortLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLongLabel, OFX::eString, 1, eDescFinished), + + // int props with checkable defaults + PropertyDescription(kOfxImageEffectPropTemporalClipAccess, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageClipPropOptional, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageClipPropIsMask, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsTiles, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + }; + + /** @brief the property set for a clip descriptor */ + static PropertySetDescription gClipDescriptorPropSet("Clip Descriptor", + gClipDescriptorProps, sizeof(gClipDescriptorProps)/sizeof(PropertyDescription), + NULLPTR); + + + /** @brief A list of properties to validate a clip instance */ + static PropertyDescription gClipInstanceProps[ ] = + { + // we can only validate this one against a fixed default + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescDefault, kOfxTypeClip, eDescFinished), + + // the rest are set by the plugin during description or by the host + PropertyDescription(kOfxPropName, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropShortLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLongLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportedComponents, OFX::eString,-1, eDescFinished), + PropertyDescription(kOfxImageClipPropFieldExtraction, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropPixelDepth, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropComponents, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropUnmappedPixelDepth, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropUnmappedComponents, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropPreMultiplication, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropFieldOrder, OFX::eString, 1, eDescFinished), + + // int props + PropertyDescription(kOfxImageEffectPropTemporalClipAccess, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropOptional, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropIsMask, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropSupportsTiles, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropConnected, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropContinuousSamples, OFX::eInt, 1, eDescFinished), + + // double props + PropertyDescription(kOfxImagePropPixelAspectRatio, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropFrameRate, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropFrameRange, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropUnmappedFrameRate, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropUnmappedFrameRange, OFX::eDouble, 2, eDescFinished), + }; + + /** @brief the property set for a clip instance */ + static PropertySetDescription gClipInstancePropSet("Clip Instance", gClipInstanceProps, sizeof(gClipInstanceProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief List of properties to validate an image or texture instance */ + static PropertyDescription gImageBaseInstanceProps[ ] = + { + // this is the only property with a checkable default + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescDefault, kOfxTypeImage, eDescFinished), + + // all other properties are set by the host + PropertyDescription(kOfxImageEffectPropPixelDepth, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropComponents, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropPreMultiplication, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImagePropField, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImagePropUniqueIdentifier, OFX::eString, 1, eDescFinished), + + // double props + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImagePropPixelAspectRatio, OFX::eDouble, 1, eDescFinished), + + // pointer props + PropertyDescription(kOfxImagePropData, OFX::ePointer, 1, eDescFinished), + + // int props + PropertyDescription(kOfxImagePropBounds, OFX::eInt, 4, eDescFinished), + PropertyDescription(kOfxImagePropRegionOfDefinition, OFX::eInt, 4, eDescFinished), + PropertyDescription(kOfxImagePropRowBytes, OFX::eInt, 1, eDescFinished), + }; + + /** @brief the property set for an image instance */ + static PropertySetDescription gImageBaseInstancePropSet("Image or Texture Instance", + gImageBaseInstanceProps, sizeof(gImageBaseInstanceProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief List of properties to validate an image or texture instance */ + static PropertyDescription gImageInstanceProps[ ] = + { + // pointer props + PropertyDescription(kOfxImagePropData, OFX::ePointer, 1, eDescFinished), + }; + + /** @brief the property set for an image instance */ + static PropertySetDescription gImageInstancePropSet("Image Instance", + gImageInstanceProps, sizeof(gImageInstanceProps)/sizeof(PropertyDescription), + NULLPTR); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief List of properties to validate an image or texture instance */ + static PropertyDescription gTextureInstanceProps[ ] = + { + // pointer props + PropertyDescription(kOfxImageEffectPropOpenGLTextureIndex, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropOpenGLTextureTarget, OFX::eInt, 1, eDescFinished), + }; + + /** @brief the property set for an image instance */ + static PropertySetDescription gTextureInstancePropSet("Texture Instance", + gTextureInstanceProps, sizeof(gTextureInstanceProps)/sizeof(PropertyDescription), + NULLPTR); +#endif + + //////////////////////////////////////////////////////////////////////////////// + // Action in/out args properties + //////////////////////////////////////////////////////////////////////////////// + + /** @brief kOfxImageEffectActionDescribeInContext actions's inargs properties */ + static PropertyDescription gDescribeInContextActionInArgProps[ ] = + { + PropertyDescription(kOfxImageEffectPropContext, OFX::eString, 1, eDescFinished), + }; + + /** @brief the property set for describe in context action */ + static PropertySetDescription gDescribeInContextActionInArgPropSet(kOfxImageEffectActionDescribeInContext " in argument", + gDescribeInContextActionInArgProps, sizeof(gDescribeInContextActionInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionRender action's inargs properties */ + static PropertyDescription gRenderActionInArgProps[ ] = + { + PropertyDescription(kOfxPropTime, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderWindow, OFX::eInt, 4, eDescFinished), + PropertyDescription(kOfxImageEffectPropFieldToRender, OFX::eString, 1, eDescFinished), + // The following appeared in OFX 1.2, and are thus not mandatory + //PropertyDescription(kOfxImageEffectPropSequentialRenderStatus, OFX::eInt, 1, eDescFinished), + //PropertyDescription(kOfxImageEffectPropInteractiveRenderStatus, OFX::eInt, 1, eDescFinished), + // The following appeared in OFX 1.4, and is thus not mandatory + //PropertyDescription(kOfxImageEffectPropRenderQualityDraft, OFX::eInt, 1, eDescFinished), + }; + + /** @brief kOfxImageEffectActionRender property set */ + static PropertySetDescription gRenderActionInArgPropSet(kOfxImageEffectActionRender " in argument", + gRenderActionInArgProps, sizeof(gRenderActionInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionBeginSequenceRender action's inargs properties */ + static PropertyDescription gBeginSequenceRenderActionInArgProps[ ] = + { + PropertyDescription(kOfxImageEffectPropFrameRange, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropFrameStep, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxPropIsInteractive, OFX::eInt, 1, eDescFinished), + // The following appeared in OFX 1.2, and are thus not mandatory + //PropertyDescription(kOfxImageEffectPropSequentialRenderStatus, OFX::eInt, 1, eDescFinished), + //PropertyDescription(kOfxImageEffectPropInteractiveRenderStatus, OFX::eInt, 1, eDescFinished), + }; + + /** @brief kOfxImageEffectActionBeginSequenceRender property set */ + static PropertySetDescription gBeginSequenceRenderActionInArgPropSet(kOfxImageEffectActionBeginSequenceRender " in argument", + gBeginSequenceRenderActionInArgProps, sizeof(gBeginSequenceRenderActionInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionEndSequenceRender action's inargs properties */ + static PropertyDescription gEndSequenceRenderActionInArgProps[ ] = + { + PropertyDescription(kOfxImageEffectPropFrameRange, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropFrameStep, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxPropIsInteractive, OFX::eInt, 1, eDescFinished), + // The following appeared in OFX 1.2, and are thus not mandatory + //PropertyDescription(kOfxImageEffectPropSequentialRenderStatus, OFX::eInt, 1, eDescFinished), + //PropertyDescription(kOfxImageEffectPropInteractiveRenderStatus, OFX::eInt, 1, eDescFinished), + }; + + /** @brief kOfxImageEffectActionEndSequenceRender property set */ + static PropertySetDescription gEndSequenceRenderActionInArgPropSet(kOfxImageEffectActionEndSequenceRender " in argument", + gEndSequenceRenderActionInArgProps, sizeof(gEndSequenceRenderActionInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionIsIdentity action's inargs properties */ + static PropertyDescription gIsIdentityActionInArgProps[ ] = + { + PropertyDescription(kOfxPropTime, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderWindow, OFX::eInt, 4, eDescFinished), + PropertyDescription(kOfxImageEffectPropFieldToRender, OFX::eString, 1, eDescFinished), + }; + + /** @brief kOfxImageEffectActionIsIdentity property set */ + static PropertySetDescription gIsIdentityActionInArgPropSet(kOfxImageEffectActionIsIdentity " in argument", + gIsIdentityActionInArgProps, sizeof(gIsIdentityActionInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionIsIdentity action's outargs properties */ + static PropertyDescription gIsIdentityActionOutArgProps[ ] = + { + PropertyDescription(kOfxPropTime, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxPropName, OFX::eString, 1, eDescFinished), + }; + + /** @brief kOfxImageEffectActionIsIdentity property set */ + static PropertySetDescription gIsIdentityActionOutArgPropSet(kOfxImageEffectActionIsIdentity " out argument", + gIsIdentityActionOutArgProps, sizeof(gIsIdentityActionOutArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionGetRegionOfDefinition action's inargs properties */ + static PropertyDescription gGetRegionOfDefinitionInArgProps[ ] = + { + PropertyDescription(kOfxPropTime, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + }; + + /** @brief kOfxImageEffectActionGetRegionOfDefinition property set */ + static PropertySetDescription gGetRegionOfDefinitionInArgPropSet(kOfxImageEffectActionGetRegionOfDefinition " in argument", + gGetRegionOfDefinitionInArgProps, sizeof(gGetRegionOfDefinitionInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionGetRegionOfDefinition action's outargs properties */ + static PropertyDescription gGetRegionOfDefinitionOutArgProps[ ] = + { + PropertyDescription(kOfxImageEffectPropRegionOfDefinition, OFX::eDouble, 4, eDescFinished), + }; + + /** @brief kOfxImageEffectActionGetRegionOfDefinition property set */ + static PropertySetDescription gGetRegionOfDefinitionOutArgPropSet(kOfxImageEffectActionGetRegionOfDefinition " out argument", + gGetRegionOfDefinitionOutArgProps, sizeof(gGetRegionOfDefinitionOutArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionGetRegionsOfInterest action's inargs properties */ + static PropertyDescription gGetRegionOfInterestInArgProps[ ] = + { + PropertyDescription(kOfxPropTime, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxImageEffectPropRegionOfInterest, OFX::eDouble, 4, eDescFinished), + }; + + /** @brief kOfxImageEffectActionGetRegionsOfInterest property set */ + static PropertySetDescription gGetRegionOfInterestInArgPropSet(kOfxImageEffectActionGetRegionsOfInterest "in argument", + gGetRegionOfInterestInArgProps, sizeof(gGetRegionOfInterestInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionGetTimeDomain action's outargs properties */ + static PropertyDescription gGetTimeDomainOutArgProps[ ] = + { + PropertyDescription(kOfxImageEffectPropFrameRange, OFX::eDouble, 2, eDescFinished), + }; + + /** @brief kOfxImageEffectActionGetTimeDomain property set */ + static PropertySetDescription gGetTimeDomainOutArgPropSet(kOfxImageEffectActionGetTimeDomain " out argument", + gGetTimeDomainOutArgProps, sizeof(gGetTimeDomainOutArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionGetFramesNeeded action's inargs properties */ + static PropertyDescription gGetFramesNeededInArgProps[ ] = + { + PropertyDescription(kOfxPropTime, OFX::eDouble, 1, eDescFinished), + }; + + /** @brief kOfxImageEffectActionGetFramesNeeded property set */ + static PropertySetDescription gGetFramesNeededInArgPropSet(kOfxImageEffectActionGetFramesNeeded " in argument", + gGetFramesNeededInArgProps, sizeof(gGetFramesNeededInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxImageEffectActionGetClipPreferences action's outargs properties */ + static PropertyDescription gGetClipPreferencesOutArgProps[ ] = + { + PropertyDescription(kOfxImageEffectPropFrameRate, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropFieldOrder, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxImageClipPropContinuousSamples, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageEffectFrameVarying, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxImageEffectPropPreMultiplication, OFX::eString, 1, eDescFinished), + }; + + /** @brief kOfxImageEffectActionGetClipPreferences property set */ + static PropertySetDescription gGetClipPreferencesOutArgPropSet(kOfxImageEffectActionGetClipPreferences " out argument", + gGetClipPreferencesOutArgProps, sizeof(gGetClipPreferencesOutArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxActionInstanceChanged action's inargs properties */ + static PropertyDescription gInstanceChangedInArgProps[ ] = + { + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropName, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropChangeReason, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropTime, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxImageEffectPropRenderScale, OFX::eDouble, 2, eDescFinished), + }; + + /** @brief kOfxActionInstanceChanged property set */ + static PropertySetDescription gInstanceChangedInArgPropSet(kOfxActionInstanceChanged " in argument", + gInstanceChangedInArgProps, sizeof(gInstanceChangedInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + /** @brief kOfxActionBeginInstanceChanged and kOfxActionEndInstanceChanged actions' inargs properties */ + static PropertyDescription gBeginEndInstanceChangedInArgProps[ ] = + { + PropertyDescription(kOfxPropChangeReason, OFX::eString, 1, eDescFinished), + }; + + /** @brief kOfxActionBeginInstanceChanged property set */ + static PropertySetDescription gBeginInstanceChangedInArgPropSet(kOfxActionBeginInstanceChanged " in argument", + gBeginEndInstanceChangedInArgProps, sizeof(gBeginEndInstanceChangedInArgProps)/sizeof(PropertyDescription), + NULLPTR); + /** @brief kOfxActionEndInstanceChanged property set */ + static PropertySetDescription gEndInstanceChangedInArgPropSet(kOfxActionEndInstanceChanged " in argument", + gBeginEndInstanceChangedInArgProps, sizeof(gBeginEndInstanceChangedInArgProps)/sizeof(PropertyDescription), + NULLPTR); + + + //////////////////////////////////////////////////////////////////////////////// + // parameter properties + //////////////////////////////////////////////////////////////////////////////// + + /** @brief Basic parameter descriptor properties */ + static PropertyDescription gBasicParamProps[ ] = + { + PropertyDescription(kOfxPropType, OFX::eString, 1, eDescDefault, kOfxTypeParameter, eDescFinished), + PropertyDescription(kOfxPropName, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropShortLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxPropLongLabel, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropType, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropSecret, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxParamPropHint, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropScriptName, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropParent, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropEnabled, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropDataPtr, OFX::ePointer,1, eDescDefault, (void *)(0), eDescFinished), + }; + + + /** @brief Props for params that can have an interact override their UI */ + static PropertyDescription gInteractOverideParamProps[ ] = + { + PropertyDescription(kOfxParamPropInteractV1, OFX::ePointer,1, eDescDefault, (void *)(0), eDescFinished), + PropertyDescription(kOfxParamPropInteractSize, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxParamPropInteractSizeAspect, OFX::eDouble, 1, eDescDefault, 1.0, eDescFinished), + PropertyDescription(kOfxParamPropInteractMinimumSize, OFX::eDouble, 2, eDescDefault, 10, 10, eDescFinished), + PropertyDescription(kOfxParamPropInteractPreferedSize, OFX::eInt, 2, eDescDefault, 10, 10, eDescFinished), + }; + + /** @brief Props for params that can hold values. */ + static PropertyDescription gValueHolderParamProps[ ] = + { + PropertyDescription(kOfxParamPropIsAnimating, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropIsAutoKeying, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropPersistant, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropEvaluateOnChange, OFX::eInt, 1, eDescDefault, 1, eDescFinished), +# ifdef kOfxParamPropPluginMayWrite + PropertyDescription(kOfxParamPropPluginMayWrite, OFX::eInt, 1, eDescDefault, 0, eDescFinished), // removed in OFX 1.4 +# endif + PropertyDescription(kOfxParamPropCacheInvalidation, OFX::eString, 1, eDescDefault, kOfxParamInvalidateValueChange, eDescFinished), + PropertyDescription(kOfxParamPropCanUndo, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + }; + + /** @brief values for a string param */ + static PropertyDescription gStringParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxParamPropStringMode, OFX::eString, 1, eDescDefault, kOfxParamStringIsSingleLine, eDescFinished), + PropertyDescription(kOfxParamPropStringFilePathExists, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + }; + + /** @brief values for a string param */ + static PropertyDescription gCustomParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxParamPropCustomInterpCallbackV1, OFX::ePointer, 1, eDescDefault, NULLPTR, eDescFinished), + }; + + /** @brief properties for an RGB colour param */ + static PropertyDescription gRGBColourParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eDouble, 3, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eDouble, 3, eDescDefault, 0., 0., 0., eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eDouble, 3, eDescDefault, 1., 1., 1., eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eDouble, 3, eDescDefault, 0., 0., 0., eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eDouble, 3, eDescDefault, 1., 1., 1., eDescFinished), + PropertyDescription(kOfxParamPropDimensionLabel, OFX::eString, 3, eDescDefault, "r", "g", "b", eDescFinished), + }; + + /** @brief properties for an RGBA colour param */ + static PropertyDescription gRGBAColourParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eDouble, 4, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eDouble, 4, eDescDefault, 0., 0., 0., 0., eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eDouble, 4, eDescDefault, 1., 1., 1., 1., eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eDouble, 4, eDescDefault, 0., 0., 0., 0., eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eDouble, 4, eDescDefault, 1., 1., 1., 1., eDescFinished), + PropertyDescription(kOfxParamPropDimensionLabel, OFX::eString, 4, eDescDefault, "r", "g", "b", "a", eDescFinished), + }; + + /** @brief properties for a boolean param */ + static PropertyDescription gBooleanParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + }; + + + /** @brief properties for a choice param */ + static PropertyDescription gChoiceParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxParamPropChoiceOption, OFX::eString, -1, eDescFinished), + }; + + /** @brief properties for a string choice param */ + static PropertyDescription gStrChoiceParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eString, 1, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + PropertyDescription(kOfxParamPropChoiceEnum, OFX::eString, -1, eDescFinished), + PropertyDescription(kOfxParamPropChoiceOption, OFX::eString, -1, eDescFinished), + }; + + /** @brief properties for a 1D integer param */ + static PropertyDescription gInt1DParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + }; + + /** @brief properties for a 2D integer param */ + static PropertyDescription gInt2DParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eInt, 2, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eInt, 2, eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eInt, 2, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eInt, 2, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eInt, 2, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropDimensionLabel, OFX::eString, 2, eDescDefault, "x", "y", eDescFinished), + }; + + /** @brief properties for a 3D integer param */ + static PropertyDescription gInt3DParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eInt, 3, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eInt, 3, eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eInt, 3, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eInt, 3, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eInt, 3, eDescFinished), + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropDimensionLabel, OFX::eString, 3, eDescDefault, "x", "y", "z", eDescFinished), + }; + + /** @brief Properties common to all double params */ + static PropertyDescription gDoubleParamProps[ ] = + { + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropIncrement, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxParamPropDigits, OFX::eInt, 1, eDescFinished), + PropertyDescription(kOfxParamPropDoubleType, OFX::eString, 1, eDescDefault, kOfxParamDoubleTypePlain, eDescFinished), + }; + + + /** @brief properties for a 1D double param */ + static PropertyDescription gDouble1DParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eDouble, 1, eDescFinished), + PropertyDescription(kOfxParamPropShowTimeMarker, OFX::eInt, 1, eDescDefault, 0, eDescFinished), + }; + + /** @brief properties for a 2D double param */ + static PropertyDescription gDouble2DParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eDouble, 2, eDescFinished), + PropertyDescription(kOfxParamPropDimensionLabel, OFX::eString, 2, eDescDefault, "x", "y", eDescFinished), + }; + + /** @brief properties for a 3D double param */ + static PropertyDescription gDouble3DParamProps[ ] = + { + PropertyDescription(kOfxParamPropDefault, OFX::eDouble, 3, eDescFinished), + PropertyDescription(kOfxParamPropMin, OFX::eDouble, 3, eDescFinished), + PropertyDescription(kOfxParamPropMax, OFX::eDouble, 3, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMin, OFX::eDouble, 3, eDescFinished), + PropertyDescription(kOfxParamPropDisplayMax, OFX::eDouble, 3, eDescFinished), + PropertyDescription(kOfxParamPropDimensionLabel, OFX::eString, 3, eDescDefault, "x", "y", "z", eDescFinished), + }; + + /** @brief properties for a group param */ + static PropertyDescription gGroupParamProps[ ] = + { + PropertyDescription(kOfxParamPropGroupOpen, OFX::eInt, 1, eDescFinished), + }; + + /** @brief properties for a page param */ + static PropertyDescription gPageParamProps[ ] = + { + PropertyDescription(kOfxParamPropPageChild, OFX::eString, -1, eDescFinished), + }; + + /** @brief properties for a parametric param */ + static PropertyDescription gParametricParamProps[ ] = + { + PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropCanUndo, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropParametricDimension, OFX::eInt, 1, eDescDefault, 1, eDescFinished), + PropertyDescription(kOfxParamPropParametricUIColour, OFX::eDouble, -1, eDescFinished), + PropertyDescription(kOfxParamPropParametricInteractBackground, OFX::ePointer, 1, eDescDefault, (void*)(0), eDescFinished), + PropertyDescription(kOfxParamPropParametricRange, OFX::eDouble, 2, eDescDefault, 0.0, 1.0, eDescFinished), + }; + + /** @brief Property set for 1D ints */ + static PropertySetDescription gInt1DParamPropSet("1D Integer parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gInt1DParamProps), + NULLPTR); + + + /** @brief Property set for 2D ints */ + static PropertySetDescription gInt2DParamPropSet("2D Integer parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gInt2DParamProps), + NULLPTR); + + /** @brief Property set for 3D ints */ + static PropertySetDescription gInt3DParamPropSet("3D Integer parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gInt3DParamProps), + NULLPTR); + + /** @brief Property set for 1D doubles */ + static PropertySetDescription gDouble1DParamPropSet("1D Double parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gDoubleParamProps), + mPropDescriptionArg(gDouble1DParamProps), + NULLPTR); + + + /** @brief Property set for 2D doubles */ + static PropertySetDescription gDouble2DParamPropSet("2D Double parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gDoubleParamProps), + mPropDescriptionArg(gDouble2DParamProps), + NULLPTR); + + /** @brief Property set for 3D doubles */ + static PropertySetDescription gDouble3DParamPropSet("3D Double parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gDoubleParamProps), + mPropDescriptionArg(gDouble3DParamProps), + NULLPTR); + + /** @brief Property set for RGB colour params */ + static PropertySetDescription gRGBParamPropSet("RGB Colour parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gRGBColourParamProps), + NULLPTR); + + /** @brief Property set for RGB colour params */ + static PropertySetDescription gRGBAParamPropSet("RGB Colour parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gRGBAColourParamProps), + NULLPTR); + + /** @brief Property set for string params */ + static PropertySetDescription gStringParamPropSet("String parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gStringParamProps), + NULLPTR); + + /** @brief Property set for string params */ + static PropertySetDescription gCustomParamPropSet("Custom parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gCustomParamProps), + NULLPTR); + + /** @brief Property set for boolean params */ + static PropertySetDescription gBooleanParamPropSet("Boolean parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gBooleanParamProps), + NULLPTR); + + /** @brief Property set for choice params */ + static PropertySetDescription gChoiceParamPropSet("Choice parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gChoiceParamProps), + NULLPTR); + + /** @brief Property set for string choice params */ + static PropertySetDescription gStrChoiceParamPropSet("String Choice parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gStrChoiceParamProps), + NULLPTR); + + /** @brief Property set for push button params */ + static PropertySetDescription gPushButtonParamPropSet("PushButton parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + NULLPTR); + + /** @brief Property set for group params */ + static PropertySetDescription gGroupParamPropSet("Group Parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gGroupParamProps), + NULLPTR); + + /** @brief Property set for page params */ + static PropertySetDescription gPageParamPropSet("Page Parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gPageParamProps), + NULLPTR); + + static PropertySetDescription gParametricParamPropSet("Parametric Parameter", + mPropDescriptionArg(gBasicParamProps), + mPropDescriptionArg(gInteractOverideParamProps), + mPropDescriptionArg(gValueHolderParamProps), + mPropDescriptionArg(gParametricParamProps), + NULLPTR); + +#endif + /** @brief Validates the host structure and property handle */ + void + validateHostProperties(OfxHost *host) + { +#ifdef kOfxsDisableValidation + (void)host; +#else + // make a description set + PropertySet props(host->host); + gHostPropSet.validate(props); +#endif + } + + /** @brief Validates the effect descriptor properties */ + void + validatePluginDescriptorProperties(PropertySet props) + { +#ifdef kOfxsDisableValidation + (void)props; +#else + gPluginDescriptorPropSet.validate(props); +#endif + } + + /** @brief Validates the effect instance properties */ + void + validatePluginInstanceProperties(PropertySet props) + { +#ifdef kOfxsDisableValidation + (void)props; +#else + gPluginInstancePropSet.validate(props); +#endif + } + + /** @brief validates a clip descriptor */ + void + validateClipDescriptorProperties(PropertySet props) + { +#ifdef kOfxsDisableValidation + (void)props; +#else + gClipDescriptorPropSet.validate(props); +#endif + } + + /** @brief validates a clip instance */ + void + validateClipInstanceProperties(PropertySet props) + { +#ifdef kOfxsDisableValidation + (void)props; +#else + gClipInstancePropSet.validate(props); +#endif + } + + /** @brief validates an image or texture instance */ + void + validateImageBaseProperties(PropertySet props) + { +#ifdef kOfxsDisableValidation + (void)props; +#else + gImageBaseInstancePropSet.validate(props); +#endif + } + + /** @brief validates an image instance */ + void + validateImageProperties(PropertySet props) + { +#ifdef kOfxsDisableValidation + (void)props; +#else + gImageInstancePropSet.validate(props); +#endif + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief validates an OpenGL texture instance */ + void + validateTextureProperties(PropertySet props) + { +#ifdef kOfxsDisableValidation + (void)props; +#else + gTextureInstancePropSet.validate(props); +#endif + } +#endif + + /** @brief Validates action in/out arguments */ + void + validateActionArgumentsProperties(const std::string &action, PropertySet inArgs, PropertySet outArgs) + { +#ifdef kOfxsDisableValidation + (void)action; + (void)inArgs; + (void)outArgs; +#else + if(action == kOfxActionInstanceChanged) { + gInstanceChangedInArgPropSet.validate(inArgs); + } + else if(action == kOfxActionBeginInstanceChanged) { + gBeginInstanceChangedInArgPropSet.validate(inArgs); + } + else if(action == kOfxActionEndInstanceChanged) { + gEndInstanceChangedInArgPropSet.validate(inArgs); + } + else if(action == kOfxImageEffectActionGetRegionOfDefinition) { + gGetRegionOfDefinitionInArgPropSet.validate(inArgs); + gGetRegionOfDefinitionOutArgPropSet.validate(outArgs); + } + else if(action == kOfxImageEffectActionGetRegionsOfInterest) { + gGetRegionOfInterestInArgPropSet.validate(inArgs); + } + else if(action == kOfxImageEffectActionGetTimeDomain) { + gGetTimeDomainOutArgPropSet.validate(outArgs); + } + else if(action == kOfxImageEffectActionGetFramesNeeded) { + gGetFramesNeededInArgPropSet.validate(inArgs); + } + else if(action == kOfxImageEffectActionGetClipPreferences) { + gGetClipPreferencesOutArgPropSet.validate(outArgs); + } + else if(action == kOfxImageEffectActionIsIdentity) { + gIsIdentityActionInArgPropSet.validate(inArgs); + gIsIdentityActionOutArgPropSet.validate(outArgs); + } + else if(action == kOfxImageEffectActionRender) { + gRenderActionInArgPropSet.validate(inArgs); + } + else if(action == kOfxImageEffectActionBeginSequenceRender) { + gBeginSequenceRenderActionInArgPropSet.validate(inArgs); + } + else if(action == kOfxImageEffectActionEndSequenceRender) { + gEndSequenceRenderActionInArgPropSet.validate(inArgs); + } + else if(action == kOfxImageEffectActionDescribeInContext) { + gDescribeInContextActionInArgPropSet.validate(inArgs); + } +#endif + } + + /** @brief Validates parameter properties */ + void + validateParameterProperties(ParamTypeEnum paramType, + OFX::PropertySet paramProps, + bool checkDefaults) + { +#ifdef kOfxsDisableValidation + (void)paramType; + (void)paramProps; + (void)checkDefaults; +#else + // should use a map here + switch(paramType) + { + case eStringParam : + gStringParamPropSet.validate(paramProps, checkDefaults); + break; + case eIntParam : + gInt1DParamPropSet.validate(paramProps, checkDefaults); + break; + case eInt2DParam : + gInt2DParamPropSet.validate(paramProps, checkDefaults); + break; + case eInt3DParam : + gInt3DParamPropSet.validate(paramProps, checkDefaults); + break; + case eDoubleParam : + gDouble1DParamPropSet.validate(paramProps, checkDefaults); + break; + case eDouble2DParam : + gDouble2DParamPropSet.validate(paramProps, checkDefaults); + break; + case eDouble3DParam : + gDouble3DParamPropSet.validate(paramProps, checkDefaults); + break; + case eRGBParam : + gRGBParamPropSet.validate(paramProps, checkDefaults); + break; + case eRGBAParam : + gRGBAParamPropSet.validate(paramProps, checkDefaults); + break; + case eBooleanParam : + gBooleanParamPropSet.validate(paramProps, checkDefaults); + break; + case eChoiceParam : + gChoiceParamPropSet.validate(paramProps, checkDefaults); + break; + case eStrChoiceParam : + gStrChoiceParamPropSet.validate(paramProps, checkDefaults); + break; + case eCustomParam : + gCustomParamPropSet.validate(paramProps, checkDefaults); + break; + case eGroupParam : + gGroupParamPropSet.validate(paramProps, checkDefaults); + break; + case ePageParam : + gPageParamPropSet.validate(paramProps, checkDefaults); + break; + case ePushButtonParam : + gPushButtonParamPropSet.validate(paramProps, checkDefaults); + break; + case eParametricParam: + gParametricParamPropSet.validate(paramProps, checkDefaults); + break; + case eDummyParam: + //default: + break; + } +#endif + } + + //////////////////////////////////////////////////////////////////////////////// + // + + /** @brief Initialises validation stuff that needs to be done once we know how the host behaves, called during the onload action */ + void + initialise(void) + { +#ifndef kOfxsDisableValidation + static bool beenInitialised = false; + if(!beenInitialised && getImageEffectHostDescription()) { + beenInitialised = true; + + // create new property descriptions depending on certain host states + PropertyDescription *desc; + + // do custom params animate ? + desc = new PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, + eDescDefault, int(getImageEffectHostDescription()->supportsCustomAnimation), + eDescFinished); + gCustomParamPropSet.addProperty(desc, true); + + // do strings animate ? + desc = new PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, + eDescDefault, int(getImageEffectHostDescription()->supportsStringAnimation), + eDescFinished); + gStringParamPropSet.addProperty(desc, true); + + // do choice params animate + desc = new PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, + eDescDefault, int(getImageEffectHostDescription()->supportsChoiceAnimation), + eDescFinished); + gChoiceParamPropSet.addProperty(desc, true); + + // do string choice params animate + desc = new PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, + eDescDefault, int(getImageEffectHostDescription()->supportsStrChoiceAnimation), + eDescFinished); + gStrChoiceParamPropSet.addProperty(desc, true); + + // do boolean params animate + desc = new PropertyDescription(kOfxParamPropAnimates, OFX::eInt, 1, + eDescDefault, int(getImageEffectHostDescription()->supportsBooleanAnimation), + eDescFinished); + gBooleanParamPropSet.addProperty(desc, true); + } +#endif + } + }; +}; diff --git a/third_party/openfx/Support/Library/ofxsSupportPrivate.h b/third_party/openfx/Support/Library/ofxsSupportPrivate.h new file mode 100644 index 000000000..55865305d --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsSupportPrivate.h @@ -0,0 +1,228 @@ + + +#ifndef _ofxsSupportPrivate_H_ +#define _ofxsSupportPrivate_H_ + +#include "ofxsInteract.h" +#include "ofxsImageEffect.h" +#include "ofxsLog.h" +#include "ofxsMultiThread.h" + +/** @brief Namespace private to the ofx support library. +*/ +namespace OFX { + + namespace Private { + /** @brief Pointer to the host */ + extern OfxHost *gHost; + + /** @brief Pointer to the effect suite */ + extern OfxImageEffectSuiteV1 *gEffectSuite; + + /** @brief Pointer to the property suite */ + extern OfxPropertySuiteV1 *gPropSuite; + + /** @brief Pointer to the interact suite */ + extern OfxInteractSuiteV1 *gInteractSuite; + + /** @brief Pointer to the parameter suite */ + extern OfxParameterSuiteV1 *gParamSuite; + + /** @brief Pointer to the general memory suite */ + extern OfxMemorySuiteV1 *gMemorySuite; + + /** @brief Pointer to the threading suite */ + extern OfxMultiThreadSuiteV1 *gThreadSuite; + + /** @brief Pointer to the message suite */ + extern OfxMessageSuiteV1 *gMessageSuite; + + /** @brief Pointer to the optional message suite V2 */ + extern OfxMessageSuiteV2 *gMessageSuiteV2; + + /** @brief Pointer to the optional progress suite */ + extern OfxProgressSuiteV1 *gProgressSuiteV1; + + /** @brief Pointer to the optional progress suite */ + extern OfxProgressSuiteV2 *gProgressSuiteV2; + + /** @brief Pointer to the optional timeline suite */ + extern OfxTimeLineSuiteV1 *gTimeLineSuite; + + /** @brief Pointer to the parametric parameter suite */ + extern OfxParametricParameterSuiteV1* gParametricParameterSuite; + + /** @brief Support lib function called on an ofx load action */ + void loadAction(void); + + /** @brief Support lib function called on an ofx unload action */ + void unloadAction(void); + + /** @brief The plugin function that gets passed the host structure. + */ + void setHost(OfxHost *host); + + /** @brief fetches our pointer out of the props on the handle */ + ImageEffect *retrieveImageEffectPointer(OfxImageEffectHandle handle); + + /** @brief fetch the prop set from the effect handle */ + OFX::PropertySet + fetchEffectProps(OfxImageEffectHandle handle); + + /** @brief the set of descriptors, one per context used by kOfxActionDescribeInContext, 'eContextNone' is the one used by the kOfxActionDescribe */ + typedef std::map EffectContextMap; + typedef std::map EffectDescriptorMap; + extern EffectDescriptorMap gEffectDescriptors; + }; + + /** @brief The validation code has its own namespace */ + namespace Validation { + + /** @brief This is uses to hold a property value, used by the property checking classes. + + Could have been a union, but std::string can't be in one. + */ + struct ValueHolder { + std::string vString; + int vInt; + double vDouble; + void *vPointer; + + ValueHolder(void) : vString(), vInt(0), vDouble(0.), vPointer(0) {} + ValueHolder(char *s) : vString(s), vInt(0), vDouble(0.), vPointer(0) {} + ValueHolder(const std::string &s) : vString(s), vInt(0), vDouble(0.), vPointer(0) {} + ValueHolder(int i) : vString(), vInt(i), vDouble(0.), vPointer(0) {} + ValueHolder(double d) : vString(), vInt(0), vDouble(d), vPointer(0) {} + ValueHolder(void *p) : vString(), vInt(0), vDouble(0.), vPointer(p) {} + + ValueHolder &operator = (char *v) {vString = v; return *this;} + ValueHolder &operator = (std::string v) {vString = v; return *this;} + ValueHolder &operator = (void *v) {vPointer = v; return *this;} + ValueHolder &operator = (int v) {vInt = v; return *this;} + ValueHolder &operator = (double v) {vDouble = v; return *this;} + + operator const char * () {return vString.c_str();} + operator std::string &() {return vString;} + operator int &() {return vInt;} + operator double &() {return vDouble;} + operator void * &() {return vPointer;} + }; + + /** @brief Enum used in the varargs list of the PropertyDescription constructor */ + enum DescriptionTag { + eDescDefault, /** @brief following values are the default to check against */ + eDescFinished /** @brief we have finished the description */ + }; + + /** @brief class to describe properties, check their default and set their values */ + class PropertyDescription + { + public : + /** @brief name of the property */ + const std::string _name; + + /** @brief Was it validated */ + bool _exists; + + /** @brief dimension of the property */ + int _dimension; + + /** @brief What type of property is it */ + OFX::PropertyTypeEnum _ilk; + + /** @brief The default value that this property should have. Empty implies no default (eg: a host name has no default). */ + std::vector _defaultValue; + + public : + /** @brief var args constructor that is use to describe properties */ + PropertyDescription(const char *name, OFX::PropertyTypeEnum ilk, int dimension, ...); + + /** @brief Die! Die! Die! */ + virtual ~PropertyDescription(void) {} + + /** @brief See if the property exists in the containing property set and has the correct dimension */ + void validate(bool checkDefaults, PropertySet &propSet); + }; + + /** @brief Describes a set of properties */ + class PropertySetDescription { + protected : + /** @brief name of the property set */ + const std::string _setName; + + /** @brief the descriptions of each property */ + std::vector _descriptions; + + /** @brief The descriptions of each property */ + std::vector _deleteThese; + + public : + /** @brief constructor. + + The varargs zero terminated are made from pairs of PropertyDescription * and ints indicating the number of properties pointed to. + These are to come from static arrays and need not be deleted + */ + PropertySetDescription(const char *setName, ...);// [PropertyDescription *v, int nSetToThese] + + /** @brief destructor */ + virtual ~PropertySetDescription(); + + /** @brief add another property in */ + void addProperty(PropertyDescription *desc, bool deleteOnDestruction = true); + + /** @brief See if all properties exist and have the correct dimensions */ + void validate(PropertySet &propSet, bool checkDefaults = true, bool logOrdinaryMessages = false); + }; + + + /** @brief Validates the host structure and property handle */ + void + validateHostProperties(OfxHost *host); + + /** @brief Validates the effect descriptor properties */ + void + validatePluginDescriptorProperties(PropertySet props); + + /** @brief Validates the effect instance properties */ + void + validatePluginInstanceProperties(PropertySet props); + + /** @brief validates a clip descriptor */ + void + validateClipDescriptorProperties(PropertySet props); + + /** @brief validates a clip instance */ + void + validateClipInstanceProperties(PropertySet props); + + /** @brief validates an image or texture instance */ + void + validateImageBaseProperties(PropertySet props); + + /** @brief validates an image instance */ + void + validateImageProperties(PropertySet props); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief validates an OpenGL texture descriptor */ + void + validateTextureProperties(PropertySet props); +#endif + + /** @brief Validates action in/out arguments */ + void + validateActionArgumentsProperties(const std::string &action, PropertySet inArgs, PropertySet outArgs); + + /** @brief Validates parameter properties */ + void + validateParameterProperties(ParamTypeEnum paramType, + OFX::PropertySet paramProps, + bool checkDefaults); + + /** @brief initialises the validation code, call this in on load */ + void initialise(void); + }; + +}; + +#endif diff --git a/third_party/openfx/Support/Library/ofxsupport.dsw b/third_party/openfx/Support/Library/ofxsupport.dsw new file mode 100755 index 000000000..d326040fd --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsupport.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ofxsupport"=.\ofxsupport.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/third_party/openfx/Support/Library/ofxsupport.vcproj b/third_party/openfx/Support/Library/ofxsupport.vcproj new file mode 100755 index 000000000..450f30441 --- /dev/null +++ b/third_party/openfx/Support/Library/ofxsupport.vcproj @@ -0,0 +1,695 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/OSXStaticLoader/pluginLoader.cpp b/third_party/openfx/Support/OSXStaticLoader/pluginLoader.cpp new file mode 100644 index 000000000..f42c2b3bc --- /dev/null +++ b/third_party/openfx/Support/OSXStaticLoader/pluginLoader.cpp @@ -0,0 +1,74 @@ + + +#include "ofxCore.h" +#include "CoreFoundation/CoreFoundation.h" + + + +typedef OfxPlugin *(OfxGetPluginFunc)(int nth); +typedef int (OfxGetNumberOfPluginsFunc)(void); + +int +main(int argc, char *argv[]) +{ + CFURLRef bundleURL; + CFBundleRef myBundle; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + CFStringRef bundlePath = CFStringCreateWithCString(kCFAllocatorDefault, + argv[1], + kCFStringEncodingASCII); + + // Make a CFURLRef from the CFString representation of the + // bundle's path. + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + bundlePath, + kCFURLPOSIXPathStyle, + true ); + + // Make a bundle instance using the URLRef. + myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); + + if(myBundle) { + // Value returned from the loaded function. + //long result; + + OfxGetNumberOfPluginsFunc *nPluginsFunc = (OfxGetNumberOfPluginsFunc *)CFBundleGetFunctionPointerForName(myBundle, CFSTR("OfxGetNumberOfPlugins") ); + OfxGetPluginFunc *getPlugin = (OfxGetPluginFunc *)CFBundleGetFunctionPointerForName(myBundle, CFSTR("OfxGetPlugin") ); + + // If the function was found, call it with a test value. + if (nPluginsFunc && getPlugin) { + // This should add 1 to whatever was passed in + int nP = nPluginsFunc(); + + + printf("Sucessfully loaded '%s', containing %d %s\n", argv[1], nP, (nP == 1 ? "plugin" : "plugins")); + + for(int i = 0; i < nP; i++) { + // get a plugin + OfxPlugin *plugin = getPlugin(i); + if(plugin) { + printf("\tFound plugin...\n\t\tAPI = %s (%d)\n\t\tid = %s (%d.%d)\n", + plugin->pluginApi, plugin->apiVersion, + plugin->pluginIdentifier, plugin->pluginVersionMajor, plugin->pluginVersionMinor); + + plugin->mainEntry(kOfxActionLoad, NULL, NULL, NULL); + plugin->mainEntry(kOfxActionUnload, NULL, NULL, NULL); + } + else + fprintf(stderr, "fetching %dth plugin returned NULL\n", i); + } + } + else + fprintf(stderr, "Failed to find symbols OfxGetPlugin or OfxGetNumberOfPlugins\n"); + } + else + fprintf(stderr, "Failed to load bundle %s\n", argv[1]); + + // Any CF objects returned from functions with "create" or + // "copy" in their names must be released by us! + CFRelease( bundleURL ); +} diff --git a/third_party/openfx/Support/Plugins/Basic/Info.plist b/third_party/openfx/Support/Plugins/Basic/Info.plist new file mode 100644 index 000000000..21152b3e8 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Basic/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + basic.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/Basic/basic.cpp b/third_party/openfx/Support/Plugins/Basic/basic.cpp new file mode 100644 index 000000000..fc78cd927 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Basic/basic.cpp @@ -0,0 +1,727 @@ + + +#ifdef _WINDOWS +#include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" + +#include "../include/ofxsProcessing.H" + +//////////////////////////////////////////////////////////////////////////////// +// a dumb interact that just draw's a square you can drag +static const OfxPointD kBoxSize = {20, 20}; + +class BasicInteract : public OFX::OverlayInteract { +protected : + enum StateEnum { + eInActive, + ePoised, + ePicked + }; + + OfxPointD _position; + StateEnum _state; + +public : + BasicInteract(OfxInteractHandle handle, OFX::ImageEffect* /*effect*/) + : OFX::OverlayInteract(handle) + , _state(eInActive) + { + _position.x = 0; + _position.y = 0; + } + + // overridden functions from OFX::Interact to do things + virtual bool draw(const OFX::DrawArgs &args); + virtual bool penMotion(const OFX::PenArgs &args); + virtual bool penDown(const OFX::PenArgs &args); + virtual bool penUp(const OFX::PenArgs &args); +}; + +//////////////////////////////////////////////////////////////////////////////// +// rendering routines +template inline T +Minimum(T a, T b) { return (a < b) ? a : b;} + +template inline T +Absolute(T a) { return (a < 0) ? -a : a;} + +template inline T +Clamp(T v, int min, int max) +{ + if(v < T(min)) return T(min); + if(v > T(max)) return T(max); + return v; +} + +// Base class for the RGBA and the Alpha processor +class ImageScalerBase : public OFX::ImageProcessor { +protected : + OFX::Image *_srcImg; + OFX::Image *_maskImg; + double _rScale, _gScale, _bScale, _aScale; + bool _doMasking; + +public : + /** @brief no arg ctor */ + ImageScalerBase(OFX::ImageEffect &instance) + : OFX::ImageProcessor(instance) + , _srcImg(0) + , _maskImg(0) + , _rScale(1) + , _gScale(1) + , _bScale(1) + , _aScale(1) + , _doMasking(false) + { + } + + /** @brief set the src image */ + void setSrcImg(OFX::Image *v) {_srcImg = v;} + + /** @brief set the optional mask image */ + void setMaskImg(OFX::Image *v) {_maskImg = v;} + + // Are we masking. We can't derive this from the mask image being set as NULL is a valid value for an input image + void doMasking(bool v) {_doMasking = v;} + + + /** @brief set the scale */ + void setScales(float r, float g, float b, float a) + { + _rScale = r; + _gScale = g; + _bScale = b; + _aScale = a; + } + +}; + +// template to do the RGBA processing +template +class ImageScaler : public ImageScalerBase { +public : + // ctor + ImageScaler(OFX::ImageEffect &instance) + : ImageScalerBase(instance) + {} + + // and do some processing + void multiThreadProcessImages(OfxRectI procWindow) + { + float scales[4]; + scales[0] = nComponents == 1 ? (float)_aScale : (float)_rScale; + scales[1] = (float)_gScale; + scales[2] = (float)_bScale; + scales[3] = (float)_aScale; + + float maskScale = 1.0f; + + for(int y = procWindow.y1; y < procWindow.y2; y++) { + if(_effect.abort()) break; + + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + + for(int x = procWindow.x1; x < procWindow.x2; x++) { + + PIX *srcPix = (PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0); + + // are we doing masking + if(_doMasking) { + // we do, get the pixel from the mask + if(!_maskImg) + maskScale = 1.0f; + else + { + PIX *maskPix = (PIX *) (_maskImg ? _maskImg->getPixelAddress(x, y) : 0); + // figure the scale factor from that pixel + maskScale = maskPix != 0 ? float(*maskPix)/float(max) : 0.0f; + } + } + + // do we have a source image to scale up + if(srcPix) { + for(int c = 0; c < nComponents; c++) { + float v; + + // scale the component up by the scale factor, modulated by the maskScale + if(maskScale != 1.0f) + v = srcPix[c] * (1.0f + (scales[c] - 1.0f) * maskScale); + else + v = srcPix[c] * scales[c]; + + if(max == 1) // implies floating point and so no clamping + dstPix[c] = PIX(v); + else // integer based and we need to clamp + dstPix[c] = PIX(Clamp(v, 0, max)); + } + } + else { + // no src pixel here, be black and transparent + for(int c = 0; c < nComponents; c++) { + dstPix[c] = 0; + } + } + // increment the dst pixel + dstPix += nComponents; + } + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class BasicPlugin : public OFX::ImageEffect { +protected : + // do not need to delete these, the ImageEffect is managing them for us + OFX::Clip *dstClip_; + OFX::Clip *srcClip_; + OFX::Clip *maskClip_; + + OFX::DoubleParam *scale_; + OFX::DoubleParam *rScale_; + OFX::DoubleParam *gScale_; + OFX::DoubleParam *bScale_; + OFX::DoubleParam *aScale_; + OFX::BooleanParam *componentScalesEnabled_; + +public : + /** @brief ctor */ + BasicPlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + , srcClip_(0) + , scale_(0) + , rScale_(0) + , gScale_(0) + , bScale_(0) + , aScale_(0) + , componentScalesEnabled_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + // name of mask clip depends on the context + maskClip_ = getContext() == OFX::eContextFilter ? NULL : fetchClip(getContext() == OFX::eContextPaint ? "Brush" : "Mask"); + scale_ = fetchDoubleParam("scale"); + rScale_ = fetchDoubleParam("scaleR"); + gScale_ = fetchDoubleParam("scaleG"); + bScale_ = fetchDoubleParam("scaleB"); + aScale_ = fetchDoubleParam("scaleA"); + componentScalesEnabled_ = fetchBooleanParam("scaleComponents"); + + // set the enabledness of our RGBA sliders + setEnabledness(); + } + + /* sets the enabledness of the component scale params depending on the type of input image and the state of the scaleComponents param */ + void setEnabledness(void); + + /* Override the render */ + virtual void render(const OFX::RenderArguments &args); + + /* override is identity */ + virtual bool isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime); + + /* override changedParam */ + virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string ¶mName); + + /* override changed clip */ + virtual void changedClip(const OFX::InstanceChangedArgs &args, const std::string &clipName); + + // override the rod call + virtual bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod); + + // override the roi call + virtual void getRegionsOfInterest(const OFX::RegionsOfInterestArguments &args, OFX::RegionOfInterestSetter &rois); + + /* set up and run a processor */ + void + setupAndProcess(ImageScalerBase &, const OFX::RenderArguments &args); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ + +//////////////////////////////////////////////////////////////////////////////// +// basic plugin render function, just a skelington to instantiate templates from + + +/* set up and run a processor */ +void +BasicPlugin::setupAndProcess(ImageScalerBase &processor, const OFX::RenderArguments &args) +{ + // get a dst image + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // fetch main input image + std::unique_ptr src(srcClip_->fetchImage(args.time)); + + // make sure bit depths are sane + if(src.get()) { + OFX::BitDepthEnum srcBitDepth = src->getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src->getPixelComponents(); + + // see if they have the same depths and bytes and all + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); // HACK!! need to throw an sensible exception here! + } + + std::unique_ptr mask; + + // do we do masking + if(getContext() != OFX::eContextFilter) { + mask.reset(maskClip_->fetchImage(args.time)); + // say we are masking + processor.doMasking(true); + + // Set it in the processor + processor.setMaskImg(mask.get()); + } + + // get the scale parameter values... + double r, g, b, a = aScale_->getValueAtTime(args.time); + r = g = b = scale_->getValueAtTime(args.time); + + // see if the individual component scales are enabled + if(componentScalesEnabled_->getValueAtTime(args.time)) { + r *= rScale_->getValueAtTime(args.time); + g *= gScale_->getValueAtTime(args.time); + b *= bScale_->getValueAtTime(args.time); + } + + // set the images + processor.setDstImg(dst.get()); + processor.setSrcImg(src.get()); + + + // set the render window + processor.setRenderWindow(args.renderWindow); + + // set the scales + processor.setScales((float)r, (float)g, (float)b, (float)a); + + // Call the base class process member, this will call the derived templated process code + processor.process(); +} + +// override the rod call +bool +BasicPlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod) +{ + // our RoD is the same as the 'Source' clip's, we are not interested in the mask + rod = srcClip_->getRegionOfDefinition(args.time); + + // say we set it + return true; +} + +// override the roi call +void +BasicPlugin::getRegionsOfInterest(const OFX::RegionsOfInterestArguments &args, OFX::RegionOfInterestSetter &rois) +{ + // we don't actually need to do this as this is the default, but do it for examples sake + rois.setRegionOfInterest(*srcClip_, args.regionOfInterest); + + // set it on the mask only if we are in an interesting context + if(getContext() != OFX::eContextFilter) + rois.setRegionOfInterest(*maskClip_, args.regionOfInterest); +} + +// the overridden render function +void +BasicPlugin::render(const OFX::RenderArguments &args) +{ + // instantiate the render code based on the pixel depth of the dst clip + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + // do the rendering + if(dstComponents == OFX::ePixelComponentRGBA) { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + +// overridden is identity +bool +BasicPlugin:: isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime) +{ + // get the scale parameters + double scale = scale_->getValueAtTime(args.time); + double rScale = 1, gScale = 1, bScale = 1, aScale = 1; + if(componentScalesEnabled_->getValueAtTime(args.time)) { + rScale = rScale_->getValueAtTime(args.time); + gScale = gScale_->getValueAtTime(args.time); + bScale = bScale_->getValueAtTime(args.time); + aScale = aScale_->getValueAtTime(args.time); + } + rScale *= scale; gScale *= scale; bScale *= scale; + + // do we do any scaling ? + if(rScale == 1 && gScale == 1 && bScale == 1 && aScale == 1) { + identityClip = srcClip_; + identityTime = args.time; + return true; + } + + // nope, idenity we is + return false; +} + +// set the enabledness of the individual component scales +void +BasicPlugin::setEnabledness(void) +{ + // the componet enabledness depends on the clip being RGBA and the param being true + bool v = componentScalesEnabled_->getValue() && srcClip_->getPixelComponents() == OFX::ePixelComponentRGBA; + + // enable them + rScale_->setEnabled(v); + gScale_->setEnabled(v); + bScale_->setEnabled(v); + aScale_->setEnabled(v); +} + +// we have changed a param +void +BasicPlugin::changedParam(const OFX::InstanceChangedArgs &/*args*/, const std::string ¶mName) +{ + if(paramName == "scaleComponents") setEnabledness(); +} + +// we have changed a param +void +BasicPlugin::changedClip(const OFX::InstanceChangedArgs &/*args*/, const std::string &clipName) +{ + if(clipName == kOfxImageEffectSimpleSourceClipName) setEnabledness(); +} + +//////////////////////////////////////////////////////////////////////////////// +// stuff for the interact + +// draw the interact +bool BasicInteract::draw(const OFX::DrawArgs &args) +{ + OfxRGBColourF col; + switch(_state) + { + case eInActive : col.r = col.g = col.b = 0.0f; break; + case ePoised : col.r = col.g = col.b = 0.5f; break; + case ePicked : col.r = col.g = col.b = 1.0f; break; + } + + // make the box a constant size on screen by scaling by the pixel scale + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + + // Draw a cross hair, the current coordinate system aligns with the image plane. + glPushMatrix(); + + // draw the bo + glColor3f(col.r, col.g, col.b); + glTranslated(_position.x, _position.y, 0); + glBegin(GL_POLYGON); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + + glPushMatrix(); + // draw a complementary outline + glColor3f(1.0f - col.r, 1.0f - col.g, 1.0f - col.b); + glTranslated(_position.x, _position.y, 0); + glBegin(GL_LINE_LOOP); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + + return true; +} + +// overridden functions from OFX::Interact to do things +bool +BasicInteract::penMotion(const OFX::PenArgs &args) +{ + // figure the size of the box in cannonical coords + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + + // pen position is in cannonical coords + OfxPointD penPos = args.penPosition; + + switch(_state) { +case eInActive : +case ePoised : + { + // are we in the box, become 'poised' + StateEnum newState; + penPos.x -= _position.x; + penPos.y -= _position.y; + if(Absolute(penPos.x) < dx && + Absolute(penPos.y) < dy) { + newState = ePoised; + } + else { + newState = eInActive; + } + + if(_state != newState) { + // we have a new state + _state = newState; + + // and force an overlay redraw + _effect->redrawOverlays(); + } + } + break; + +case ePicked : + { + // move our position + _position = penPos; + + // and force an overlay redraw + _effect->redrawOverlays(); + } + break; + } + + // we have trapped it only if the mouse ain't over it or we are actively dragging + return _state != eInActive; +} + +bool +BasicInteract::penDown(const OFX::PenArgs &args) +{ + // this will refigure the state + penMotion(args); + + // if poised means we were over it when the pen went down, so pick it + if(_state == ePoised) { + // we are now picked + _state = ePicked; + + // move our position + _position = args.penPosition; + + // and request a redraw just incase + _effect->redrawOverlays(); + } + + return _state == ePicked; +} + +bool +BasicInteract::penUp(const OFX::PenArgs &args) +{ + if(_state == ePicked) { + // reset to poised for a moment + _state = ePoised; + + // this will refigure the state + penMotion(args); + + // and redraw for good measure + _effect->redrawOverlays(); + + // we did trap it + return true; + } + + // we didn't trap it + return false; +} + + +using namespace OFX; + +mDeclarePluginFactory(BasicExamplePluginFactory, {}, {}); + +class BasicExampleOverlayDescriptor : public DefaultEffectOverlayDescriptor {}; + +void BasicExamplePluginFactory::describe(OFX::ImageEffectDescriptor& desc) +{ + // basic labels + desc.setLabels("Gain", "Gain", "Gain"); + desc.setPluginGrouping("OFX Example (Support)"); + + // add the supported contexts, only filter at the moment + desc.addSupportedContext(eContextFilter); + desc.addSupportedContext(eContextGeneral); + desc.addSupportedContext(eContextPaint); + + // add supported pixel depths + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + // set a few flags + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + + desc.setOverlayInteractDescriptor( new BasicExampleOverlayDescriptor); +} + +// make a double scale param +static +DoubleParamDescriptor *defineScaleParam(OFX::ImageEffectDescriptor &desc, + const std::string &name, const std::string &label, const std::string &hint, + GroupParamDescriptor *parent) +{ + DoubleParamDescriptor *param = desc.defineDoubleParam(name); + param->setLabels(label, label, label); + param->setScriptName(name); + param->setHint(hint); + param->setDefault(1); + param->setRange(0, 10); + param->setIncrement(0.1); + param->setDisplayRange(0, 10); + param->setDoubleType(eDoubleTypeScale); + if(parent) param->setParent(*parent); + return param; +} + + +void BasicExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor& desc, OFX::ContextEnum context) +{ + // Source clip only in the filter context + // create the mandated source clip + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->addSupportedComponent(ePixelComponentAlpha); + srcClip->setTemporalClipAccess(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + + // if general or paint context, define the mask clip + if(context == eContextGeneral || context == eContextPaint) { + // if paint context, it is a mandated input called 'brush' + ClipDescriptor *maskClip = context == eContextGeneral ? desc.defineClip("Mask") : desc.defineClip("Brush"); + maskClip->addSupportedComponent(ePixelComponentAlpha); + maskClip->setTemporalClipAccess(false); + if(context == eContextGeneral) + maskClip->setOptional(true); + maskClip->setSupportsTiles(true); + maskClip->setIsMask(true); // we are a mask input + } + + // create the mandated output clip + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + + // make some pages and to things in + PageParamDescriptor *page = desc.definePageParam("Controls"); + + // group param to group the scales + GroupParamDescriptor *componentScalesGroup = desc.defineGroupParam("componentScales"); + componentScalesGroup->setHint("Scales on the individual component"); + componentScalesGroup->setLabels("Components", "Components", "Components"); + + // make overall scale params + DoubleParamDescriptor *param = defineScaleParam(desc, "scale", "scale", "Scales all component in the image", 0); + page->addChild(*param); + + // add a boolean to enable the component scale + BooleanParamDescriptor *boolP = desc.defineBooleanParam("scaleComponents"); + boolP->setDefault(true); + boolP->setHint("Enables scales on individual components"); + boolP->setLabels("Scale Components", "Scale Components", "Scale Components"); + boolP->setParent(*componentScalesGroup); + page->addChild(*boolP); + + // make the four component scale params + param = defineScaleParam(desc, "scaleR", "red", "Scales the red component of the image", componentScalesGroup); + page->addChild(*param); + + param = defineScaleParam(desc, "scaleG", "green", "Scales the green component of the image", componentScalesGroup); + page->addChild(*param); + + param = defineScaleParam(desc, "scaleB", "blue", "Scales the blue component of the image", componentScalesGroup); + page->addChild(*param); + + param = defineScaleParam(desc, "scaleA", "alpha", "Scales the alpha component of the image", componentScalesGroup); + page->addChild(*param); +} + +ImageEffect *BasicExamplePluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum /*context*/) +{ + return new BasicPlugin(handle); +} + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static BasicExamplePluginFactory p("net.sf.openfx.basicPlugin", 1, 0); + ids.push_back(&p); + } + } +} diff --git a/third_party/openfx/Support/Plugins/Basic/basic.dsp b/third_party/openfx/Support/Plugins/Basic/basic.dsp new file mode 100755 index 000000000..c58eafeca --- /dev/null +++ b/third_party/openfx/Support/Plugins/Basic/basic.dsp @@ -0,0 +1,107 @@ +# Microsoft Developer Studio Project File - Name="basic" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=basic - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "basic.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "basic.mak" CFG="basic - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "basic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "basic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "basic - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib /nologo /dll /machine:I386 /out:"Release/PropTester.ofx.bundle/Contents/Win32/basic.ofx" + +!ELSEIF "$(CFG)" == "basic - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include" /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\Common Files\OFX\Plugins\Basic.ofx.bundle\Contents\Win32\basic.ofx" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "basic - Win32 Release" +# Name "basic - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\basic.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/third_party/openfx/Support/Plugins/Basic/basic.dsw b/third_party/openfx/Support/Plugins/Basic/basic.dsw new file mode 100755 index 000000000..a98a697c9 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Basic/basic.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "basic"=.\basic.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ofxsupport + End Project Dependency +}}} + +############################################################################### + +Project: "ofxsupport"=..\..\Library\ofxsupport.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/third_party/openfx/Support/Plugins/Basic/basic.vcproj b/third_party/openfx/Support/Plugins/Basic/basic.vcproj new file mode 100755 index 000000000..eda736e58 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Basic/basic.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/CMakeLists.txt b/third_party/openfx/Support/Plugins/CMakeLists.txt new file mode 100644 index 000000000..731b6cdc7 --- /dev/null +++ b/third_party/openfx/Support/Plugins/CMakeLists.txt @@ -0,0 +1,48 @@ +include(OpenFX) + +set(PLUGINS + Basic + ChoiceParams + Field + Generator + GPUGain + Invert + MultiBundle + Retimer + Tester + Transition) + +foreach(PLUGIN IN LISTS PLUGINS) + file(GLOB_RECURSE PLUGIN_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${PLUGIN}/*.cpp") + if (${PLUGIN} STREQUAL "GPUGain") + if(APPLE) + file(GLOB_RECURSE METAL_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${PLUGIN}/*.mm") # add Metal kernel + list(APPEND PLUGIN_SOURCES ${METAL_SOURCES}) + endif() + if (OFX_SUPPORTS_CUDARENDER) + file(GLOB_RECURSE CUDA_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${PLUGIN}/*.cu") + list(APPEND PLUGIN_SOURCES ${CUDA_SOURCES}) + endif() + if (NOT OFX_SUPPORTS_OPENCLRENDER) + list(FILTER PLUGIN_SOURCES EXCLUDE REGEX "OpenCLKernel") + endif() + endif() + + set(TGT example-${PLUGIN}-support) + add_ofx_plugin(${TGT} ${PLUGIN}) + target_sources(${TGT} PUBLIC ${PLUGIN_SOURCES}) + target_link_libraries(${TGT} ${CONAN_LIBS} OfxSupport opengl::opengl) + target_include_directories(${TGT} PUBLIC ${OFX_HEADER_DIR} ${OFX_SUPPORT_HEADER_DIR}) + if(APPLE) + target_link_libraries(${TGT} "-framework Metal" "-framework Foundation" "-framework QuartzCore") + if (OFX_SUPPORTS_OPENCLRENDER) + target_link_libraries(${TGT} "-framework OpenCL") + endif() + else() + if (OFX_SUPPORTS_OPENCLRENDER) + target_link_libraries(${TGT} OpenCL::Headers OpenCL::OpenCL) + endif() + endif() + + +endforeach() diff --git a/third_party/openfx/Support/Plugins/ChoiceParams/Info.plist b/third_party/openfx/Support/Plugins/ChoiceParams/Info.plist new file mode 100644 index 000000000..750eda640 --- /dev/null +++ b/third_party/openfx/Support/Plugins/ChoiceParams/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + choiceparams.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/ChoiceParams/choiceparams.cpp b/third_party/openfx/Support/Plugins/ChoiceParams/choiceparams.cpp new file mode 100644 index 000000000..c83f5d4ba --- /dev/null +++ b/third_party/openfx/Support/Plugins/ChoiceParams/choiceparams.cpp @@ -0,0 +1,681 @@ + + +#ifdef _WINDOWS +#include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include "ofxsImageEffect.h" + +#include "../include/ofxsProcessing.H" + +//////////////////////////////////////////////////////////////////////////////// +// a dumb interact that just draw's a square you can drag +static const OfxPointD kBoxSize = {20, 20}; + +class ChoiceParamsInteract : public OFX::OverlayInteract { +protected : + enum StateEnum { + eInActive, + ePoised, + ePicked + }; + + OfxPointD _position; + StateEnum _state; + +public : + ChoiceParamsInteract(OfxInteractHandle handle, OFX::ImageEffect* /*effect*/) + : OFX::OverlayInteract(handle) + , _state(eInActive) + { + _position.x = 0; + _position.y = 0; + } + + // overridden functions from OFX::Interact to do things + virtual bool draw(const OFX::DrawArgs &args); + virtual bool penMotion(const OFX::PenArgs &args); + virtual bool penDown(const OFX::PenArgs &args); + virtual bool penUp(const OFX::PenArgs &args); +}; + +//////////////////////////////////////////////////////////////////////////////// +// rendering routines +template inline T +Minimum(T a, T b) { return (a < b) ? a : b;} + +template inline T +Absolute(T a) { return (a < 0) ? -a : a;} + +template inline T +Clamp(T v, int min, int max) +{ + if(v < T(min)) return T(min); + if(v > T(max)) return T(max); + return v; +} + +// Base class for the RGBA and the Alpha processor +class ImageScalerBase : public OFX::ImageProcessor { +protected : + OFX::Image *_srcImg; + OFX::Image *_maskImg; + double _rScale, _gScale, _bScale, _aScale; + bool _doMasking; + +public : + /** @brief no arg ctor */ + ImageScalerBase(OFX::ImageEffect &instance) + : OFX::ImageProcessor(instance) + , _srcImg(0) + , _maskImg(0) + , _rScale(1) + , _gScale(1) + , _bScale(1) + , _aScale(1) + , _doMasking(false) + { + } + + /** @brief set the src image */ + void setSrcImg(OFX::Image *v) {_srcImg = v;} + + /** @brief set the optional mask image */ + void setMaskImg(OFX::Image *v) {_maskImg = v;} + + // Are we masking. We can't derive this from the mask image being set as NULL is a valid value for an input image + void doMasking(bool v) {_doMasking = v;} + + + /** @brief set the scale */ + void setScales(float r, float g, float b, float a) + { + _rScale = r; + _gScale = g; + _bScale = b; + _aScale = a; + } + +}; + +// template to do the RGBA processing +template +class ImageScaler : public ImageScalerBase { +public : + // ctor + ImageScaler(OFX::ImageEffect &instance) + : ImageScalerBase(instance) + {} + + // and do some processing + void multiThreadProcessImages(OfxRectI procWindow) + { + float scales[4]; + scales[0] = nComponents == 1 ? (float)_aScale : (float)_rScale; + scales[1] = (float)_gScale; + scales[2] = (float)_bScale; + scales[3] = (float)_aScale; + + float maskScale = 1.0f; + + for(int y = procWindow.y1; y < procWindow.y2; y++) { + if(_effect.abort()) break; + + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + + for(int x = procWindow.x1; x < procWindow.x2; x++) { + + PIX *srcPix = (PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0); + + // are we doing masking + if(_doMasking) { + // we do, get the pixel from the mask + if(!_maskImg) + maskScale = 1.0f; + else + { + PIX *maskPix = (PIX *) (_maskImg ? _maskImg->getPixelAddress(x, y) : 0); + // figure the scale factor from that pixel + maskScale = maskPix != 0 ? float(*maskPix)/float(max) : 0.0f; + } + } + + // do we have a source image to scale up + if(srcPix) { + for(int c = 0; c < nComponents; c++) { + float v; + + // scale the component up by the scale factor, modulated by the maskScale + if(maskScale != 1.0f) + v = srcPix[c] * (1.0f + (scales[c] - 1.0f) * maskScale); + else + v = srcPix[c] * scales[c]; + + if(max == 1) // implies floating point and so no clamping + dstPix[c] = PIX(v); + else // integer based and we need to clamp + dstPix[c] = PIX(Clamp(v, 0, max)); + } + } + else { + // no src pixel here, be black and transparent + for(int c = 0; c < nComponents; c++) { + dstPix[c] = 0; + } + } + // increment the dst pixel + dstPix += nComponents; + } + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class ChoiceParamsPlugin : public OFX::ImageEffect { +protected : + // do not need to delete these, the ImageEffect is managing them for us + OFX::Clip *dstClip_; + OFX::Clip *srcClip_; + OFX::Clip *maskClip_; + + OFX::ChoiceParam *red_choice_; + OFX::ChoiceParam *green_choice_; + OFX::StrChoiceParam *blue_choice_; + +public : + /** @brief ctor */ + ChoiceParamsPlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + , srcClip_(0) + , red_choice_(0) + , green_choice_(0) + , blue_choice_() + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + // name of mask clip depends on the context + maskClip_ = getContext() == OFX::eContextFilter ? NULL : fetchClip(getContext() == OFX::eContextPaint ? "Brush" : "Mask"); + red_choice_ = fetchChoiceParam("red_choice"); + green_choice_ = fetchChoiceParam("green_choice"); + if (OFX::getImageEffectHostDescription()->supportsStrChoice) { + blue_choice_ = fetchStrChoiceParam("blue_choice"); + } + } + + /* Override the render */ + virtual void render(const OFX::RenderArguments &args); + + /* override is identity */ + virtual bool isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime); + + /* override changedParam */ + virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string ¶mName); + + /* override changed clip */ + virtual void changedClip(const OFX::InstanceChangedArgs &args, const std::string &clipName); + + // override the rod call + virtual bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod); + + // override the roi call + virtual void getRegionsOfInterest(const OFX::RegionsOfInterestArguments &args, OFX::RegionOfInterestSetter &rois); + + /* set up and run a processor */ + void + setupAndProcess(ImageScalerBase &, const OFX::RenderArguments &args); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ + +//////////////////////////////////////////////////////////////////////////////// +// basic plugin render function, just a skelington to instantiate templates from + + +/* set up and run a processor */ +void +ChoiceParamsPlugin::setupAndProcess(ImageScalerBase &processor, const OFX::RenderArguments &args) +{ + // get a dst image + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // fetch main input image + std::unique_ptr src(srcClip_->fetchImage(args.time)); + + // make sure bit depths are sane + if(src.get()) { + OFX::BitDepthEnum srcBitDepth = src->getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src->getPixelComponents(); + + // see if they have the same depths and bytes and all + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); // HACK!! need to throw an sensible exception here! + } + + std::unique_ptr mask; + + // do we do masking + if(getContext() != OFX::eContextFilter) { + mask.reset(maskClip_->fetchImage(args.time)); + // say we are masking + processor.doMasking(true); + + // Set it in the processor + processor.setMaskImg(mask.get()); + } + + // get the scale parameter values... + + int ri = 0; + int gi = 0; + std::string bi; + double r = 0, g = 0, b = 0, a = 0; + + red_choice_->getValueAtTime(args.time, ri); + green_choice_->getValueAtTime(args.time, gi); + + if (ri == 0) + r = 0; + if (ri == 1) + r = 0.5; + if (ri == 2) + r = 1.0; + + // Note that green options are out of order + if (gi == 0) + g = 0; + if (gi == 2) + g = 0.5; + if (gi == 1) + g = 1.0; + + if (OFX::getImageEffectHostDescription()->supportsStrChoice) { + blue_choice_->getValueAtTime(args.time, bi); + if (bi == "blue_0.0") + b = 0; + if (bi == "blue_0.5") + b = 0.5; + if (bi == "blue_1.0") + b = 1.0; + } else { + b = 1.0; + } + + a = 1.0; // always + + // set the images + processor.setDstImg(dst.get()); + processor.setSrcImg(src.get()); + + + // set the render window + processor.setRenderWindow(args.renderWindow); + + // set the scales + processor.setScales((float)r, (float)g, (float)b, (float)a); + + // Call the base class process member, this will call the derived templated process code + processor.process(); +} + +// override the rod call +bool +ChoiceParamsPlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod) +{ + // our RoD is the same as the 'Source' clip's, we are not interested in the mask + rod = srcClip_->getRegionOfDefinition(args.time); + + // say we set it + return true; +} + +// override the roi call +void +ChoiceParamsPlugin::getRegionsOfInterest(const OFX::RegionsOfInterestArguments &args, OFX::RegionOfInterestSetter &rois) +{ + // we don't actually need to do this as this is the default, but do it for examples sake + rois.setRegionOfInterest(*srcClip_, args.regionOfInterest); + + // set it on the mask only if we are in an interesting context + if(getContext() != OFX::eContextFilter) + rois.setRegionOfInterest(*maskClip_, args.regionOfInterest); +} + +// the overridden render function +void +ChoiceParamsPlugin::render(const OFX::RenderArguments &args) +{ + // instantiate the render code based on the pixel depth of the dst clip + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + // do the rendering + if(dstComponents == OFX::ePixelComponentRGBA) { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + ImageScaler fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + +// overridden is identity +bool +ChoiceParamsPlugin:: isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime) +{ + return false; +} + +// we have changed a param +void +ChoiceParamsPlugin::changedParam(const OFX::InstanceChangedArgs &/*args*/, const std::string ¶mName) +{ +} + +// we have changed a param +void +ChoiceParamsPlugin::changedClip(const OFX::InstanceChangedArgs &/*args*/, const std::string &clipName) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// stuff for the interact + +// draw the interact +bool ChoiceParamsInteract::draw(const OFX::DrawArgs &args) +{ + OfxRGBColourF col; + switch(_state) + { + case eInActive : col.r = col.g = col.b = 0.0f; break; + case ePoised : col.r = col.g = col.b = 0.5f; break; + case ePicked : col.r = col.g = col.b = 1.0f; break; + } + + // make the box a constant size on screen by scaling by the pixel scale + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + + // Draw a cross hair, the current coordinate system aligns with the image plane. + glPushMatrix(); + + // draw the bo + glColor3f(col.r, col.g, col.b); + glTranslated(_position.x, _position.y, 0); + glBegin(GL_POLYGON); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + + glPushMatrix(); + // draw a complementary outline + glColor3f(1.0f - col.r, 1.0f - col.g, 1.0f - col.b); + glTranslated(_position.x, _position.y, 0); + glBegin(GL_LINE_LOOP); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + + return true; +} + +// overridden functions from OFX::Interact to do things +bool +ChoiceParamsInteract::penMotion(const OFX::PenArgs &args) +{ + // figure the size of the box in cannonical coords + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + + // pen position is in cannonical coords + OfxPointD penPos = args.penPosition; + + switch(_state) { +case eInActive : +case ePoised : + { + // are we in the box, become 'poised' + StateEnum newState; + penPos.x -= _position.x; + penPos.y -= _position.y; + if(Absolute(penPos.x) < dx && + Absolute(penPos.y) < dy) { + newState = ePoised; + } + else { + newState = eInActive; + } + + if(_state != newState) { + // we have a new state + _state = newState; + + // and force an overlay redraw + _effect->redrawOverlays(); + } + } + break; + +case ePicked : + { + // move our position + _position = penPos; + + // and force an overlay redraw + _effect->redrawOverlays(); + } + break; + } + + // we have trapped it only if the mouse ain't over it or we are actively dragging + return _state != eInActive; +} + +bool +ChoiceParamsInteract::penDown(const OFX::PenArgs &args) +{ + // this will refigure the state + penMotion(args); + + // if poised means we were over it when the pen went down, so pick it + if(_state == ePoised) { + // we are now picked + _state = ePicked; + + // move our position + _position = args.penPosition; + + // and request a redraw just incase + _effect->redrawOverlays(); + } + + return _state == ePicked; +} + +bool +ChoiceParamsInteract::penUp(const OFX::PenArgs &args) +{ + if(_state == ePicked) { + // reset to poised for a moment + _state = ePoised; + + // this will refigure the state + penMotion(args); + + // and redraw for good measure + _effect->redrawOverlays(); + + // we did trap it + return true; + } + + // we didn't trap it + return false; +} + + +using namespace OFX; + +mDeclarePluginFactory(ChoiceParamsExamplePluginFactory, {}, {}); + +class ChoiceParamsExampleOverlayDescriptor : public DefaultEffectOverlayDescriptor {}; + +void ChoiceParamsExamplePluginFactory::describe(OFX::ImageEffectDescriptor& desc) +{ + // basic labels + desc.setLabels("Choice Params (Support)", "ChoiceParams(spt)", "Choice Params (Support)"); + desc.setPluginGrouping("OFX Example (Support)"); + + // add the supported contexts, only filter at the moment + desc.addSupportedContext(eContextFilter); + desc.addSupportedContext(eContextGeneral); + desc.addSupportedContext(eContextPaint); + + // add supported pixel depths + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + // set a few flags + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + + desc.setOverlayInteractDescriptor( new ChoiceParamsExampleOverlayDescriptor); +} + +void ChoiceParamsExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor& desc, OFX::ContextEnum context) +{ + // Source clip only in the filter context + // create the mandated source clip + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->addSupportedComponent(ePixelComponentAlpha); + srcClip->setTemporalClipAccess(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + + // if general or paint context, define the mask clip + if(context == eContextGeneral || context == eContextPaint) { + // if paint context, it is a mandated input called 'brush' + ClipDescriptor *maskClip = context == eContextGeneral ? desc.defineClip("Mask") : desc.defineClip("Brush"); + maskClip->addSupportedComponent(ePixelComponentAlpha); + maskClip->setTemporalClipAccess(false); + if(context == eContextGeneral) + maskClip->setOptional(true); + maskClip->setSupportsTiles(true); + maskClip->setIsMask(true); // we are a mask input + } + + // create the mandated output clip + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + + // make some pages and to things in + PageParamDescriptor *page = desc.definePageParam("Controls"); + + auto *choice1 = desc.defineChoiceParam("red_choice"); + choice1->appendOption("red: none"); + choice1->appendOption("red: some"); + choice1->appendOption("red: lots"); + choice1->setDefault(0); + page->addChild(*choice1); + + // Note: index 1 is "lots" (even though UI order is 2), index 2 is "some" + // because options are appended in order. + auto *choice2 = desc.defineChoiceParam("green_choice"); + choice2->appendOption("green: none", "", 0); + choice2->appendOption("green: lots", "", 2); + choice2->appendOption("green: some", "", 1); + choice2->setDefault(0); + page->addChild(*choice2); + + if (getImageEffectHostDescription()->supportsStrChoice) { + auto *choice3 = desc.defineStrChoiceParam("blue_choice"); + choice3->appendOption("blue_0.0", "blue: none", 0); + choice3->appendOption("blue_0.5", "blue: some", 1); + choice3->appendOption("blue_1.0", "blue: lots", 2); + choice3->setDefault("blue_0.0"); + page->addChild(*choice3); + } +} + +ImageEffect *ChoiceParamsExamplePluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum /*context*/) +{ + return new ChoiceParamsPlugin(handle); +} + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static ChoiceParamsExamplePluginFactory p("org.openeffects.support.choiceParamsPlugin", 1, 0); + ids.push_back(&p); + } + } +} diff --git a/third_party/openfx/Support/Plugins/ExamplePlugs.sln b/third_party/openfx/Support/Plugins/ExamplePlugs.sln new file mode 100755 index 000000000..f76427b95 --- /dev/null +++ b/third_party/openfx/Support/Plugins/ExamplePlugs.sln @@ -0,0 +1,115 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic", "Basic\basic.vcproj", "{F14E0B69-3767-44B1-A28C-326B09350C7E}" + ProjectSection(ProjectDependencies) = postProject + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} = {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ofxsupport", "..\Library\ofxsupport.vcproj", "{257EC9EE-530A-4A6F-8B2E-AAB1C8458707}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "noise", "Generator\noise.vcproj", "{F14EBC69-3767-44B1-A28C-326B59350C7F}" + ProjectSection(ProjectDependencies) = postProject + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} = {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "invert", "Invert\invert.vcproj", "{F14E0B89-3767-88B1-A28C-326B0B350C7E}" + ProjectSection(ProjectDependencies) = postProject + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} = {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "retimer", "Retimer\retimer.vcproj", "{F14E0B89-3767-48B1-A28C-326B0F350C7B}" + ProjectSection(ProjectDependencies) = postProject + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} = {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crossfade", "Transition\crossFade.vcproj", "{C14CCB89-3767-88B1-A28C-326B0B350C7E}" + ProjectSection(ProjectDependencies) = postProject + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} = {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proptester", "..\PropTester\propTester.vcproj", "{F14E0B69-BD67-4CB1-A28C-326B09350C7B}" + ProjectSection(ProjectDependencies) = postProject + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} = {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MultiBundle", "MultiBundle\multibundle.vcproj", "{F14ECC69-3767-44B1-A28C-32FB09F50C7E}" + ProjectSection(ProjectDependencies) = postProject + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} = {257EC9EE-530A-4A6F-8B2E-AAB1C8458707} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Debug|Win32.ActiveCfg = Debug|Win32 + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Debug|Win32.Build.0 = Debug|Win32 + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Debug|x64.ActiveCfg = Debug|x64 + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Debug|x64.Build.0 = Debug|x64 + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Release|Win32.ActiveCfg = Release|Win32 + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Release|Win32.Build.0 = Release|Win32 + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Release|x64.ActiveCfg = Release|x64 + {F14E0B69-3767-44B1-A28C-326B09350C7E}.Release|x64.Build.0 = Release|x64 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Debug|Win32.ActiveCfg = Debug|Win32 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Debug|Win32.Build.0 = Debug|Win32 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Debug|x64.ActiveCfg = Debug|x64 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Debug|x64.Build.0 = Debug|x64 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Release|Win32.ActiveCfg = Release|Win32 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Release|Win32.Build.0 = Release|Win32 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Release|x64.ActiveCfg = Release|x64 + {257EC9EE-530A-4A6F-8B2E-AAB1C8458707}.Release|x64.Build.0 = Release|x64 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Debug|Win32.ActiveCfg = Debug|Win32 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Debug|Win32.Build.0 = Debug|Win32 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Debug|x64.ActiveCfg = Debug|x64 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Debug|x64.Build.0 = Debug|x64 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Release|Win32.ActiveCfg = Release|Win32 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Release|Win32.Build.0 = Release|Win32 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Release|x64.ActiveCfg = Release|x64 + {F14EBC69-3767-44B1-A28C-326B59350C7F}.Release|x64.Build.0 = Release|x64 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Debug|Win32.ActiveCfg = Debug|Win32 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Debug|Win32.Build.0 = Debug|Win32 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Debug|x64.ActiveCfg = Debug|x64 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Debug|x64.Build.0 = Debug|x64 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Release|Win32.ActiveCfg = Release|Win32 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Release|Win32.Build.0 = Release|Win32 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Release|x64.ActiveCfg = Release|x64 + {F14E0B89-3767-88B1-A28C-326B0B350C7E}.Release|x64.Build.0 = Release|x64 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Debug|Win32.ActiveCfg = Debug|Win32 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Debug|Win32.Build.0 = Debug|Win32 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Debug|x64.ActiveCfg = Debug|x64 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Debug|x64.Build.0 = Debug|x64 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Release|Win32.ActiveCfg = Release|Win32 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Release|Win32.Build.0 = Release|Win32 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Release|x64.ActiveCfg = Release|x64 + {F14E0B89-3767-48B1-A28C-326B0F350C7B}.Release|x64.Build.0 = Release|x64 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Debug|Win32.ActiveCfg = Debug|Win32 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Debug|Win32.Build.0 = Debug|Win32 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Debug|x64.ActiveCfg = Debug|x64 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Debug|x64.Build.0 = Debug|x64 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Release|Win32.ActiveCfg = Release|Win32 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Release|Win32.Build.0 = Release|Win32 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Release|x64.ActiveCfg = Release|x64 + {C14CCB89-3767-88B1-A28C-326B0B350C7E}.Release|x64.Build.0 = Release|x64 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Debug|Win32.ActiveCfg = Debug|Win32 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Debug|Win32.Build.0 = Debug|Win32 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Debug|x64.ActiveCfg = Debug|x64 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Debug|x64.Build.0 = Debug|x64 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Release|Win32.ActiveCfg = Release|Win32 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Release|Win32.Build.0 = Release|Win32 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Release|x64.ActiveCfg = Release|x64 + {F14E0B69-BD67-4CB1-A28C-326B09350C7B}.Release|x64.Build.0 = Release|x64 + {F14ECC69-3767-44B1-A28C-32FB09F50C7E}.Debug|Win32.ActiveCfg = Debug|Win32 + {F14ECC69-3767-44B1-A28C-32FB09F50C7E}.Debug|Win32.Build.0 = Debug|Win32 + {F14ECC69-3767-44B1-A28C-32FB09F50C7E}.Debug|x64.ActiveCfg = Debug|Win32 + {F14ECC69-3767-44B1-A28C-32FB09F50C7E}.Release|Win32.ActiveCfg = Release|Win32 + {F14ECC69-3767-44B1-A28C-32FB09F50C7E}.Release|Win32.Build.0 = Release|Win32 + {F14ECC69-3767-44B1-A28C-32FB09F50C7E}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/third_party/openfx/Support/Plugins/Field/Info.plist b/third_party/openfx/Support/Plugins/Field/Info.plist new file mode 100644 index 000000000..f98fcd72a --- /dev/null +++ b/third_party/openfx/Support/Plugins/Field/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + field.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/Field/field.cpp b/third_party/openfx/Support/Plugins/Field/field.cpp new file mode 100644 index 000000000..b844b58cd --- /dev/null +++ b/third_party/openfx/Support/Plugins/Field/field.cpp @@ -0,0 +1,286 @@ + + +#ifdef _WINDOWS +#include +#endif + +#include +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" + +#include "../include/ofxsProcessing.H" + + +// Base class for the RGBA and the Alpha processor +class FieldBase : public OFX::ImageProcessor { +protected : + OFX::Image *_srcImg; + OFX::FieldEnum _field; +public : + /** @brief no arg ctor */ + FieldBase(OFX::ImageEffect &instance, OFX::FieldEnum field) + : OFX::ImageProcessor(instance) + , _srcImg(0), _field(field) + { + } + + /** @brief set the src image */ + void setSrcImg(OFX::Image *v) {_srcImg = v;} +}; + +// template to do the RGBA processing +template +class ImageFielder : public FieldBase { +public : + // ctor + ImageFielder(OFX::ImageEffect &instance, OFX::FieldEnum field) + : FieldBase(instance, field) + {} + + // and do some processing + void multiThreadProcessImages(OfxRectI procWindow) + { + //eFieldLower only the spatially lower field is present + //eFieldUpper only the spatially upper field is present + + for(int y = procWindow.y1; y < procWindow.y2; y++) { + if(_effect.abort()) break; + + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + + for(int x = procWindow.x1; x < procWindow.x2; x++) { + + PIX *srcPix = (PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0); + + // do we have a source image to scale up + if(srcPix) { + for(int c = 0; c < nComponents; c++) { + if((_field == OFX::eFieldLower) && (c==0)) + dstPix[c] = max; + else if((_field == OFX::eFieldUpper) && (c==2)) + dstPix[c] = max; + else + dstPix[c] = max - srcPix[c]; + } + } + else { + // no src pixel here, be black and transparent + for(int c = 0; c < nComponents; c++) { + if((_field == OFX::eFieldLower) && (c==0)) + dstPix[c] = max; + else if((_field == OFX::eFieldUpper) && (c==2)) + dstPix[c] = max; + else + dstPix[c] = 0; + } + } + + // increment the dst pixel + dstPix += nComponents; + } + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class FieldPlugin : public OFX::ImageEffect { +protected : + // do not need to delete these, the ImageEffect is managing them for us + OFX::Clip *dstClip_; + OFX::Clip *srcClip_; + +public : + /** @brief ctor */ + FieldPlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + , srcClip_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + } + + /* Override the render */ + virtual void render(const OFX::RenderArguments &args); + + /* set up and run a processor */ + void setupAndProcess(FieldBase &, const OFX::RenderArguments &args); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ + +//////////////////////////////////////////////////////////////////////////////// +// basic plugin render function, just a skelington to instantiate templates from + + +/* set up and run a processor */ +void +FieldPlugin::setupAndProcess(FieldBase &processor, const OFX::RenderArguments &args) +{ + // get a dst image + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // fetch main input image + std::unique_ptr src(srcClip_->fetchImage(args.time)); + + // make sure bit depths are sane + if(src.get()) { + OFX::BitDepthEnum srcBitDepth = src->getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src->getPixelComponents(); + + // see if they have the same depths and bytes and all + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); // HACK!! need to throw an sensible exception here! + } + + // set the images + processor.setDstImg(dst.get()); + processor.setSrcImg(src.get()); + + // set the render window + processor.setRenderWindow(args.renderWindow); + + // Call the base class process member, this will call the derived templated process code + processor.process(); +} + +// the overridden render function +void +FieldPlugin::render(const OFX::RenderArguments &args) +{ + // instantiate the render code based on the pixel depth of the dst clip + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + double time = args.time; + std::cout << "Rendering at time " << time << std::endl; + OFX::FieldEnum field = args.fieldToRender; + + // do the rendering + if(dstComponents == OFX::ePixelComponentRGBA) + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + ImageFielder fred(*this, field); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : + { + ImageFielder fred(*this, field); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : + { + ImageFielder fred(*this, field); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + ImageFielder fred(*this, field); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : + { + ImageFielder fred(*this, field); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : + { + ImageFielder fred(*this, field); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + +mDeclarePluginFactory(FieldExamplePluginFactory, {}, {}); + +using namespace OFX; +void FieldExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + // basic labels + desc.setLabels("Field", "Field", "Field"); + desc.setPluginGrouping("OFX Example (Support)"); + + // add the supported contexts, only filter at the moment + desc.addSupportedContext(eContextFilter); + + // add supported pixel depths + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + // set a few flags + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(true); + desc.setSupportsMultipleClipPARs(false); +} + +void FieldExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum /*context*/) +{ + // Source clip only in the filter context + // create the mandated source clip + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->addSupportedComponent(ePixelComponentAlpha); + srcClip->setTemporalClipAccess(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + srcClip->setFieldExtraction(eFieldExtractSingle); + + // create the mandated output clip + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + +} + +OFX::ImageEffect* FieldExamplePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/) +{ + return new FieldPlugin(handle); +} + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static FieldExamplePluginFactory p("net.sf.openfx.fieldPlugin", 1, 0); + ids.push_back(&p); + } + } +} diff --git a/third_party/openfx/Support/Plugins/Field/field.vcproj b/third_party/openfx/Support/Plugins/Field/field.vcproj new file mode 100755 index 000000000..d4e50e768 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Field/field.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/GPUGain/CudaKernel.cu b/third_party/openfx/Support/Plugins/GPUGain/CudaKernel.cu new file mode 100644 index 000000000..46d0ca03e --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/CudaKernel.cu @@ -0,0 +1,26 @@ + + +__global__ void GainAdjustKernel(int p_Width, int p_Height, float p_GainR, float p_GainG, float p_GainB, float p_GainA, const float* p_Input, float* p_Output) +{ + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if ((x < p_Width) && (y < p_Height)) + { + const int index = ((y * p_Width) + x) * 4; + + p_Output[index + 0] = p_Input[index + 0] * p_GainR; + p_Output[index + 1] = p_Input[index + 1] * p_GainG; + p_Output[index + 2] = p_Input[index + 2] * p_GainB; + p_Output[index + 3] = p_Input[index + 3] * p_GainA; + } +} + +void RunCudaKernel(void* p_Stream, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output) +{ + dim3 threads(128, 1, 1); + dim3 blocks(((p_Width + threads.x - 1) / threads.x), p_Height, 1); + cudaStream_t stream = static_cast(p_Stream); + + GainAdjustKernel<<>>(p_Width, p_Height, p_Gain[0], p_Gain[1], p_Gain[2], p_Gain[3], p_Input, p_Output); +} diff --git a/third_party/openfx/Support/Plugins/GPUGain/GPUGain.cpp b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.cpp new file mode 100644 index 000000000..3c43378e8 --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.cpp @@ -0,0 +1,462 @@ + + +#include "GPUGain.h" + +#include + +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" +#include "ofxsProcessing.h" +#include "ofxsLog.h" + +#define kPluginName "GPU Gain" +#define kPluginGrouping "OFX Example (Support)" +#define kPluginDescription "Apply separate RGB gain adjustments to each channels; CUDA/OpenCL Buffers/OpenCL Images/Metal" +#define kPluginIdentifier "com.OpenFXSample.GPUGain" +#define kPluginVersionMajor 1 +#define kPluginVersionMinor 0 + +#define kSupportsTiles false +#define kSupportsMultiResolution false +#define kSupportsMultipleClipPARs false + +//////////////////////////////////////////////////////////////////////////////// + +class GainExample : public OFX::ImageProcessor +{ +public: + explicit GainExample(OFX::ImageEffect& p_Instance); + + virtual void processImagesCuda(); + virtual void processImagesOpenCL(); + virtual void processImagesMetal(); + virtual void multiThreadProcessImages(OfxRectI p_ProcWindow); + + void setSrcImg(OFX::Image* p_SrcImg); + void setScales(float p_ScaleR, float p_ScaleG, float p_ScaleB, float p_ScaleA); + +private: + OFX::Image* _srcImg; + float _scales[4]; +}; + +GainExample::GainExample(OFX::ImageEffect& p_Instance) + : OFX::ImageProcessor(p_Instance) +{ +} + +#ifdef OFX_SUPPORTS_CUDARENDER +extern void RunCudaKernel(void* p_Stream, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output); +#endif + +void GainExample::processImagesCuda() +{ +#ifdef OFX_SUPPORTS_CUDARENDER + const OfxRectI& bounds = _srcImg->getBounds(); + const int width = bounds.x2 - bounds.x1; + const int height = bounds.y2 - bounds.y1; + + float* input = static_cast(_srcImg->getPixelData()); + float* output = static_cast(_dstImg->getPixelData()); + + RunCudaKernel(_pCudaStream, width, height, _scales, input, output); +#endif +} + +#ifdef __APPLE__ +extern void RunMetalKernel(void* p_CmdQ, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output); +#endif + +void GainExample::processImagesMetal() +{ +#ifdef __APPLE__ + const OfxRectI& bounds = _srcImg->getBounds(); + const int width = bounds.x2 - bounds.x1; + const int height = bounds.y2 - bounds.y1; + + float* input = static_cast(_srcImg->getPixelData()); + float* output = static_cast(_dstImg->getPixelData()); + + RunMetalKernel(_pMetalCmdQ, width, height, _scales, input, output); +#endif +} + +extern void RunOpenCLKernelBuffers(void* p_CmdQ, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output); +extern void RunOpenCLKernelImages(void* p_CmdQ, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output); + +void GainExample::processImagesOpenCL() +{ +#ifdef OFX_SUPPORTS_OPENCLRENDER + const OfxRectI& bounds = _srcImg->getBounds(); + const int width = bounds.x2 - bounds.x1; + const int height = bounds.y2 - bounds.y1; + + float* input = static_cast(_srcImg->getOpenCLImage()); + float* output = static_cast(_dstImg->getOpenCLImage()); + + // if a plugin supports both OpenCL Buffers and Images, the host decides which is used and + // the plugin must determine which based on whether kOfxImageEffectPropOpenCLImage or kOfxImagePropData is set + if (input || output) + { + RunOpenCLKernelImages(_pOpenCLCmdQ, width, height, _scales, input, output); + } + else + { + input = static_cast(_srcImg->getPixelData()); + output = static_cast(_dstImg->getPixelData()); + + RunOpenCLKernelBuffers(_pOpenCLCmdQ, width, height, _scales, input, output); +} +#endif +} + +void GainExample::multiThreadProcessImages(OfxRectI p_ProcWindow) +{ + for (int y = p_ProcWindow.y1; y < p_ProcWindow.y2; ++y) + { + if (_effect.abort()) break; + + float* dstPix = static_cast(_dstImg->getPixelAddress(p_ProcWindow.x1, y)); + + for (int x = p_ProcWindow.x1; x < p_ProcWindow.x2; ++x) + { + float* srcPix = static_cast(_srcImg ? _srcImg->getPixelAddress(x, y) : 0); + + // do we have a source image to scale up + if (srcPix) + { + for(int c = 0; c < 4; ++c) + { + dstPix[c] = srcPix[c] * _scales[c]; + } + } + else + { + // no src pixel here, be black and transparent + for (int c = 0; c < 4; ++c) + { + dstPix[c] = 0; + } + } + + // increment the dst pixel + dstPix += 4; + } + } +} + +void GainExample::setSrcImg(OFX::Image* p_SrcImg) +{ + _srcImg = p_SrcImg; +} + +void GainExample::setScales(float p_ScaleR, float p_ScaleG, float p_ScaleB, float p_ScaleA) +{ + _scales[0] = p_ScaleR; + _scales[1] = p_ScaleG; + _scales[2] = p_ScaleB; + _scales[3] = p_ScaleA; +} + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class GPUGain : public OFX::ImageEffect +{ +public: + explicit GPUGain(OfxImageEffectHandle p_Handle); + + /* Override the render */ + virtual void render(const OFX::RenderArguments& p_Args); + + /* Override is identity */ + virtual bool isIdentity(const OFX::IsIdentityArguments& p_Args, OFX::Clip*& p_IdentityClip, double& p_IdentityTime); + + /* Override changedParam */ + virtual void changedParam(const OFX::InstanceChangedArgs& p_Args, const std::string& p_ParamName); + + /* Override changed clip */ + virtual void changedClip(const OFX::InstanceChangedArgs& p_Args, const std::string& p_ClipName); + + /* Set the enabledness of the component scale params depending on the type of input image and the state of the scaleComponents param */ + void setEnabledness(); + + /* Set up and run a processor */ + void setupAndProcess(GainExample &p_GainExample, const OFX::RenderArguments& p_Args); + +private: + // Does not own the following pointers + OFX::Clip* m_DstClip; + OFX::Clip* m_SrcClip; + + OFX::DoubleParam* m_Scale; + OFX::DoubleParam* m_ScaleR; + OFX::DoubleParam* m_ScaleG; + OFX::DoubleParam* m_ScaleB; + OFX::DoubleParam* m_ScaleA; + OFX::BooleanParam* m_ComponentScalesEnabled; +}; + +GPUGain::GPUGain(OfxImageEffectHandle p_Handle) + : ImageEffect(p_Handle) +{ + m_DstClip = fetchClip(kOfxImageEffectOutputClipName); + m_SrcClip = fetchClip(kOfxImageEffectSimpleSourceClipName); + + m_Scale = fetchDoubleParam("scale"); + m_ScaleR = fetchDoubleParam("scaleR"); + m_ScaleG = fetchDoubleParam("scaleG"); + m_ScaleB = fetchDoubleParam("scaleB"); + m_ScaleA = fetchDoubleParam("scaleA"); + m_ComponentScalesEnabled = fetchBooleanParam("scaleComponents"); + + // Set the enabledness of our RGBA sliders + setEnabledness(); +} + +void GPUGain::render(const OFX::RenderArguments& p_Args) +{ + if ((m_DstClip->getPixelDepth() == OFX::eBitDepthFloat) && (m_DstClip->getPixelComponents() == OFX::ePixelComponentRGBA)) + { + GainExample imageScaler(*this); + setupAndProcess(imageScaler, p_Args); + } + else + { + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } +} + +bool GPUGain::isIdentity(const OFX::IsIdentityArguments& p_Args, OFX::Clip*& p_IdentityClip, double& p_IdentityTime) +{ + double rScale = 1.0, gScale = 1.0, bScale = 1.0, aScale = 1.0; + + if (m_ComponentScalesEnabled->getValueAtTime(p_Args.time)) + { + rScale = m_ScaleR->getValueAtTime(p_Args.time); + gScale = m_ScaleG->getValueAtTime(p_Args.time); + bScale = m_ScaleB->getValueAtTime(p_Args.time); + aScale = m_ScaleA->getValueAtTime(p_Args.time); + } + + const double scale = m_Scale->getValueAtTime(p_Args.time); + rScale *= scale; + gScale *= scale; + bScale *= scale; + + if ((rScale == 1.0) && (gScale == 1.0) && (bScale == 1.0) && (aScale == 1.0)) + { + p_IdentityClip = m_SrcClip; + p_IdentityTime = p_Args.time; + return true; + } + + return false; +} + +void GPUGain::changedParam(const OFX::InstanceChangedArgs& p_Args, const std::string& p_ParamName) +{ + if (p_ParamName == "scaleComponents") + { + setEnabledness(); + } +} + +void GPUGain::changedClip(const OFX::InstanceChangedArgs& p_Args, const std::string& p_ClipName) +{ + if (p_ClipName == kOfxImageEffectSimpleSourceClipName) + { + setEnabledness(); + } +} + +void GPUGain::setEnabledness() +{ + // the component enabledness depends on the clip being RGBA and the param being true + const bool enable = (m_ComponentScalesEnabled->getValue() && (m_SrcClip->getPixelComponents() == OFX::ePixelComponentRGBA)); + + m_ScaleR->setEnabled(enable); + m_ScaleG->setEnabled(enable); + m_ScaleB->setEnabled(enable); + m_ScaleA->setEnabled(enable); +} + +void GPUGain::setupAndProcess(GainExample& p_GainExample, const OFX::RenderArguments& p_Args) +{ + // Get the dst image + std::unique_ptr dst(m_DstClip->fetchImage(p_Args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // Get the src image + std::unique_ptr src(m_SrcClip->fetchImage(p_Args.time)); + OFX::BitDepthEnum srcBitDepth = src->getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src->getPixelComponents(); + + // Check to see if the bit depth and number of components are the same + if ((srcBitDepth != dstBitDepth) || (srcComponents != dstComponents)) + { + OFX::throwSuiteStatusException(kOfxStatErrValue); + } + + double rScale = 1.0, gScale = 1.0, bScale = 1.0, aScale = 1.0; + + if (m_ComponentScalesEnabled->getValueAtTime(p_Args.time)) + { + rScale = m_ScaleR->getValueAtTime(p_Args.time); + gScale = m_ScaleG->getValueAtTime(p_Args.time); + bScale = m_ScaleB->getValueAtTime(p_Args.time); + aScale = m_ScaleA->getValueAtTime(p_Args.time); + } + + const double scale = m_Scale->getValueAtTime(p_Args.time); + rScale *= scale; + gScale *= scale; + bScale *= scale; + + // Set the images + p_GainExample.setDstImg(dst.get()); + p_GainExample.setSrcImg(src.get()); + + // Setup OpenCL and CUDA Render arguments + p_GainExample.setGPURenderArgs(p_Args); + + // Set the render window + p_GainExample.setRenderWindow(p_Args.renderWindow); + + // Set the scales + p_GainExample.setScales(rScale, gScale, bScale, aScale); + + // Call the base class process member, this will call the derived templated process code + p_GainExample.process(); +} + +//////////////////////////////////////////////////////////////////////////////// + +using namespace OFX; + +GPUGainFactory::GPUGainFactory() + : OFX::PluginFactoryHelper(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor) +{ +} + +void GPUGainFactory::describe(OFX::ImageEffectDescriptor& p_Desc) +{ + // Basic labels + p_Desc.setLabels(kPluginName, kPluginName, kPluginName); + p_Desc.setPluginGrouping(kPluginGrouping); + p_Desc.setPluginDescription(kPluginDescription); + + // Add the supported contexts, only filter at the moment + p_Desc.addSupportedContext(eContextFilter); + p_Desc.addSupportedContext(eContextGeneral); + + // Add supported pixel depths + p_Desc.addSupportedBitDepth(eBitDepthFloat); + + // Set a few flags + p_Desc.setSingleInstance(false); + p_Desc.setHostFrameThreading(false); + p_Desc.setSupportsMultiResolution(kSupportsMultiResolution); + p_Desc.setSupportsTiles(kSupportsTiles); + p_Desc.setTemporalClipAccess(false); + p_Desc.setRenderTwiceAlways(false); + p_Desc.setSupportsMultipleClipPARs(kSupportsMultipleClipPARs); + + // Setup OpenCL render capability flags + p_Desc.setSupportsOpenCLBuffersRender(true); + p_Desc.setSupportsOpenCLImagesRender(true); + + // Setup CUDA render capability flags on non-Apple system +#ifndef __APPLE__ + p_Desc.setSupportsCudaRender(true); + p_Desc.setSupportsCudaStream(true); +#endif + + // Setup Metal render capability flags only on Apple system +#ifdef __APPLE__ + p_Desc.setSupportsMetalRender(true); +#endif +} + +static DoubleParamDescriptor* defineScaleParam(OFX::ImageEffectDescriptor& p_Desc, const std::string& p_Name, const std::string& p_Label, + const std::string& p_Hint, GroupParamDescriptor* p_Parent) +{ + DoubleParamDescriptor* param = p_Desc.defineDoubleParam(p_Name); + param->setLabels(p_Label, p_Label, p_Label); + param->setScriptName(p_Name); + param->setHint(p_Hint); + param->setDefault(1); + param->setRange(0, 10); + param->setIncrement(0.1); + param->setDisplayRange(0, 10); + param->setDoubleType(eDoubleTypeScale); + + if (p_Parent) + { + param->setParent(*p_Parent); + } + + return param; +} + + +void GPUGainFactory::describeInContext(OFX::ImageEffectDescriptor& p_Desc, OFX::ContextEnum /*p_Context*/) +{ + // Source clip only in the filter context + // Create the mandated source clip + ClipDescriptor* srcClip = p_Desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->setTemporalClipAccess(false); + srcClip->setSupportsTiles(kSupportsTiles); + srcClip->setIsMask(false); + + // Create the mandated output clip + ClipDescriptor* dstClip = p_Desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(kSupportsTiles); + + // Make some pages and to things in + PageParamDescriptor* page = p_Desc.definePageParam("Controls"); + + // Group param to group the scales + GroupParamDescriptor* componentScalesGroup = p_Desc.defineGroupParam("componentScales"); + componentScalesGroup->setHint("Scales on the individual component"); + componentScalesGroup->setLabels("Components", "Components", "Components"); + + // Make overall scale params + DoubleParamDescriptor* param = defineScaleParam(p_Desc, "scale", "scale", "Scales all component in the image", 0); + page->addChild(*param); + + // Add a boolean to enable the component scale + BooleanParamDescriptor* boolParam = p_Desc.defineBooleanParam("scaleComponents"); + boolParam->setDefault(true); + boolParam->setHint("Enables scales on individual components"); + boolParam->setLabels("Scale Components", "Scale Components", "Scale Components"); + boolParam->setParent(*componentScalesGroup); + page->addChild(*boolParam); + + // Make the four component scale params + param = defineScaleParam(p_Desc, "scaleR", "red", "Scales the red component of the image", componentScalesGroup); + page->addChild(*param); + + param = defineScaleParam(p_Desc, "scaleG", "green", "Scales the green component of the image", componentScalesGroup); + page->addChild(*param); + + param = defineScaleParam(p_Desc, "scaleB", "blue", "Scales the blue component of the image", componentScalesGroup); + page->addChild(*param); + + param = defineScaleParam(p_Desc, "scaleA", "alpha", "Scales the alpha component of the image", componentScalesGroup); + page->addChild(*param); +} + +ImageEffect* GPUGainFactory::createInstance(OfxImageEffectHandle p_Handle, ContextEnum /*p_Context*/) +{ + return new GPUGain(p_Handle); +} + +void OFX::Plugin::getPluginIDs(PluginFactoryArray& p_FactoryArray) +{ + static GPUGainFactory gainPlugin; + p_FactoryArray.push_back(&gainPlugin); +} diff --git a/third_party/openfx/Support/Plugins/GPUGain/GPUGain.h b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.h new file mode 100644 index 000000000..528aa3a30 --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.h @@ -0,0 +1,16 @@ + + +#pragma once + +#include "ofxsImageEffect.h" + +class GPUGainFactory : public OFX::PluginFactoryHelper +{ +public: + GPUGainFactory(); + virtual void load() {} + virtual void unload() {} + virtual void describe(OFX::ImageEffectDescriptor& p_Desc); + virtual void describeInContext(OFX::ImageEffectDescriptor& p_Desc, OFX::ContextEnum p_Context); + virtual OFX::ImageEffect* createInstance(OfxImageEffectHandle p_Handle, OFX::ContextEnum p_Context); +}; diff --git a/third_party/openfx/Support/Plugins/GPUGain/GPUGain.sln b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.sln new file mode 100644 index 000000000..e6335a2ca --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPUGain", "GPUGain.vcxproj", "{88405F0E-918E-4523-8627-1380BC83A605}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {88405F0E-918E-4523-8627-1380BC83A605}.Debug|x64.ActiveCfg = Debug|x64 + {88405F0E-918E-4523-8627-1380BC83A605}.Debug|x64.Build.0 = Debug|x64 + {88405F0E-918E-4523-8627-1380BC83A605}.Release|x64.ActiveCfg = Release|x64 + {88405F0E-918E-4523-8627-1380BC83A605}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/third_party/openfx/Support/Plugins/GPUGain/GPUGain.vcxproj b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.vcxproj new file mode 100644 index 000000000..fc45ab913 --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.vcxproj @@ -0,0 +1,143 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {88405F0E-918E-4523-8627-1380BC83A605} + GPUGain + Win32Proj + + + + DynamicLibrary + v120 + Unicode + true + + + DynamicLibrary + v120 + Unicode + + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(CUDA_INC_PATH);$(AMDAPPSDKROOT)/include;../OpenFX-1.4/include;../Support/include + $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(CUDA_LIB_PATH);$(AMDAPPSDKROOT)/lib/x86_64 + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(CUDA_INC_PATH);$(AMDAPPSDKROOT)/include;../OpenFX-1.4/include;../Support/include + $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(CUDA_LIB_PATH);$(AMDAPPSDKROOT)/lib/x86_64 + + + + + + + X64 + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + ProgramDatabase + + + true + Windows + MachineX64 + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;cuda.lib;cudart.lib;OpenCL.lib;%(AdditionalDependencies) + + + Creating bundle... + if not exist "$(OutDir)GPUGain.ofx.bundle\Contents\Resources" mkdir "$(OutDir)GPUGain.ofx.bundle\Contents\Resources" +if not exist "$(OutDir)GPUGain.ofx.bundle\Contents\Win64" mkdir "$(OutDir)GPUGain.ofx.bundle\Contents\Win64" +copy /Y "$(TargetPath)" /B "$(OutDir)GPUGain.ofx.bundle\Contents\Win64\GPUGain.ofx" /B + + + + 64 + + + + + X64 + + + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX64 + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;cuda.lib;cudart.lib;OpenCL.lib;%(AdditionalDependencies) + + + Creating bundle... + if not exist "$(OutDir)GPUGain.ofx.bundle\Contents\Resources" mkdir "$(OutDir)GPUGain.ofx.bundle\Contents\Resources" +if not exist "$(OutDir)GPUGain.ofx.bundle\Contents\Win64" mkdir "$(OutDir)GPUGain.ofx.bundle\Contents\Win64" +copy /Y "$(TargetPath)" /B "$(OutDir)GPUGain.ofx.bundle\Contents\Win64\GPUGain.ofx" /B + + + + 64 + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/GPUGain/GPUGain.xcodeproj/project.pbxproj b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.xcodeproj/project.pbxproj new file mode 100644 index 000000000..1a66eb8b2 --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/GPUGain.xcodeproj/project.pbxproj @@ -0,0 +1,225 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXFileReference section */ + 3DF51C6C1CB741110070CA48 /* CudaKernel.cu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CudaKernel.cu; sourceTree = ""; }; + 3DF51C6D1CB741110070CA48 /* GPUGain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GPUGain.cpp; sourceTree = ""; }; + 3DF51C6E1CB741110070CA48 /* GPUGain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPUGain.h; sourceTree = ""; }; + 3DF51C701CB741110070CA48 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 3DF51C711CB741110070CA48 /* OpenCLKernel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenCLKernel.cpp; sourceTree = ""; }; + 3DF51C721CB7413B0070CA48 /* ofxsCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsCore.cpp; path = ../../Support/Library/ofxsCore.cpp; sourceTree = ""; }; + 3DF51C731CB7413B0070CA48 /* ofxsImageEffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsImageEffect.cpp; path = ../../Support/Library/ofxsImageEffect.cpp; sourceTree = ""; }; + 3DF51C741CB7413B0070CA48 /* ofxsInteract.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsInteract.cpp; path = ../../Support/Library/ofxsInteract.cpp; sourceTree = ""; }; + 3DF51C751CB7413B0070CA48 /* ofxsLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsLog.cpp; path = ../../Support/Library/ofxsLog.cpp; sourceTree = ""; }; + 3DF51C761CB7413B0070CA48 /* ofxsMultiThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsMultiThread.cpp; path = ../../Support/Library/ofxsMultiThread.cpp; sourceTree = ""; }; + 3DF51C771CB7413B0070CA48 /* ofxsParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsParams.cpp; path = ../../Support/Library/ofxsParams.cpp; sourceTree = ""; }; + 3DF51C781CB7413B0070CA48 /* ofxsProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsProperty.cpp; path = ../../Support/Library/ofxsProperty.cpp; sourceTree = ""; }; + 3DF51C791CB7413B0070CA48 /* ofxsPropertyValidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxsPropertyValidation.cpp; path = ../../Support/Library/ofxsPropertyValidation.cpp; sourceTree = ""; }; + 4F799E1E1EC4662F00E46226 /* MetalKernel.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MetalKernel.mm; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 3D2F26961CBB8F6B00FC8803 /* Support */ = { + isa = PBXGroup; + children = ( + 3DF51C721CB7413B0070CA48 /* ofxsCore.cpp */, + 3DF51C731CB7413B0070CA48 /* ofxsImageEffect.cpp */, + 3DF51C741CB7413B0070CA48 /* ofxsInteract.cpp */, + 3DF51C751CB7413B0070CA48 /* ofxsLog.cpp */, + 3DF51C761CB7413B0070CA48 /* ofxsMultiThread.cpp */, + 3DF51C771CB7413B0070CA48 /* ofxsParams.cpp */, + 3DF51C781CB7413B0070CA48 /* ofxsProperty.cpp */, + 3DF51C791CB7413B0070CA48 /* ofxsPropertyValidation.cpp */, + ); + name = Support; + sourceTree = ""; + }; + 3DF51C611CB740BF0070CA48 = { + isa = PBXGroup; + children = ( + 3D2F26961CBB8F6B00FC8803 /* Support */, + 3DF51C6C1CB741110070CA48 /* CudaKernel.cu */, + 3DF51C6D1CB741110070CA48 /* GPUGain.cpp */, + 3DF51C6E1CB741110070CA48 /* GPUGain.h */, + 3DF51C701CB741110070CA48 /* Makefile */, + 3DF51C711CB741110070CA48 /* OpenCLKernel.cpp */, + 4F799E1E1EC4662F00E46226 /* MetalKernel.mm */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXLegacyTarget section */ + 3DF51C661CB740BF0070CA48 /* GPUGain */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION)"; + buildConfigurationList = 3DF51C691CB740BF0070CA48 /* Build configuration list for PBXLegacyTarget "GPUGain" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + dependencies = ( + ); + name = GPUGain; + passBuildSettingsInEnvironment = 1; + productName = GPUGain; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXProject section */ + 3DF51C621CB740BF0070CA48 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0640; + ORGANIZATIONNAME = blackmagicdesign; + TargetAttributes = { + 3DF51C661CB740BF0070CA48 = { + CreatedOnToolsVersion = 6.4; + }; + }; + }; + buildConfigurationList = 3DF51C651CB740BF0070CA48 /* Build configuration list for PBXProject "GPUGain" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + ); + mainGroup = 3DF51C611CB740BF0070CA48; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3DF51C661CB740BF0070CA48 /* GPUGain */, + ); + }; +/* End PBXProject section */ + +/* Begin XCBuildConfiguration section */ + 3DF51C671CB740BF0070CA48 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 3DF51C681CB740BF0070CA48 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 3DF51C6A1CB740BF0070CA48 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUGGING_SYMBOLS = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 3DF51C6B1CB740BF0070CA48 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3DF51C651CB740BF0070CA48 /* Build configuration list for PBXProject "GPUGain" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DF51C671CB740BF0070CA48 /* Debug */, + 3DF51C681CB740BF0070CA48 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3DF51C691CB740BF0070CA48 /* Build configuration list for PBXLegacyTarget "GPUGain" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DF51C6A1CB740BF0070CA48 /* Debug */, + 3DF51C6B1CB740BF0070CA48 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3DF51C621CB740BF0070CA48 /* Project object */; +} diff --git a/third_party/openfx/Support/Plugins/GPUGain/Info.plist b/third_party/openfx/Support/Plugins/GPUGain/Info.plist new file mode 100644 index 000000000..2c98dddd9 --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + GPUGain.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/GPUGain/MetalKernel.mm b/third_party/openfx/Support/Plugins/GPUGain/MetalKernel.mm new file mode 100644 index 000000000..70af47a49 --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/MetalKernel.mm @@ -0,0 +1,108 @@ + + +#import + +#include +#include + +const char* kernelSource = \ +"#include \n" \ +"using namespace metal; \n" \ +"kernel void GainAdjustKernel(constant int& p_Width [[buffer (11)]], constant int& p_Height [[buffer (12)]], constant float& p_GainR [[buffer (13)]], \n" \ +" constant float& p_GainG [[buffer (14)]], constant float& p_GainB [[buffer (15)]], constant float& p_GainA [[buffer (16)]], \n" \ +" const device float* p_Input [[buffer (0)]], device float* p_Output [[buffer (8)]], uint2 id [[ thread_position_in_grid ]]) \n" \ +"{ \n" \ +" if ((id.x < p_Width) && (id.y < p_Height)) \n" \ +" { \n" \ +" const int index = ((id.y * p_Width) + id.x) * 4; \n" \ +" p_Output[index + 0] = p_Input[index + 0] * p_GainR; \n" \ +" p_Output[index + 1] = p_Input[index + 1] * p_GainG; \n" \ +" p_Output[index + 2] = p_Input[index + 2] * p_GainB; \n" \ +" p_Output[index + 3] = p_Input[index + 3] * p_GainA; \n" \ +" } \n" \ +"} \n"; + +std::mutex s_PipelineQueueMutex; +typedef std::unordered_map, id> PipelineQueueMap; +PipelineQueueMap s_PipelineQueueMap; + +void RunMetalKernel(void* p_CmdQ, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output) +{ + const char* kernelName = "GainAdjustKernel"; + + id queue = static_cast >(p_CmdQ); + id device = queue.device; + id metalLibrary; // Metal library + id kernelFunction; // Compute kernel + id pipelineState; // Metal pipeline + NSError* err; + + std::unique_lock lock(s_PipelineQueueMutex); + + const auto it = s_PipelineQueueMap.find(queue); + if (it == s_PipelineQueueMap.end()) + { + id metalLibrary; // Metal library + id kernelFunction; // Compute kernel + NSError* err; + + MTLCompileOptions* options = [MTLCompileOptions new]; + options.fastMathEnabled = YES; + if (!(metalLibrary = [device newLibraryWithSource:@(kernelSource) options:options error:&err])) + { + fprintf(stderr, "Failed to load metal library, %s\n", err.localizedDescription.UTF8String); + return; + } + [options release]; + if (!(kernelFunction = [metalLibrary newFunctionWithName:[NSString stringWithUTF8String:kernelName]/* constantValues : constantValues */])) + { + fprintf(stderr, "Failed to retrieve kernel\n"); + [metalLibrary release]; + return; + } + if (!(pipelineState = [device newComputePipelineStateWithFunction:kernelFunction error:&err])) + { + fprintf(stderr, "Unable to compile, %s\n", err.localizedDescription.UTF8String); + [metalLibrary release]; + [kernelFunction release]; + return; + } + + s_PipelineQueueMap[queue] = pipelineState; + + //Release resources + [metalLibrary release]; + [kernelFunction release]; + } + else + { + pipelineState = it->second; + } + + id srcDeviceBuf = reinterpret_cast >(const_cast(p_Input)); + id dstDeviceBuf = reinterpret_cast >(p_Output); + + id commandBuffer = [queue commandBuffer]; + commandBuffer.label = [NSString stringWithFormat:@"GainAdjustKernel"]; + + id computeEncoder = [commandBuffer computeCommandEncoder]; + [computeEncoder setComputePipelineState:pipelineState]; + + int exeWidth = [pipelineState threadExecutionWidth]; + MTLSize threadGroupCount = MTLSizeMake(exeWidth, 1, 1); + MTLSize threadGroups = MTLSizeMake((p_Width + exeWidth - 1)/exeWidth, p_Height, 1); + + [computeEncoder setBuffer:srcDeviceBuf offset: 0 atIndex: 0]; + [computeEncoder setBuffer:dstDeviceBuf offset: 0 atIndex: 8]; + [computeEncoder setBytes:&p_Width length:sizeof(int) atIndex:11]; + [computeEncoder setBytes:&p_Height length:sizeof(int) atIndex:12]; + [computeEncoder setBytes:&p_Gain[0] length:sizeof(float) atIndex:13]; + [computeEncoder setBytes:&p_Gain[1] length:sizeof(float) atIndex:14]; + [computeEncoder setBytes:&p_Gain[2] length:sizeof(float) atIndex:15]; + [computeEncoder setBytes:&p_Gain[3] length:sizeof(float) atIndex:16]; + + [computeEncoder dispatchThreadgroups:threadGroups threadsPerThreadgroup: threadGroupCount]; + + [computeEncoder endEncoding]; + [commandBuffer commit]; +} diff --git a/third_party/openfx/Support/Plugins/GPUGain/OpenCLKernel.cpp b/third_party/openfx/Support/Plugins/GPUGain/OpenCLKernel.cpp new file mode 100644 index 000000000..2b237bdf1 --- /dev/null +++ b/third_party/openfx/Support/Plugins/GPUGain/OpenCLKernel.cpp @@ -0,0 +1,270 @@ + + +#ifdef _WIN64 +#include +#else +#include +#endif +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +const char *KernelSourceBuffers = "\n" \ +"__kernel void GainAdjustKernelBuffers( \n" \ +" int p_Width, \n" \ +" int p_Height, \n" \ +" float p_GainR, \n" \ +" float p_GainG, \n" \ +" float p_GainB, \n" \ +" float p_GainA, \n" \ +" __global const float* p_Input, \n" \ +" __global float* p_Output) \n" \ +"{ \n" \ +" const int x = get_global_id(0); \n" \ +" const int y = get_global_id(1); \n" \ +" \n" \ +" if ((x < p_Width) && (y < p_Height)) \n" \ +" { \n" \ +" const int index = ((y * p_Width) + x) * 4; \n" \ +" \n" \ +" p_Output[index + 0] = p_Input[index + 0] * p_GainR; \n" \ +" p_Output[index + 1] = p_Input[index + 1] * p_GainG; \n" \ +" p_Output[index + 2] = p_Input[index + 2] * p_GainB; \n" \ +" p_Output[index + 3] = p_Input[index + 3] * p_GainA; \n" \ +" } \n" \ +"} \n" \ +"\n"; + +const char *KernelSourceImages = "\n" \ +"__constant sampler_t imageSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; \n" \ +" \n" \ +"__kernel void GainAdjustKernelImages( \n" \ +" int p_Width, \n" \ +" int p_Height, \n" \ +" float p_GainR, \n" \ +" float p_GainG, \n" \ +" float p_GainB, \n" \ +" float p_GainA, \n" \ +" __read_only image2d_t p_Input, \n" \ +" __write_only image2d_t p_Output) \n" \ +"{ \n" \ +" const int x = get_global_id(0); \n" \ +" const int y = get_global_id(1); \n" \ +" \n" \ +" if ((x < p_Width) && (y < p_Height)) \n" \ +" { \n" \ +" int2 coord = (int2)(x, y); \n" \ +" float4 out = read_imagef(p_Input, imageSampler, coord); \n" \ +" out *= (float4)(p_GainR, p_GainG, p_GainB, p_GainA); \n" \ +" write_imagef(p_Output, coord, out); \n" \ +" } \n" \ +"} \n" \ +"\n"; + +void CheckError(cl_int p_Error, const char* p_Msg) +{ + if (p_Error != CL_SUCCESS) + { + fprintf(stderr, "%s [%d]\n", p_Msg, p_Error); + } +} + +class Locker +{ +public: + Locker() + { +#ifdef _WIN64 + InitializeCriticalSection(&mutex); +#else + pthread_mutex_init(&mutex, NULL); +#endif + } + + ~Locker() + { +#ifdef _WIN64 + DeleteCriticalSection(&mutex); +#else + pthread_mutex_destroy(&mutex); +#endif + } + + void Lock() + { +#ifdef _WIN64 + EnterCriticalSection(&mutex); +#else + pthread_mutex_lock(&mutex); +#endif + } + + void Unlock() + { +#ifdef _WIN64 + LeaveCriticalSection(&mutex); +#else + pthread_mutex_unlock(&mutex); +#endif + } + +private: +#ifdef _WIN64 + CRITICAL_SECTION mutex; +#else + pthread_mutex_t mutex; +#endif +}; + +void RunOpenCLKernelBuffers(void* p_CmdQ, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output) +{ + cl_int error; + + cl_command_queue cmdQ = static_cast(p_CmdQ); + + // store device id and kernel per command queue (required for multi-GPU systems) + static std::map deviceIdMap; + static std::map kernelMap; + + static Locker locker; // simple lock to control access to the above maps from multiple threads + + locker.Lock(); + + // find the device id corresponding to the command queue + cl_device_id deviceId = NULL; + if (deviceIdMap.find(cmdQ) == deviceIdMap.end()) + { + error = clGetCommandQueueInfo(cmdQ, CL_QUEUE_DEVICE, sizeof(cl_device_id), &deviceId, NULL); + CheckError(error, "Unable to get the device"); + + deviceIdMap[cmdQ] = deviceId; + } + else + { + deviceId = deviceIdMap[cmdQ]; + } + + // find the program kernel corresponding to the command queue + cl_kernel kernel = NULL; + if (kernelMap.find(cmdQ) == kernelMap.end()) + { + cl_context clContext = NULL; + error = clGetCommandQueueInfo(cmdQ, CL_QUEUE_CONTEXT, sizeof(cl_context), &clContext, NULL); + CheckError(error, "Unable to get the context"); + + cl_program program = clCreateProgramWithSource(clContext, 1, (const char **)&KernelSourceBuffers, NULL, &error); + CheckError(error, "Unable to create program"); + + error = clBuildProgram(program, 0, NULL, NULL, NULL, NULL); + CheckError(error, "Unable to build program"); + + kernel = clCreateKernel(program, "GainAdjustKernelBuffers", &error); + CheckError(error, "Unable to create kernel"); + + kernelMap[cmdQ] = kernel; + } + else + { + kernel = kernelMap[cmdQ]; + } + + locker.Unlock(); + + int count = 0; + error = clSetKernelArg(kernel, count++, sizeof(int), &p_Width); + error |= clSetKernelArg(kernel, count++, sizeof(int), &p_Height); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[0]); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[1]); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[2]); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[3]); + error |= clSetKernelArg(kernel, count++, sizeof(cl_mem), &p_Input); + error |= clSetKernelArg(kernel, count++, sizeof(cl_mem), &p_Output); + CheckError(error, "Unable to set kernel arguments"); + + size_t localWorkSize[2], globalWorkSize[2]; + clGetKernelWorkGroupInfo(kernel, deviceId, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), localWorkSize, NULL); + localWorkSize[1] = 1; + globalWorkSize[0] = ((p_Width + localWorkSize[0] - 1) / localWorkSize[0]) * localWorkSize[0]; + globalWorkSize[1] = p_Height; + + clEnqueueNDRangeKernel(cmdQ, kernel, 2, NULL, globalWorkSize, localWorkSize, 0, NULL, NULL); +} + +void RunOpenCLKernelImages(void* p_CmdQ, int p_Width, int p_Height, float* p_Gain, const float* p_Input, float* p_Output) +{ + cl_int error; + + cl_command_queue cmdQ = static_cast(p_CmdQ); + + // store device id and kernel per command queue (required for multi-GPU systems) + static std::map deviceIdMap; + static std::map kernelMap; + + static Locker locker; // simple lock to control access to the above maps from multiple threads + + locker.Lock(); + + // find the device id corresponding to the command queue + cl_device_id deviceId = NULL; + if (deviceIdMap.find(cmdQ) == deviceIdMap.end()) + { + error = clGetCommandQueueInfo(cmdQ, CL_QUEUE_DEVICE, sizeof(cl_device_id), &deviceId, NULL); + CheckError(error, "Unable to get the device"); + + deviceIdMap[cmdQ] = deviceId; + } + else + { + deviceId = deviceIdMap[cmdQ]; + } + + // find the program kernel corresponding to the command queue + cl_kernel kernel = NULL; + if (kernelMap.find(cmdQ) == kernelMap.end()) + { + cl_context clContext = NULL; + error = clGetCommandQueueInfo(cmdQ, CL_QUEUE_CONTEXT, sizeof(cl_context), &clContext, NULL); + CheckError(error, "Unable to get the context"); + + cl_program program = clCreateProgramWithSource(clContext, 1, (const char **)&KernelSourceImages, NULL, &error); + CheckError(error, "Unable to create program"); + + error = clBuildProgram(program, 0, NULL, NULL, NULL, NULL); + CheckError(error, "Unable to build program"); + + kernel = clCreateKernel(program, "GainAdjustKernelImages", &error); + CheckError(error, "Unable to create kernel"); + + kernelMap[cmdQ] = kernel; + } + else + { + kernel = kernelMap[cmdQ]; + } + + locker.Unlock(); + + int count = 0; + error = clSetKernelArg(kernel, count++, sizeof(int), &p_Width); + error |= clSetKernelArg(kernel, count++, sizeof(int), &p_Height); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[0]); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[1]); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[2]); + error |= clSetKernelArg(kernel, count++, sizeof(float), &p_Gain[3]); + error |= clSetKernelArg(kernel, count++, sizeof(cl_mem), &p_Input); + error |= clSetKernelArg(kernel, count++, sizeof(cl_mem), &p_Output); + CheckError(error, "Unable to set kernel arguments"); + + size_t localWorkSize[2], globalWorkSize[2]; + clGetKernelWorkGroupInfo(kernel, deviceId, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), localWorkSize, NULL); + localWorkSize[1] = 1; + globalWorkSize[0] = ((p_Width + localWorkSize[0] - 1) / localWorkSize[0]) * localWorkSize[0]; + globalWorkSize[1] = p_Height; + + clEnqueueNDRangeKernel(cmdQ, kernel, 2, NULL, globalWorkSize, localWorkSize, 0, NULL, NULL); +} diff --git a/third_party/openfx/Support/Plugins/Generator/Info.plist b/third_party/openfx/Support/Plugins/Generator/Info.plist new file mode 100644 index 000000000..fa60366ec --- /dev/null +++ b/third_party/openfx/Support/Plugins/Generator/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + noise.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/Generator/noise.cpp b/third_party/openfx/Support/Plugins/Generator/noise.cpp new file mode 100644 index 000000000..b8496f3a7 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Generator/noise.cpp @@ -0,0 +1,293 @@ + + +#include +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" + +#include "../include/ofxsProcessing.H" + +#include + +//////////////////////////////////////////////////////////////////////////////// +// base class for the noise + +/** @brief Base class used to blend two images together */ +class NoiseGeneratorBase : public OFX::ImageProcessor { +protected : + float _noiseLevel; // how much to blend + uint32_t _seed; // base seed +public : + /** @brief no arg ctor */ + NoiseGeneratorBase(OFX::ImageEffect &instance) + : OFX::ImageProcessor(instance) + , _noiseLevel(0.5f) + , _seed(0) + { + } + + /** @brief set the scale */ + void setNoiseLevel(float v) {_noiseLevel = v;} + + /** @brief the seed to use */ + void setSeed(uint32_t v) {_seed = v;} +}; + +/** @brief templated class to blend between two images */ +template +class NoiseGenerator : public NoiseGeneratorBase { +public : + // ctor + NoiseGenerator(OFX::ImageEffect &instance) + : NoiseGeneratorBase(instance) + {} + + // and do some processing + void multiThreadProcessImages(OfxRectI procWindow) + { + float noiseLevel = _noiseLevel; + + // set up a random number generator + // Distribution is from 0 to pixel max level times noise level + std::random_device rd; + std::mt19937_64 mt(rd()); + mt.seed(_seed + procWindow.y1); + std::uniform_real_distribution dist(0.0, max * noiseLevel); + + // push pixels + for(int y = procWindow.y1; y < procWindow.y2; y++) { + if(_effect.abort()) break; + + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + + for(int x = procWindow.x1; x < procWindow.x2; x++) { + for(int c = 0; c < nComponents; c++) { + double randValue = dist(mt); + + if(max == 1) // implies floating point, so don't clamp + dstPix[c] = PIX(randValue); + else { // integer base one, clamp it + dstPix[c] = randValue < 0 ? 0 : (randValue > max ? max : PIX(randValue)); + } + } + dstPix += nComponents; + } + } + } + +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class NoisePlugin : public OFX::ImageEffect { +protected : + // do not need to delete these, the ImageEffect is managing them for us + OFX::Clip *dstClip_; + + OFX::DoubleParam *noise_; + +public : + /** @brief ctor */ + NoisePlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + , noise_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + noise_ = fetchDoubleParam("Noise"); + } + + /* Override the render */ + virtual void render(const OFX::RenderArguments &args); + + /* Override the clip preferences, we need to say we are setting the frame varying flag */ + virtual void getClipPreferences(OFX::ClipPreferencesSetter &clipPreferences); + + /* set up and run a processor */ + void setupAndProcess(NoiseGeneratorBase &, const OFX::RenderArguments &args); + + /** @brief The get RoD action. We flag an infinite rod */ + bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ + +//////////////////////////////////////////////////////////////////////////////// +// basic plugin render function, just a skelington to instantiate templates from + + +/* set up and run a processor */ +void +NoisePlugin::setupAndProcess(NoiseGeneratorBase &processor, const OFX::RenderArguments &args) +{ + // get a dst image + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + //OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + //OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // set the images + processor.setDstImg(dst.get()); + + // set the render window + processor.setRenderWindow(args.renderWindow); + + // set the scales + processor.setNoiseLevel((float)noise_->getValueAtTime(args.time)); + + // set the seed based on the current time, and double it we get difference seeds on different fields + processor.setSeed(uint32_t(args.time * 2.0f + 2000.0f)); + + // Call the base class process member, this will call the derived templated process code + processor.process(); +} + +/* Override the clip preferences, we need to say we are setting the frame varying flag */ +void +NoisePlugin::getClipPreferences(OFX::ClipPreferencesSetter &clipPreferences) +{ + clipPreferences.setOutputFrameVarying(true); +} + +/** @brief The get RoD action. We flag an infinite rod */ +bool +NoisePlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &/*args*/, OfxRectD &rod) +{ + // we can generate noise anywhere on the image plan, so set our RoD to be infinite + rod.x1 = rod.y1 = kOfxFlagInfiniteMin; + rod.x2 = rod.y2 = kOfxFlagInfiniteMax; + return true; +} + +// the overridden render function +void +NoisePlugin::render(const OFX::RenderArguments &args) +{ + // instantiate the render code based on the pixel depth of the dst clip + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + // do the rendering + if(dstComponents == OFX::ePixelComponentRGBA) { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : { + NoiseGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : + { + NoiseGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : + { + NoiseGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + NoiseGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : + { + NoiseGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : + { + NoiseGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + +mDeclarePluginFactory(NoiseExamplePluginFactory, {}, {}); + +using namespace OFX; + +void NoiseExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + desc.setLabels("Noise", "Noise", "Noise"); + desc.setPluginGrouping("OFX Example (Support)"); + desc.addSupportedContext(eContextGenerator); + desc.addSupportedContext(eContextGeneral); + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + desc.setRenderTwiceAlways(false); +} + +void NoiseExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum /*context*/) +{ + // there has to be an input clip, even for generators + ClipDescriptor* srcClip = desc.defineClip( kOfxImageEffectSimpleSourceClipName ); + srcClip->addSupportedComponent( OFX::ePixelComponentRGBA ); + srcClip->addSupportedComponent( OFX::ePixelComponentAlpha ); + srcClip->setSupportsTiles(true); + srcClip->setOptional(true); + + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + dstClip->setFieldExtraction(eFieldExtractSingle); + DoubleParamDescriptor *param = desc.defineDoubleParam("Noise"); + param->setLabels("noise", "noise", "noise"); + param->setScriptName("noise"); + param->setHint("How much noise to make."); + param->setDefault(0.2); + param->setRange(0, 10); + param->setIncrement(0.1); + param->setDisplayRange(0, 1); + param->setAnimates(true); // can animate + param->setDoubleType(eDoubleTypeScale); + PageParamDescriptor *page = desc.definePageParam("Controls"); + page->addChild(*param); +} + +ImageEffect* NoiseExamplePluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum /*context*/) +{ + return new NoisePlugin(handle); +} + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static NoiseExamplePluginFactory p("net.sf.openfx.noisePlugin", 1, 0); + ids.push_back(&p); + } + }; +}; diff --git a/third_party/openfx/Support/Plugins/Generator/noise.dsp b/third_party/openfx/Support/Plugins/Generator/noise.dsp new file mode 100755 index 000000000..d09c95c41 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Generator/noise.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="noise" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=noise - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "noise.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "noise.mak" CFG="noise - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "noise - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "noise - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "noise - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/PropTester.ofx.bundle/Contents/Win32/noise.ofx" + +!ELSEIF "$(CFG)" == "noise - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include" /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\Common Files\OFX\Plugins\Noise.ofx.bundle\Contents\Win32\noise.ofx" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "noise - Win32 Release" +# Name "noise - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\noise.cpp +# End Source File +# Begin Source File + +SOURCE=.\randomGenerator.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/third_party/openfx/Support/Plugins/Generator/noise.dsw b/third_party/openfx/Support/Plugins/Generator/noise.dsw new file mode 100755 index 000000000..d8cd6285f --- /dev/null +++ b/third_party/openfx/Support/Plugins/Generator/noise.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "noise"=.\noise.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ofxsupport + End Project Dependency +}}} + +############################################################################### + +Project: "ofxsupport"=..\..\Library\ofxsupport.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/third_party/openfx/Support/Plugins/Generator/noise.vcproj b/third_party/openfx/Support/Plugins/Generator/noise.vcproj new file mode 100755 index 000000000..49531691f --- /dev/null +++ b/third_party/openfx/Support/Plugins/Generator/noise.vcproj @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/Invert/Info.plist b/third_party/openfx/Support/Plugins/Invert/Info.plist new file mode 100644 index 000000000..76f334ab6 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Invert/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + invert.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/Invert/invert.cpp b/third_party/openfx/Support/Plugins/Invert/invert.cpp new file mode 100644 index 000000000..36533022b --- /dev/null +++ b/third_party/openfx/Support/Plugins/Invert/invert.cpp @@ -0,0 +1,257 @@ + + +#ifdef _WINDOWS +#include +#endif + +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" + +#include "../include/ofxsProcessing.H" + + +// Base class for the RGBA and the Alpha processor +class InvertBase : public OFX::ImageProcessor { +protected : + OFX::Image *_srcImg; +public : + /** @brief no arg ctor */ + InvertBase(OFX::ImageEffect &instance) + : OFX::ImageProcessor(instance) + , _srcImg(0) + { + } + + /** @brief set the src image */ + void setSrcImg(OFX::Image *v) {_srcImg = v;} +}; + +// template to do the RGBA processing +template +class ImageInverter : public InvertBase { +public : + // ctor + ImageInverter(OFX::ImageEffect &instance) + : InvertBase(instance) + {} + + // and do some processing + void multiThreadProcessImages(OfxRectI procWindow) + { + for(int y = procWindow.y1; y < procWindow.y2; y++) { + if(_effect.abort()) break; + + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + + for(int x = procWindow.x1; x < procWindow.x2; x++) { + + PIX *srcPix = (PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0); + + // do we have a source image to scale up + if(srcPix) { + for(int c = 0; c < nComponents; c++) { + dstPix[c] = max - srcPix[c]; + } + } + else { + // no src pixel here, be black and transparent + for(int c = 0; c < nComponents; c++) { + dstPix[c] = 0; + } + } + + // increment the dst pixel + dstPix += nComponents; + } + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class InvertPlugin : public OFX::ImageEffect { +protected : + // do not need to delete these, the ImageEffect is managing them for us + OFX::Clip *dstClip_; + OFX::Clip *srcClip_; + +public : + /** @brief ctor */ + InvertPlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + , srcClip_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + } + + /* Override the render */ + virtual void render(const OFX::RenderArguments &args); + + /* set up and run a processor */ + void setupAndProcess(InvertBase &, const OFX::RenderArguments &args); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ + +//////////////////////////////////////////////////////////////////////////////// +// basic plugin render function, just a skelington to instantiate templates from + + +/* set up and run a processor */ +void +InvertPlugin::setupAndProcess(InvertBase &processor, const OFX::RenderArguments &args) +{ + // get a dst image + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // fetch main input image + std::unique_ptr src(srcClip_->fetchImage(args.time)); + + // make sure bit depths are sane + if(src.get()) { + OFX::BitDepthEnum srcBitDepth = src->getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src->getPixelComponents(); + + // see if they have the same depths and bytes and all + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); // HACK!! need to throw an sensible exception here! + } + + // set the images + processor.setDstImg(dst.get()); + processor.setSrcImg(src.get()); + + // set the render window + processor.setRenderWindow(args.renderWindow); + + // Call the base class process member, this will call the derived templated process code + processor.process(); +} + +// the overridden render function +void +InvertPlugin::render(const OFX::RenderArguments &args) +{ + // instantiate the render code based on the pixel depth of the dst clip + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + // do the rendering + if(dstComponents == OFX::ePixelComponentRGBA) { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + ImageInverter fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + ImageInverter fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + ImageInverter fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + ImageInverter fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + ImageInverter fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + ImageInverter fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + +mDeclarePluginFactory(InvertExamplePluginFactory, {}, {}); + +using namespace OFX; +void InvertExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + // basic labels + desc.setLabels("Invert", "Invert", "Invert"); + desc.setPluginGrouping("OFX Example (Support)"); + + // add the supported contexts, only filter at the moment + desc.addSupportedContext(eContextFilter); + + // add supported pixel depths + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + // set a few flags + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + +} + +void InvertExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum /*context*/) +{ + // Source clip only in the filter context + // create the mandated source clip + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->addSupportedComponent(ePixelComponentAlpha); + srcClip->setTemporalClipAccess(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + + // create the mandated output clip + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + +} + +OFX::ImageEffect* InvertExamplePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/) +{ + return new InvertPlugin(handle); +} + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static InvertExamplePluginFactory p("net.sf.openfx.invertPlugin", 1, 0); + ids.push_back(&p); + } + } +} diff --git a/third_party/openfx/Support/Plugins/Invert/invert.vcproj b/third_party/openfx/Support/Plugins/Invert/invert.vcproj new file mode 100755 index 000000000..9b06942c0 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Invert/invert.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/MultiBundle/Info.plist b/third_party/openfx/Support/Plugins/MultiBundle/Info.plist new file mode 100644 index 000000000..c960b6bc1 --- /dev/null +++ b/third_party/openfx/Support/Plugins/MultiBundle/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + multibundle.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/MultiBundle/PluginRegistration.cpp b/third_party/openfx/Support/Plugins/MultiBundle/PluginRegistration.cpp new file mode 100755 index 000000000..4444824bf --- /dev/null +++ b/third_party/openfx/Support/Plugins/MultiBundle/PluginRegistration.cpp @@ -0,0 +1,20 @@ + + +#include +#include "ofxsImageEffect.h" +#include "multibundle1.h" +#include "multibundle2.h" + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static DotExamplePluginFactory p1; + ids.push_back(&p1); + static GammaExamplePluginFactory p2; + ids.push_back(&p2); + } + } +} diff --git a/third_party/openfx/Support/Plugins/MultiBundle/multibundle.vcproj b/third_party/openfx/Support/Plugins/MultiBundle/multibundle.vcproj new file mode 100755 index 000000000..dfd8eed3e --- /dev/null +++ b/third_party/openfx/Support/Plugins/MultiBundle/multibundle.vcproj @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/MultiBundle/multibundle1.cpp b/third_party/openfx/Support/Plugins/MultiBundle/multibundle1.cpp new file mode 100755 index 000000000..385969a67 --- /dev/null +++ b/third_party/openfx/Support/Plugins/MultiBundle/multibundle1.cpp @@ -0,0 +1,529 @@ + + +#ifdef _WINDOWS +#include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" +#include "../include/ofxsProcessing.H" + +#include "multibundle1.h" + +static const OfxPointD kBoxSize = {20, 20}; +class GammaInteract : public OFX::OverlayInteract +{ +protected : + enum StateEnum { + eInActive, + ePoised, + ePicked + }; + OfxPointD _position; + StateEnum _state; +public : + GammaInteract(OfxInteractHandle handle, OFX::ImageEffect* /*effect*/) : OFX::OverlayInteract(handle), _state(eInActive) + { + _position.x = 0; + _position.y = 0; + } + virtual bool draw(const OFX::DrawArgs &args); + virtual bool penMotion(const OFX::PenArgs &args); + virtual bool penDown(const OFX::PenArgs &args); + virtual bool penUp(const OFX::PenArgs &args); +}; + +template +inline T Absolute(T a) +{ + return (a < 0) ? -a : a; +} + +template +inline T Clamp(T v, int min, int max) +{ + if(v < T(min)) + return T(min); + if(v > T(max)) + return T(max); + return v; +} + +class ImageScalerBase : public OFX::ImageProcessor +{ +protected : + OFX::Image *_srcImg; + OFX::Image *_maskImg; + double _rScale, _gScale, _bScale, _aScale; + bool _doMasking; + +public : + ImageScalerBase(OFX::ImageEffect &instance): OFX::ImageProcessor(instance), _srcImg(0), _maskImg(0), + _rScale(1), _gScale(1), _bScale(1), _aScale(1), _doMasking(false) + { + } + void setSrcImg(OFX::Image *v) {_srcImg = v;} + void setMaskImg(OFX::Image *v) {_maskImg = v;} + void doMasking(bool v) {_doMasking = v;} + void setScales(float r, float g, float b, float a) + { + _rScale = r; + _gScale = g; + _bScale = b; + _aScale = a; + } +}; + +template +class ImageScaler : public ImageScalerBase +{ +public : + ImageScaler(OFX::ImageEffect &instance): ImageScalerBase(instance) + {} + void multiThreadProcessImages(OfxRectI procWindow) + { + float scales[4]; + scales[0] = nComponents == 1 ? (float)_aScale : (float)_rScale; + scales[1] = (float)_gScale; + scales[2] = (float)_bScale; + scales[3] = (float)_aScale; + float maskScale = 1.0f; + for(int y = procWindow.y1; y < procWindow.y2; y++) + { + if(_effect.abort()) + break; + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + for(int x = procWindow.x1; x < procWindow.x2; x++) + { + PIX *srcPix = (PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0); + if(_doMasking) + { + if(!_maskImg) + maskScale = 1.0f; + else + { + PIX *maskPix = (PIX *) (_maskImg ? _maskImg->getPixelAddress(x, y) : 0); + maskScale = maskPix != 0 ? float(*maskPix)/float(max) : 0.0f; + } + } + if(srcPix) + { + for(int c = 0; c < nComponents; c++) + { + float v = (float)(pow((double)srcPix[c], (double)scales[c])) * maskScale + (1.0f - maskScale) * srcPix[c]; + if(max == 1) + dstPix[c] = PIX(v); + else + dstPix[c] = PIX(Clamp(v, 0, max)); + } + } + else + { + for(int c = 0; c < nComponents; c++) + dstPix[c] = 0; + } + dstPix += nComponents; + } + } + } +}; + + +class GammaPlugin : public OFX::ImageEffect +{ +protected : + OFX::Clip *dstClip_; + OFX::Clip *srcClip_; + OFX::Clip *maskClip_; + OFX::DoubleParam *scale_; + OFX::DoubleParam *rScale_; + OFX::DoubleParam *gScale_; + OFX::DoubleParam *bScale_; + OFX::DoubleParam *aScale_; + OFX::BooleanParam *componentScalesEnabled_; +public : + GammaPlugin(OfxImageEffectHandle handle): ImageEffect(handle), dstClip_(0), srcClip_(0), scale_(0) + , rScale_(0), gScale_(0), bScale_(0), aScale_(0), componentScalesEnabled_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + maskClip_ = getContext() == OFX::eContextFilter ? NULL : fetchClip(getContext() == OFX::eContextPaint ? "Brush" : "Mask"); + scale_ = fetchDoubleParam("scale"); + rScale_ = fetchDoubleParam("scaleR"); + gScale_ = fetchDoubleParam("scaleG"); + bScale_ = fetchDoubleParam("scaleB"); + aScale_ = fetchDoubleParam("scaleA"); + componentScalesEnabled_ = fetchBooleanParam("scaleComponents"); + setEnabledness(); + } + void setEnabledness(); + virtual void render(const OFX::RenderArguments &args); + virtual bool isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime); + virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string ¶mName); + virtual void changedClip(const OFX::InstanceChangedArgs &args, const std::string &clipName); + virtual bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod); + virtual void getRegionsOfInterest(const OFX::RegionsOfInterestArguments &args, OFX::RegionOfInterestSetter &rois); + void setupAndProcess(ImageScalerBase &, const OFX::RenderArguments &args); +}; + +void GammaPlugin::setupAndProcess(ImageScalerBase &processor, const OFX::RenderArguments &args) +{ + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + std::unique_ptr src(srcClip_->fetchImage(args.time)); + if(src.get()) + { + OFX::BitDepthEnum srcBitDepth = src->getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src->getPixelComponents(); + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); + } + std::unique_ptr mask; + if(getContext() != OFX::eContextFilter) + { + mask.reset(maskClip_->fetchImage(args.time)); + processor.doMasking(true); + processor.setMaskImg(mask.get()); + } + double r, g, b, a = aScale_->getValueAtTime(args.time); + r = g = b = scale_->getValueAtTime(args.time); + if(componentScalesEnabled_->getValueAtTime(args.time)) + { + r += rScale_->getValueAtTime(args.time); + g += gScale_->getValueAtTime(args.time); + b += bScale_->getValueAtTime(args.time); + } + processor.setDstImg(dst.get()); + processor.setSrcImg(src.get()); + processor.setRenderWindow(args.renderWindow); + processor.setScales((float)r, (float)g, (float)b, (float)a); + processor.process(); +} + +bool GammaPlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod) +{ + rod = srcClip_->getRegionOfDefinition(args.time); + return true; +} + +void GammaPlugin::getRegionsOfInterest(const OFX::RegionsOfInterestArguments &args, OFX::RegionOfInterestSetter &rois) +{ + rois.setRegionOfInterest(*srcClip_, args.regionOfInterest); + if(getContext() != OFX::eContextFilter) + rois.setRegionOfInterest(*maskClip_, args.regionOfInterest); +} + +void GammaPlugin::render(const OFX::RenderArguments &args) +{ + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + if(dstComponents == OFX::ePixelComponentRGBA) + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + ImageScaler fred(*this); + setupAndProcess(fred, args); + break; + } + case OFX::eBitDepthUShort : + { + ImageScaler fred(*this); + setupAndProcess(fred, args); + break; + } + case OFX::eBitDepthFloat : + { + ImageScaler fred(*this); + setupAndProcess(fred, args); + break; + } + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + ImageScaler fred(*this); + setupAndProcess(fred, args); + break; + } + case OFX::eBitDepthUShort : + { + ImageScaler fred(*this); + setupAndProcess(fred, args); + break; + } + case OFX::eBitDepthFloat : + { + ImageScaler fred(*this); + setupAndProcess(fred, args); + break; + } + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + +bool GammaPlugin:: isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime) +{ + double scale = scale_->getValueAtTime(args.time); + double rScale = 1, gScale = 1, bScale = 1, aScale = 1; + if(componentScalesEnabled_->getValueAtTime(args.time)) { + rScale = rScale_->getValueAtTime(args.time); + gScale = gScale_->getValueAtTime(args.time); + bScale = bScale_->getValueAtTime(args.time); + aScale = aScale_->getValueAtTime(args.time); + } + rScale += scale; + gScale += scale; + bScale += scale; + if(rScale == 1 && gScale == 1 && bScale == 1 && aScale == 1) { + identityClip = srcClip_; + identityTime = args.time; + return true; + } + return false; +} + +void GammaPlugin::setEnabledness(void) +{ + bool v = componentScalesEnabled_->getValue() && srcClip_->getPixelComponents() == OFX::ePixelComponentRGBA; + rScale_->setEnabled(v); + gScale_->setEnabled(v); + bScale_->setEnabled(v); + aScale_->setEnabled(v); +} + +void GammaPlugin::changedParam(const OFX::InstanceChangedArgs &/*args*/, const std::string ¶mName) +{ + if(paramName == "scaleComponents") + setEnabledness(); +} + +void GammaPlugin::changedClip(const OFX::InstanceChangedArgs &/*args*/, const std::string &clipName) +{ + if(clipName == kOfxImageEffectSimpleSourceClipName) + setEnabledness(); +} + +bool GammaInteract::draw(const OFX::DrawArgs &args) +{ + OfxRGBColourF col; + switch(_state) { +case eInActive : + col.r = col.g = col.b = 0.0f; + break; +case ePoised : + col.r = col.g = col.b = 0.5f; + break; +case ePicked : + col.r = col.g = col.b = 1.0f; + break; + } + + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + glPushMatrix(); + glColor3f(col.r, col.g, col.b); + glTranslated(_position.x, _position.y, 0); + glBegin(GL_POLYGON); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + glColor3f(1.0f - col.r, 1.0f - col.g, 1.0f - col.b); + glTranslated(_position.x, _position.y, 0); + glBegin(GL_LINE_LOOP); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + return true; +} + +bool GammaInteract::penMotion(const OFX::PenArgs &args) +{ + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + OfxPointD penPos = args.penPosition; + switch(_state) + { + case eInActive : + case ePoised : + { + StateEnum newState; + penPos.x -= _position.x; + penPos.y -= _position.y; + if(Absolute(penPos.x) < dx && Absolute(penPos.y) < dy) + { + newState = ePoised; + } + else + { + newState = eInActive; + } + + if(_state != newState) + { + _state = newState; + _effect->redrawOverlays(); + } + } + break; + case ePicked : + { + _position = penPos; + _effect->redrawOverlays(); + } + break; + } + return _state != eInActive; +} + +bool GammaInteract::penDown(const OFX::PenArgs &args) +{ + penMotion(args); + if(_state == ePoised) + { + _state = ePicked; + _position = args.penPosition; + _effect->redrawOverlays(); + } + return _state == ePicked; +} + +bool GammaInteract::penUp(const OFX::PenArgs &args) +{ + if(_state == ePicked) + { + _state = ePoised; + penMotion(args); + _effect->redrawOverlays(); + return true; + } + return false; +} + +using namespace OFX; + +class GammaOverlayDescriptor : public DefaultEffectOverlayDescriptor {}; + +void GammaExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + desc.setLabels("Gamma", "Gamma", "Gamma"); + desc.setPluginGrouping("OFX Example (Support)"); + desc.addSupportedContext(eContextFilter); + desc.addSupportedContext(eContextGeneral); + desc.addSupportedContext(eContextPaint); + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + desc.setOverlayInteractDescriptor( new GammaOverlayDescriptor ); +} + +static +DoubleParamDescriptor *defineScaleParam(OFX::ImageEffectDescriptor &desc, + const std::string &name, const std::string &label, const std::string &hint, + GroupParamDescriptor *parent, double def = 1.0) +{ + DoubleParamDescriptor *param = desc.defineDoubleParam(name); + param->setLabels(label, label, label); + param->setScriptName(name); + param->setHint(hint); + param->setDefault(def); + param->setRange(0, 10); + param->setIncrement(0.1); + param->setDisplayRange(0, 10); + param->setDoubleType(eDoubleTypeScale); + if(parent) + param->setParent(*parent); + return param; +} + +void GammaExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context) +{ + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->addSupportedComponent(ePixelComponentAlpha); + srcClip->setTemporalClipAccess(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + + if(context == eContextGeneral || context == eContextPaint) + { + ClipDescriptor *maskClip = context == eContextGeneral ? desc.defineClip("Mask") : desc.defineClip("Brush"); + maskClip->addSupportedComponent(ePixelComponentAlpha); + maskClip->setTemporalClipAccess(false); + if(context == eContextGeneral) + maskClip->setOptional(true); + maskClip->setSupportsTiles(true); + maskClip->setIsMask(true); + } + + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + + PageParamDescriptor *page = desc.definePageParam("Controls"); + + GroupParamDescriptor *componentScalesGroup = desc.defineGroupParam("componentScales"); + componentScalesGroup->setHint("Scales on the individual component"); + componentScalesGroup->setLabels("Components", "Components", "Components"); + + DoubleParamDescriptor *param = defineScaleParam(desc, "scale", "scale", "Scales all component in the image", 0, 1.0); + page->addChild(*param); + + BooleanParamDescriptor *boolP = desc.defineBooleanParam("scaleComponents"); + boolP->setDefault(true); + boolP->setHint("Enables gamma correction on individual components"); + boolP->setLabels("Gamma Components", "Gamma Components", "Gamma Components"); + boolP->setParent(*componentScalesGroup); + page->addChild(*boolP); + + param = defineScaleParam(desc, "scaleR", "red", "Gamma corrects the red component of the image", componentScalesGroup, 0.0); + page->addChild(*param); + + param = defineScaleParam(desc, "scaleG", "green", "Gamma corrects the green component of the image", componentScalesGroup, 0.0); + page->addChild(*param); + + param = defineScaleParam(desc, "scaleB", "blue", "Gamma corrects the blue component of the image", componentScalesGroup, 0.0); + page->addChild(*param); + + param = defineScaleParam(desc, "scaleA", "alpha", "Gamma corrects the alpha component of the image", componentScalesGroup, 0.0); + page->addChild(*param); + +} + +ImageEffect* GammaExamplePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/) +{ + return new GammaPlugin(handle); +} + diff --git a/third_party/openfx/Support/Plugins/MultiBundle/multibundle1.h b/third_party/openfx/Support/Plugins/MultiBundle/multibundle1.h new file mode 100755 index 000000000..7e6d6553f --- /dev/null +++ b/third_party/openfx/Support/Plugins/MultiBundle/multibundle1.h @@ -0,0 +1,13 @@ + + +#include "ofxsCore.h" + +class GammaExamplePluginFactory : public OFX::PluginFactoryHelper +{ +public: + GammaExamplePluginFactory():OFX::PluginFactoryHelper("net.sf.openfx.gammaexample", 1, 0){} + virtual void describe(OFX::ImageEffectDescriptor &desc); + virtual void describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context); + virtual OFX::ImageEffect* createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context); +}; + diff --git a/third_party/openfx/Support/Plugins/MultiBundle/multibundle2.cpp b/third_party/openfx/Support/Plugins/MultiBundle/multibundle2.cpp new file mode 100644 index 000000000..699ad871d --- /dev/null +++ b/third_party/openfx/Support/Plugins/MultiBundle/multibundle2.cpp @@ -0,0 +1,431 @@ + + +#ifdef _WINDOWS +#include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" +#include "../include/ofxsProcessing.H" + +#include "multibundle2.h" + +static const OfxPointD kBoxSize = {20, 20}; + +class DotExampleInteract : public OFX::OverlayInteract +{ +protected : + enum StateEnum { + eInActive, + ePoised, + ePicked + }; + StateEnum _state; + OFX::Double2DParam* position_; +public : + DotExampleInteract(OfxInteractHandle handle, OFX::ImageEffect* effect) : OFX::OverlayInteract(handle), _state(eInActive) + { + position_ = effect->fetchDouble2DParam("position"); + } + virtual bool draw(const OFX::DrawArgs &args); + virtual bool penMotion(const OFX::PenArgs &args); + virtual bool penDown(const OFX::PenArgs &args); + virtual bool penUp(const OFX::PenArgs &args); +}; + +template +inline T Absolute(T a) +{ + return (a < 0) ? -a : a; +} + +class DotGeneratorBase : public OFX::ImageProcessor +{ +public : + DotGeneratorBase(OFX::ImageEffect &instance) : OFX::ImageProcessor(instance), _radius(0.0f), _positionx(0.0f), _positiony(0.0f) + { + _colour[0] = _colour[1] = _colour[2] = _colour[3] = 0; + } + void setRadius(float v) { _radius = v; } + void setR(float v) { _colour[0] = v;} + void setG(float v) { _colour[1] = v;} + void setB(float v) { _colour[2] = v;} + void setA(float v) { _colour[3] = v;} + void setColour(double r, double g, double b, double a) + { + setR((float)r); + setG((float)g); + setB((float)b); + setA((float)a); + } + void setPosition(float x, float y) + { + _positionx = x; + _positiony = y; + } +protected: + float _radius; + float _colour[4]; + float _positionx; + float _positiony; +}; + +template +class DotGenerator : public DotGeneratorBase { +public : + DotGenerator(OFX::ImageEffect &instance): DotGeneratorBase(instance){} + void multiThreadProcessImages(OfxRectI procWindow) + { + float radiusSq = _radius * _radius; + for(int y = procWindow.y1; y < procWindow.y2; y++) + { + if(_effect.abort()) + break; + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + for(int x = procWindow.x1; x < procWindow.x2; x++) + { + float radsq = (x - _positionx)*(x - _positionx) + (y - _positiony)*(y - _positiony); + float val = radsq/radiusSq; + for(int c = 0; c < nComponents; c++) + { + dstPix[c] = val < 1.0f ? PIX((1.0f-val)*max) : PIX(0); + dstPix[c] = (PIX)(dstPix[c] * _colour[c]); + } + dstPix += nComponents; + } + } + } +}; + +class DotExamplePlugin : public OFX::ImageEffect +{ +protected: + OFX::Clip *dstClip_; + OFX::DoubleParam *radius_; + OFX::RGBAParam *colour_; + OFX::Double2DParam* position_; +public: + DotExamplePlugin(OfxImageEffectHandle handle): ImageEffect(handle), dstClip_(0), radius_(0) , colour_(0), position_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + radius_ = fetchDoubleParam("radius"); + colour_ = fetchRGBAParam("colour"); + position_ = fetchDouble2DParam("position"); + } + virtual void render(const OFX::RenderArguments &args); + void setupAndProcess(DotGeneratorBase &, const OFX::RenderArguments &args); + bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod); + template + void getPositionInPixels(double& x, double& y, const ARGS& args); + template + void getPositionInCanonical(double& x, double& y, const ARGS& args); +}; + +template +void DotExamplePlugin::getPositionInCanonical(double& x, double& y, const ARGS& args) +{ + position_->getValueAtTime(args.time, x, y); +} + +template +void DotExamplePlugin::getPositionInPixels(double& x, double& y, const ARGS& args) +{ + double xpos, ypos; + getPositionInCanonical(xpos, ypos, args); + x = (xpos * args.renderScale.x) /getProjectPixelAspectRatio(); + y = ypos * args.renderScale.y; +} + +void DotExamplePlugin::setupAndProcess(DotGeneratorBase &processor, const OFX::RenderArguments &args) +{ + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + //OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + //OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + double rad = radius_->getValueAtTime(args.time); + processor.setRadius((float)(rad)); + double r, g, b, a; + colour_->getValueAtTime(args.time, r, g, b, a); + processor.setColour(r,g,b,a); + processor.setDstImg(dst.get()); + processor.setRenderWindow(args.renderWindow); + double xpospixel, ypospixel; + getPositionInPixels(xpospixel, ypospixel, args); + float fieldScaler = (args.fieldToRender == OFX::eFieldLower || args.fieldToRender == OFX::eFieldUpper)? 0.5f: 1.0f; + ypospixel *= fieldScaler; + processor.setPosition((float)xpospixel, (float)ypospixel); + processor.process(); +} + + +bool DotExamplePlugin::getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod) +{ + double r = radius_->getValueAtTime(args.time); + double x, y; + position_->getValueAtTime(args.time, x, y); + rod.x1 = x - r; + rod.y1 = y - r; + rod.x2 = x + r; + rod.y2 = y + r; + return true; +} + +void DotExamplePlugin::render(const OFX::RenderArguments &args) +{ + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + if(dstComponents == OFX::ePixelComponentRGBA) + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + DotGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + case OFX::eBitDepthUShort : + { + DotGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + case OFX::eBitDepthFloat : + { + DotGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + DotGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + case OFX::eBitDepthUShort : + { + DotGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + case OFX::eBitDepthFloat : + { + DotGenerator fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + + +bool DotExampleInteract::draw(const OFX::DrawArgs &args) +{ + OfxRGBColourF col; + col.r = 0.5f; + col.g = 0.0f; + + switch(_state) + { + case eInActive : + col.b = 0.0f; + break; + case ePoised : + col.b = 0.5f; + break; + case ePicked : + col.b = 1.0f; + break; + } + + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + double xpos = 0., ypos = 0.; + DotExamplePlugin* plug = dynamic_cast(_effect); + assert(plug); + if (plug) { + plug->getPositionInCanonical(xpos, ypos, args); + } + glPushMatrix(); + glColor3f(col.r, col.g, col.b); + glTranslated(xpos, ypos, 0); + glBegin(GL_POLYGON); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + glColor3f(1.0f - col.r, 1.0f - col.g, 1.0f - col.b); + glTranslated(xpos, ypos, 0); + glBegin(GL_LINE_LOOP); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + return true; +} + +bool DotExampleInteract::penMotion(const OFX::PenArgs &args) +{ + float dx = (float)(kBoxSize.x * args.pixelScale.x); + float dy = (float)(kBoxSize.y * args.pixelScale.y); + OfxPointD penPos = args.penPosition; + switch(_state) + { + case eInActive : + case ePoised : + { + StateEnum newState; + double xpos = 0., ypos = 0.; + DotExamplePlugin* plug = dynamic_cast(_effect); + if (plug) { + plug->getPositionInCanonical(xpos, ypos, args); + } + penPos.x -= xpos; + penPos.y -= ypos; + if(Absolute(penPos.x) < dx && Absolute(penPos.y) < dy) + { + newState = ePoised; + } + else + { + newState = eInActive; + } + + if(_state != newState) + { + _state = newState; + _effect->redrawOverlays(); + } + } + break; + case ePicked : + { + + position_->setValueAtTime(args.time, args.penPosition.x, args.penPosition.y); + _effect->redrawOverlays(); + } + break; + } + return _state != eInActive; +} + +bool DotExampleInteract::penDown(const OFX::PenArgs &args) +{ + penMotion(args); + if(_state == ePoised) + { + _state = ePicked; + _effect->redrawOverlays(); + } + return _state == ePicked; +} + +bool DotExampleInteract::penUp(const OFX::PenArgs &args) +{ + if(_state == ePicked) + { + _state = ePoised; + penMotion(args); + _effect->redrawOverlays(); + return true; + } + return false; +} + +using namespace OFX; + +class DotExampleOverlayDescriptor : public DefaultEffectOverlayDescriptor {}; + +void DotExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + desc.setLabels("Dot Generator", "Dot Generator", "Dot Generator"); + desc.setPluginGrouping("OFX Example (Support)"); + desc.addSupportedContext(eContextGenerator); + desc.addSupportedContext(eContextGeneral); + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + desc.setRenderTwiceAlways(false); + desc.setOverlayInteractDescriptor( new DotExampleOverlayDescriptor ); +} + +void DotExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum /*context*/) +{ + // there has to be an input clip, even for generators + ClipDescriptor* srcClip = desc.defineClip( kOfxImageEffectSimpleSourceClipName ); + srcClip->addSupportedComponent( OFX::ePixelComponentRGBA ); + srcClip->addSupportedComponent( OFX::ePixelComponentAlpha ); + srcClip->setSupportsTiles(true); + srcClip->setOptional(true); + + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + dstClip->setFieldExtraction(eFieldExtractSingle); + + DoubleParamDescriptor *param = desc.defineDoubleParam("radius"); + param->setLabels("Radius", "Radius", "Radius"); + param->setScriptName("radius"); + param->setHint("The radius of the dot produced."); + param->setDoubleType(eDoubleTypeX); + param->setDefaultCoordinateSystem(eCoordinatesNormalised); + param->setDefault(0.02); + //param->setRange(0, 1); + param->setIncrement(1); + param->setDisplayRange(0, 1); + param->setAnimates(true); + + RGBAParamDescriptor *param2 = desc.defineRGBAParam("colour"); + param2->setAnimates(true); + param2->setLabels("Colour", "Colour", "Colour"); + param2->setHint("The colour of the dot produced."); + param2->setScriptName("colour"); + param2->setDefault(1.0, 1.0, 1.0, 1.0); + + Double2DParamDescriptor* param3 = desc.defineDouble2DParam("position"); + param3->setLabels("Dot Position", "Dot Position", "Dot Position"); + param3->setDoubleType(eDoubleTypeXY); + param3->setDefaultCoordinateSystem(eCoordinatesNormalised); + param3->setAnimates(true); + param3->setDimensionLabels("X", "Y"); + param3->setDefault(0.5, 0.5); + + PageParamDescriptor *page = desc.definePageParam("Controls"); + page->addChild(*param); + page->addChild(*param2); + page->addChild(*param3); +} + +ImageEffect* DotExamplePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/) +{ + return new DotExamplePlugin(handle); +} + diff --git a/third_party/openfx/Support/Plugins/MultiBundle/multibundle2.h b/third_party/openfx/Support/Plugins/MultiBundle/multibundle2.h new file mode 100755 index 000000000..47ea7104b --- /dev/null +++ b/third_party/openfx/Support/Plugins/MultiBundle/multibundle2.h @@ -0,0 +1,13 @@ + + +#include "ofxsImageEffect.h" + +class DotExamplePluginFactory : public OFX::PluginFactoryHelper +{ +public: + DotExamplePluginFactory():OFX::PluginFactoryHelper("net.sf.openfx.dotexample", 1, 0){} + virtual void describe(OFX::ImageEffectDescriptor &desc); + virtual void describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context); + virtual OFX::ImageEffect* createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context); +}; + diff --git a/third_party/openfx/Support/Plugins/Retimer/Info.plist b/third_party/openfx/Support/Plugins/Retimer/Info.plist new file mode 100644 index 000000000..2156abb22 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Retimer/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + retimer.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/Retimer/retimer.cpp b/third_party/openfx/Support/Plugins/Retimer/retimer.cpp new file mode 100644 index 000000000..d7361adb7 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Retimer/retimer.cpp @@ -0,0 +1,386 @@ + + +#include // for floor +#include // for FLT_MAX + +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" + +#include "../include/ofxsProcessing.H" +#include "../include/ofxsImageBlender.H" + + namespace OFX { + extern ImageEffectHostDescription gHostDescription; + } +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class RetimerPlugin : public OFX::ImageEffect { +protected : + // do not need to delete these, the ImageEffect is managing them for us + OFX::Clip *dstClip_; /**< @brief Mandated output clips */ + OFX::Clip *srcClip_; /**< @brief Mandated input clips */ + + OFX::DoubleParam *sourceTime_; /**< @brief mandated parameter, only used in the retimer context. */ + OFX::DoubleParam *speed_; /**< @brief only used in the filter context. */ + OFX::DoubleParam *duration_; /**< @brief how long the output should be as a proportion of input. General context only */ + +public : + /** @brief ctor */ + RetimerPlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + , srcClip_(0) + , sourceTime_(0) + , speed_(0) + , duration_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + + // What parameters we instantiate depend on the context + if(getContext() == OFX::eContextRetimer) + // fetch the mandated parameter which the host uses to pass us the frame to retime to + sourceTime_ = fetchDoubleParam(kOfxImageEffectRetimerParamName); + else // context == OFX::eContextFilter || context == OFX::eContextGeneral + // filter context means we are in charge of how to retime, and our example is using a speed curve to do that + speed_ = fetchDoubleParam("Speed"); + + // fetch duration param for general context + if(getContext() == OFX::eContextGeneral) + duration_ = fetchDoubleParam("Duration"); + } + + /* Override the render */ + virtual void render(const OFX::RenderArguments &args); + + /** Override the get frames needed action */ + virtual void getFramesNeeded(const OFX::FramesNeededArguments &args, OFX::FramesNeededSetter &frames); + + /* override the time domain action, only for the general context */ + virtual bool getTimeDomain(OfxRangeD &range); + + /* set up and run a processor */ + void + setupAndProcess(OFX::ImageBlenderBase &, const OFX::RenderArguments &args); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ + +//////////////////////////////////////////////////////////////////////////////// +// basic plugin render function, just a skelington to instantiate templates from + +// make sure components are sane +static void +checkComponents(const OFX::Image &src, + OFX::BitDepthEnum dstBitDepth, + OFX::PixelComponentEnum dstComponents) +{ + OFX::BitDepthEnum srcBitDepth = src.getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src.getPixelComponents(); + + // see if they have the same depths and bytes and all + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); // HACK!! need to throw an sensible exception here! +} + +static void framesNeeded(double sourceTime, OFX::FieldEnum fieldToRender, double *fromTimep, double *toTimep, double *blendp) +{ + // figure the two images we are blending between + double fromTime, toTime; + double blend; + + if (fieldToRender == OFX::eFieldNone) { + // unfielded, easy peasy + fromTime = floor(sourceTime); + toTime = fromTime + 1; + blend = sourceTime - fromTime; + } + else { + // Fielded clips, pook. We are rendering field doubled images, + // and so need to blend between fields, not frames. + double frac = sourceTime - floor(sourceTime); + if(frac < 0.5) { + // need to go between the first and second fields of this frame + fromTime = floor(sourceTime); // this will get the first field + toTime = fromTime + 0.5; // this will get the second field of the same frame + blend = frac * 2.0; // and the blend is between those two + } + else { // frac > 0.5 + fromTime = floor(sourceTime) + 0.5; // this will get the second field of this frame + toTime = floor(sourceTime) + 1.0; // this will get the first field of the next frame + blend = (frac - 0.5) * 2.0; + } + } + *fromTimep = fromTime; + *toTimep = toTime; + *blendp = blend; +} + +/* set up and run a processor */ +void +RetimerPlugin::setupAndProcess(OFX::ImageBlenderBase &processor, const OFX::RenderArguments &args) +{ + // get a dst image + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // figure the frame we should be retiming from + double sourceTime; + + if(getContext() == OFX::eContextRetimer) { + // the host is specifying it, so fetch it from the kOfxImageEffectRetimerParamName pseudo-param + sourceTime = sourceTime_->getValueAtTime(args.time); + } + else { + // we have our own param, which is a speed, so we integrate it to get the time we want + sourceTime = speed_->integrate(0, args.time); + } + + // figure the two images we are blending between + double fromTime, toTime; + double blend; + framesNeeded(sourceTime, args.fieldToRender, &fromTime, &toTime, &blend); + + // fetch the two source images + std::unique_ptr fromImg(srcClip_->fetchImage(fromTime)); + std::unique_ptr toImg(srcClip_->fetchImage(toTime)); + + // make sure bit depths are sane + if(fromImg.get()) checkComponents(*fromImg, dstBitDepth, dstComponents); + if(toImg.get()) checkComponents(*toImg, dstBitDepth, dstComponents); + + // set the images + processor.setDstImg(dst.get()); + processor.setFromImg(fromImg.get()); + processor.setToImg(toImg.get()); + + // set the render window + processor.setRenderWindow(args.renderWindow); + + // set the blend between + processor.setBlend((float)blend); + + // Call the base class process member, this will call the derived templated process code + processor.process(); +} + +void +RetimerPlugin::getFramesNeeded(const OFX::FramesNeededArguments &args, + OFX::FramesNeededSetter &frames) +{ + // figure the two images we are blending between + double fromTime, toTime; + double blend; + // whatever the rendered field is, the frames are the same + framesNeeded(args.time, OFX::eFieldNone, &fromTime, &toTime, &blend); + OfxRangeD range; + range.min = fromTime; + range.max = toTime; + frames.setFramesNeeded(*srcClip_, range); +} + +/* override the time domain action, only for the general context */ +bool +RetimerPlugin::getTimeDomain(OfxRangeD &range) +{ + // this should only be called in the general context, ever! + if(getContext() == OFX::eContextGeneral) { + // If we are a general context, we can changed the duration of the effect, so have a param to do that + // We need a separate param as it is impossible to derive this from a speed param and the input clip + // duration (the speed may be animating or wired to an expression). + double duration = duration_->getValue(); //don't animate + + // how many frames on the input clip + OfxRangeD srcRange = srcClip_->getFrameRange(); + + range.min = 0; + range.max = srcRange.max * duration; + return true; + } + + return false; +} + +// the overridden render function +void +RetimerPlugin::render(const OFX::RenderArguments &args) +{ + // instantiate the render code based on the pixel depth of the dst clip + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + // do the rendering + if(dstComponents == OFX::ePixelComponentRGBA) { + switch(dstBitDepth) { + case OFX::eBitDepthUByte : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else { + switch(dstBitDepth) { + case OFX::eBitDepthUByte : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } // switch +} + +using namespace OFX; +mDeclarePluginFactory(RetimerExamplePluginFactory, ;, {}); + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static RetimerExamplePluginFactory p("net.sf.openfx.retimer", 1, 0); + ids.push_back(&p); + } + }; +}; + +void RetimerExamplePluginFactory::load() +{ + // we can't be used on hosts that don't perfrom temporal clip access + if(!gHostDescription.temporalClipAccess) { + throw OFX::Exception::HostInadequate("Need random temporal image access to work"); + } +} + +/** @brief The basic describe function, passed a plugin descriptor */ +void RetimerExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + // basic labels + desc.setLabels("Retimer", "Retimer", "Retimer"); + desc.setPluginGrouping("OFX Example (Support)"); + + // Say we are a transition context + desc.addSupportedContext(OFX::eContextRetimer); + desc.addSupportedContext(OFX::eContextFilter); + desc.addSupportedContext(OFX::eContextGeneral); + + // Add supported pixel depths + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + // set a few flags + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(true); // say we will be doing random time access on clips + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); +} + +/** @brief The describe in context function, passed a plugin descriptor and a context */ +void RetimerExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum context) +{ + // we are a transition, so define the sourceTo input clip + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->addSupportedComponent(ePixelComponentAlpha); + srcClip->setTemporalClipAccess(true); // say we will be doing random time access on this clip + srcClip->setSupportsTiles(true); + srcClip->setFieldExtraction(eFieldExtractDoubled); // which is the default anyway + + // create the mandated output clip + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setFieldExtraction(eFieldExtractDoubled); // which is the default anyway + dstClip->setSupportsTiles(true); + + // what param we have is dependant on the host + if(context == OFX::eContextRetimer) { + // Define the mandated kOfxImageEffectRetimerParamName param, note that we don't do anything with this other than. + // describe it. It is not a true param but how the host indicates to the plug-in which frame + // it wants you to retime to. It appears on no plug-in side UI, it is purely the host's to manage. + DoubleParamDescriptor *param = desc.defineDoubleParam(kOfxImageEffectRetimerParamName); + (void)param; + } + else { + // We are a general or filter context, define a speed param and a page of controls to put that in + DoubleParamDescriptor *param = desc.defineDoubleParam("Speed"); + param->setLabels("speed", "speed", "speed"); + param->setScriptName("speed"); + param->setHint("How much to changed the speed of the input clip"); + param->setDefault(1); + param->setRange(-FLT_MAX, FLT_MAX); + param->setIncrement(0.05); + param->setDisplayRange(0, 1); + param->setAnimates(true); // can animate + param->setDoubleType(eDoubleTypeScale); + + // make a page to put it in + PageParamDescriptor *page = desc.definePageParam("Controls"); + + // add our speed param into it + page->addChild(*param); + + // If we are a general context, we can change the duration of the effect, so have a param to do that + // We need a separate param as it is impossible to derive this from a speed param and the input clip + // duration (the speed may be animating or wired to an expression). + if(context == OFX::eContextGeneral) { + // We are a general or filter context, define a speed param and a page of controls to put that in + DoubleParamDescriptor *param = desc.defineDoubleParam("Duration"); + param->setLabels("duration", "duraction", "duration"); + param->setScriptName("duration"); + param->setHint("How long the output clip should be, as a proportion of the input clip's length."); + param->setDefault(1); + param->setRange(0, 10); + param->setIncrement(0.1); + param->setDisplayRange(0, 10); + param->setAnimates(false); // no animation here! + param->setDoubleType(eDoubleTypeScale); + + // add param to page + page->addChild(*param); + } + } +} + +/** @brief The create instance function, the plugin must return an object derived from the \ref OFX::ImageEffect class */ +ImageEffect* RetimerExamplePluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum /*context*/) +{ + return new RetimerPlugin(handle); +} diff --git a/third_party/openfx/Support/Plugins/Retimer/retimer.dsp b/third_party/openfx/Support/Plugins/Retimer/retimer.dsp new file mode 100755 index 000000000..bff7dd3cc --- /dev/null +++ b/third_party/openfx/Support/Plugins/Retimer/retimer.dsp @@ -0,0 +1,107 @@ +# Microsoft Developer Studio Project File - Name="retimer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=retimer - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "retimer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "retimer.mak" CFG="retimer - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "retimer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "retimer - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "retimer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/PropTester.ofx.bundle/Contents/Win32/retimer.ofx" + +!ELSEIF "$(CFG)" == "retimer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include" /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\Common Files\OFX\Plugins\Retimer.ofx.bundle\Contents\Win32\retimer.ofx" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "retimer - Win32 Release" +# Name "retimer - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\retimer.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/third_party/openfx/Support/Plugins/Retimer/retimer.dsw b/third_party/openfx/Support/Plugins/Retimer/retimer.dsw new file mode 100755 index 000000000..614ef8642 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Retimer/retimer.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "retimer"=.\retimer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ofxsupport + End Project Dependency +}}} + +############################################################################### + +Project: "ofxsupport"=..\..\Library\ofxsupport.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/third_party/openfx/Support/Plugins/Retimer/retimer.vcproj b/third_party/openfx/Support/Plugins/Retimer/retimer.vcproj new file mode 100755 index 000000000..ed934eb5e --- /dev/null +++ b/third_party/openfx/Support/Plugins/Retimer/retimer.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/Tester/Info.plist b/third_party/openfx/Support/Plugins/Tester/Info.plist new file mode 100644 index 000000000..01a1c0f1c --- /dev/null +++ b/third_party/openfx/Support/Plugins/Tester/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + tester.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/Tester/Tester.cpp b/third_party/openfx/Support/Plugins/Tester/Tester.cpp new file mode 100644 index 000000000..2b2506544 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Tester/Tester.cpp @@ -0,0 +1,528 @@ + + +#ifdef _WINDOWS +#include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" +#include "ofxsInteract.h" + +#include "../include/ofxsProcessing.H" + +static const OfxPointD kBoxSize = {5, 5}; + +template +inline T Minimum(T a, T b) { return (a < b) ? a : b;} + +template +inline T Absolute(T a) { return (a < 0) ? -a : a;} + +class PositionInteract : public OFX::OverlayInteract +{ +protected : + enum StateEnum { + eInActive, + ePoised, + ePicked + }; + + StateEnum _state; + OFX::Double2DParam* _position; +public : + PositionInteract(OfxInteractHandle handle, OFX::ImageEffect* effect) + : OFX::OverlayInteract(handle) + , _state(eInActive) + { + _position = effect->fetchDouble2DParam("widgetPos"); + } + + // overridden functions from OFX::Interact to do things + virtual bool draw(const OFX::DrawArgs &args); + virtual bool penMotion(const OFX::PenArgs &args); + virtual bool penDown(const OFX::PenArgs &args); + virtual bool penUp(const OFX::PenArgs &args); + OfxPointD getCanonicalPosition(double time) const + { + OfxPointD retVal; + _position->getValueAtTime(time, retVal.x, retVal.y); + return retVal; + } + void setCanonicalPosition(double x, double y, double time) + { + _position->setValueAtTime(time, x, y); + } +}; + +bool PositionInteract::draw(const OFX::DrawArgs &args) +{ + OfxRGBColourF col; + switch(_state) + { + case eInActive : col.r = col.g = col.b = 0.0f; break; + case ePoised : col.r = col.g = col.b = 0.5f; break; + case ePicked : col.r = col.g = col.b = 1.0f; break; + } + + // make the box a constant size on screen by scaling by the pixel scale + float dx = (float)(kBoxSize.x / args.pixelScale.x); + float dy = (float)(kBoxSize.y / args.pixelScale.y); + + // Draw a cross hair, the current coordinate system aligns with the image plane. + glPushMatrix(); + + // draw the bo + OfxPointD pos = getCanonicalPosition(args.time); + glColor3f(col.r, col.g, col.b); + glTranslated(pos.x, pos.y, 0); + glBegin(GL_POLYGON); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + + glPushMatrix(); + // draw a complementary outline + glColor3f(1.0f - col.r, 1.0f - col.g, 1.0f - col.b); + glTranslated(pos.x, pos.y, 0); + glBegin(GL_LINE_LOOP); + glVertex2f(-dx, -dy); + glVertex2f(-dx, dy); + glVertex2f( dx, dy); + glVertex2f( dx, -dy); + glEnd(); + glPopMatrix(); + + return true; +} + +// overridden functions from OFX::Interact to do things +bool PositionInteract::penMotion(const OFX::PenArgs &args) +{ + // figure the size of the box in cannonical coords + float dx = (float)(kBoxSize.x / args.pixelScale.x); + float dy = (float)(kBoxSize.y / args.pixelScale.y); + + OfxPointD pos = getCanonicalPosition(args.time); + + // pen position is in cannonical coords + OfxPointD penPos = args.penPosition; + + switch(_state) + { + case eInActive : + case ePoised : + { + // are we in the box, become 'poised' + StateEnum newState; + penPos.x -= pos.x; + penPos.y -= pos.y; + if(Absolute(penPos.x) < dx && + Absolute(penPos.y) < dy) { + newState = ePoised; + } + else { + newState = eInActive; + } + + if(_state != newState) { + _state = newState; + _effect->redrawOverlays(); + } + } + break; + + case ePicked : + { + setCanonicalPosition(penPos.x, penPos.y, args.time); + _effect->redrawOverlays(); + } + break; + } + return _state != eInActive; +} + +bool PositionInteract::penDown(const OFX::PenArgs &args) +{ + penMotion(args); + if(_state == ePoised) { + _state = ePicked; + setCanonicalPosition(args.penPosition.x, args.penPosition.y, args.time); + _effect->redrawOverlays(); + } + + return _state == ePicked; +} + +bool PositionInteract::penUp(const OFX::PenArgs &args) +{ + if(_state == ePicked) + { + _state = ePoised; + penMotion(args); + _effect->redrawOverlays(); + return true; + } + return false; +} + +class GenericTestBase : public OFX::ImageProcessor { +protected : + OFX::Image *_srcImg; +public : + GenericTestBase(OFX::ImageEffect &instance): OFX::ImageProcessor(instance), _srcImg(0) + { + } + void setSrcImg(OFX::Image *v) {_srcImg = v;} +}; + +template +class ImageGenericTester : public GenericTestBase +{ +public : + ImageGenericTester(OFX::ImageEffect &instance) : GenericTestBase(instance){} + void multiThreadProcessImages(OfxRectI procWindow) + { + for(int y = procWindow.y1; y < procWindow.y2; y++) + { + if(_effect.abort()) + break; + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + for(int x = procWindow.x1; x < procWindow.x2; x++) + { + PIX *srcPix = (PIX *) (_srcImg ? _srcImg->getPixelAddress(x, y) : 0); + if(srcPix) + { + for(int c = 0; c < nComponents; c++) + dstPix[c] = max - srcPix[c]; + } + else + { + for(int c = 0; c < nComponents; c++) + dstPix[c] = 0; + } + dstPix += nComponents; + } + } + } +}; + + + +template +class Analyser +{ +public: + Analyser(OFX::Clip* srcClip, OFX::DoubleParam* dbl) + { + OfxRangeD range = srcClip->getFrameRange(); + for(double d = range.min; d< range.max; ++d) + { + std::unique_ptr src(srcClip->fetchImage(d)); + dbl->setValueAtTime(d, d); + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class GenericTestPlugin : public OFX::ImageEffect +{ +protected : + OFX::Clip *dstClip_; + OFX::Clip *srcClip_; + +public : + GenericTestPlugin(OfxImageEffectHandle handle) : ImageEffect(handle), dstClip_(0), srcClip_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + } + + virtual void render(const OFX::RenderArguments &args); + void setupAndProcess(GenericTestBase &, const OFX::RenderArguments &args); + void changedParam(const OFX::InstanceChangedArgs &args, const std::string ¶mName) + { + if(paramName=="enableTest") + { + OFX::ChoiceParam* choice = fetchChoiceParam("enableTest"); + OFX::DoubleParam* dbl = fetchDoubleParam("enableDbl"); + int value = 0; + choice->getValueAtTime(args.time, value); + dbl->setEnabled(value ==0 ); + } + else if(paramName=="pbButton") + { + sendMessage(OFX::Message::eMessageMessage, "", "Push Button Pressed - TestPassed!"); + } + else if(paramName=="widgetPos") + { + redrawOverlays(); + } + else if(paramName == "analyseButton") + { + OFX::BitDepthEnum dstBitDepth = srcClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = srcClip_->getPixelComponents(); + OFX::DoubleParam* dbl = fetchDoubleParam("analysisParam"); + + if(dstComponents == OFX::ePixelComponentRGBA) + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + Analyser analyse(srcClip_, dbl); + break; + } + case OFX::eBitDepthUShort : + { + Analyser analyse(srcClip_, dbl); + break; + } + case OFX::eBitDepthFloat : + { + Analyser analyse(srcClip_, dbl); + break; + } + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + Analyser analyse(srcClip_, dbl); + break; + } + case OFX::eBitDepthUShort : + { + Analyser analyse(srcClip_, dbl); + break; + } + case OFX::eBitDepthFloat : + { + Analyser analyse(srcClip_, dbl); + break; + } + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + } + } +}; + + +void GenericTestPlugin::setupAndProcess(GenericTestBase &processor, const OFX::RenderArguments &args) +{ + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + std::unique_ptr src(srcClip_->fetchImage(args.time)); + + if(src.get()) + { + OFX::BitDepthEnum srcBitDepth = src->getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src->getPixelComponents(); + + // see if they have the same depths and bytes and all + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); // HACK!! need to throw an sensible exception here! + } + + processor.setDstImg(dst.get()); + processor.setSrcImg(src.get()); + processor.setRenderWindow(args.renderWindow); + processor.process(); +} + + +void GenericTestPlugin::render(const OFX::RenderArguments &args) +{ + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + if(dstComponents == OFX::ePixelComponentRGBA) + { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + ImageGenericTester fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : + { + ImageGenericTester fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : + { + ImageGenericTester fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else { + switch(dstBitDepth) + { + case OFX::eBitDepthUByte : + { + ImageGenericTester fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthUShort : + { + ImageGenericTester fred(*this); + setupAndProcess(fred, args); + } + break; + + case OFX::eBitDepthFloat : + { + ImageGenericTester fred(*this); + setupAndProcess(fred, args); + } + break; + default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } +} + +class PositionOverlayDescriptor : public OFX::DefaultEffectOverlayDescriptor {}; + +mDeclarePluginFactory(GenericTestExamplePluginFactory, {}, {}); + +using namespace OFX; +void GenericTestExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + desc.setLabels("GenericTest", "GenericTest", "GenericTest"); + desc.setPluginGrouping("OFX Example (Support)"); + desc.addSupportedContext(eContextFilter); + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + + desc.setOverlayInteractDescriptor( new PositionOverlayDescriptor); +} + +void GenericTestExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum /*context*/) +{ + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->addSupportedComponent(ePixelComponentAlpha); + srcClip->setTemporalClipAccess(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + + DoubleParamDescriptor *param1 = desc.defineDoubleParam("MinMaxTest"); + param1->setLabels("Min/Max Test", "Min/Max Test", "Min/Max Test"); + param1->setScriptName("minMaxTest"); + param1->setHint("A double parameter to illustrate visual min/max."); + param1->setDefault(50.0); + param1->setRange(-1000, 1000); + param1->setDisplayRange(-1000, 1000); + param1->setDoubleType(eDoubleTypePlain); + + ChoiceParamDescriptor* param2 = desc.defineChoiceParam("enableTest"); + param2->setLabels("Enabler", "Enabler", "Enabler"); + param2->appendOption("Enable parameter", "Enable parameter"); + param2->appendOption("Disable parameter", "Disable parameter"); + + DoubleParamDescriptor *param3 = desc.defineDoubleParam("enableDbl"); + param3->setLabels("Enabled by Enabler", "Enabled by Enabler", "Enabled by Enabler"); + + + BooleanParamDescriptor* bparam = desc.defineBooleanParam("Insignificant"); + bparam->setLabels("Insignificant", "Insignificant", "Insignificant"); + bparam->setHint("Shouldn't cause a re-render."); + bparam->setEvaluateOnChange(false); + + BooleanParamDescriptor* bparam2 = desc.defineBooleanParam("secretTest"); + bparam2->setLabels("SECRET!", "SECRET!", "SECRET!"); + bparam2->setIsSecret(true); + bparam2->setHint("Shouldn't be shown in the user interface."); + + BooleanParamDescriptor* bparam3 = desc.defineBooleanParam("nonPersistant"); + bparam3->setLabels("Non-persistant", "Non-persistant", "Non-persistant"); + bparam3->setHint("Shouldn't be saved in the plugin description."); + bparam3->setIsPersistant(false); + + DoubleParamDescriptor *param5 = desc.defineDoubleParam("animateDbl"); + param5->setLabels("No Animation", "No Animation", "No Animation"); + param5->setAnimates(false); + + DoubleParamDescriptor *param6 = desc.defineDoubleParam("angleTest"); + param6->setLabels("Angle?", "Angle?", "Angle?"); + param6->setRange(-180.0, 180.0); + param6->setHint("An angle parameter."); + param6->setDoubleType(eDoubleTypeAngle); + + PushButtonParamDescriptor* pb = desc.definePushButtonParam("pbButton"); + pb->setLabels("Push Me", "Push Me", "Push Me"); + + PushButtonParamDescriptor* pb2 = desc.definePushButtonParam("analyseButton"); + pb2->setLabels("Analyse", "Analyse", "Analyse"); + + DoubleParamDescriptor *param7 = desc.defineDoubleParam("analysisParam"); + param7->setLabels("Analysis Slave", "Analysis Slave", "Analysis Slave"); + + Double2DParamDescriptor* widgetPos = desc.defineDouble2DParam("widgetPos"); + widgetPos->setLabels("Widget Position", "Widget Position", "Widget Position"); + widgetPos->setDoubleType(OFX::eDoubleTypeXYAbsolute); + widgetPos->setDefaultCoordinateSystem(eCoordinatesNormalised); + widgetPos->setDimensionLabels("X Position", "Y Position"); + widgetPos->setDefault(0.5, 0.5); +} + +OFX::ImageEffect* GenericTestExamplePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/) +{ + return new GenericTestPlugin(handle); +} + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static GenericTestExamplePluginFactory p("net.sf.openfx.GenericTestPlugin", 1, 0); + ids.push_back(&p); + } + } +} diff --git a/third_party/openfx/Support/Plugins/Tester/Tester.vcproj b/third_party/openfx/Support/Plugins/Tester/Tester.vcproj new file mode 100644 index 000000000..35220a0b9 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Tester/Tester.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/Transition/Info.plist b/third_party/openfx/Support/Plugins/Transition/Info.plist new file mode 100644 index 000000000..cfbee0c70 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Transition/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + crossFade.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/Plugins/Transition/crossFade.cpp b/third_party/openfx/Support/Plugins/Transition/crossFade.cpp new file mode 100644 index 000000000..ca007cbfa --- /dev/null +++ b/third_party/openfx/Support/Plugins/Transition/crossFade.cpp @@ -0,0 +1,260 @@ + + +#include +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" + +#include "../include/ofxsProcessing.H" +#include "../include/ofxsImageBlender.H" + +//////////////////////////////////////////////////////////////////////////////// +/** @brief The plugin that does our work */ +class CrossFadePlugin : public OFX::ImageEffect { +protected : + // do not need to delete these, the ImageEffect is managing them for us + OFX::Clip *dstClip_; + OFX::Clip *fromClip_; + OFX::Clip *toClip_; + + OFX::DoubleParam *transition_; + +public : + /** @brief ctor */ + CrossFadePlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + , fromClip_(0) + , toClip_(0) + , transition_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + fromClip_ = fetchClip(kOfxImageEffectTransitionSourceFromClipName); + toClip_ = fetchClip(kOfxImageEffectTransitionSourceToClipName); + transition_ = fetchDoubleParam("Transition"); + } + + /* Override the render */ + virtual void render(const OFX::RenderArguments &args); + + /* override is identity */ + virtual bool isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime); + + /* set up and run a processor */ + void + setupAndProcess(OFX::ImageBlenderBase &, const OFX::RenderArguments &args); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ + +//////////////////////////////////////////////////////////////////////////////// +// basic plugin render function, just a skelington to instantiate templates from + +// make sure components are sane +static void +checkComponents(const OFX::Image &src, + OFX::BitDepthEnum dstBitDepth, + OFX::PixelComponentEnum dstComponents) +{ + OFX::BitDepthEnum srcBitDepth = src.getPixelDepth(); + OFX::PixelComponentEnum srcComponents = src.getPixelComponents(); + + // see if they have the same depths and bytes and all + if(srcBitDepth != dstBitDepth || srcComponents != dstComponents) + throw int(1); // HACK!! need to throw an sensible exception here! +} + +/* set up and run a processor */ +void +CrossFadePlugin::setupAndProcess(OFX::ImageBlenderBase &processor, const OFX::RenderArguments &args) +{ + // get a dst image + std::unique_ptr dst(dstClip_->fetchImage(args.time)); + OFX::BitDepthEnum dstBitDepth = dst->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dst->getPixelComponents(); + + // fetch the two source images + std::unique_ptr fromImg(fromClip_->fetchImage(args.time)); + std::unique_ptr toImg(toClip_->fetchImage(args.time)); + + // make sure bit depths are sane + if(fromImg.get()) checkComponents(*fromImg, dstBitDepth, dstComponents); + if(toImg.get()) checkComponents(*toImg, dstBitDepth, dstComponents); + + // get the transition value + float blend = (float)transition_->getValueAtTime(args.time); + + // set the images + processor.setDstImg(dst.get()); + processor.setFromImg(fromImg.get()); + processor.setToImg(toImg.get()); + + // set the render window + processor.setRenderWindow(args.renderWindow); + + // set the scales + processor.setBlend(blend); + + // Call the base class process member, this will call the derived templated process code + processor.process(); +} + +// the overridden render function +void +CrossFadePlugin::render(const OFX::RenderArguments &args) +{ + // instantiate the render code based on the pixel depth of the dst clip + OFX::BitDepthEnum dstBitDepth = dstClip_->getPixelDepth(); + OFX::PixelComponentEnum dstComponents = dstClip_->getPixelComponents(); + + // do the rendering + if(dstComponents == OFX::ePixelComponentRGBA) { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } + else { + switch(dstBitDepth) { +case OFX::eBitDepthUByte : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthUShort : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; + +case OFX::eBitDepthFloat : { + OFX::ImageBlender fred(*this); + setupAndProcess(fred, args); + } + break; +default : + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + } + } // switch +} + +// overridden is identity +bool +CrossFadePlugin::isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime) +{ + // get the transition value + float blend = (float)transition_->getValueAtTime(args.time); + + identityTime = args.time; + + // at the start? + if(blend <= 0.0) { + identityClip = fromClip_; + identityTime = args.time; + return true; + } + + // at the end? + if(blend >= 1.0) { + identityClip = toClip_; + identityTime = args.time; + return true; + } + + // nope, identity we isnt + return false; +} + +mDeclarePluginFactory(CrossFadeExamplePluginFactory, {}, {}); +using namespace OFX; + +void CrossFadeExamplePluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + // basic labels + desc.setLabels("Cross Fade", "Cross Fade", "Cross Fade"); + desc.setPluginGrouping("OFX Example (Support)"); + + // Say we are a transition context + desc.addSupportedContext(eContextTransition); + desc.addSupportedContext(eContextGeneral); + + // Add supported pixel depths + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + // set a few flags + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); + +} + +void CrossFadeExamplePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum /*context*/) +{ + // we are a transition, so define the sourceFrom input clip + ClipDescriptor *fromClip = desc.defineClip(kOfxImageEffectTransitionSourceFromClipName); + fromClip->addSupportedComponent(ePixelComponentRGBA); + fromClip->addSupportedComponent(ePixelComponentAlpha); + fromClip->setTemporalClipAccess(false); + fromClip->setSupportsTiles(true); + + // we are a transition, so define the sourceTo input clip + ClipDescriptor *toClip = desc.defineClip(kOfxImageEffectTransitionSourceToClipName); + toClip->addSupportedComponent(ePixelComponentRGBA); + toClip->addSupportedComponent(ePixelComponentAlpha); + toClip->setTemporalClipAccess(false); + toClip->setSupportsTiles(true); + + // create the mandated output clip + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->addSupportedComponent(ePixelComponentAlpha); + dstClip->setSupportsTiles(true); + + // Define the mandated "Transition" param, note that we don't do anything with this other than. + // describe it. It is not a true param but how the host indicates to the plug-in how far through + // the transition it is. It appears on no plug-in side UI, it is purely the hosts to manage. + DoubleParamDescriptor *param = desc.defineDoubleParam("Transition"); + (void)param; +} + +ImageEffect* CrossFadeExamplePluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum /*context*/) +{ + return new CrossFadePlugin(handle); +} + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static CrossFadeExamplePluginFactory p("net.sf.openfx.crossFade", 1, 0); + ids.push_back(&p); + } + } +} diff --git a/third_party/openfx/Support/Plugins/Transition/crossFade.dsp b/third_party/openfx/Support/Plugins/Transition/crossFade.dsp new file mode 100755 index 000000000..406c4bcef --- /dev/null +++ b/third_party/openfx/Support/Plugins/Transition/crossFade.dsp @@ -0,0 +1,107 @@ +# Microsoft Developer Studio Project File - Name="crossFade" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=crossFade - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "crossFade.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "crossFade.mak" CFG="crossFade - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "crossFade - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "crossFade - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "crossFade - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/PropTester.ofx.bundle/Contents/Win32/crossFade.ofx" + +!ELSEIF "$(CFG)" == "crossFade - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include" /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\Common Files\OFX\Plugins\CrossFade.ofx.bundle\Contents\Win32\crossFade.ofx" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "crossFade - Win32 Release" +# Name "crossFade - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\crossFade.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/third_party/openfx/Support/Plugins/Transition/crossFade.dsw b/third_party/openfx/Support/Plugins/Transition/crossFade.dsw new file mode 100755 index 000000000..5689f7aaa --- /dev/null +++ b/third_party/openfx/Support/Plugins/Transition/crossFade.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "crossFade"=.\crossFade.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ofxsupport + End Project Dependency +}}} + +############################################################################### + +Project: "ofxsupport"=..\..\Library\ofxsupport.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/third_party/openfx/Support/Plugins/Transition/crossFade.vcproj b/third_party/openfx/Support/Plugins/Transition/crossFade.vcproj new file mode 100755 index 000000000..8d94e35a6 --- /dev/null +++ b/third_party/openfx/Support/Plugins/Transition/crossFade.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/Plugins/include/README b/third_party/openfx/Support/Plugins/include/README new file mode 100644 index 000000000..d4a1355b0 --- /dev/null +++ b/third_party/openfx/Support/Plugins/include/README @@ -0,0 +1,3 @@ +This directory contains header code that is used by the OFX Support library example plugins to perform basic processing functions. + +The code in this directory is not so much a skin on the base OFX classes, but code used in implementing specific image processing algorithms. As such it does not sit in the support include lib, but in its own include directory. \ No newline at end of file diff --git a/third_party/openfx/Support/Plugins/include/ofxsImageBlender.H b/third_party/openfx/Support/Plugins/include/ofxsImageBlender.H new file mode 100644 index 000000000..c5f349bc5 --- /dev/null +++ b/third_party/openfx/Support/Plugins/include/ofxsImageBlender.H @@ -0,0 +1,95 @@ + + +#ifndef _ofxsImageBlender_h_ +#define _ofxsImageBlender_h_ + +#include "ofxsProcessing.H" + +namespace OFX { + + /** @brief Base class used to blend two images together */ + class ImageBlenderBase : public OFX::ImageProcessor { + protected : + const OFX::Image *_fromImg; // be this at 0 + const OFX::Image *_toImg; // be this at 1 + float _blend; // how much to blend + + public : + /** @brief no arg ctor */ + ImageBlenderBase(OFX::ImageEffect &instance) + : OFX::ImageProcessor(instance) + , _fromImg(0) + , _toImg(0) + , _blend(0.5f) + { + } + + /** @brief set the src image */ + void setFromImg(const OFX::Image *v) {_fromImg = v;} + void setToImg(const OFX::Image *v) {_toImg = v;} + + /** @brief set the scale */ + void setBlend(float v) {_blend = v;} + }; + + /** @brief templated class to blend between two images */ + template + class ImageBlender : public ImageBlenderBase { + public : + // ctor + ImageBlender(OFX::ImageEffect &instance) + : ImageBlenderBase(instance) + {} + + static PIX Lerp(const PIX &v1, + const PIX &v2, + float blend) + { + return PIX((v2 - v1) * blend + v1); + } + + // and do some processing + void multiThreadProcessImages(OfxRectI procWindow) + { + float blend = _blend; + float blendComp = 1.0f - blend; + + for(int y = procWindow.y1; y < procWindow.y2; y++) { + if(_effect.abort()) break; + + PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y); + + for(int x = procWindow.x1; x < procWindow.x2; x++) { + + PIX *fromPix = (PIX *) (_fromImg ? _fromImg->getPixelAddress(x, y) : 0); + PIX *toPix = (PIX *) (_toImg ? _toImg->getPixelAddress(x, y) : 0); + + if(fromPix && toPix) { + for(int c = 0; c < nComponents; c++) + dstPix[c] = Lerp(fromPix[c], toPix[c], blend); + } + else if(fromPix) { + for(int c = 0; c < nComponents; c++) + dstPix[c] = PIX(fromPix[c] * blendComp); + } + else if(toPix) { + for(int c = 0; c < nComponents; c++) + dstPix[c] = PIX(toPix[c] * blend); + } + else { + for(int c = 0; c < nComponents; c++) + dstPix[c] = PIX(0); + } + + dstPix += nComponents; + } + } + } + + }; + +}; + +#endif + + diff --git a/third_party/openfx/Support/Plugins/include/ofxsProcessing.H b/third_party/openfx/Support/Plugins/include/ofxsProcessing.H new file mode 100644 index 000000000..982475e8d --- /dev/null +++ b/third_party/openfx/Support/Plugins/include/ofxsProcessing.H @@ -0,0 +1,121 @@ + + +#ifndef _ofxsProcessing_h_ +#define _ofxsProcessing_h_ + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include + +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" + +/** @file This file contains a useful base class that can be used to process images + +The code below is not so much a skin on the base OFX classes, but code used in implementing +specific image processing algorithms. As such it does not sit in the support include lib, but in +its own include directory. +*/ + +namespace OFX { + + //////////////////////////////////////////////////////////////////////////////// + // base class to process images with + class ImageProcessor : public OFX::MultiThread::Processor { + protected : + OFX::ImageEffect &_effect; /**< @brief effect to render with */ + OFX::Image *_dstImg; /**< @brief image to process into */ + OfxRectI _renderWindow; /**< @brief render window to use */ + + public : + /** @brief ctor */ + ImageProcessor(OFX::ImageEffect &effect) + : _effect(effect) + , _dstImg(0) + { + _renderWindow.x1 = _renderWindow.y1 = _renderWindow.x2 = _renderWindow.y2 = 0; + } + + /** @brief set the destination image */ + void setDstImg(OFX::Image *v) {_dstImg = v; } + + /** @brief reset the render window */ + void setRenderWindow(OfxRectI rect) {_renderWindow = rect;} + + /** @brief overridden from OFX::MultiThread::Processor. This function is called once on each SMP thread by the base class */ + void multiThreadFunction(unsigned int threadId, unsigned int nThreads) + { + // slice the y range into the number of threads it has + unsigned int dy = _renderWindow.y2 - _renderWindow.y1; + // the following is equivalent to std::ceil(dy/(double)nThreads); + unsigned int h = (dy+nThreads-1)/nThreads; + if (h == 0) { + // there are more threads than lines to process + h = 1; + } + if (threadId * h >= dy) { + // empty render subwindow + return; + } + unsigned int y1 = _renderWindow.y1 + threadId * h; + + unsigned int step = (threadId + 1) * h; + unsigned int y2 = _renderWindow.y1 + (step < dy ? step : dy); + + OfxRectI win = _renderWindow; + win.y1 = y1; win.y2 = y2; + + // and render that thread on each + multiThreadProcessImages(win); + } + + /** @brief called before any MP is done */ + virtual void preProcess(void) {} + + /** @brief this is called by multiThreadFunction to actually process images, override in derived classes */ + virtual void multiThreadProcessImages(OfxRectI window) = 0; + + /** @brief called before any MP is done */ + virtual void postProcess(void) {} + + /** @brief called to process everything */ + virtual void process(void) + { + // If _dstImg was set, check that the _renderWindow is lying into dstBounds + if (_dstImg) { + const OfxRectI& dstBounds = _dstImg->getBounds(); + // is the renderWindow within dstBounds ? + assert(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 && + dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2); + // exit gracefully in case of error + if (!(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 && + dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2) || + (_renderWindow.x1 >= _renderWindow.x2) || + (_renderWindow.y1 >= _renderWindow.y2)) { + return; + } + } + + // call the pre MP pass + preProcess(); + + // make sure there are at least 4096 pixels per CPU and at least 1 line par CPU + unsigned int nCPUs = (std::min(_renderWindow.x2 - _renderWindow.x1, 4096) * + (_renderWindow.y2 - _renderWindow.y1)) / 4096; + // make sure the number of CPUs is valid (and use at least 1 CPU) + nCPUs = std::max(1u, std::min(nCPUs, OFX::MultiThread::getNumCPUs())); + + // call the base multi threading code, should put a pre & post thread calls in too + multiThread(nCPUs); + + // call the post MP pass + postProcess(); + } + + }; + + +}; +#endif diff --git a/third_party/openfx/Support/PropTester/CMakeLists.txt b/third_party/openfx/Support/PropTester/CMakeLists.txt new file mode 100644 index 000000000..bbe75a33c --- /dev/null +++ b/third_party/openfx/Support/PropTester/CMakeLists.txt @@ -0,0 +1,7 @@ +include(OpenFX) +file(GLOB_RECURSE PLUGIN_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") +set(TGT example-PropTester) +add_ofx_plugin(${TGT} .) +target_sources(${TGT} PUBLIC ${PLUGIN_SOURCES}) +target_link_libraries(${TGT} ${CONAN_LIBS} OfxSupport opengl::opengl) +target_include_directories(${TGT} PUBLIC ${OFX_HEADER_DIR} ${OFX_SUPPORT_HEADER_DIR}) diff --git a/third_party/openfx/Support/PropTester/Info.plist b/third_party/openfx/Support/PropTester/Info.plist new file mode 100644 index 000000000..cfbee0c70 --- /dev/null +++ b/third_party/openfx/Support/PropTester/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + crossFade.ofx + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + + diff --git a/third_party/openfx/Support/PropTester/propTester.cpp b/third_party/openfx/Support/PropTester/propTester.cpp new file mode 100644 index 000000000..5ab1dd3a1 --- /dev/null +++ b/third_party/openfx/Support/PropTester/propTester.cpp @@ -0,0 +1,579 @@ + + +#ifdef _WINDOWS +#include +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include "ofxsImageEffect.h" + +class ColourInteract : public OFX::ParamInteract +{ +protected: + enum State + { + eDefault, + ePoised, + eDragging + }; + State _state; + double _radius; + +public: + ColourInteract(OfxInteractHandle handle, OFX::ImageEffect* effect, const std::string& paramName): + OFX::ParamInteract(handle, effect), _state(eDefault), _radius(5.0) + { + _param = effect->fetchRGBParam(paramName); + } + virtual bool draw(const OFX::DrawArgs &args) + { + OfxPointI size = getInteractSize(); + glBegin (GL_POLYGON); + + glColor3f (0.0f, 0.0f, 0.0f); + glVertex2f (-0.5f, -0.5f); + + glColor3f (1.0f, 0.0f, 0.0f); + glVertex2f (-0.5f, size.y-0.5f); + + glColor3f (0.0f, 1.0f, 0.0f); + glVertex2f (size.x - 0.5f, size.y - 0.5f); + + glColor3f (0.0f, 0.0f, 1.0f); + glVertex2f (size.x - 0.5f, -0.5f); + + glEnd(); + + double r,g,b,x,y; + _param->getValueAtTime(args.time, r, g, b); + positionFromColour(r, g, b, x, y); + glColor3f(1.0f, 1.0f, 1.0f); + if(_state==ePoised) + glColor3f(0.5f, 0.5f, 0.5f); + + glBegin(GL_POLYGON); + glVertex2d(x - _radius, y - _radius); + glVertex2d(x - _radius, y + _radius); + glVertex2d(x + _radius, y + _radius); + glVertex2d(x + _radius, y - _radius); + glEnd(); + + return true; + } + bool hitTest(double posx, double posy, double time) const + { + double r,g,b,x,y; + _param->getValueAtTime(time, r, g, b); + positionFromColour(r, g, b, x, y); + if(posx > x - _radius && + posy > y - _radius && + posx < x + _radius && + posy < y + _radius) + return true; + return false; + } + void positionFromColour(double r, double g, double b, double& x, double& y) const + { + x = (b/(g+b)) * 100.0 - 0.5; + y = (r/(g+r)) * 100.0 - 0.5; + } + void colourFromPosition(double x, double y, double& r, double& g, double& b) const + { + x += 0.5; + y += 0.5; + x = x*0.01; + y = y*0.01; + r = y * ( 1.0 - x); + b = x * ( 1.0 - y); + g = (1.0 - x) * (1.0 - y); + } + virtual bool penMotion(const OFX::PenArgs &args) + { + if(_state != eDragging) + { + if(hitTest(args.penPosition.x, args.penPosition.y, args.time)) + { + _state = ePoised; + requestRedraw(); + return true; + } + } + else + { + double r,g,b; + colourFromPosition(args.penPosition.x, args.penPosition.y, r, g, b); + _param->setValueAtTime(args.time, r, g, b); + requestRedraw(); + return true; + } + _state = eDefault; + requestRedraw(); + return false; + } + virtual bool penDown(const OFX::PenArgs &args) + { + if(hitTest(args.penPosition.x, args.penPosition.y, args.time)) + { + _state = eDragging; + return true; + } + return false; + } + virtual bool penUp(const OFX::PenArgs &/*args*/) + { + _state = ePoised; + requestRedraw(); + return true; + } + virtual ~ColourInteract(){} +protected: + OFX::RGBParam* _param; +}; + +//Need an instance count as a template parameter in order to generate a different mainEntry point for each instance. +// Hopefully this will be fixed in the next iteration of the OFX standard. +template +class ColourInteractDescriptor : public OFX::DefaultParamInteractDescriptor, ColourInteract> +{ +public: + using OFX::DefaultParamInteractDescriptor,ColourInteract>::setInteractSizeAspect; + using OFX::DefaultParamInteractDescriptor,ColourInteract>::setInteractMinimumSize; + using OFX::DefaultParamInteractDescriptor,ColourInteract>::setInteractPreferredSize; + virtual void describe() + { + setInteractSizeAspect(1.0); + setInteractMinimumSize(50, 50); + setInteractPreferredSize(100, 100); + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief base class of the plugin */ +class BasePlugin : public OFX::ImageEffect { +protected : + // do not need to delete this, the ImageEffect is managing them for us + OFX::Clip *dstClip_; + +public : + /** @brief ctor */ + BasePlugin(OfxImageEffectHandle handle) + : ImageEffect(handle) + , dstClip_(0) + { + dstClip_ = fetchClip(kOfxImageEffectOutputClipName); + } + +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief generator effect version of the plugin */ +class GeneratorPlugin : public BasePlugin { +public : + /** @brief ctor */ + GeneratorPlugin(OfxImageEffectHandle handle) + : BasePlugin(handle) + {} + + /** @brief client render function, this is one of the few that must be set */ + virtual void render(const OFX::RenderArguments &args); +}; + +//////////////////////////////////////////////////////////////////////////////// +/** @brief filter version of the plugin */ +class FilterPlugin : public BasePlugin { +protected : + // do not need to delete this, the ImageEffect is managing them for us + OFX::Clip *srcClip_; + +public : + /** @brief ctor */ + FilterPlugin(OfxImageEffectHandle handle) + : BasePlugin(handle) + , srcClip_(0) + { + srcClip_ = fetchClip(kOfxImageEffectSimpleSourceClipName); + } + + /** @brief client render function, this is one of the few that must be set */ + virtual void render(const OFX::RenderArguments &args); +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief filter version of the plugin */ +class GeneralPlugin : public FilterPlugin { +protected : + // do not need to delete this, the ImageEffect is managing them for us + OFX::Clip *extraClip_; + +public : + /** @brief ctor */ + GeneralPlugin(OfxImageEffectHandle handle) + : FilterPlugin(handle) + , extraClip_(0) + { + extraClip_ = fetchClip("Extra"); + } +}; + +using namespace OFX; + +class PropTesterPluginFactory : public OFX::PluginFactoryHelper +{ +public: + PropTesterPluginFactory():OFX::PluginFactoryHelper("net.sf.openfx.propertyTester", 1, 0){} + virtual void describe(OFX::ImageEffectDescriptor &desc); + virtual void describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context); + virtual OFX::ImageEffect* createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context); +}; + +namespace OFX +{ + namespace Plugin + { + void getPluginIDs(OFX::PluginFactoryArray &ids) + { + static PropTesterPluginFactory p; + ids.push_back(&p); + } + } +} + +void PropTesterPluginFactory::describe(OFX::ImageEffectDescriptor &desc) +{ + // basic labels + desc.setLabels("Prop Tester", "Prop Tester", "Property Tester"); + desc.setPluginGrouping("OFX Example (Support)"); + + // add the supported contexts, only filter at the moment + desc.addSupportedContext(eContextGenerator); + desc.addSupportedContext(eContextFilter); + desc.addSupportedContext(eContextGeneral); + + + // add supported pixel depths + desc.addSupportedBitDepth(eBitDepthUByte); + desc.addSupportedBitDepth(eBitDepthUShort); + desc.addSupportedBitDepth(eBitDepthFloat); + + // set a few flags + desc.setSingleInstance(false); + desc.setHostFrameThreading(false); + desc.setSupportsMultiResolution(true); + desc.setSupportsTiles(true); + desc.setTemporalClipAccess(false); + desc.setRenderTwiceAlways(false); + desc.setSupportsMultipleClipPARs(false); +} + +/** @brief describe a string param with the given name and type */ +static +void describeStringParam(OFX::ImageEffectDescriptor &desc, const std::string &name, StringTypeEnum strType, PageParamDescriptor *page) +{ + StringParamDescriptor *param = desc.defineStringParam(name); + param->setDefault(name); + param->setScriptName(name); + param->setHint("A string parameter"); + param->setLabels(name, name, name); + param->setStringType(strType); + page->addChild(*param); +} + +/** @brief describe a double param */ +static +void describeDoubleParam(OFX::ImageEffectDescriptor &desc, const std::string &name, DoubleTypeEnum doubleType, + double min, double max, PageParamDescriptor *page) +{ + DoubleParamDescriptor *param = desc.defineDoubleParam(name); + param->setLabels(name, name, name); + param->setScriptName(name); + param->setHint("A double parameter"); + param->setDefault(0); + param->setRange(min, max); + param->setDisplayRange(min, max); + param->setDoubleType(doubleType); + page->addChild(*param); +} + +/** @brief describe a double param */ +static +void describe2DDoubleParam(OFX::ImageEffectDescriptor &desc, const std::string &name, DoubleTypeEnum doubleType, + double min, double max, PageParamDescriptor *page) +{ + Double2DParamDescriptor *param = desc.defineDouble2DParam(name); + param->setLabels(name, name, name); + param->setScriptName(name); + param->setHint("A 2D double parameter"); + param->setDefault(0, 0); + param->setRange(min, min, max, max); + param->setDisplayRange(min, min, max, max); + param->setDoubleType(doubleType); + page->addChild(*param); +} + +/** @brief describe a double param */ +static +void describe3DDoubleParam(OFX::ImageEffectDescriptor &desc, const std::string &name, DoubleTypeEnum doubleType, + double min, double max, PageParamDescriptor *page) +{ + Double3DParamDescriptor *param = desc.defineDouble3DParam(name); + param->setLabels(name, name, name); + param->setScriptName(name); + param->setHint("A 3D double parameter"); + param->setDefault(0, 0, 0); + param->setRange(min, min, min, max, max, max); + param->setDisplayRange(min, min, min, max, max, max); + param->setDoubleType(doubleType); + page->addChild(*param); +} + +/** @brief The describe in context function, passed a plugin descriptor and a context */ +void PropTesterPluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum context) +{ + // Source clip only in the filter context + if(context == eContextGeneral) { + // create the mandated source clip + ClipDescriptor *srcClip = desc.defineClip("Extra"); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->setTemporalClipAccess(false); + srcClip->setOptional(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + } + + // Source clip only in the filter context + if(context == eContextFilter || context == eContextGeneral) { + // create the mandated source clip + ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName); + srcClip->addSupportedComponent(ePixelComponentRGBA); + srcClip->setTemporalClipAccess(false); + //srcClip->setOptional(false); + srcClip->setSupportsTiles(true); + srcClip->setIsMask(false); + } + + // create the mandated output clip + ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName); + dstClip->addSupportedComponent(ePixelComponentRGBA); + dstClip->setTemporalClipAccess(false); + //dstClip->setOptional(false); + dstClip->setSupportsTiles(true); + dstClip->setIsMask(false); + + + // make some pages and to things in + PageParamDescriptor *page1 = desc.definePageParam("page1"); + PageParamDescriptor *page2 = desc.definePageParam("page2"); + PageParamDescriptor *page3 = desc.definePageParam("page3"); + + // make an int param + IntParamDescriptor *iParam = desc.defineIntParam("Int"); + iParam->setLabels("Int", "Int", "Int"); + iParam->setScriptName("int"); + iParam->setHint("An integer parameter"); + iParam->setDefault(0); + iParam->setRange(-100, 100); + iParam->setDisplayRange(-100, 100); + + page1->addChild(*iParam); + + // make a 2D int param + Int2DParamDescriptor *i2DParam = desc.defineInt2DParam("Int2D"); + i2DParam->setLabels("Int2D", "Int2D", "Int2D"); + i2DParam->setScriptName("int2D"); + i2DParam->setHint("A 2D integer parameter"); + i2DParam->setDefault(0, 0); + i2DParam->setRange(-100, -100, 100, 100); + i2DParam->setDisplayRange(-100, -100, 100, 100); + + page1->addChild(*i2DParam); + + // make a 3D int param + Int3DParamDescriptor *i3DParam = desc.defineInt3DParam("Int3D"); + i3DParam->setLabels("Int3D", "Int3D", "Int2D"); + i3DParam->setScriptName("int3D"); + i3DParam->setHint("A 3D integer parameter"); + i3DParam->setDefault(0, 0, 0); + i3DParam->setRange(-100, -100, -100, 100, 100, 100); + i3DParam->setDisplayRange(-100, -100, -100, 100, 100, 100); + + page1->addChild(*i3DParam); + + page1->addChild(PageParamDescriptor::gSkipColumn); + + // boolean + BooleanParamDescriptor *boolean = desc.defineBooleanParam("bool"); + boolean->setLabels("bool", "bool", "bool"); + boolean->setDefault(false); + + page1->addChild(*boolean); + + // choice + ChoiceParamDescriptor *choice = desc.defineChoiceParam("choice"); + choice->setLabels("choice", "choice", "choice"); + choice->appendOption("This", "This"); + choice->appendOption("That", "That"); + choice->appendOption("The Other", "The Other"); + choice->resetOptions(); + choice->appendOption("Tom", "Tom"); + choice->appendOption("Dick", "Dick"); + choice->appendOption("Harry", "Harry"); + choice->setDefault(0); + + page1->addChild(*choice); + + page1->addChild(PageParamDescriptor::gSkipColumn); + + // push button + PushButtonParamDescriptor *push = desc.definePushButtonParam("push"); + push->setLabels("push me", "push me", "push me Big Nose"); + page1->addChild(*push); + + // make a custom param + CustomParamDescriptor *custom = desc.defineCustomParam("custom"); + custom->setLabels("custom", "custom", "custom"); + custom->setDefault("wibble"); + + // rgba colours + RGBAParamDescriptor *rgba = desc.defineRGBAParam("rgba"); + rgba->setLabels("rgba", "rgba", "rgba"); + rgba->setDefault(0, 0, 0, 1); + + page1->addChild(*rgba); + + RGBParamDescriptor *rgba2 = desc.defineRGBParam("rgbaCustom"); + rgba2->setLabels("RGB Custom", "RGB Custom", "RGB Custom"); + rgba2->setDefault(0, 1, 1); + rgba2->setInteractDescriptor(new ColourInteractDescriptor<0>); + page1->addChild(*rgba2); + + RGBParamDescriptor *rgba3 = desc.defineRGBParam("rgbaCustom2"); + rgba3->setLabels("RGB Custom 2", "RGB Custom 2", "RGB Custom 2"); + rgba3->setDefault(1, 0, 1); + rgba3->setInteractDescriptor(new ColourInteractDescriptor<1>); + page1->addChild(*rgba3); + + page1->addChild(PageParamDescriptor::gSkipRow); + + // rgb colour + RGBParamDescriptor *rgb = desc.defineRGBParam("rgb"); + rgb->setLabels("rgb", "rgb", "rgb"); + rgb->setDefault(0, 0, 0); + page1->addChild(*rgb); + + // make a 1D double parameter of each type + describeDoubleParam(desc, "double", eDoubleTypePlain, -100, 100, page2); + describeDoubleParam(desc, "angle", eDoubleTypeAngle, -100, 100, page2); + describeDoubleParam(desc, "scale", eDoubleTypeScale, -1, 1, page2); + describeDoubleParam(desc, "time", eDoubleTypeTime, -100, 100, page2); + describeDoubleParam(desc, "absoluteTime", eDoubleTypeAbsoluteTime, 0, 1000, page2); + describeDoubleParam(desc, "X_Value", eDoubleTypeX, -1, 1, page2); + describeDoubleParam(desc, "Y_Value", eDoubleTypeY, -1, 1, page2); + describeDoubleParam(desc, "X_Position", eDoubleTypeXAbsolute, -1, 1, page2); + describeDoubleParam(desc, "Y_Position", eDoubleTypeYAbsolute, -1, 1, page2); + + page2->addChild(PageParamDescriptor::gSkipColumn); + + // make a 2D double parameter of each type + describe2DDoubleParam(desc, "double2D", eDoubleTypePlain, -100, 100, page2); + describe2DDoubleParam(desc, "angle2D", eDoubleTypeAngle, -100, 100, page2); + describe2DDoubleParam(desc, "scale2D", eDoubleTypeScale, -1, 1, page2); + describe2DDoubleParam(desc, "XY_Value", eDoubleTypeXY, -1, 1, page2); + describe2DDoubleParam(desc, "XY_Position", eDoubleTypeXYAbsolute, -1, 1, page2); + + page2->addChild(PageParamDescriptor::gSkipColumn); + + // make a 3D double parameter of each type + describe3DDoubleParam(desc, "double3D", eDoubleTypePlain, -100, 100, page2); + describe3DDoubleParam(desc, "angle3D", eDoubleTypeAngle, -100, 100, page2); + describe3DDoubleParam(desc, "scale3D", eDoubleTypeScale, -1, 1, page2); + + // make a string param param of each type + describeStringParam(desc, "singleLine", eStringTypeSingleLine, page3); + describeStringParam(desc, "multiLine", eStringTypeMultiLine, page3); + describeStringParam(desc, "filePath", eStringTypeFilePath, page3); + describeStringParam(desc, "dirPath", eStringTypeDirectoryPath, page3); + describeStringParam(desc, "label", eStringTypeLabel, page3); + +} + +/** @brief The create instance function, the plugin must return an object derived from the \ref OFX::ImageEffect class */ +ImageEffect* PropTesterPluginFactory::createInstance(OfxImageEffectHandle handle, ContextEnum context) +{ + if(context == eContextFilter) + return new FilterPlugin(handle); + else if(context == eContextGenerator) + return new GeneratorPlugin(handle); + else if(context == eContextGeneral) + return new GeneralPlugin(handle); + + + // HACK!!! Throw something here! + return NULL; // to shut the warning up +} + + + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the generator */ +void +GeneratorPlugin::render(const OFX::RenderArguments &args) +{ + OFX::Image *dst = 0; + + try { + // get a dst image + dst = dstClip_->fetchImage(args.time); + + // push some pixels + // blah; + // blah; + // blah; + } + + catch(...) { + delete dst; + throw; + } + + // delete them + delete dst; +} + +//////////////////////////////////////////////////////////////////////////////// +/** @brief render for the filter */ +void +FilterPlugin::render(const OFX::RenderArguments &args) +{ + OFX::Image *src = 0, *dst = 0; + + try { + // get a src image + src = srcClip_->fetchImage(args.time); + + // get a dst image + dst = dstClip_->fetchImage(args.time); + + // push some pixels + // blah; + // blah; + // blah; + } + + catch(...) { + delete src; + delete dst; + throw; + } + + // delete them + delete src; + delete dst; +} diff --git a/third_party/openfx/Support/PropTester/propTester.dsp b/third_party/openfx/Support/PropTester/propTester.dsp new file mode 100755 index 000000000..d314ab6c2 --- /dev/null +++ b/third_party/openfx/Support/PropTester/propTester.dsp @@ -0,0 +1,107 @@ +# Microsoft Developer Studio Project File - Name="propTester" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=propTester - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "propTester.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "propTester.mak" CFG="propTester - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "propTester - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "propTester - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "propTester - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/PropTester.bundle.ofx/Contents/Win32/propTester.ofx" + +!ELSEIF "$(CFG)" == "propTester - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /GB /Zp8 /MDd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PROPTESTER_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\Common Files\OFX\Plugins\PropTester.bundle.ofx\Contents\Win32\propTester.ofx" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "propTester - Win32 Release" +# Name "propTester - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\propTester.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/third_party/openfx/Support/PropTester/propTester.dsw b/third_party/openfx/Support/PropTester/propTester.dsw new file mode 100755 index 000000000..0b3e872e5 --- /dev/null +++ b/third_party/openfx/Support/PropTester/propTester.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ofxsupport"=..\Library\ofxsupport.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "propTester"=.\propTester.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ofxsupport + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/third_party/openfx/Support/PropTester/propTester.vcproj b/third_party/openfx/Support/PropTester/propTester.vcproj new file mode 100755 index 000000000..d753e68a2 --- /dev/null +++ b/third_party/openfx/Support/PropTester/propTester.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/openfx/Support/README b/third_party/openfx/Support/README new file mode 100644 index 000000000..31c8a766b --- /dev/null +++ b/third_party/openfx/Support/README @@ -0,0 +1,73 @@ +OFX Support Library + + This directory tree contains the source to a C++ library that skins the OFX + C plugin API with a set of classes. It is meant to act as a guide to people implementing + plugins and hosts using the API and reveal the logical structure of the OFX API. + + +******************************************************************************** +Copyright and License + + The library is copyright OpenFX and contributors to the OpenFX project, and was + written by Bruno Nicoletti (bruno@thefoundry.co.uk). + + It was originally released under the GNU Lesser General Public License. + + It has subsequently been released under a 'BSD-3-Clause' license. See the + file 'LICENSE' for details. + +******************************************************************************** +Structure + - include - contains the headers for any client code. + - Library - contains the code that implements the support library. + - PropTester - contains code for a plugin that performs extensive property testing. + - Plugins - contains a set of example plugins using the support library. + +******************************************************************************** +Building + Plug-ins and library have OSX makefiles and windows MSDEV project files. They build and link and load happily on compliant hosts. + +******************************************************************************** +Problems And Debugging + + - unsupported properties on a host. If a hosts returns kOfxStatErrUnsupported when the plugin sets a property that is not absolutely essential (eg the hint property on a parameter), an exception is thrown at line 39 of Library/ofxsProperty.cpp. This in turn will cause the plug-in to return kOfxStatFailed. Comment out this line out if you encounter failure on a host and it may run. + + - if compiled in debug, the plugin writes a log file out, call "ofxTestLog.txt" in the current directory. This log will contain a variety of error messages. The most important of which concern property validation. The file Library/ofxsPropertyValidation.cpp contains code to validate each possible type of property handle used by OFX, making sure the host has the correct properties on each. If it finds a property not to exist, or to have the wrong default, it will print messages to the log file. + +******************************************************************************** +Release Notes + + +31-1-2005 + All accessor functions have had 'get' prepended to their name. + Added integrate and differentiate functions to 2D and 3D double parameters. + The generic memory allocator takes an option ImageEffect pointer, not a void * handle. + Refactored plugins to use new member names. + Added a root makefile to the plugins directory. + Added a 'clean' target to the plugin makefiles. + +13-01-2005 Version 0.2 + + Skinned everything except message suite and parameter interacts custom GUIS, + Skinned overlays, + Build enviromnments for OSX and MSDEV, + Example plug-ins written for each context, + Doxygen documentation (especially proud of my 15 line plugin writing guide), + Still to be done, + decent set of exceptions and exception specifiers on each function, + skin the parameter custom interact, + parameter integration and differentiation functions needed on 2D and 3D doubles and the colour classses, + parameters should return their values in a struct, as well as by a reference arg (some do already), + write examples showing custom param and param animation, + write an example showing use of external resource files, + more testing. + +15-12-2004 Version 0.1 + + Implemented most of the basic classes, need to do more work on clip instances and image effect instances. + Library builds fine on OSX 10.3, not fully tested yet. + No where near finsihed yet, + Need to finish off the actions. + Need to do a cleaner set of exception classes. + Need to test somewhat more (hey they do compile though!). + Need to build on more machines too (OSX 10.3 fine) and come up with make files for the appropriates diff --git a/third_party/openfx/Support/Support.xcodeproj/project.pbxproj b/third_party/openfx/Support/Support.xcodeproj/project.pbxproj new file mode 100644 index 000000000..2b9b6b9bb --- /dev/null +++ b/third_party/openfx/Support/Support.xcodeproj/project.pbxproj @@ -0,0 +1,1691 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXAggregateTarget section */ + 1E551F461799509100A4135C /* all */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 1E551F471799509100A4135C /* Build configuration list for PBXAggregateTarget "all" */; + buildPhases = ( + ); + dependencies = ( + 1E3E3D27179960AC005F2132 /* PBXTargetDependency */, + 1E3E3D29179960AC005F2132 /* PBXTargetDependency */, + 1E3E3D2B179960AC005F2132 /* PBXTargetDependency */, + 1E3E3D2D179960AC005F2132 /* PBXTargetDependency */, + 1E3E3D2F179960AC005F2132 /* PBXTargetDependency */, + 1E3E3D52179961ED005F2132 /* PBXTargetDependency */, + 1E3E3D6817996270005F2132 /* PBXTargetDependency */, + 1E3E3D8217996301005F2132 /* PBXTargetDependency */, + 1E3E3D98179963C5005F2132 /* PBXTargetDependency */, + 1E3E3DAC17996479005F2132 /* PBXTargetDependency */, + ); + name = all; + productName = all; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 1E08327B19A1E2C100A819A5 /* pluginLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E08327919A1E2C100A819A5 /* pluginLoader.cpp */; }; + 1E3E3CB317995CC9005F2132 /* basic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB217995CC9005F2132 /* basic.cpp */; }; + 1E3E3CBE17995D5C005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3CBF17995D5C005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3CC017995D5C005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3CC117995D5C005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3CC217995D5C005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3CC317995D5C005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3CC417995D5C005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3CC517995D5C005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3CC617995D8C005F2132 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E551F5A179950EC00A4135C /* OpenGL.framework */; }; + 1E3E3CCA17995DBB005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3CCB17995DBB005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3CCC17995DBB005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3CCD17995DBB005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3CCE17995DBB005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3CCF17995DBB005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3CD017995DBB005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3CD117995DBB005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3CDB17995DF6005F2132 /* field.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CDA17995DF6005F2132 /* field.cpp */; }; + 1E3E3CDE17995E76005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3CDF17995E76005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3CE017995E76005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3CE117995E76005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3CE217995E76005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3CE317995E76005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3CE417995E76005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3CE517995E76005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3CF117995F2C005F2132 /* noise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CEE17995F2C005F2132 /* noise.cpp */; }; + 1E3E3CF217995F2C005F2132 /* randomGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CEF17995F2C005F2132 /* randomGenerator.cpp */; }; + 1E3E3CF517995F57005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3CF617995F57005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3CF717995F57005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3CF817995F57005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3CF917995F57005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3CFA17995F57005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3CFB17995F57005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3CFC17995F57005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3D0717995F83005F2132 /* invert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D0617995F83005F2132 /* invert.cpp */; }; + 1E3E3D0A17995FB3005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3D0B17995FB3005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3D0C17995FB3005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3D0D17995FB3005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3D0E17995FB3005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3D0F17995FB3005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3D1017995FB3005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3D1117995FB3005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3D2217996042005F2132 /* multibundle1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D1A17996029005F2132 /* multibundle1.cpp */; }; + 1E3E3D2317996042005F2132 /* multibundle2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D1C1799602A005F2132 /* multibundle2.cpp */; }; + 1E3E3D2417996042005F2132 /* PluginRegistration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D1E1799602A005F2132 /* PluginRegistration.cpp */; }; + 1E3E3D251799609D005F2132 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E551F5A179950EC00A4135C /* OpenGL.framework */; }; + 1E3E3D3B179961B4005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3D3C179961B4005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3D3D179961B4005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3D3E179961B4005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3D3F179961B4005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3D40179961B4005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3D41179961B4005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3D42179961B4005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3D50179961E2005F2132 /* retimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D4E179961D6005F2132 /* retimer.cpp */; }; + 1E3E3D5517996232005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3D5617996232005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3D5717996232005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3D5817996232005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3D5917996232005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3D5A17996232005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3D5B17996232005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3D5C17996232005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3D6617996262005F2132 /* Tester.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D6517996262005F2132 /* Tester.cpp */; }; + 1E3E3D691799629F005F2132 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E551F5A179950EC00A4135C /* OpenGL.framework */; }; + 1E3E3D6C179962A4005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3D6D179962A4005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3D6E179962A4005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3D6F179962A4005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3D70179962A4005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3D71179962A4005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3D72179962A4005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3D73179962A4005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3D80179962DE005F2132 /* crossFade.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D7F179962DE005F2132 /* crossFade.cpp */; }; + 1E3E3D8517996363005F2132 /* ofxsCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */; }; + 1E3E3D8617996363005F2132 /* ofxsImageEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */; }; + 1E3E3D8717996363005F2132 /* ofxsInteract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */; }; + 1E3E3D8817996363005F2132 /* ofxsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */; }; + 1E3E3D8917996363005F2132 /* ofxsMultiThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */; }; + 1E3E3D8A17996363005F2132 /* ofxsParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */; }; + 1E3E3D8B17996363005F2132 /* ofxsProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */; }; + 1E3E3D8C17996363005F2132 /* ofxsPropertyValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */; }; + 1E3E3D96179963B4005F2132 /* propTester.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1E3E3D95179963B4005F2132 /* propTester.cpp */; }; + 1E3E3D99179963E0005F2132 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E551F5A179950EC00A4135C /* OpenGL.framework */; }; + 1E3E3DAA1799646E005F2132 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E3E3DA91799646E005F2132 /* CoreFoundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1E3E3D26179960AC005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3CA317995BEE005F2132; + remoteInfo = basic.ofx; + }; + 1E3E3D28179960AC005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3CC717995DBB005F2132; + remoteInfo = field.ofx; + }; + 1E3E3D2A179960AC005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3CDC17995E76005F2132; + remoteInfo = noise.ofx; + }; + 1E3E3D2C179960AC005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3CF317995F57005F2132; + remoteInfo = invert.ofx; + }; + 1E3E3D2E179960AC005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3D0817995FB3005F2132; + remoteInfo = multibundle.ofx; + }; + 1E3E3D51179961ED005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3D39179961B4005F2132; + remoteInfo = retimer.ofx; + }; + 1E3E3D6717996270005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3D5317996232005F2132; + remoteInfo = tester.ofx; + }; + 1E3E3D8117996301005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3D6A179962A4005F2132; + remoteInfo = transition.ofx; + }; + 1E3E3D97179963C5005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3D8317996363005F2132; + remoteInfo = PropTester.ofx; + }; + 1E3E3DAB17996479005F2132 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1E551EB917994D4000A4135C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1E3E3D9D1799644B005F2132; + remoteInfo = pluginLoader; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 1E3E3D9C1799644B005F2132 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1E009D5C17F44C72003071CC /* ofxsImageBlender.H */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ofxsImageBlender.H; sourceTree = ""; }; + 1E009D5D17F44C72003071CC /* ofxsProcessing.H */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ofxsProcessing.H; sourceTree = ""; }; + 1E009D5E17F44D5C003071CC /* ofxsHWNDInteract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxsHWNDInteract.h; sourceTree = ""; }; + 1E009D5F17F44D70003071CC /* ofxCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxCore.h; path = ../../include/ofxCore.h; sourceTree = ""; }; + 1E009D6017F44D70003071CC /* ofxImageEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxImageEffect.h; path = ../../include/ofxImageEffect.h; sourceTree = ""; }; + 1E009D6117F44D70003071CC /* ofxInteract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxInteract.h; path = ../../include/ofxInteract.h; sourceTree = ""; }; + 1E009D6217F44D70003071CC /* ofxKeySyms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxKeySyms.h; path = ../../include/ofxKeySyms.h; sourceTree = ""; }; + 1E009D6317F44D70003071CC /* ofxMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxMemory.h; path = ../../include/ofxMemory.h; sourceTree = ""; }; + 1E009D6417F44D70003071CC /* ofxMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxMessage.h; path = ../../include/ofxMessage.h; sourceTree = ""; }; + 1E009D6517F44D70003071CC /* ofxMultiThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxMultiThread.h; path = ../../include/ofxMultiThread.h; sourceTree = ""; }; + 1E009D6617F44D70003071CC /* ofxOpenGLRender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxOpenGLRender.h; path = ../../include/ofxOpenGLRender.h; sourceTree = ""; }; + 1E009D6717F44D70003071CC /* ofxParam.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxParam.h; path = ../../include/ofxParam.h; sourceTree = ""; }; + 1E009D6817F44D70003071CC /* ofxParametricParam.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxParametricParam.h; path = ../../include/ofxParametricParam.h; sourceTree = ""; }; + 1E009D6917F44D70003071CC /* ofxPixels.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxPixels.h; path = ../../include/ofxPixels.h; sourceTree = ""; }; + 1E009D6A17F44D70003071CC /* ofxProgress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxProgress.h; path = ../../include/ofxProgress.h; sourceTree = ""; }; + 1E009D6B17F44D70003071CC /* ofxProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxProperty.h; path = ../../include/ofxProperty.h; sourceTree = ""; }; + 1E009D6C17F44D70003071CC /* ofxTimeLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxTimeLine.h; path = ../../include/ofxTimeLine.h; sourceTree = ""; }; + 1E08326B19A1E1B900A819A5 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + 1E08326C19A1E1B900A819A5 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + 1E08326D19A1E1B900A819A5 /* support.doxy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = support.doxy; sourceTree = ""; }; + 1E08326E19A1E1B900A819A5 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; + 1E08326F19A1E23C00A819A5 /* linuxSymbols */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = linuxSymbols; path = include/linuxSymbols; sourceTree = ""; }; + 1E08327019A1E23C00A819A5 /* osxDeploy.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = osxDeploy.sh; path = include/osxDeploy.sh; sourceTree = ""; }; + 1E08327119A1E23C00A819A5 /* osxSymbols */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = osxSymbols; path = include/osxSymbols; sourceTree = ""; }; + 1E08327219A1E23C00A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08327319A1E23C00A819A5 /* ofxSupport.dsp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ofxSupport.dsp; path = Library/ofxSupport.dsp; sourceTree = ""; }; + 1E08327419A1E23C00A819A5 /* ofxsupport.dsw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ofxsupport.dsw; path = Library/ofxsupport.dsw; sourceTree = ""; }; + 1E08327519A1E23C00A819A5 /* ofxsupport.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = ofxsupport.vcproj; path = Library/ofxsupport.vcproj; sourceTree = ""; }; + 1E08327619A1E25600A819A5 /* ofxsHWNDInteract.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsHWNDInteract.cpp; sourceTree = ""; }; + 1E08327819A1E2C100A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08327919A1E2C100A819A5 /* pluginLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pluginLoader.cpp; sourceTree = ""; }; + 1E08327D19A1E30D00A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E08327E19A1E30D00A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08327F19A1E30D00A819A5 /* propTester.dsp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = propTester.dsp; sourceTree = ""; }; + 1E08328019A1E30D00A819A5 /* propTester.dsw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = propTester.dsw; sourceTree = ""; }; + 1E08328119A1E30D00A819A5 /* propTester.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = propTester.vcproj; sourceTree = ""; }; + 1E08328219A1E32500A819A5 /* ExamplePlugs.sln */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ExamplePlugs.sln; sourceTree = ""; }; + 1E08328419A1E34E00A819A5 /* basic.dsp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = basic.dsp; sourceTree = ""; }; + 1E08328519A1E34E00A819A5 /* basic.dsw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = basic.dsw; sourceTree = ""; }; + 1E08328619A1E34E00A819A5 /* basic.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = basic.vcproj; sourceTree = ""; }; + 1E08328719A1E34E00A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E08328819A1E34E00A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08328919A1E36800A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08328A19A1E36800A819A5 /* Makefile.master */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Makefile.master; sourceTree = ""; }; + 1E08328C19A1E39600A819A5 /* field.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = field.vcproj; sourceTree = ""; }; + 1E08328D19A1E39600A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E08328E19A1E39600A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08329019A1E3C300A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E08329119A1E3C300A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08329219A1E3C300A819A5 /* noise.dsp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = noise.dsp; sourceTree = ""; }; + 1E08329319A1E3C400A819A5 /* noise.dsw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = noise.dsw; sourceTree = ""; }; + 1E08329419A1E3C400A819A5 /* noise.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = noise.vcproj; sourceTree = ""; }; + 1E08329919A1E43500A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E08329A19A1E43500A819A5 /* invert.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = invert.vcproj; sourceTree = ""; }; + 1E08329B19A1E43500A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08329C19A1E46C00A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E08329D19A1E46C00A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E08329E19A1E46C00A819A5 /* multibundle.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = multibundle.vcproj; sourceTree = ""; }; + 1E08329F19A1E48500A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E0832A019A1E48500A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E0832A119A1E48500A819A5 /* Tester.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Tester.vcproj; sourceTree = ""; }; + 1E0832A219A1E4A600A819A5 /* crossFade.dsp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = crossFade.dsp; sourceTree = ""; }; + 1E0832A319A1E4A600A819A5 /* crossFade.dsw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = crossFade.dsw; sourceTree = ""; }; + 1E0832A419A1E4A600A819A5 /* crossFade.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = crossFade.vcproj; sourceTree = ""; }; + 1E0832A519A1E4A600A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E0832A619A1E4A600A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 1E0832A819A1E4D900A819A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Retimer/Info.plist; sourceTree = ""; }; + 1E0832A919A1E4D900A819A5 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = Retimer/Makefile; sourceTree = ""; }; + 1E0832AA19A1E4D900A819A5 /* retimer.dsp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = retimer.dsp; path = Retimer/retimer.dsp; sourceTree = ""; }; + 1E0832AB19A1E4D900A819A5 /* retimer.dsw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = retimer.dsw; path = Retimer/retimer.dsw; sourceTree = ""; }; + 1E0832AC19A1E4D900A819A5 /* retimer.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = retimer.vcproj; path = Retimer/retimer.vcproj; sourceTree = ""; }; + 1E0832AE19A1E50100A819A5 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + 1E378A86194DCF4200800F5F /* ofxReadWrite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxReadWrite.h; sourceTree = ""; }; + 1E3E3CA417995BEE005F2132 /* basic.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = basic.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3CB217995CC9005F2132 /* basic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = basic.cpp; sourceTree = ""; }; + 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsCore.cpp; sourceTree = ""; }; + 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsImageEffect.cpp; sourceTree = ""; }; + 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsInteract.cpp; sourceTree = ""; }; + 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsLog.cpp; sourceTree = ""; }; + 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsMultiThread.cpp; sourceTree = ""; }; + 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsParams.cpp; sourceTree = ""; }; + 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsProperty.cpp; sourceTree = ""; }; + 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxsPropertyValidation.cpp; sourceTree = ""; }; + 1E3E3CBD17995D5C005F2132 /* ofxsSupportPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxsSupportPrivate.h; sourceTree = ""; }; + 1E3E3CD817995DBB005F2132 /* field.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = field.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3CDA17995DF6005F2132 /* field.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = field.cpp; sourceTree = ""; }; + 1E3E3CEC17995E76005F2132 /* noise.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = noise.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3CEE17995F2C005F2132 /* noise.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = noise.cpp; sourceTree = ""; }; + 1E3E3CEF17995F2C005F2132 /* randomGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randomGenerator.cpp; sourceTree = ""; }; + 1E3E3CF017995F2C005F2132 /* randomGenerator.H */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = randomGenerator.H; sourceTree = ""; }; + 1E3E3D0417995F57005F2132 /* invert.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = invert.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3D0617995F83005F2132 /* invert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = invert.cpp; sourceTree = ""; }; + 1E3E3D1817995FB3005F2132 /* multibundle.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = multibundle.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3D1A17996029005F2132 /* multibundle1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = multibundle1.cpp; sourceTree = ""; }; + 1E3E3D1B17996029005F2132 /* multibundle1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = multibundle1.h; sourceTree = ""; }; + 1E3E3D1C1799602A005F2132 /* multibundle2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = multibundle2.cpp; sourceTree = ""; }; + 1E3E3D1D1799602A005F2132 /* multibundle2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = multibundle2.h; sourceTree = ""; }; + 1E3E3D1E1799602A005F2132 /* PluginRegistration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginRegistration.cpp; sourceTree = ""; }; + 1E3E3D3117996112005F2132 /* ofxsCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsCore.h; sourceTree = ""; }; + 1E3E3D3217996112005F2132 /* ofxsImageEffect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsImageEffect.h; sourceTree = ""; }; + 1E3E3D3317996112005F2132 /* ofxsInteract.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsInteract.h; sourceTree = ""; }; + 1E3E3D3417996112005F2132 /* ofxsLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsLog.h; sourceTree = ""; }; + 1E3E3D3517996112005F2132 /* ofxsMemory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsMemory.h; sourceTree = ""; }; + 1E3E3D3617996112005F2132 /* ofxsMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsMessage.h; sourceTree = ""; }; + 1E3E3D3717996112005F2132 /* ofxsMultiThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsMultiThread.h; sourceTree = ""; }; + 1E3E3D3817996112005F2132 /* ofxsParam.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxsParam.h; sourceTree = ""; }; + 1E3E3D4C179961B4005F2132 /* retimer.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = retimer.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3D4E179961D6005F2132 /* retimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = retimer.cpp; path = Retimer/retimer.cpp; sourceTree = ""; }; + 1E3E3D6317996232005F2132 /* tester.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = tester.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3D6517996262005F2132 /* Tester.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Tester.cpp; sourceTree = ""; }; + 1E3E3D7B179962A4005F2132 /* transition.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = transition.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3D7F179962DE005F2132 /* crossFade.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crossFade.cpp; sourceTree = ""; }; + 1E3E3D9317996363005F2132 /* PropTester.ofx.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PropTester.ofx.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3D95179963B4005F2132 /* propTester.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = propTester.cpp; sourceTree = ""; }; + 1E3E3D9E1799644B005F2132 /* pluginLoader */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pluginLoader; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3E3DA91799646E005F2132 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; }; + 1E551F5A179950EC00A4135C /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 1E985639194F2BC300D20D5D /* ofxNatron.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxNatron.h; path = ../../include/ofxNatron.h; sourceTree = ""; }; + 1E9FC1CE180BF74400EFE0F9 /* camera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = camera.h; sourceTree = ""; }; + 1E9FC1CF180BF74400EFE0F9 /* fnPublicOfxExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fnPublicOfxExtensions.h; sourceTree = ""; }; + 1EA6849218C51E42006EE43D /* fnOfxExtensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fnOfxExtensions.h; sourceTree = ""; }; + 1ECA10E818C7492E00D6E38C /* ofxDialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofxDialog.h; path = ../../include/ofxDialog.h; sourceTree = ""; }; + 1ECA10E918C7492E00D6E38C /* ofxSonyVegas.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofxSonyVegas.h; path = ../../include/ofxSonyVegas.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1E3E3CA117995BEE005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3CC617995D8C005F2132 /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CD217995DBB005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CE717995E76005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CFF17995F57005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D1317995FB3005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D251799609D005F2132 /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D46179961B4005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D5E17996232005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D691799629F005F2132 /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D75179962A4005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D8E17996363005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D99179963E0005F2132 /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D9B1799644B005F2132 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3DAA1799646E005F2132 /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1E08326A19A1E19F00A819A5 /* Other */ = { + isa = PBXGroup; + children = ( + 1E08326F19A1E23C00A819A5 /* linuxSymbols */, + 1E08327019A1E23C00A819A5 /* osxDeploy.sh */, + 1E08327119A1E23C00A819A5 /* osxSymbols */, + 1E08327319A1E23C00A819A5 /* ofxSupport.dsp */, + 1E08327419A1E23C00A819A5 /* ofxsupport.dsw */, + 1E08327519A1E23C00A819A5 /* ofxsupport.vcproj */, + 1E08326B19A1E1B900A819A5 /* LICENSE */, + 1E08326C19A1E1B900A819A5 /* README */, + 1E08326D19A1E1B900A819A5 /* support.doxy */, + 1E08326E19A1E1B900A819A5 /* TODO */, + ); + name = Other; + sourceTree = ""; + }; + 1E08327719A1E26300A819A5 /* OSXStaticLoader */ = { + isa = PBXGroup; + children = ( + 1E08327819A1E2C100A819A5 /* Makefile */, + 1E08327919A1E2C100A819A5 /* pluginLoader.cpp */, + ); + path = OSXStaticLoader; + sourceTree = ""; + }; + 1E08327C19A1E2DC00A819A5 /* PropTester */ = { + isa = PBXGroup; + children = ( + 1E3E3D95179963B4005F2132 /* propTester.cpp */, + 1E08327D19A1E30D00A819A5 /* Info.plist */, + 1E08327E19A1E30D00A819A5 /* Makefile */, + 1E08327F19A1E30D00A819A5 /* propTester.dsp */, + 1E08328019A1E30D00A819A5 /* propTester.dsw */, + 1E08328119A1E30D00A819A5 /* propTester.vcproj */, + ); + path = PropTester; + sourceTree = ""; + }; + 1E08328319A1E33700A819A5 /* Basic */ = { + isa = PBXGroup; + children = ( + 1E3E3CB217995CC9005F2132 /* basic.cpp */, + 1E08328419A1E34E00A819A5 /* basic.dsp */, + 1E08328519A1E34E00A819A5 /* basic.dsw */, + 1E08328619A1E34E00A819A5 /* basic.vcproj */, + 1E08328719A1E34E00A819A5 /* Info.plist */, + 1E08328819A1E34E00A819A5 /* Makefile */, + ); + path = Basic; + sourceTree = ""; + }; + 1E08328B19A1E37B00A819A5 /* Field */ = { + isa = PBXGroup; + children = ( + 1E3E3CDA17995DF6005F2132 /* field.cpp */, + 1E08328C19A1E39600A819A5 /* field.vcproj */, + 1E08328D19A1E39600A819A5 /* Info.plist */, + 1E08328E19A1E39600A819A5 /* Makefile */, + ); + path = Field; + sourceTree = ""; + }; + 1E08328F19A1E3A200A819A5 /* Generator */ = { + isa = PBXGroup; + children = ( + 1E3E3CEE17995F2C005F2132 /* noise.cpp */, + 1E3E3CEF17995F2C005F2132 /* randomGenerator.cpp */, + 1E3E3CF017995F2C005F2132 /* randomGenerator.H */, + 1E08329019A1E3C300A819A5 /* Info.plist */, + 1E08329119A1E3C300A819A5 /* Makefile */, + 1E08329219A1E3C300A819A5 /* noise.dsp */, + 1E08329319A1E3C400A819A5 /* noise.dsw */, + 1E08329419A1E3C400A819A5 /* noise.vcproj */, + ); + path = Generator; + sourceTree = ""; + }; + 1E08329519A1E3E400A819A5 /* Invert */ = { + isa = PBXGroup; + children = ( + 1E3E3D0617995F83005F2132 /* invert.cpp */, + 1E08329919A1E43500A819A5 /* Info.plist */, + 1E08329A19A1E43500A819A5 /* invert.vcproj */, + 1E08329B19A1E43500A819A5 /* Makefile */, + ); + path = Invert; + sourceTree = ""; + }; + 1E08329619A1E3EA00A819A5 /* MultiBundle */ = { + isa = PBXGroup; + children = ( + 1E3E3D1A17996029005F2132 /* multibundle1.cpp */, + 1E3E3D1B17996029005F2132 /* multibundle1.h */, + 1E3E3D1C1799602A005F2132 /* multibundle2.cpp */, + 1E3E3D1D1799602A005F2132 /* multibundle2.h */, + 1E3E3D1E1799602A005F2132 /* PluginRegistration.cpp */, + 1E08329C19A1E46C00A819A5 /* Info.plist */, + 1E08329D19A1E46C00A819A5 /* Makefile */, + 1E08329E19A1E46C00A819A5 /* multibundle.vcproj */, + ); + path = MultiBundle; + sourceTree = ""; + }; + 1E08329719A1E3F700A819A5 /* Tester */ = { + isa = PBXGroup; + children = ( + 1E3E3D6517996262005F2132 /* Tester.cpp */, + 1E08329F19A1E48500A819A5 /* Info.plist */, + 1E0832A019A1E48500A819A5 /* Makefile */, + 1E0832A119A1E48500A819A5 /* Tester.vcproj */, + ); + path = Tester; + sourceTree = ""; + }; + 1E08329819A1E3FF00A819A5 /* Transition */ = { + isa = PBXGroup; + children = ( + 1E3E3D7F179962DE005F2132 /* crossFade.cpp */, + 1E0832A219A1E4A600A819A5 /* crossFade.dsp */, + 1E0832A319A1E4A600A819A5 /* crossFade.dsw */, + 1E0832A419A1E4A600A819A5 /* crossFade.vcproj */, + 1E0832A519A1E4A600A819A5 /* Info.plist */, + 1E0832A619A1E4A600A819A5 /* Makefile */, + ); + path = Transition; + sourceTree = ""; + }; + 1E0832A719A1E4B200A819A5 /* Retimer */ = { + isa = PBXGroup; + children = ( + 1E0832A819A1E4D900A819A5 /* Info.plist */, + 1E0832A919A1E4D900A819A5 /* Makefile */, + 1E0832AA19A1E4D900A819A5 /* retimer.dsp */, + 1E0832AB19A1E4D900A819A5 /* retimer.dsw */, + 1E0832AC19A1E4D900A819A5 /* retimer.vcproj */, + 1E3E3D4E179961D6005F2132 /* retimer.cpp */, + ); + name = Retimer; + sourceTree = ""; + }; + 1E0832AD19A1E4E700A819A5 /* Plugins */ = { + isa = PBXGroup; + children = ( + 1E009D5C17F44C72003071CC /* ofxsImageBlender.H */, + 1E009D5D17F44C72003071CC /* ofxsProcessing.H */, + 1E0832AE19A1E50100A819A5 /* README */, + ); + name = Plugins; + path = ../Plugins/include; + sourceTree = ""; + }; + 1E0832AF19A1E51900A819A5 /* Support */ = { + isa = PBXGroup; + children = ( + 1E3E3D3117996112005F2132 /* ofxsCore.h */, + 1E009D5E17F44D5C003071CC /* ofxsHWNDInteract.h */, + 1E3E3D3217996112005F2132 /* ofxsImageEffect.h */, + 1E3E3D3317996112005F2132 /* ofxsInteract.h */, + 1E3E3D3417996112005F2132 /* ofxsLog.h */, + 1E3E3D3517996112005F2132 /* ofxsMemory.h */, + 1E3E3D3617996112005F2132 /* ofxsMessage.h */, + 1E3E3D3717996112005F2132 /* ofxsMultiThread.h */, + 1E3E3D3817996112005F2132 /* ofxsParam.h */, + ); + name = Support; + sourceTree = ""; + }; + 1E378A81194DCEF500800F5F /* tuttle */ = { + isa = PBXGroup; + children = ( + 1E378A86194DCF4200800F5F /* ofxReadWrite.h */, + ); + name = tuttle; + path = ../../include/tuttle; + sourceTree = ""; + }; + 1E3E3CB117995CB1005F2132 /* Plugins */ = { + isa = PBXGroup; + children = ( + 1E08328919A1E36800A819A5 /* Makefile */, + 1E08328A19A1E36800A819A5 /* Makefile.master */, + 1E08328219A1E32500A819A5 /* ExamplePlugs.sln */, + 1E08328319A1E33700A819A5 /* Basic */, + 1E08328B19A1E37B00A819A5 /* Field */, + 1E08328F19A1E3A200A819A5 /* Generator */, + 1E08329519A1E3E400A819A5 /* Invert */, + 1E08329619A1E3EA00A819A5 /* MultiBundle */, + 1E0832A719A1E4B200A819A5 /* Retimer */, + 1E08329719A1E3F700A819A5 /* Tester */, + 1E08329819A1E3FF00A819A5 /* Transition */, + ); + path = Plugins; + sourceTree = ""; + }; + 1E3E3CB417995D15005F2132 /* Library */ = { + isa = PBXGroup; + children = ( + 1E08327219A1E23C00A819A5 /* Makefile */, + 1E3E3CB517995D5C005F2132 /* ofxsCore.cpp */, + 1E08327619A1E25600A819A5 /* ofxsHWNDInteract.cpp */, + 1E3E3CB617995D5C005F2132 /* ofxsImageEffect.cpp */, + 1E3E3CB717995D5C005F2132 /* ofxsInteract.cpp */, + 1E3E3CB817995D5C005F2132 /* ofxsLog.cpp */, + 1E3E3CB917995D5C005F2132 /* ofxsMultiThread.cpp */, + 1E3E3CBA17995D5C005F2132 /* ofxsParams.cpp */, + 1E3E3CBB17995D5C005F2132 /* ofxsProperty.cpp */, + 1E3E3CBC17995D5C005F2132 /* ofxsPropertyValidation.cpp */, + 1E3E3CBD17995D5C005F2132 /* ofxsSupportPrivate.h */, + ); + path = Library; + sourceTree = ""; + }; + 1E3E3D30179960F9005F2132 /* Headers */ = { + isa = PBXGroup; + children = ( + 1E0832AF19A1E51900A819A5 /* Support */, + 1E0832AD19A1E4E700A819A5 /* Plugins */, + 1E378A81194DCEF500800F5F /* tuttle */, + 1E9FC1CC180BF70A00EFE0F9 /* nuke */, + 1E009D5F17F44D70003071CC /* ofxCore.h */, + 1ECA10E818C7492E00D6E38C /* ofxDialog.h */, + 1E009D6017F44D70003071CC /* ofxImageEffect.h */, + 1E009D6117F44D70003071CC /* ofxInteract.h */, + 1E009D6217F44D70003071CC /* ofxKeySyms.h */, + 1E009D6317F44D70003071CC /* ofxMemory.h */, + 1E009D6417F44D70003071CC /* ofxMessage.h */, + 1E009D6517F44D70003071CC /* ofxMultiThread.h */, + 1E985639194F2BC300D20D5D /* ofxNatron.h */, + 1E009D6617F44D70003071CC /* ofxOpenGLRender.h */, + 1E009D6717F44D70003071CC /* ofxParam.h */, + 1E009D6817F44D70003071CC /* ofxParametricParam.h */, + 1E009D6917F44D70003071CC /* ofxPixels.h */, + 1E009D6A17F44D70003071CC /* ofxProgress.h */, + 1E009D6B17F44D70003071CC /* ofxProperty.h */, + 1ECA10E918C7492E00D6E38C /* ofxSonyVegas.h */, + 1E009D6C17F44D70003071CC /* ofxTimeLine.h */, + ); + name = Headers; + path = include; + sourceTree = ""; + }; + 1E551EB817994D4000A4135C = { + isa = PBXGroup; + children = ( + 1E3E3DA91799646E005F2132 /* CoreFoundation.framework */, + 1E3E3D30179960F9005F2132 /* Headers */, + 1E551ED217994DEF00A4135C /* Sources */, + 1E08326A19A1E19F00A819A5 /* Other */, + 1E551EDA17994E8100A4135C /* Frameworks */, + 1E551EC217994D4000A4135C /* Products */, + ); + sourceTree = ""; + }; + 1E551EC217994D4000A4135C /* Products */ = { + isa = PBXGroup; + children = ( + 1E3E3CA417995BEE005F2132 /* basic.ofx.bundle */, + 1E3E3CD817995DBB005F2132 /* field.ofx.bundle */, + 1E3E3CEC17995E76005F2132 /* noise.ofx.bundle */, + 1E3E3D0417995F57005F2132 /* invert.ofx.bundle */, + 1E3E3D1817995FB3005F2132 /* multibundle.ofx.bundle */, + 1E3E3D4C179961B4005F2132 /* retimer.ofx.bundle */, + 1E3E3D6317996232005F2132 /* tester.ofx.bundle */, + 1E3E3D7B179962A4005F2132 /* transition.ofx.bundle */, + 1E3E3D9317996363005F2132 /* PropTester.ofx.bundle */, + 1E3E3D9E1799644B005F2132 /* pluginLoader */, + ); + name = Products; + sourceTree = ""; + }; + 1E551ED217994DEF00A4135C /* Sources */ = { + isa = PBXGroup; + children = ( + 1E08327C19A1E2DC00A819A5 /* PropTester */, + 1E08327719A1E26300A819A5 /* OSXStaticLoader */, + 1E3E3CB417995D15005F2132 /* Library */, + 1E3E3CB117995CB1005F2132 /* Plugins */, + ); + name = Sources; + sourceTree = ""; + }; + 1E551EDA17994E8100A4135C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1E551F5A179950EC00A4135C /* OpenGL.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1E9FC1CC180BF70A00EFE0F9 /* nuke */ = { + isa = PBXGroup; + children = ( + 1E9FC1CE180BF74400EFE0F9 /* camera.h */, + 1EA6849218C51E42006EE43D /* fnOfxExtensions.h */, + 1E9FC1CF180BF74400EFE0F9 /* fnPublicOfxExtensions.h */, + ); + name = nuke; + path = ../../include/nuke; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1E3E3CA317995BEE005F2132 /* basic.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3CAE17995BEE005F2132 /* Build configuration list for PBXNativeTarget "basic.ofx" */; + buildPhases = ( + 1E3E3CA017995BEE005F2132 /* Sources */, + 1E3E3CA117995BEE005F2132 /* Frameworks */, + 1E3E3CA217995BEE005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = basic.ofx; + productName = basic.ofx; + productReference = 1E3E3CA417995BEE005F2132 /* basic.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3CC717995DBB005F2132 /* field.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3CD517995DBB005F2132 /* Build configuration list for PBXNativeTarget "field.ofx" */; + buildPhases = ( + 1E3E3CC817995DBB005F2132 /* Sources */, + 1E3E3CD217995DBB005F2132 /* Frameworks */, + 1E3E3CD417995DBB005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = field.ofx; + productName = basic.ofx; + productReference = 1E3E3CD817995DBB005F2132 /* field.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3CDC17995E76005F2132 /* noise.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3CE917995E76005F2132 /* Build configuration list for PBXNativeTarget "noise.ofx" */; + buildPhases = ( + 1E3E3CDD17995E76005F2132 /* Sources */, + 1E3E3CE717995E76005F2132 /* Frameworks */, + 1E3E3CE817995E76005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = noise.ofx; + productName = basic.ofx; + productReference = 1E3E3CEC17995E76005F2132 /* noise.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3CF317995F57005F2132 /* invert.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3D0117995F57005F2132 /* Build configuration list for PBXNativeTarget "invert.ofx" */; + buildPhases = ( + 1E3E3CF417995F57005F2132 /* Sources */, + 1E3E3CFF17995F57005F2132 /* Frameworks */, + 1E3E3D0017995F57005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = invert.ofx; + productName = basic.ofx; + productReference = 1E3E3D0417995F57005F2132 /* invert.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3D0817995FB3005F2132 /* multibundle.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3D1517995FB3005F2132 /* Build configuration list for PBXNativeTarget "multibundle.ofx" */; + buildPhases = ( + 1E3E3D0917995FB3005F2132 /* Sources */, + 1E3E3D1317995FB3005F2132 /* Frameworks */, + 1E3E3D1417995FB3005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = multibundle.ofx; + productName = basic.ofx; + productReference = 1E3E3D1817995FB3005F2132 /* multibundle.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3D39179961B4005F2132 /* retimer.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3D49179961B4005F2132 /* Build configuration list for PBXNativeTarget "retimer.ofx" */; + buildPhases = ( + 1E3E3D3A179961B4005F2132 /* Sources */, + 1E3E3D46179961B4005F2132 /* Frameworks */, + 1E3E3D48179961B4005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = retimer.ofx; + productName = basic.ofx; + productReference = 1E3E3D4C179961B4005F2132 /* retimer.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3D5317996232005F2132 /* tester.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3D6017996232005F2132 /* Build configuration list for PBXNativeTarget "tester.ofx" */; + buildPhases = ( + 1E3E3D5417996232005F2132 /* Sources */, + 1E3E3D5E17996232005F2132 /* Frameworks */, + 1E3E3D5F17996232005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = tester.ofx; + productName = basic.ofx; + productReference = 1E3E3D6317996232005F2132 /* tester.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3D6A179962A4005F2132 /* transition.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3D78179962A4005F2132 /* Build configuration list for PBXNativeTarget "transition.ofx" */; + buildPhases = ( + 1E3E3D6B179962A4005F2132 /* Sources */, + 1E3E3D75179962A4005F2132 /* Frameworks */, + 1E3E3D77179962A4005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = transition.ofx; + productName = basic.ofx; + productReference = 1E3E3D7B179962A4005F2132 /* transition.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3D8317996363005F2132 /* PropTester.ofx */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3D9017996363005F2132 /* Build configuration list for PBXNativeTarget "PropTester.ofx" */; + buildPhases = ( + 1E3E3D8417996363005F2132 /* Sources */, + 1E3E3D8E17996363005F2132 /* Frameworks */, + 1E3E3D8F17996363005F2132 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PropTester.ofx; + productName = basic.ofx; + productReference = 1E3E3D9317996363005F2132 /* PropTester.ofx.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1E3E3D9D1799644B005F2132 /* pluginLoader */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E3E3DA41799644B005F2132 /* Build configuration list for PBXNativeTarget "pluginLoader" */; + buildPhases = ( + 1E3E3D9A1799644B005F2132 /* Sources */, + 1E3E3D9B1799644B005F2132 /* Frameworks */, + 1E3E3D9C1799644B005F2132 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = pluginLoader; + productName = pluginLoader; + productReference = 1E3E3D9E1799644B005F2132 /* pluginLoader */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 1E551EB917994D4000A4135C /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0460; + ORGANIZATIONNAME = OpenFX; + }; + buildConfigurationList = 1E551EBC17994D4000A4135C /* Build configuration list for PBXProject "Support" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 1E551EB817994D4000A4135C; + productRefGroup = 1E551EC217994D4000A4135C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1E551F461799509100A4135C /* all */, + 1E3E3CA317995BEE005F2132 /* basic.ofx */, + 1E3E3CC717995DBB005F2132 /* field.ofx */, + 1E3E3CDC17995E76005F2132 /* noise.ofx */, + 1E3E3CF317995F57005F2132 /* invert.ofx */, + 1E3E3D0817995FB3005F2132 /* multibundle.ofx */, + 1E3E3D39179961B4005F2132 /* retimer.ofx */, + 1E3E3D5317996232005F2132 /* tester.ofx */, + 1E3E3D6A179962A4005F2132 /* transition.ofx */, + 1E3E3D8317996363005F2132 /* PropTester.ofx */, + 1E3E3D9D1799644B005F2132 /* pluginLoader */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1E3E3CA217995BEE005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CD417995DBB005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CE817995E76005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D0017995F57005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D1417995FB3005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D48179961B4005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D5F17996232005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D77179962A4005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D8F17996363005F2132 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1E3E3CA017995BEE005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3CBE17995D5C005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3CBF17995D5C005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3CC017995D5C005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3CC117995D5C005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3CC217995D5C005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3CC317995D5C005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3CC417995D5C005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3CC517995D5C005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3CB317995CC9005F2132 /* basic.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CC817995DBB005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3CCA17995DBB005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3CCB17995DBB005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3CCC17995DBB005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3CCD17995DBB005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3CCE17995DBB005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3CCF17995DBB005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3CD017995DBB005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3CD117995DBB005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3CDB17995DF6005F2132 /* field.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CDD17995E76005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3CDE17995E76005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3CDF17995E76005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3CE017995E76005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3CE117995E76005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3CE217995E76005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3CE317995E76005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3CE417995E76005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3CE517995E76005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3CF117995F2C005F2132 /* noise.cpp in Sources */, + 1E3E3CF217995F2C005F2132 /* randomGenerator.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3CF417995F57005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3CF517995F57005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3CF617995F57005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3CF717995F57005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3CF817995F57005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3CF917995F57005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3CFA17995F57005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3CFB17995F57005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3CFC17995F57005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3D0717995F83005F2132 /* invert.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D0917995FB3005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D0A17995FB3005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3D0B17995FB3005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3D0C17995FB3005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3D0D17995FB3005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3D0E17995FB3005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3D0F17995FB3005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3D1017995FB3005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3D1117995FB3005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3D2217996042005F2132 /* multibundle1.cpp in Sources */, + 1E3E3D2317996042005F2132 /* multibundle2.cpp in Sources */, + 1E3E3D2417996042005F2132 /* PluginRegistration.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D3A179961B4005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D3B179961B4005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3D3C179961B4005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3D3D179961B4005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3D3E179961B4005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3D3F179961B4005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3D40179961B4005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3D41179961B4005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3D42179961B4005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3D50179961E2005F2132 /* retimer.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D5417996232005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D5517996232005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3D5617996232005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3D5717996232005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3D5817996232005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3D5917996232005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3D5A17996232005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3D5B17996232005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3D5C17996232005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3D6617996262005F2132 /* Tester.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D6B179962A4005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D6C179962A4005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3D6D179962A4005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3D6E179962A4005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3D6F179962A4005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3D70179962A4005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3D71179962A4005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3D72179962A4005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3D73179962A4005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3D80179962DE005F2132 /* crossFade.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D8417996363005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E3E3D8517996363005F2132 /* ofxsCore.cpp in Sources */, + 1E3E3D8617996363005F2132 /* ofxsImageEffect.cpp in Sources */, + 1E3E3D8717996363005F2132 /* ofxsInteract.cpp in Sources */, + 1E3E3D8817996363005F2132 /* ofxsLog.cpp in Sources */, + 1E3E3D8917996363005F2132 /* ofxsMultiThread.cpp in Sources */, + 1E3E3D8A17996363005F2132 /* ofxsParams.cpp in Sources */, + 1E3E3D8B17996363005F2132 /* ofxsProperty.cpp in Sources */, + 1E3E3D8C17996363005F2132 /* ofxsPropertyValidation.cpp in Sources */, + 1E3E3D96179963B4005F2132 /* propTester.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1E3E3D9A1799644B005F2132 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E08327B19A1E2C100A819A5 /* pluginLoader.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 1E3E3D27179960AC005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3CA317995BEE005F2132 /* basic.ofx */; + targetProxy = 1E3E3D26179960AC005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D29179960AC005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3CC717995DBB005F2132 /* field.ofx */; + targetProxy = 1E3E3D28179960AC005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D2B179960AC005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3CDC17995E76005F2132 /* noise.ofx */; + targetProxy = 1E3E3D2A179960AC005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D2D179960AC005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3CF317995F57005F2132 /* invert.ofx */; + targetProxy = 1E3E3D2C179960AC005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D2F179960AC005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3D0817995FB3005F2132 /* multibundle.ofx */; + targetProxy = 1E3E3D2E179960AC005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D52179961ED005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3D39179961B4005F2132 /* retimer.ofx */; + targetProxy = 1E3E3D51179961ED005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D6817996270005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3D5317996232005F2132 /* tester.ofx */; + targetProxy = 1E3E3D6717996270005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D8217996301005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3D6A179962A4005F2132 /* transition.ofx */; + targetProxy = 1E3E3D8117996301005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3D98179963C5005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3D8317996363005F2132 /* PropTester.ofx */; + targetProxy = 1E3E3D97179963C5005F2132 /* PBXContainerItemProxy */; + }; + 1E3E3DAC17996479005F2132 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E3E3D9D1799644B005F2132 /* pluginLoader */; + targetProxy = 1E3E3DAB17996479005F2132 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1E3E3CAF17995BEE005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Basic/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3CB017995BEE005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Basic/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3CD617995DBB005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Field/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = field.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3CD717995DBB005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Field/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = field.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3CEA17995E76005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Generator/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = noise.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3CEB17995E76005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Generator/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = noise.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3D0217995F57005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Invert/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = invert.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3D0317995F57005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Invert/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = invert.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3D1617995FB3005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/MultiBundle/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = multibundle.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3D1717995FB3005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/MultiBundle/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = multibundle.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3D4A179961B4005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Retimer/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = retimer.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3D4B179961B4005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Retimer/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = retimer.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3D6117996232005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Tester/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = tester.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3D6217996232005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Tester/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = tester.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3D79179962A4005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Transition/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = transition.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3D7A179962A4005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = Plugins/Transition/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = transition.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3D9117996363005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = PropTester/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = PropTester.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 1E3E3D9217996363005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXPORTED_SYMBOLS_FILE = "$(OFX_PATH)/Support/include/osxSymbols"; + HEADER_SEARCH_PATHS = ( + "$(OFX_PATH)/include", + include, + ); + INFOPLIST_FILE = PropTester/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/OFX/Plugins/$(PROJECT_NAME)"; + PRODUCT_NAME = PropTester.ofx; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1E3E3DA51799644B005F2132 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 1E3E3DA61799644B005F2132 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; + 1E551ECD17994D4000A4135C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + OFX_SUPPORTS_OPENGLRENDER, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(OFX_PATH)/include"; + LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/../Libraries"; + OFX_PATH = ..; + ONLY_ACTIVE_ARCH = YES; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + ); + }; + name = Debug; + }; + 1E551ECE17994D4000A4135C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "NDEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(OFX_PATH)/include"; + LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/../Libraries"; + OFX_PATH = ..; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + ); + }; + name = Release; + }; + 1E551F481799509100A4135C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 1E551F491799509100A4135C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1E3E3CAE17995BEE005F2132 /* Build configuration list for PBXNativeTarget "basic.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3CAF17995BEE005F2132 /* Debug */, + 1E3E3CB017995BEE005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3CD517995DBB005F2132 /* Build configuration list for PBXNativeTarget "field.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3CD617995DBB005F2132 /* Debug */, + 1E3E3CD717995DBB005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3CE917995E76005F2132 /* Build configuration list for PBXNativeTarget "noise.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3CEA17995E76005F2132 /* Debug */, + 1E3E3CEB17995E76005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3D0117995F57005F2132 /* Build configuration list for PBXNativeTarget "invert.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3D0217995F57005F2132 /* Debug */, + 1E3E3D0317995F57005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3D1517995FB3005F2132 /* Build configuration list for PBXNativeTarget "multibundle.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3D1617995FB3005F2132 /* Debug */, + 1E3E3D1717995FB3005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3D49179961B4005F2132 /* Build configuration list for PBXNativeTarget "retimer.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3D4A179961B4005F2132 /* Debug */, + 1E3E3D4B179961B4005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3D6017996232005F2132 /* Build configuration list for PBXNativeTarget "tester.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3D6117996232005F2132 /* Debug */, + 1E3E3D6217996232005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3D78179962A4005F2132 /* Build configuration list for PBXNativeTarget "transition.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3D79179962A4005F2132 /* Debug */, + 1E3E3D7A179962A4005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3D9017996363005F2132 /* Build configuration list for PBXNativeTarget "PropTester.ofx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3D9117996363005F2132 /* Debug */, + 1E3E3D9217996363005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E3E3DA41799644B005F2132 /* Build configuration list for PBXNativeTarget "pluginLoader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E3E3DA51799644B005F2132 /* Debug */, + 1E3E3DA61799644B005F2132 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E551EBC17994D4000A4135C /* Build configuration list for PBXProject "Support" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E551ECD17994D4000A4135C /* Debug */, + 1E551ECE17994D4000A4135C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E551F471799509100A4135C /* Build configuration list for PBXAggregateTarget "all" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E551F481799509100A4135C /* Debug */, + 1E551F491799509100A4135C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 1E551EB917994D4000A4135C /* Project object */; +} diff --git a/third_party/openfx/Support/TODO b/third_party/openfx/Support/TODO new file mode 100644 index 000000000..0da9952a3 --- /dev/null +++ b/third_party/openfx/Support/TODO @@ -0,0 +1,8 @@ + - Skin message suite. + - Skin the parameter custom interacts. + - Return native OFX types from the various param functions, currently tend to return via reference args. + - integrate/differentiate on all the various param instances, + - Come up with a set of exception classes that the plugin can throw that will be trapped by the main routine so it can return an appropriate error code. + - Exception specs on all functions. + - test test test! + - examples examples examples! \ No newline at end of file diff --git a/third_party/openfx/Support/include/ofxsCore.h b/third_party/openfx/Support/include/ofxsCore.h new file mode 100755 index 000000000..d0884634e --- /dev/null +++ b/third_party/openfx/Support/include/ofxsCore.h @@ -0,0 +1,334 @@ + + +#ifndef _ofxsCore_H_ +#define _ofxsCore_H_ +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + + +/** @mainpage OFX Support Library + +@section mainpageIntro Introduction + +This support library skins the raw OFX C API with a set of C++ classes and functions that makes it easier to understand and write plug-ins to the API. Look at the examples to see how it is done. + +
+ +@section fifteenLineGuide Fifteen Line Plugin Writing Guide + +- work from the examples +- you need to write the following functions.... +- void OFX::Plugin::getPluginID(OFX::PluginID &id) +- gives the unique name and version numbers of the plug-in +- void OFX::Plugin::loadAction(void) +- called after the plug-in is first loaded, and before any instance has been made, +- void OFX::Plugin::unloadAction(void) +- called before the plug-in is unloaded, and all instances have been destroyed, +- void OFX::Plugin::describe(OFX::ImageEffectDescriptor &desc) +- called to describe the plugin to the host +- void OFX::Plugin::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context) +- called to describe the plugin to the host for a context reported in OFX::Plugin::describe +- OFX::ImageEffect * OFX::Plugin::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context) +- called when a new instance of a plug-in needs to be created. You need to derive a class from ImageEffect, new it and return it. + +The OFX::ImageEffect class has a set of members you can override to do various things, like rendering an effect. Again, look at the examples. + +
+ +@section license Copyright and License + +The library is Copyright OpenFX and contributors to the OpenFX project. and was +written by Bruno Nicoletti (bruno@thefoundry.co.uk). + +It has been released under the GNU Lesser General Public License, see the +top of any source file for details. + +*/ + +/** @file This file contains core code that wraps OFX 'objects' with C++ classes. + +This file only holds code that is visible to a plugin implementation, and so hides much +of the direct OFX objects and any library side only functions. +*/ + +#ifdef _MSC_VER +#pragma warning( disable : 4290 ) +#endif + +#include "ofxCore.h" +#include "ofxImageEffect.h" +#include "ofxInteract.h" +#include "ofxKeySyms.h" +#include "ofxMemory.h" +#include "ofxMessage.h" +#include "ofxMultiThread.h" +#include "ofxParam.h" +#include "ofxProperty.h" +#include "ofxPixels.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef OFX_CLIENT_EXCEPTION_HEADER +#include OFX_CLIENT_EXCEPTION_HEADER +#endif + +/** @brief Defines an integer 3D point + +Should migrate this to the ofxCore.h in a v1.1 +*/ +struct Ofx3DPointI { + int x, y, z; +}; + +/** @brief Defines a double precision 3D point + +Should migrate this to the ofxCore.h in a v1.1 +*/ +struct Ofx3DPointD { + double x, y, z; +}; + +/** @brief Nasty macro used to define empty protected copy ctors and assign ops */ +#define mDeclareProtectedAssignAndCC(CLASS) \ + CLASS &operator=(const CLASS &) {assert(false); return *this;} \ + CLASS(const CLASS &) {assert(false); } + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. +*/ +namespace OFX { + /** forward class declarations */ + class PropertySet; + + /** @brief Enumerates the different types a property can be */ + enum PropertyTypeEnum { + ePointer, + eInt, + eString, + eDouble + }; + + /** @brief Enumerates the reasons a plug-in instance may have had one of its values changed */ + enum InstanceChangeReason { + eChangeUserEdit, /**< @brief A user actively editted something in the plugin, eg: changed the value of an integer param on an interface */ + eChangePluginEdit, /**< @brief The plugin's own code changed something in the instance, eg: a callback on on param settting the value of another */ + eChangeTime /**< @brief The current value of a parameter has changed because the param animates and the current time has changed */ + }; + + /** @brief maps a status to a string for debugging purposes, note a c-str for printf */ + const char * mapStatusToString(OfxStatus stat); + + /** @brief namespace for OFX support lib exceptions, all derive from std::exception, calling it */ + namespace Exception { + + /** @brief thrown when a suite returns a dud status code + */ + class Suite : public std::exception { + protected : + OfxStatus _status; + public : + Suite(OfxStatus s) : _status(s) {} + OfxStatus status(void) const {return _status;} + operator OfxStatus() const {return _status;} + + /** @brief reimplemented from std::exception */ + virtual const char * what () const noexcept {return mapStatusToString(_status);} + + }; + + /** @brief Exception indicating that a host doesn't know about a property that is should do */ + class PropertyUnknownToHost : public std::exception { + protected : + std::string _what; + public : + PropertyUnknownToHost(const char *what) : _what(what) {} + virtual ~PropertyUnknownToHost() noexcept {} + + /** @brief reimplemented from std::exception */ + virtual const char * what () const noexcept + { + return _what.c_str(); + } + }; + + /** @brief exception indicating that the host thinks a property has an illegal value */ + class PropertyValueIllegalToHost : public std::exception { + protected : + std::string _what; + public : + PropertyValueIllegalToHost(const char *what) : _what(what) {} + virtual ~PropertyValueIllegalToHost() noexcept {} + + /** @brief reimplemented from std::exception */ + virtual const char * what () const noexcept + { + return _what.c_str(); + } + }; + + /** @brief exception indicating a request for a named thing exists (eg: a param), but is of the wrong type, should never make it back to the main entry + indicates a logical error in the code. Asserts are raised in debug code in these situations. + */ + class TypeRequest : public std::exception { + protected : + std::string _what; + public : + TypeRequest(const char *what) : _what(what) {} + virtual ~TypeRequest() noexcept {} + + /** @brief reimplemented from std::exception */ + virtual const char * what () const noexcept + { + return _what.c_str(); + } + }; + + //////////////////////////////////////////////////////////////////////////////// + // These exceptions are to be thrown by the plugin if it hits a problem, the + // code managing the main entry will trap the exception and return a suitable + // status code to the host. + + /** @brief exception indicating a required host feature is missing */ + class HostInadequate : public std::exception { + protected : + std::string _what; + public : + HostInadequate(const char *what) : _what(what) {} + virtual ~HostInadequate() noexcept {} + + /** @brief reimplemented from std::exception */ + virtual const char * what () const noexcept + { + return _what.c_str(); + } + }; + + }; // end of Exception namespace + + /** @brief Throws an @ref OFX::Exception::Suite depending on the status flag passed in */ + void + throwSuiteStatusException(OfxStatus stat); + + void + throwHostMissingSuiteException(std::string name); + + /** @brief This struct is used to return an identifier for the plugin by the function @ref OFX:Plugin::getPlugin. + The members correspond to those in the OfxPlugin struct defined in ofxCore.h. + */ + + class ImageEffectDescriptor; + class ImageEffect; + + /** @brief This class wraps up an OFX property set */ + class PropertySet { + protected : + /** @brief The raw property handle */ + OfxPropertySetHandle _propHandle; + + /** @brief Class static, whether we are logging each property action */ + static int _gPropLogging; + + /** @brief Do not throw an exception if a host returns 'unsupported' when setting a property */ + static bool _gThrowOnUnsupported; + + public : + /** @brief turns on logging of property access functions */ + static void propEnableLogging(void) {++_gPropLogging;} + + /** @brief turns off logging of property access functions */ + static void propDisableLogging(void) {--_gPropLogging;} + + /** @brief Do we throw an exception if a host returns 'unsupported' when setting a property. Default is true */ + static void setThrowOnUnsupportedProperties(bool v) {_gThrowOnUnsupported = v;} + + /** @brief Do we throw an exception if a host returns 'unsupported' when setting a property. Default is true */ + static bool getThrowOnUnsupportedProperties(void) {return _gThrowOnUnsupported;} + + /** @brief construct a property set */ + PropertySet(OfxPropertySetHandle h = 0) : _propHandle(h) {} + virtual ~PropertySet(); + + /** @brief set the handle to use for this set */ + void propSetHandle(OfxPropertySetHandle h) { _propHandle = h;} + + /** @brief return the handle for this property set */ + OfxPropertySetHandle propSetHandle(void) const {return _propHandle;} + + int propGetDimension(const char* property, bool throwOnFailure = true) const; + void propReset(const char* property); + + // set single values + void propSetPointer(const char* property, void *value, int idx, bool throwOnFailure = true); + void propSetString(const char* property, const std::string &value, int idx, bool throwOnFailure = true); + void propSetDouble(const char* property, double value, int idx, bool throwOnFailure = true); + void propSetInt(const char* property, int value, int idx, bool throwOnFailure = true); + + // set multiple values + void propSetDoubleN(const char* property, const double *value, int count, bool throwOnFailure = true); + + void propSetPointer(const char* property, void *value, bool throwOnFailure = true) + {propSetPointer(property, value, 0, throwOnFailure);} + + void propSetString(const char* property, const std::string &value, bool throwOnFailure = true) + {propSetString(property, value, 0, throwOnFailure);} + + void propSetDouble(const char* property, double value, bool throwOnFailure = true) + {propSetDouble(property, value, 0, throwOnFailure);} + + void propSetInt(const char* property, int value, bool throwOnFailure = true) + {propSetInt(property, value, 0, throwOnFailure);} + + + /// get a pointer property + void *propGetPointer(const char* property, int idx, bool throwOnFailure = true) const; + + /// get a string property + std::string propGetString(const char* property, int idx, bool throwOnFailure = true) const; + /// get a double property + double propGetDouble(const char* property, int idx, bool throwOnFailure = true) const; + + /// get an int property + int propGetInt(const char* property, int idx, bool throwOnFailure = true) const; + + /// get a pointer property with index 0 + void* propGetPointer(const char* property, bool throwOnFailure = true) const + { + return propGetPointer(property, 0, throwOnFailure); + } + + /// get a string property with index 0 + std::string propGetString(const char* property, bool throwOnFailure = true) const + { + return propGetString(property, 0, throwOnFailure); + } + + /// get a double property with index 0 + double propGetDouble(const char* property, bool throwOnFailure = true) const + { + return propGetDouble(property, 0, throwOnFailure); + } + + /// get an int property with index 0 + int propGetInt(const char* property, bool throwOnFailure = true) const + { + return propGetInt(property, 0, throwOnFailure); + } + + std::list propGetNString(const char* property, bool throwOnFailure = true) const; + + }; + + // forward decl of the image effect + class ImageEffect; +}; + +// undeclare the protected assign and CC macro +#undef mDeclareProtectedAssignAndCC + +#endif diff --git a/third_party/openfx/Support/include/ofxsImageEffect.h b/third_party/openfx/Support/include/ofxsImageEffect.h new file mode 100644 index 000000000..1cce91a07 --- /dev/null +++ b/third_party/openfx/Support/include/ofxsImageEffect.h @@ -0,0 +1,1224 @@ + + +#ifndef _ofxsImageEffect_H_ +#define _ofxsImageEffect_H_ +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +/** @file This file contains core code that wraps OFX 'objects' with C++ classes. + +This file only holds code that is visible to a plugin implementation, and so hides much +of the direct OFX objects and any library side only functions. +*/ +#include +#include +#include +#include +#include "ofxsParam.h" +#include "ofxsInteract.h" +#include "ofxsMessage.h" +#include "ofxProgress.h" +#include "ofxTimeLine.h" +#include "ofxParametricParam.h" + +/** @brief Nasty macro used to define empty protected copy ctors and assign ops */ +#define mDeclareProtectedAssignAndCC(CLASS) \ + CLASS &operator=(const CLASS &) {assert(false); return *this;} \ + CLASS(const CLASS &) {assert(false); } +#define mDeclareProtectedAssignAndCCBase(CLASS,BASE) \ + CLASS &operator=(const CLASS &) {assert(false); return *this;} \ + CLASS(const CLASS &c) : BASE(c) {assert(false); } + +namespace OFX +{ + namespace Private + { + OfxStatus mainEntryStr(const char *actionRaw, + const void *handleRaw, + OfxPropertySetHandle inArgsRaw, + OfxPropertySetHandle outArgsRaw, + const char* plugname); + + OfxStatus customParamInterpolationV1Entry( + const void* handleRaw, + OfxPropertySetHandle inArgsRaw, + OfxPropertySetHandle outArgsRaw); + } +} + + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. +*/ +namespace OFX { + /** forward class declarations */ + class ClipDescriptor; + class ImageEffectDescriptor; + + class Image; + class Clip; + class ImageEffect; + class ImageMemory; + + /** @brief Enumerates the contexts a plugin can be used in */ + enum ContextEnum {eContextNone, + eContextGenerator, + eContextFilter, + eContextTransition, + eContextPaint, + eContextGeneral, + eContextRetimer, + }; + + /** @brief Enumerates the pixel depths supported */ + enum BitDepthEnum {eBitDepthNone, /**< @brief bit depth that indicates no data is present */ + eBitDepthUByte, + eBitDepthUShort, + eBitDepthHalf, + eBitDepthFloat, + eBitDepthCustom, ///< some non standard bit depth + }; + + /** @brief Enumerates the component types supported */ + enum PixelComponentEnum {ePixelComponentNone, + ePixelComponentRGBA, + ePixelComponentRGB, + ePixelComponentAlpha, + ePixelComponentCustom ///< some non standard pixel type + }; + + /** @brief Enumerates the ways a fielded image can be extracted from a clip */ + enum FieldExtractionEnum {eFieldExtractBoth, /**< @brief extract both fields */ + eFieldExtractSingle, /**< @brief extracts a single field, so you have a half height image */ + eFieldExtractDoubled /**< @brief extracts a single field, but doubles up the field, so you have a full height image */ + }; + + /** @brief Enumerates the kind of render thread safety a plugin has */ + enum RenderSafetyEnum {eRenderUnsafe, /**< @brief can only render a single instance at any one time */ + eRenderInstanceSafe, /**< @brief can call a single render on an instance, but can render multiple instances simultaneously */ + eRenderFullySafe /**< @brief can call render any number of times on an instance, and render multiple instances simultaneously */ + }; + + /** @brief Enumerates the fields present in an image */ + enum FieldEnum {eFieldNone, /**< @brief unfielded image */ + eFieldBoth, /**< @brief fielded image with both fields present */ + eFieldLower, /**< @brief only the spatially lower field is present */ + eFieldUpper, /**< @brief only the spatially upper field is present */ + eFieldSingle, /**< @brief image that consists of a single field, and so is half height */ + eFieldDoubled /**< @brief image that consists of a single field, but each scan line is double, and so is full height */ + }; + + enum PreMultiplicationEnum { eImageOpaque, /**< @brief the image is opaque and so has no premultiplication state */ + eImagePreMultiplied, /**< @brief the image is premultiplied by it's alpha */ + eImageUnPreMultiplied, /**< @brief the image is unpremultiplied */ + }; + + enum NativeOriginEnum { + eNativeOriginBottomLeft, + eNativeOriginTopLeft, + eNativeOriginCenter + }; + + /** @brief turns a field string into and enum */ + FieldEnum mapStrToFieldEnum(const std::string &str); + + //////////////////////////////////////////////////////////////////////////////// + /** @brief map a std::string to a context enum */ + ContextEnum mapToContextEnum(const std::string &s); + + const char* mapContextEnumToStr(ContextEnum context); + + const char* mapMessageTypeEnumToStr(OFX::Message::MessageTypeEnum type); + + OFX::Message::MessageReplyEnum mapToMessageReplyEnum(OfxStatus stat); + + InstanceChangeReason mapToInstanceChangedReason(const std::string &s); + + BitDepthEnum mapStrToBitDepthEnum(const std::string &str); + + const char* mapBitDepthEnumToStr(BitDepthEnum bitDepth); + + PixelComponentEnum mapStrToPixelComponentEnum(const std::string &str); + + const char* mapPixelComponentEnumToStr(PixelComponentEnum pixelComponent); + + class PluginFactory + { + public: + virtual void load() {} + virtual void unload() {} + virtual void describe(OFX::ImageEffectDescriptor &desc) = 0; + virtual void describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum context) = 0; + virtual ImageEffect* createInstance(OfxImageEffectHandle handle, ContextEnum context) = 0; + virtual const std::string& getID() const = 0; + virtual const std::string& getUID() const = 0; + virtual unsigned int getMajorVersion() const = 0; + virtual unsigned int getMinorVersion() const = 0; + virtual OfxPluginEntryPoint* getMainEntry() = 0; + }; + + template + class FactoryMainEntryHelper + { + protected: + const std::string& getHelperID() const { return _id; } + unsigned int getHelperMajorVersion() const { return _maj; } + unsigned int getHelperMinorVersion() const { return _min; } + std::string toString(unsigned int val) + { + std::ostringstream ss; + ss << val; + return ss.str(); + } + FactoryMainEntryHelper(const std::string& id, unsigned int maj, unsigned int min): _id(id), _maj(maj), _min(min) + { + assert(_uid.empty()); // constructor should only be called once + _uid = id + toString(maj) + toString(min); + } + const std::string& getHelperUID() const { return _uid; } + static OfxStatus mainEntry(const char *action, const void* handle, OfxPropertySetHandle in, OfxPropertySetHandle out) + { + return OFX::Private::mainEntryStr(action, handle, in, out, _uid.c_str()); + } + + static std::string _uid; + std::string _id; + unsigned int _maj; + unsigned int _min; + }; + template std::string OFX::FactoryMainEntryHelper::_uid; + + template + class PluginFactoryHelper : public FactoryMainEntryHelper, public PluginFactory + { + public: + PluginFactoryHelper(const std::string& id, unsigned int maj, unsigned int min): FactoryMainEntryHelper(id, maj, min) + {} + OfxPluginEntryPoint* getMainEntry() { return FactoryMainEntryHelper::mainEntry; } + const std::string& getID() const { return FactoryMainEntryHelper::getHelperID(); } + const std::string& getUID() const { return FactoryMainEntryHelper::getHelperUID(); } + unsigned int getMajorVersion() const { return FactoryMainEntryHelper::getHelperMajorVersion(); } + unsigned int getMinorVersion() const { return FactoryMainEntryHelper::getHelperMinorVersion(); } + }; + +#define mDeclarePluginFactory(CLASS, LOADFUNCDEF, UNLOADFUNCDEF) \ + class CLASS : public OFX::PluginFactoryHelper \ + { \ + public: \ + CLASS(const std::string& id, unsigned int verMaj, unsigned int verMin):OFX::PluginFactoryHelper(id, verMaj, verMin){} \ + virtual void load() LOADFUNCDEF ;\ + virtual void unload() UNLOADFUNCDEF ;\ + virtual void describe(OFX::ImageEffectDescriptor &desc); \ + virtual void describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context); \ + virtual OFX::ImageEffect* createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context); \ + }; + + typedef std::vector PluginFactoryArray; + + /** @brief Fetch's a suite from the host and logs errors + + All the standard suites are fetched by the support code, you should use this + to fetch any extra non-standard suites. + */ + const void * fetchSuite(const char *suiteName, int suiteVersion, bool optional = false); + + //////////////////////////////////////////////////////////////////////////////// + /** @brief A class that lists all the properties of a host */ + struct ImageEffectHostDescription { + public : + int APIVersionMajor; + int APIVersionMinor; + std::string hostName; + std::string hostLabel; + int versionMajor; + int versionMinor; + int versionMicro; + std::string versionLabel; + bool hostIsBackground; + bool supportsOverlays; + bool supportsMultiResolution; + bool supportsTiles; + bool temporalClipAccess; + bool supportsMultipleClipDepths; + bool supportsMultipleClipPARs; + bool supportsSetableFrameRate; + bool supportsSetableFielding; + int sequentialRender; + bool supportsStringAnimation; + bool supportsCustomInteract; + bool supportsChoiceAnimation; + bool supportsStrChoice; + bool supportsStrChoiceAnimation; + bool supportsBooleanAnimation; + bool supportsCustomAnimation; + void* osHandle; + bool supportsParametricParameter; + bool supportsParametricAnimation; + bool supportsRenderQualityDraft; + NativeOriginEnum nativeOrigin; + bool supportsOpenCLRender; + bool supportsCudaRender; + bool supportsCudaStream; + bool supportsMetalRender; +#ifdef OFX_SUPPORTS_OPENGLRENDER + bool supportsOpenGLRender; +#endif + int maxParameters; + int maxPages; + int pageRowCount; + int pageColumnCount; + typedef std::vector PixelComponentArray; + PixelComponentArray _supportedComponents; + typedef std::vector ContextArray; + ContextArray _supportedContexts; + typedef std::vector PixelDepthArray; + PixelDepthArray _supportedPixelDepths; + bool supportsProgressSuite; + bool supportsTimeLineSuite; + bool supportsMessageSuiteV2; + + public: + bool supportsPixelComponent(const PixelComponentEnum component) const; + bool supportsBitDepth( const BitDepthEnum bitDepth) const; + bool supportsContext(const ContextEnum context) const; + + /** @return default pixel depth supported by host application. */ + BitDepthEnum getDefaultPixelDepth() const; + + /** @return default pixel component supported by host application. */ + PixelComponentEnum getDefaultPixelComponent() const; + }; + + + /// retrieve the host description + ImageEffectHostDescription* getImageEffectHostDescription(); + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a clip */ + class ClipDescriptor { + protected : + mDeclareProtectedAssignAndCC(ClipDescriptor); + ClipDescriptor(void) {assert(false);} + + protected : + /** @brief name of the clip */ + std::string _clipName; + + /** @brief properties for this clip */ + PropertySet _clipProps; + + protected : + /** @brief hidden constructor */ + ClipDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ImageEffectDescriptor; + + public : + const PropertySet &getPropertySet() const {return _clipProps;} + + PropertySet &getPropertySet() {return _clipProps;} + + + /** @brief set the label properties */ + void setLabel(const std::string &label); + + /** @brief set the label properties */ + void setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel); + + /** @brief set how fielded images are extracted from the clip defaults to eFieldExtractDoubled */ + void setFieldExtraction(FieldExtractionEnum v); + + /** @brief set which components are supported, defaults to none set, this must be called at least once! */ + void addSupportedComponent(PixelComponentEnum v); + + /** @brief set which components are supported. This version adds by the raw C-string label, allowing you to add + custom component types */ + void addSupportedComponent(const std::string &comp); + + /** @brief say whether we are going to do random temporal access on this clip, defaults to false */ + void setTemporalClipAccess(bool v); + + /** @brief say whether if the clip is optional, defaults to false */ + void setOptional(bool v); + + /** @brief say whether this clip supports tiling, defaults to true */ + void setSupportsTiles(bool v); + + /** @brief say whether this clip is a 'mask', so the host can know to replace with a roto or similar, defaults to false */ + void setIsMask(bool v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an effect descriptor, used in the describe actions */ + class ImageEffectDescriptor : public ParamSetDescriptor + { + protected : + mDeclareProtectedAssignAndCCBase(ImageEffectDescriptor,ParamSetDescriptor); + ImageEffectDescriptor(void) {assert(false);} + + protected : + /** @brief The effect handle */ + OfxImageEffectHandle _effectHandle; + + /** @brief properties for this clip */ + PropertySet _effectProps; + + /** @brief Set of all previously defined parameters, defined on demand */ + std::map _definedClips; + + /** @brief Set of strings for clip preferences action (stored in here so the array persists and can be used in a property name)*/ + std::map _clipComponentsPropNames; + std::map _clipDepthPropNames; + std::map _clipPARPropNames; + std::map _clipROIPropNames; + std::map _clipFrameRangePropNames; + + std::unique_ptr _overlayDescriptor; + public : + /** @brief ctor */ + ImageEffectDescriptor(OfxImageEffectHandle handle); + + /** @brief dtor */ + ~ImageEffectDescriptor(); + + const PropertySet &getPropertySet() const {return _effectProps;} + + PropertySet &getPropertySet() {return _effectProps;} + + /** @brief, set the label properties in a plugin */ + void setLabel(const std::string &label); + + /** @brief, set the label properties in a plugin */ + void setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel); + + /** @brief, set the version properties in a plugin */ + void setVersion(int major, int minor, int micro, int build, const std::string &versionLabel); + + /** @brief Set the plugin grouping, defaults to "" */ + void setPluginGrouping(const std::string &group); + + /** @brief Set the plugin description, defaults to "" */ + void setPluginDescription(const std::string &description); + + /** @brief Add a context to those supported, defaults to none, must be called at least once */ + void addSupportedContext(ContextEnum v); + + /** @brief Add a pixel depth to those supported, defaults to none, must be called at least once */ + void addSupportedBitDepth(BitDepthEnum v); + + /** @brief Add a pixel depth to those supported for OpenGL rendering, defaults to all */ + void addSupportedOpenGLBitDepth(BitDepthEnum v); + + /** @brief Is the plugin single instance only ? defaults to false */ + void setSingleInstance(bool v); + + /** @brief Does the plugin expect the host to perform per frame SMP threading defaults to true */ + void setHostFrameThreading(bool v); + + /** @brief Does the plugin support multi resolution images, defaults to true */ + void setSupportsMultiResolution(bool v); + + /** @brief Does the plugin support image tiling, defaults to true */ + void setSupportsTiles(bool v); + + /** @brief Does the plugin perform temporal clip access, defaults to false */ + void setTemporalClipAccess(bool v); + + /** @brief Does the plugin want to have render called twice per frame in all circumanstances for fielded images ? defaults to true */ + void setRenderTwiceAlways(bool v); + + /** @brief Does the plugin support inputs and output clips of differing depths, defaults to false */ + void setSupportsMultipleClipDepths(bool v); + + /** @brief Does the plugin support inputs and output clips of pixel aspect ratios, defaults to false */ + void setSupportsMultipleClipPARs(bool v); + + /** @brief How thread safe is the plugin, defaults to eRenderInstanceSafe */ + void setRenderThreadSafety(RenderSafetyEnum v); + + /** @brief If the slave param changes the clip preferences need to be re-evaluated */ + void addClipPreferencesSlaveParam(ParamDescriptor &p); + + /** @brief Does the plugin support OpenCL Buffers Render, defaults to false */ + void setSupportsOpenCLBuffersRender(bool v); + + /** @brief Does the plugin support OpenCL Images Render, defaults to false */ + void setSupportsOpenCLImagesRender(bool v); + + /** @brief Does the plugin support CUDA Render, defaults to false */ + void setSupportsCudaRender(bool v); + + /** @brief Does the plugin support CUDA Stream Render, defaults to false */ + void setSupportsCudaStream(bool v); + + /** @brief Does the plugin support Metal Render, defaults to false */ + void setSupportsMetalRender(bool v); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief Does the plugin support OpenGL accelerated rendering (but is also capable of CPU rendering) ? */ + void setSupportsOpenGLRender(bool v); + + /** @brief Does the plugin require OpenGL accelerated rendering ? */ + void setNeedsOpenGLRender(bool v); + void addOpenGLBitDepth(BitDepthEnum bitDepth); +#endif + + /** @brief Create a clip, only callable from describe in context + + The returned clip \em must not be deleted by the client code. This is all managed by the ImageEffectDescriptor itself. + */ + ClipDescriptor *defineClip(const std::string &name); + + /** @brief Access to the string maps needed for runtime properties. Because the char array must persist after the call, + we need these to be stored in the descriptor, which is only deleted on unload.*/ + + const std::map& getClipComponentPropNames() const { return _clipComponentsPropNames; } + const std::map& getClipDepthPropNames() const { return _clipDepthPropNames; } + const std::map& getClipPARPropNames() const { return _clipPARPropNames; } + const std::map& getClipROIPropNames() const { return _clipROIPropNames; } + const std::map& getClipFrameRangePropNames() const { return _clipFrameRangePropNames; } + + /** @brief override this to create an interact for the effect */ + virtual void setOverlayInteractDescriptor(EffectOverlayDescriptor* desc); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an image */ + class ImageBase { + protected : + /** @brief the handle that holds this image */ + PropertySet _imageProps; + + /** @brief friend so we get access to ctor */ + //friend class Clip; + + PixelComponentEnum _pixelComponents; /**< @brief get the components in the image */ + int _pixelComponentCount; + int _rowBytes; /**< @brief the number of bytes per scanline */ + int _pixelBytes; /**< @brief the number of bytes per pixel */ + BitDepthEnum _pixelDepth; /**< @brief get the pixel depth */ + PreMultiplicationEnum _preMultiplication; /**< @brief premultiplication on the image */ + OfxRectI _regionOfDefinition; /**< @brief the RoD in pixel coordinates, this may be more or less than the bounds! */ + OfxRectI _bounds; /**< @brief the bounds on the pixel data */ + double _pixelAspectRatio; /**< @brief the pixel aspect ratio */ + FieldEnum _field; /**< @brief which field this represents */ + std::string _uniqueID; /**< @brief the unique ID of this image */ + OfxPointD _renderScale; /**< @brief any scaling factor applied to the image */ + + public : + /** @brief ctor */ + ImageBase(OfxPropertySetHandle props); + + /** @brief dtor */ + virtual ~ImageBase(); + + const PropertySet &getPropertySet() const {return _imageProps;} + + PropertySet &getPropertySet() {return _imageProps;} + + /** @brief get the pixel depth */ + BitDepthEnum getPixelDepth(void) const {return _pixelDepth;} + + /** @brief get the components in the image */ + PixelComponentEnum getPixelComponents(void) const { return _pixelComponents;} + + /** @brief get the number of components in the image */ + int getPixelComponentCount(void) const { return _pixelComponentCount; } + + /** @brief get the string representing the pixel components */ + std::string getPixelComponentsProperty(void) const { return _imageProps.propGetString(kOfxImageEffectPropComponents);} + + /** @brief premultiplication on the image */ + PreMultiplicationEnum getPreMultiplication(void) const { return _preMultiplication;} + + /** @brief get the scale factor that has been applied to this image */ + const OfxPointD& getRenderScale(void) const { return _renderScale;} + + /** @brief get the scale factor that has been applied to this image */ + double getPixelAspectRatio(void) const { return _pixelAspectRatio;} + + /** @brief get the region of definition (in pixel coordinates) of this image */ + const OfxRectI& getRegionOfDefinition(void) const { return _regionOfDefinition;} + + /** @brief get the bounds on the image data (in pixel coordinates) of this image */ + const OfxRectI& getBounds(void) const { return _bounds;} + + /** @brief get the row bytes, may be negative */ + int getRowBytes(void) const { return _rowBytes;} + + /** @brief get the fielding of this image */ + FieldEnum getField(void) const { return _field;} + + /** @brief the unique ID of this image */ + const std::string& getUniqueIdentifier(void) const { return _uniqueID;} + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an image */ + class Image : public ImageBase { + protected : + void *_pixelData; /**< @brief the base address of the image */ + void *_OpenCLImage; /**< @brief the OpenCL Image handle */ + + public : + /** @brief ctor */ + Image(OfxPropertySetHandle props); + + /** @brief dtor */ + virtual ~Image(); + + /** @brief get the pixel data for this image */ + void *getPixelData(void) { return _pixelData;} + + /** @brief get the pixel data for this image */ + const void *getPixelData(void) const { return _pixelData;} + + /** @brief get the OpenCL Image for this image */ + void *getOpenCLImage(void) { return _OpenCLImage;} + + /** @brief get the OpenCL Image for this image */ + const void *getOpenCLImage(void) const { return _OpenCLImage;} + + /** @brief return a pixel pointer, returns NULL if (x,y) is outside the image bounds + + x and y are in pixel coordinates + + If the components are custom, then this will return NULL as the support code + can't know the pixel size to do the work. + */ + void *getPixelAddress(int x, int y); + + /** @brief return a pixel pointer, returns NULL if (x,y) is outside the image bounds + + x and y are in pixel coordinates + + If the components are custom, then this will return NULL as the support code + can't know the pixel size to do the work. + */ + const void *getPixelAddress(int x, int y) const; + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an OpenGL texture */ + class Texture : public ImageBase { + protected : + int _index; + int _target; + + public : + /** @brief ctor */ + Texture(OfxPropertySetHandle props); + + /** @brief dtor */ + virtual ~Texture(); + + /** @brief get OpenGL texture id (cast to GLuint) */ + inline int getIndex() const {return _index;} + + /** @brief get OpenGL texture target (cast to GLenum) */ + inline int getTarget() const {return _target;} + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a clip instance */ + class Clip { + protected : + mDeclareProtectedAssignAndCC(Clip); + + /** @brief name of the clip */ + std::string _clipName; + + /** @brief properties for this clip */ + PropertySet _clipProps; + + /** @brief handle for this clip */ + OfxImageClipHandle _clipHandle; + + /** @brief effect instance that owns this clip */ + ImageEffect *_effect; + + /** @brief hidden constructor */ + Clip(ImageEffect *effect, const std::string &name, OfxImageClipHandle handle, OfxPropertySetHandle props); + + /** @brief so one can be made */ + friend class ImageEffect; + + public : + /// get the underlying property set on this clip + const PropertySet &getPropertySet() const {return _clipProps;} + + /// get the underlying property set on this clip + PropertySet &getPropertySet() {return _clipProps;} + + /// get the OFX clip handle + OfxImageClipHandle getHandle() {return _clipHandle;} + + /** @brief get the name */ + const std::string &name(void) const {return _clipName;} + + /** @brief fetch the label */ + void getLabel(std::string &label) const; + + /** @brief fetch the labels */ + void getLabels(std::string &label, std::string &shortLabel, std::string &longLabel) const; + + /** @brief what is the pixel depth images will be given to us as */ + BitDepthEnum getPixelDepth(void) const; + + /** @brief what is the components images will be given to us as */ + PixelComponentEnum getPixelComponents(void) const; + + /** @brief get the number of components in the image */ + int getPixelComponentCount(void) const; + + /** @brief get the string representing the pixel components */ + std::string getPixelComponentsProperty(void) const { return _clipProps.propGetString(kOfxImageEffectPropComponents);} + + /** @brief what is the actual pixel depth of the clip */ + BitDepthEnum getUnmappedPixelDepth(void) const; + + /** @brief what is the component type of the clip */ + PixelComponentEnum getUnmappedPixelComponents(void) const; + + /** @brief get the string representing the pixel components */ + std::string getUnmappedPixelComponentsProperty(void) const { return _clipProps.propGetString(kOfxImageClipPropUnmappedComponents);} + + /** @brief get the components in the image */ + PreMultiplicationEnum getPreMultiplication(void) const; + + /** @brief which spatial field comes first temporally */ + FieldEnum getFieldOrder(void) const; + + /** @brief is the clip connected */ + bool isConnected(void) const; + + /** @brief can the clip be continuously sampled */ + bool hasContinuousSamples(void) const; + + /** @brief get the scale factor that has been applied to this clip */ + double getPixelAspectRatio(void) const; + + /** @brief get the frame rate, in frames per second on this clip, after any clip preferences have been applied */ + double getFrameRate(void) const; + + /** @brief return the range of frames over which this clip has images, after any clip preferences have been applied */ + OfxRangeD getFrameRange(void) const; + + /** @brief get the frame rate, in frames per second on this clip, before any clip preferences have been applied */ + double getUnmappedFrameRate(void) const; + + /** @brief return the range of frames over which this clip has images, before any clip preferences have been applied */ + OfxRangeD getUnmappedFrameRange(void) const; + + /** @brief get the RoD for this clip in the cannonical coordinate system */ + OfxRectD getRegionOfDefinition(double t); + + /** @brief fetch an image + + When finished with, the client code must delete the image. + + If the same image is fetched twice, it must be deleted in each case, they will not be the same pointer. + */ + Image *fetchImage(double t); + + /** @brief fetch an image, with a specific region in cannonical coordinates + + When finished with, the client code must delete the image. + + If the same image is fetched twice, it must be deleted in each case, they will not be the same pointer. + */ + Image *fetchImage(double t, const OfxRectD &bounds); + + /** @brief fetch an image, with a specific region in cannonical coordinates + + When finished with, the client code must delete the image. + + If the same image is fetched twice, it must be deleted in each case, they will not be the same pointer. + */ + Image *fetchImage(double t, const OfxRectD *bounds) + { + if(bounds) + return fetchImage(t, *bounds); + else + return fetchImage(t); + } + +#ifdef OFX_SUPPORTS_OPENGLRENDER + Texture *loadTexture(double t, BitDepthEnum format = eBitDepthNone, const OfxRectD *region = NULL); +#endif + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Class that skins image memory allocation */ + class ImageMemory { + protected : + OfxImageMemoryHandle _handle; + + public : + /** @brief ctor */ + ImageMemory(size_t nBytes, ImageEffect *associatedEffect = 0); + + /** @brief dtor */ + ~ImageMemory(); + + /** @brief lock the memory and return a pointer to it */ + void *lock(void); + + /** @brief unlock the memory */ + void unlock(void); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief POD struct to pass rendering arguments into @ref ImageEffect::render */ + struct RenderArguments { + double time; + OfxPointD renderScale; + OfxRectI renderWindow; + FieldEnum fieldToRender; + bool isEnabledOpenCLRender; + bool isEnabledCudaRender; + bool isEnabledMetalRender; + void* pOpenCLCmdQ; + void* pCudaStream; + void* pMetalCmdQ; +#ifdef OFX_SUPPORTS_OPENGLRENDER + bool openGLEnabled; +#endif + bool sequentialRenderStatus; + bool interactiveRenderStatus; + bool renderQualityDraft; + }; + + /** @brief POD struct to pass rendering arguments into @ref OFX::ImageEffect::isIdentity */ + struct IsIdentityArguments { + double time; + OfxPointD renderScale; + OfxRectI renderWindow; + FieldEnum fieldToRender; + }; + + /** @brief POD struct to pass arguments into @ref OFX::ImageEffect::render */ + struct BeginSequenceRenderArguments { + OfxRangeD frameRange; + double frameStep; + bool isInteractive; + OfxPointD renderScale; + bool isEnabledOpenCLRender; + bool isEnabledCudaRender; + bool isEnabledMetalRender; + void* pOpenCLCmdQ; + void* pCudaStream; + void* pMetalCmdQ; +#ifdef OFX_SUPPORTS_OPENGLRENDER + bool openGLEnabled; +#endif + bool sequentialRenderStatus; + bool interactiveRenderStatus; + }; + + /** @brief POD struct to pass arguments into @ref OFX::ImageEffect::beginSequenceRender */ + struct EndSequenceRenderArguments { + bool isInteractive; + OfxPointD renderScale; + bool isEnabledOpenCLRender; + bool isEnabledCudaRender; + bool isEnabledMetalRender; + void* pOpenCLCmdQ; + void* pCudaStream; + void* pMetalCmdQ; +#ifdef OFX_SUPPORTS_OPENGLRENDER + bool openGLEnabled; +#endif + bool sequentialRenderStatus; + bool interactiveRenderStatus; + }; + + /** @brief POD struct to pass arguments into @ref OFX::ImageEffect::getRegionOfDefinition */ + struct RegionOfDefinitionArguments { + double time; + OfxPointD renderScale; + }; + + /** @brief POD struct to pass arguments into @ref OFX::ImageEffect::getRegionsOfInterest */ + struct RegionsOfInterestArguments { + double time; + OfxPointD renderScale; + OfxRectD regionOfInterest; + }; + + /** @brief Class used to set regions of interest on a clip in @ref OFX::ImageEffect::getRegionsOfInterest + + This is a base class, the actual class is private and you don't need to see the glue involved. + */ + class RegionOfInterestSetter { + public : + /** @brief function to set the RoI of a clip, pass in the clip to set the RoI of, and the RoI itself */ + virtual void setRegionOfInterest(const Clip &clip, const OfxRectD &RoI) = 0; + }; + + /** @brief POD struct to pass arguments into @ref OFX::ImageEffect::getFramesNeeded */ + struct FramesNeededArguments { + double time; + }; + + /** @brief Class used to set the frames needed to render a single frame of a clip in @ref OFX::ImageEffect::getFramesNeeded + + This is a base class, the actual class is private and you don't need to see the glue involved. + */ + class FramesNeededSetter { + public : + /** @brief function to set the frames needed on a clip, the range is min <= time <= max */ + virtual void setFramesNeeded(const Clip &clip, const OfxRangeD &range) = 0; + }; + + /** @brief Class used to set the clip preferences of the effect. + */ + class ClipPreferencesSetter { + OFX::PropertySet outArgs_; + bool doneSomething_; + typedef std::map StringStringMap; + const StringStringMap& clipDepthPropNames_; + const StringStringMap& clipComponentPropNames_; + const StringStringMap& clipPARPropNames_; + const std::string& extractValueForName(const StringStringMap& m, const std::string& name); + public : + ClipPreferencesSetter( OFX::PropertySet props, + const StringStringMap& depthPropNames, + const StringStringMap& componentPropNames, + const StringStringMap& PARPropNames) + : outArgs_(props) + , doneSomething_(false) + , clipDepthPropNames_(depthPropNames) + , clipComponentPropNames_(componentPropNames) + , clipPARPropNames_(PARPropNames) + {} + + bool didSomething(void) const {return doneSomething_;} + + /** @brief, force the host to set a clip's mapped component type to be \em comps. + + Only callable on non optional clips in all contexts. Must set comps to be one of the types the effect says it supports on the given clip. + + See the OFX API documentation for the default values of this. + */ + void setClipComponents(Clip &clip, PixelComponentEnum comps); + + /** @brief, force the host to set a clip's mapped bit depth be \em bitDepth + + Only callable if the OFX::ImageEffectHostDescription::supportsMultipleClipDepths is true. + + See the OFX API documentation for the default values of this. + */ + void setClipBitDepth(Clip &clip, BitDepthEnum bitDepth); + + /** @brief, force the host to set a clip's mapped Pixel Aspect Ratio to be \em PAR + + Only callable if the OFX::ImageEffectHostDescription::supportsMultipleClipPARs is true. + + Default is up to the host, generally based on the input clips. + + Not supported by most host applications. + */ + void setPixelAspectRatio(Clip &clip, double PAR); + + /** @brief Allows an effect to change the output frame rate + + Only callable if OFX::ImageEffectHostDescription::supportsSetableFrameRate is true. + + Default is controlled by the host, typically the framerate of the input clips. + */ + void setOutputFrameRate(double v); + + /** @brief Set the premultiplication state of the output clip. + + Defaults to the premultiplication state of ??? + */ + void setOutputPremultiplication(PreMultiplicationEnum v); + + /** @brief Set whether the effect can be continously sampled. + + Defaults to false. + */ + void setOutputHasContinousSamples(bool v); + + /** @brief Sets whether the effect will produce different images in all frames, even if the no params or input images are varying (eg: a noise generator). + + Defaults to false. + */ + void setOutputFrameVarying(bool v); + + /** @brief Sets the output fielding + + Default is host dependent, must be one of + - eFieldNone, + - eFieldLower, + - eFieldUpper + */ + void setOutputFielding(FieldEnum v); + }; + + /** @brief POD data structure passing in the instance changed args */ + struct InstanceChangedArgs { + InstanceChangeReason reason; /**< @brief why did it change */ + double time; /**< time of the change */ + OfxPointD renderScale; /**< the renderscale on the instance */ + }; + + /** @brief struct to pass arguments into @ref OFX::ImageEffect::interpolateCustomParam. + It is non-POD (it contains std::string), but it is passed as const ref, so that does + not matter */ + struct InterpolateCustomArgs { + double time; + std::string value1; + std::string value2; + double keytime1; + double keytime2; + double amount; + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an effect instance, plugin implementations need to inherit from this */ + class ImageEffect : public ParamSet + { + protected : + mDeclareProtectedAssignAndCCBase(ImageEffect,ParamSet); + + private : + /** @brief to get access to the effect handle without exposing it generally via a function */ + friend class ImageMemory; + + /** @brief The effect handle */ + OfxImageEffectHandle _effectHandle; + + /** @brief properties for this clip */ + PropertySet _effectProps; + + /** @brief the context of the effect */ + ContextEnum _context; + + /** @brief Set of all previously defined parameters, defined on demand */ + std::map _fetchedClips; + + /** @brief the overlay interacts that are open on this image effect */ + std::list _overlayInteracts; + + /** @brief cached result of whether progress start succeeded. */ + bool _progressStartSuccess; + public : + /** @brief ctor */ + ImageEffect(OfxImageEffectHandle handle); + + /** @brief dtor */ + virtual ~ImageEffect(); + + const PropertySet &getPropertySet() const {return _effectProps;} + + PropertySet &getPropertySet() {return _effectProps;} + + + OfxImageEffectHandle getHandle(void) const {return _effectHandle;} + + /** @brief the context this effect was instantiate in */ + ContextEnum getContext(void) const; + + /** @brief size of the project */ + OfxPointD getProjectSize(void) const; + + /** @brief origin of the project */ + OfxPointD getProjectOffset(void) const; + + /** @brief extent of the project */ + OfxPointD getProjectExtent(void) const; + + /** @brief pixel aspect ratio of the project */ + double getProjectPixelAspectRatio(void) const; + + /** @brief how long does the effect last */ + double getEffectDuration(void) const; + + /** @brief the frame rate of the project */ + double getFrameRate(void) const; + + /** @brief is the instance currently being interacted with */ + bool isInteractive(void) const; + + /** @brief set the instance to be sequentially renderred, this should have been part of clip preferences! */ + void setSequentialRender(bool v); + + /** @brief Have we informed the host we want to be seqentially renderred ? */ + bool getSequentialRender(void) const; + + /** @brief Does the plugin support image tiling ? Can only be called from changedParam or changedClip. */ + void setSupportsTiles(bool v); + + /** @brief Have we informed the host we support image tiling ? */ + bool getSupportsTiles(void) const; + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief Does the plugin support OpenGL accelerated rendering (but is also capable of CPU rendering) ? Can only be called from changedParam or changedClip. */ + void setSupportsOpenGLRender(bool v); + + /** @brief Does the plugin require OpenGL accelerated rendering ? Can only be called from changedParam or changedClip. */ + void setNeedsOpenGLRender(bool v); +#endif + + /** @brief notify host that the internal data structures need syncing back to parameters for persistance and so on. This is reset by the host after calling SyncPrivateData. */ + void setParamSetNeedsSyncing(); + + OFX::Message::MessageReplyEnum sendMessage(OFX::Message::MessageTypeEnum type, const std::string& id, const std::string& msg); + + OFX::Message::MessageReplyEnum setPersistentMessage(OFX::Message::MessageTypeEnum type, const std::string& id, const std::string& msg); + OFX::Message::MessageReplyEnum clearPersistentMessage(); + + /** @brief Fetch the named clip from this instance + + The returned clip \em must not be deleted by the client code. This is all managed by the ImageEffect itself. + */ + Clip *fetchClip(const std::string &name); + + /** @brief does the host want us to abort rendering? */ + bool abort(void) const; + + /** @brief adds a new interact to the set of interacts open on this effect */ + void addOverlayInteract(OverlayInteract *interact); + + /** @brief removes an interact to the set of interacts open on this effect */ + void removeOverlayInteract(OverlayInteract *interact); + + /** @brief force all overlays on this interact to be redrawn */ + void redrawOverlays(void); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + bool flushOpenGLResources(void); +#endif + + //////////////////////////////////////////////////////////////////////////////// + // these are actions that need to be overridden by a plugin that implements an effect host + + /** @brief The purge caches action, a request for an instance to free up as much memory as possible in low memory situations */ + virtual void purgeCaches(void); + + /** @brief The sync private data action, called when the effect needs to sync any private data to persistant parameters */ + virtual void syncPrivateData(void); + + /** @brief client render function, this is one of the few that must be overridden */ + virtual void render(const RenderArguments &args) = 0; + + /** @brief client begin sequence render function */ + virtual void beginSequenceRender(const BeginSequenceRenderArguments &args); + + /** @brief client end sequence render function */ + virtual void endSequenceRender(const EndSequenceRenderArguments &args); + + /** @brief client is identity function, returns the clip and time for the identity function + + If the effect would do no processing for the given param set and render arguments, then this + function should return true and set the \em identityClip pointer to point to the clip that is the identity + and \em identityTime to be the time at which to access the clip for the identity operation. + */ + virtual bool isIdentity(const IsIdentityArguments &args, Clip * &identityClip, double &identityTime); + + /** @brief The get RoD action. + + If the effect wants change the rod from the default value (which is the union of RoD's of all input clips) + it should set the \em rod argument and return true. + + This is all in cannonical coordinates. + */ + virtual bool getRegionOfDefinition(const RegionOfDefinitionArguments &args, OfxRectD &rod); + + /** @brief the get region of interest action + + If the effect wants change its region of interest on any input clip from the default values (which is the same as the RoI in the arguments) + it should do so by calling the OFX::RegionOfInterestSetter::setRegionOfInterest function on the \em rois argument. + + Note, everything is in \em cannonical \em coordinates. + */ + virtual void getRegionsOfInterest(const RegionsOfInterestArguments &args, RegionOfInterestSetter &rois); + + /** @brief the get frames needed action + + If the effect wants change the frames needed on an input clip from the default values (which is the same as the frame to be renderred) + it should do so by calling the OFX::FramesNeededSetter::setFramesNeeded function on the \em frames argument. + */ + virtual void getFramesNeeded(const FramesNeededArguments &args, FramesNeededSetter &frames); + + /** @brief get the clip preferences */ + virtual void getClipPreferences(ClipPreferencesSetter &clipPreferences); + + /** @brief the effect is about to be actively edited by a user, called when the first user interface is opened on an instance */ + virtual void beginEdit(void); + + /** @brief the effect is no longer being edited by a user, called when the last user interface is closed on an instance */ + virtual void endEdit(void); + + /** @brief the effect is about to have some values changed */ + virtual void beginChanged(InstanceChangeReason reason); + + /** @brief called when a param has just had its value changed */ + virtual void changedParam(const InstanceChangedArgs &args, const std::string ¶mName); + + /** @brief called when a clip has just been changed in some way (a rewire maybe) */ + virtual void changedClip(const InstanceChangedArgs &args, const std::string &clipName); + + /** @brief the effect has just had some values changed */ + virtual void endChanged(InstanceChangeReason reason); + + /** @brief called when a custom param needs to be interpolated */ + virtual std::string interpolateCustomParam(const InterpolateCustomArgs &args, const std::string ¶mName); + + /** @brief what is the time domain of this effect, valid only in the general context + + return true is range was set, otherwise the default (the union of the time domain of all input clips) is used + */ + virtual bool getTimeDomain(OfxRangeD &range); + +#ifdef OFX_SUPPORTS_OPENGLRENDER + /** @brief OpenGL context attached */ + virtual void contextAttached(void); + + /** @brief OpenGL context detached */ + virtual void contextDetached(void); +#endif + + /// Start doing progress. + void progressStart(const std::string &message, const std::string &messageid = ""); + + /// finish yer progress + void progressEnd(); + + /// set the progress to some level of completion, returns + /// false if you should abandon processing, true to continue + bool progressUpdate(double t); + + /// get the current time on the timeline. This is not necessarily the same + /// time as being passed to an action (eg render) + double timeLineGetTime(); + + /// set the timeline to a specific time + void timeLineGotoTime(double t); + + /// get the first and last times available on the effect's timeline + void timeLineGetBounds(double &t1, double &t2); + }; + + + //////////////////////////////////////////////////////////////////////////////// + /** @brief The OFX::Plugin namespace. All the functions in here needs to be defined by each plugin that uses the support libs. + */ + namespace Plugin { + /** @brief Plugin side function used to identify the plugin to the support library */ + void getPluginIDs(OFX::PluginFactoryArray &id); + + /// If the client has defined its own exception type, allow it to catch it in the main function +#ifdef OFX_CLIENT_EXCEPTION_TYPE + OfxStatus catchException(OFX_CLIENT_EXCEPTION_TYPE &ex); +#endif + }; + +}; + +// undeclare the protected assign and CC macro +#undef mDeclareProtectedAssignAndCC +#undef mDeclareProtectedAssignAndCCBase + +#endif diff --git a/third_party/openfx/Support/include/ofxsInteract.h b/third_party/openfx/Support/include/ofxsInteract.h new file mode 100644 index 000000000..8d2feca38 --- /dev/null +++ b/third_party/openfx/Support/include/ofxsInteract.h @@ -0,0 +1,286 @@ + + +#ifndef _ofxsInteract_H_ +#define _ofxsInteract_H_ +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +/** @file This file contains core code that wraps OFX 'objects' with C++ classes. + +This file only holds code that is visible to a plugin implementation, and so hides much +of the direct OFX objects and any library side only functions. +*/ +#include "ofxsParam.h" + +#include + +/** @brief Nasty macro used to define empty protected copy ctors and assign ops */ +#define mDeclareProtectedAssignAndCC(CLASS) \ + CLASS &operator=(const CLASS &) {assert(false); return *this;} \ + CLASS(const CLASS &) {assert(false); } + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. +*/ +namespace OFX { + + /** @brief forward declaration */ + class ImageEffect; + + /// all image effect interacts have these argumens + struct InteractArgs { + /// ctor + InteractArgs(const PropertySet &props); + double time; /**< @brief The current effect time to draw at */ + OfxPointD renderScale; /**< @brief The current render scale being applied to any image that would be fetched */ + }; + + /** @brief struct to pass arguments into OFX::Interact::draw */ + struct DrawArgs : public InteractArgs { + DrawArgs(const PropertySet &props); + +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + OfxPointD viewportSize; /**< @brief The openGL viewport size for the instance */ +#endif + OfxPointD pixelScale; /**< @brief The current effect time to draw at */ + OfxRGBColourD backGroundColour; /**< @brief The current background colour, ignore the A */ + }; + + /** @brief POD to pass arguments into OFX::Interact pen actions */ + struct PenArgs : public InteractArgs { + PenArgs(const PropertySet &props); + +#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4 + OfxPointD viewportSize; /**< @brief The openGL viewport size for the instance */ +#endif + OfxPointD pixelScale; /**< @brief The current effect time to draw at */ + OfxRGBColourD backGroundColour; /**< @brief The current background colour, ignore the A */ + OfxPointD penPosition; /**< @brief The current pen position */ + OfxPointD penViewportPosition;/**< @brief The current pen position in viewport coordinates */ + double penPressure; /**< @brief The normalised pressure on the pen */ + }; + + /** @brief struct to pass arguments into OFX::Interact key actions + + Note + - some keys cannot be represented as UTF8 strings (eg: the key pad page down key kOfxKey_KP_Page_Up), in which case the key string will be set to "". + - some UTF8 symbols (generally non-English language ones) cannot be represented by one of the keySymbols, in which case the UTF8 string will be set to some non empty value, but the keySymbol will be set to kOfxKey_Unknown. + - in no case will keyString be set to "" and keySymbol be set to kOfxKey_Unknown. + */ + struct KeyArgs : public InteractArgs { + KeyArgs(const PropertySet &props); + + int keySymbol; /**< @brief The key represented as one of the entries in ofxKeySyms.h, see note in OFX::KeyArgs */ + std::string keyString; /**< @brief That key as a UTF8 string, see note in OFX::KeyArgs */ + }; + + /** @brief struct to pass arguments into OFX::Interact focus actions */ + struct FocusArgs : public InteractArgs { + FocusArgs(const PropertySet &props); + + OfxPointD viewportSize; /**< @brief The openGL viewport size for the instance */ + OfxPointD pixelScale; /**< @brief The current effect time to draw at */ + OfxRGBColourD backGroundColour; /**< @brief The current background colour, ignore the A */ + }; + + /** @brief Wraps up an OFX interact object for an Image Effect. It won't work for any other plug-in type at present (it would need to be broken into a hierarchy of classes). + */ + class Interact { + protected : + OfxInteractHandle _interactHandle; /**< @brief The handle for this interact */ + PropertySet _interactProperties; /**< @brief The property set on this interact */ + std::list _slaveParams; /**< @brief List of params we are currently slaved to */ + ImageEffect *_effect; /**< @brief The instance we are associated with */ + + public : + /** @brief ctor */ + Interact(OfxInteractHandle handle); + + /** @brief virtual destructor */ + virtual ~Interact(); + + PropertySet &getProperties() { return _interactProperties; } + + /** @brief The bitdepth of each component in the openGL frame buffer */ + int getBitDepth(void) const; + + /** @brief Does the openGL frame buffer have an alpha */ + bool hasAlpha(void) const; + + /** @brief Returns the size of a real screen pixel under the interact's cannonical projection */ + OfxPointD getPixelScale(void) const; + + /** @brief The suggested colour to draw a widget in an interact. Returns false if there is no suggestion. */ + bool getSuggestedColour(OfxRGBColourD &c) const; + + /** @brief the background colour */ + OfxRGBColourD getBackgroundColour(void) const; + + /** @brief Set a param that the interact should be redrawn on if its value changes */ + void addParamToSlaveTo(Param *p); + + /** @brief Remova a param that the interact should be redrawn on if its value changes */ + void removeParamToSlaveTo(Param *p); + + /** @brief Request a redraw */ + void requestRedraw(void) const; + + /** @brief Swap a buffer in the case of a double bufferred interact, this is possibly a silly one */ + void swapBuffers(void) const; + + //////////////////////////////////////////////////////////////////////////////// + // override the below in derived classes to do something useful + + /** @brief the function called to draw in the interact */ + virtual bool draw(const DrawArgs &args); + + /** @brief the function called to handle pen motion in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + virtual bool penMotion(const PenArgs &args); + + /** @brief the function called to handle pen down events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + virtual bool penDown(const PenArgs &args); + + /** @brief the function called to handle pen up events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + virtual bool penUp(const PenArgs &args); + + /** @brief the function called to handle key down events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + virtual bool keyDown(const KeyArgs &args); + + /** @brief the function called to handle key up events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + virtual bool keyUp(const KeyArgs &args); + + /** @brief the function called to handle key down repeat events in the interact + + returns true if the interact trapped the action in some sense. This will block the action being passed to + any other interact that may share the viewer. + */ + virtual bool keyRepeat(const KeyArgs &args); + + /** @brief Called when the interact is given input focus */ + virtual void gainFocus(const FocusArgs &args); + + /** @brief Called when the interact is loses input focus */ + virtual void loseFocus(const FocusArgs &args); + }; + + /** @brief an interact for an image effect overlay */ + class OverlayInteract : public Interact { + public : + /** @brief ctor */ + OverlayInteract(OfxInteractHandle handle); + + /** @brief dtor */ + virtual ~OverlayInteract(); + }; + + class InteractDescriptor + { + public: + InteractDescriptor():_props(0) {} + virtual ~InteractDescriptor() {} + void setPropertySet(OFX::PropertySet* props){ _props = props; } + virtual Interact* createInstance(OfxInteractHandle handle, ImageEffect *effect) = 0; + void setHasAlpha(); + bool getHasAlpha() const; + void setBitDepth(); + int getBitDepth() const; + virtual OfxPluginEntryPoint* getMainEntry() = 0; + virtual void describe() {} + protected: + OFX::PropertySet* _props; + }; + + typedef InteractDescriptor EffectOverlayDescriptor; + + class ParamInteractDescriptor : public InteractDescriptor + { + public: + ParamInteractDescriptor():InteractDescriptor(){} + virtual ~ParamInteractDescriptor() {} + void setInteractSizeAspect(double asp); + void setInteractMinimumSize(int x, int y); + void setInteractPreferredSize(int x, int y); + virtual void setParamName(const std::string& pName) { _paramName = pName; } + protected: + std::string _paramName; + }; + + class ParamInteract : public Interact + { + public: + ParamInteract(OfxInteractHandle handle, ImageEffect* effect); + virtual ~ParamInteract() {} + double getInteractSizeAspect() const; + OfxPointI getInteractMinimumSize() const; + OfxPointI getInteractPreferredSize() const; + OfxPointI getInteractSize() const; + protected: + ImageEffect* _effect; + }; + + namespace Private + { + OfxStatus interactMainEntry(const char *actionRaw, + const void *handleRaw, + OfxPropertySetHandle inArgsRaw, + OfxPropertySetHandle outArgsRaw, + InteractDescriptor& desc); + } + + template + class InteractMainEntry + { + protected: + static OfxStatus overlayInteractMainEntry(const char *action, const void* handle, OfxPropertySetHandle in, OfxPropertySetHandle out) + { + static DESC desc; + return OFX::Private::interactMainEntry(action, handle, in, out, desc); + } + }; + + template + class DefaultEffectOverlayDescriptor : public EffectOverlayDescriptor, public InteractMainEntry + { + public: + Interact* createInstance(OfxInteractHandle handle, ImageEffect *effect) { return new INSTANCE(handle, effect); } + virtual OfxPluginEntryPoint* getMainEntry() { return InteractMainEntry::overlayInteractMainEntry; } + }; + + template + class DefaultParamInteractDescriptor : public ParamInteractDescriptor, public InteractMainEntry + { + public: + Interact* createInstance(OfxInteractHandle handle, ImageEffect *effect) { return new INSTANCE(handle, effect, _paramNameStatic); } + virtual OfxPluginEntryPoint* getMainEntry() { return InteractMainEntry::overlayInteractMainEntry; } + virtual void setParamName(const std::string& pName) { _paramNameStatic = pName; } + protected: + static std::string _paramNameStatic; + }; + + template std::string OFX::DefaultParamInteractDescriptor::_paramNameStatic; +}; + + +#undef mDeclareProtectedAssignAndCC + +#endif + diff --git a/third_party/openfx/Support/include/ofxsLog.h b/third_party/openfx/Support/include/ofxsLog.h new file mode 100644 index 000000000..1a78e975b --- /dev/null +++ b/third_party/openfx/Support/include/ofxsLog.h @@ -0,0 +1,43 @@ + + +#ifndef _ofxsLog_H_ +#define _ofxsLog_H_ +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +/** @file This file contains OFX logging header code +*/ + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. +*/ +namespace OFX { + + /** @brief this namespace wraps up logging functionality */ + namespace Log { + /** @brief Indent it, not MP sane at the moment */ + void indent(void); + + /** @brief Outdent it, not MP sane at the moment */ + void outdent(void); + + /** @brief Sets the name of the log file. */ + void setFileName(const std::string &value); + + /** @brief Opens the log file, returns whether this was sucessful or not. */ + bool open(void); + + /** @brief Closes the log file. */ + void close(void); + + /** @brief Prints to the log file. */ + void print(const char *format, ...); + + /** @brief Prints to the log file only if the condition is true and prepends a warning notice. */ + void warning(bool condition, const char *format, ...); + + /** @brief Prints to the log file only if the condition is true and prepends an error notice. */ + void error(bool condition, const char *format, ...); + }; +}; + +#endif diff --git a/third_party/openfx/Support/include/ofxsMemory.h b/third_party/openfx/Support/include/ofxsMemory.h new file mode 100644 index 000000000..b73a24951 --- /dev/null +++ b/third_party/openfx/Support/include/ofxsMemory.h @@ -0,0 +1,45 @@ + + +#ifndef _ofxsMemory_H_ +#define _ofxsMemory_H_ +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +/** @file This file contains core code that wraps the ofx memory allocator with C++ functions. + +This file only holds code that is visible to a plugin implementation, and so hides much +of the direct OFX objects and any library side only functions. +*/ + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. +*/ +namespace OFX { + + // forward declaration of class + class ImageEffect; + + /** @brief Namespace for general purpose memory allocation */ + namespace Memory { + /** @brief Allocate memory. + + \arg \e nBytes - the number of bytes to allocate + \arg \e handle - effect instance to assosciate with this memory allocation, or NULL + + This function has the host allocate memory using it's own memory resources + and returns that to the plugin. This memory is distinct to any image memory allocation. + + Succeeds or throws std::bad_alloc + */ + void *allocate(size_t nBytes, + ImageEffect *handle = 0); + + /** @brief release memory + + \arg \e ptr - pointer previously returned by OFX::Memory::allocate + */ + void free(void *ptr) noexcept; + }; + +}; + +#endif diff --git a/third_party/openfx/Support/include/ofxsMessage.h b/third_party/openfx/Support/include/ofxsMessage.h new file mode 100644 index 000000000..648814cd9 --- /dev/null +++ b/third_party/openfx/Support/include/ofxsMessage.h @@ -0,0 +1,30 @@ + + +#ifndef _ofxsMessage_H_ +#define _ofxsMessage_H_ + +namespace OFX +{ + namespace Message + { + enum MessageReplyEnum + { + eMessageReplyOK, + eMessageReplyYes, + eMessageReplyNo, + eMessageReplyFailed + }; + + enum MessageTypeEnum + { + eMessageFatal, + eMessageError, + eMessageMessage, + eMessageWarning, + eMessageLog, + eMessageQuestion + }; + }; +}; + +#endif diff --git a/third_party/openfx/Support/include/ofxsMultiThread.h b/third_party/openfx/Support/include/ofxsMultiThread.h new file mode 100644 index 000000000..757996ba5 --- /dev/null +++ b/third_party/openfx/Support/include/ofxsMultiThread.h @@ -0,0 +1,106 @@ + + +#ifndef _ofxsMultiThread_H_ +#define _ofxsMultiThread_H_ +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +/** @file This file contains core code that wraps OFX 'objects' with C++ classes. + +This file only holds code that is visible to a plugin implementation, and so hides much +of the direct OFX objects and any library side only functions. +*/ + +#include "ofxsCore.h" + +typedef struct OfxMutex* OfxMutexHandle; + +namespace OFX { + + /** @brief Multi thread namespace */ + namespace MultiThread { + + /** @brief Class that wraps up SMP multi-processing */ + class Processor { + private : + /** @brief Function to pass to the multi thread suite */ + static void staticMultiThreadFunction(unsigned int threadIndex, unsigned int threadMax, void *customArg); + + public : + /** @brief ctor */ + Processor(); + + /** @brief dtor */ + virtual ~Processor(); + + /** @brief function that will be called in each thread. ID is from 0..nThreads-1 nThreads are the number of threads it is being run over */ + virtual void multiThreadFunction(unsigned int threadID, unsigned int nThreads) = 0; + + /** @brief call this to kick off multi threading + + The nCPUs is 0, the maximum allowable number of CPUs will be used. + */ + virtual void multiThread(unsigned int nCPUs = 0); + }; + + /** @brief Has the current thread been spawned from an MP */ + bool isSpawnedThread(void); + + /** @brief The number of CPUs that can be used for MP-ing */ + unsigned int getNumCPUs(void); + + /** @brief The index of the current thread. From 0 to numCPUs() - 1 */ + unsigned int getThreadIndex(void); + + /** @brief An OFX mutex */ + class Mutex { + protected : + OfxMutexHandle _handle; /**< @brief The handle */ + + public : + /** @brief ctor */ + Mutex(int lockCount = 0); + + /** @brief dtor */ + virtual ~Mutex(void); + + /** @brief lock it, blocks until lock is gained */ + void lock(); + + /** @brief unlock it */ + void unlock(); + + /** @brief attempt to lock, non-blocking + + \brief returns + - true if the lock was achieved + - false if it could not + */ + bool tryLock(); + }; + + /// a class to wrap around a mutex which is exception safe + /// it locks the mutex on construction and unlocks it on destruction + class AutoMutex { + protected : + Mutex &_mutex; + + public : + /// ctor, acquires the lock + explicit AutoMutex(Mutex &m) + : _mutex(m) + { + _mutex.lock(); + } + + /// dtor, releases the lock + virtual ~AutoMutex() + { + _mutex.unlock(); + } + + }; + }; +}; + +#endif diff --git a/third_party/openfx/Support/include/ofxsParam.h b/third_party/openfx/Support/include/ofxsParam.h new file mode 100644 index 000000000..7603b81a3 --- /dev/null +++ b/third_party/openfx/Support/include/ofxsParam.h @@ -0,0 +1,1868 @@ + + +#ifndef _ofxsParam_H_ +#define _ofxsParam_H_ + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + + +/** @file This file contains core code that wraps OFX parameters with C++ classes. + +This file only holds code that is visible to a plugin implementation, and so hides much +of the direct OFX objects and any library side only functions. + +The classes that skin parameters are broken into two sets, those used during the description phase, +eg OFX::IntParamDescriptor and those representing instances eg, OFX::IntParamInstance. The members on +each represent the actions that can be carried out on those particular OFX objects. + + */ + +#include +#include +#include "ofxsCore.h" + +/** @brief Nasty macro used to define empty protected copy ctors and assign ops */ +#define mDeclareProtectedAssignAndCC(CLASS) \ + CLASS &operator=(const CLASS &) {assert(false); return *this;} \ + CLASS(const CLASS &) {assert(false); } +#define mDeclareProtectedAssignAndCCBase(CLASS,BASE) \ + CLASS &operator=(const CLASS &) {assert(false); return *this;} \ + CLASS(const CLASS &c) : BASE(c) {assert(false); } + +/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. + */ +namespace OFX { + + class ParamInteractDescriptor; + /* forward class declarations of the descriptors */ + class ParamDescriptor; + class ValueParamDescriptor; + class IntParamDescriptor; + class Int2DParamDescriptor; + class Int3DParamDescriptor; + class DoubleParamDescriptor; + class Double2DParamDescriptor; + class Double3DParamDescriptor; + class StringParamDescriptor; + class RGBAParamDescriptor; + class RGBParamDescriptor; + class BooleanParamDescriptor; + class ChoiceParamDescriptor; + class StrChoiceParamDescriptor; + class GroupParamDescriptor; + class PageParamDescriptor; + class PushButtonParamDescriptor; + class CustomParamDescriptor; + class ParamSetDescriptor; + + /* forward class declarations of the instances */ + class Param; + class ValueParam; + class IntParam; + class Int2DParam; + class Int3DParam; + class DoubleParam; + class Double2DParam; + class Double3DParam; + class RGBAParam; + class RGBParam; + class StringParam; + class BooleanParam; + class ChoiceParam; + class StrChoiceParam; + class CustomParam; + class GroupParam; + class PageParam; + class PushButtonParam; + class ParamSet; + + + /** @brief Enumerates the different types of parameter */ + enum ParamTypeEnum {eDummyParam, + eStringParam, + eIntParam, + eInt2DParam, + eInt3DParam, + eDoubleParam, + eDouble2DParam, + eDouble3DParam, + eRGBParam, + eRGBAParam, + eBooleanParam, + eChoiceParam, + eStrChoiceParam, + eCustomParam, + eGroupParam, + ePageParam, + ePushButtonParam, + eParametricParam, + }; + + /** @brief Enumerates the different types of cache invalidation */ + enum CacheInvalidationEnum {eCacheInvalidateValueChange, + eCacheInvalidateValueChangeToEnd, + eCacheInvalidateValueAll}; + + /** @brief Enumerates how we search for keys in an animating parameter */ + enum KeySearchEnum {eKeySearchBackwards, + eKeySearchNear, + eKeySearchForwards}; + + /** @brief Enumerates the differing types of string params */ + enum StringTypeEnum { + eStringTypeSingleLine, + eStringTypeMultiLine, + eStringTypeFilePath, + eStringTypeDirectoryPath, + eStringTypeLabel, + eStringTypeRichTextFormat + }; + + /** @brief Enumerates the differing types of double params */ + enum DoubleTypeEnum { + eDoubleTypePlain, //!< parameter has no special interpretation + eDoubleTypeAngle, //!< parameter is to be interpretted as an angle + eDoubleTypeScale, //!< parameter is to be interpretted as a scale factor + eDoubleTypeTime, //!< parameter represents a time value (1D only) + eDoubleTypeAbsoluteTime, //!< parameter represents an absolute time value (1D only), + eDoubleTypeX, //!< a size in the X dimension dimension (1D only), new for 1.2 + eDoubleTypeXAbsolute, //!< a position in the X dimension (1D only), new for 1.2 + eDoubleTypeY, //!< a size in the Y dimension dimension (1D only), new for 1.2 + eDoubleTypeYAbsolute, //!< a position in the X dimension (1D only), new for 1.2 + eDoubleTypeXY, //!< a size in the X and Y dimension (2D only), new for 1.2 + eDoubleTypeXYAbsolute, //!< a position in the X and Y dimension (2D only), new for 1.2 +#ifdef kOfxParamDoubleTypeNormalisedX + eDoubleTypeNormalisedX, //!< normalised size with respect to the project's X dimension (1D only), deprecated for 1.2 + eDoubleTypeNormalisedY, //!< normalised absolute position on the X axis (1D only), deprecated for 1.2 + eDoubleTypeNormalisedXAbsolute, //!< normalised size wrt to the project's Y dimension (1D only), deprecated for 1.2 + eDoubleTypeNormalisedYAbsolute, //!< normalised absolute position on the Y axis (1D only), deprecated for 1.2 + eDoubleTypeNormalisedXY, //!< normalised to the project's X and Y size (2D only), deprecated for 1.2 + eDoubleTypeNormalisedXYAbsolute, //!< normalised to the projects X and Y size, and is an absolute position on the image plane, deprecated for 1.2 +#endif + }; + + /** @brief Enumerates the differing types of coordinate system for default values */ + enum DefaultCoordinateSystemEnum { + eCoordinatesCanonical, //!< canonical coordinate system + eCoordinatesNormalised, //!< normalized coordinate system + }; + + /** @brief turns a ParamTypeEnum into the char * that raw OFX uses */ + const char * + mapParamTypeEnumToString(ParamTypeEnum v); + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Base class for all param descriptors */ + class ParamDescriptor { + protected : + mDeclareProtectedAssignAndCC(ParamDescriptor); + ParamDescriptor(void) {assert(false);} + + protected : + std::string _paramName; + ParamTypeEnum _paramType; + PropertySet _paramProps; + + /** @brief hidden constructors */ + ParamDescriptor(const std::string &name, ParamTypeEnum type, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + public : + /** @brief dtor */ + virtual ~ParamDescriptor(); + + ParamTypeEnum getType(void) const {return _paramType;} + + /** @brief name */ + const std::string &getName(void) const {return _paramName;} + + /** @brief Get the property set */ + PropertySet &getPropertySet() + { + return _paramProps; + } + + + /** @brief set the label property in a param */ + void setLabel(const std::string &label); + + /** @brief set the label properties in a param */ + void setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel); + + /** @brief set the param hint */ + void setHint(const std::string &hint); + + /** @brief set the script name, default is the name it was created with */ + void setScriptName(const std::string &hint); + + /** @brief set the secretness of the param, defaults to false */ + void setIsSecret(bool v); + + /** @brief set the group param that is the parent of this one, default is to be ungrouped at the root level */ + void setParent(const GroupParamDescriptor &v); + + /** @brief set the icon file name (SVG or PNG) */ + void setIcon(const std::string &v, bool pngFormat); + + /** @brief whether the param is enabled, defaults to true */ + void setEnabled(bool v); + + bool getHostHasNativeOverlayHandle() const; + + void setUseHostNativeOverlayHandle(bool use); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Used to implement dummy parameters for page positioning commands */ + class DummyParamDescriptor : public ParamDescriptor { + public : + /** @brief ctor */ + DummyParamDescriptor(const std::string &name) + : ParamDescriptor(name, eDummyParam, 0) + {} + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a value holding param */ + class ValueParamDescriptor : public ParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(ValueParamDescriptor,ParamDescriptor); + ValueParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + ValueParamDescriptor(const std::string &name, ParamTypeEnum type, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + std::unique_ptr _interact; + public : + /** @brief dtor */ + ~ValueParamDescriptor(); + + /** @brief set whether the param can animate, defaults to true in most cases */ + void setAnimates(bool v); + + /** @brief set whether the param is persistant, defaults to true */ + void setIsPersistant(bool v); + + /** @brief Set's whether the value of the param is significant (ie: affects the rendered image), defaults to true */ + void setEvaluateOnChange(bool v); + + /** @brief Set's how any cache should be invalidated if the parameter is changed, defaults to eCacheInvalidateValueChange */ + void setCacheInvalidation(CacheInvalidationEnum v); + + /// @brief Set whether the param should appear on any undo stack + void setCanUndo(bool v); + + void setInteractDescriptor(ParamInteractDescriptor* desc); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a string param */ + class StringParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(StringParamDescriptor,ValueParamDescriptor); + StringParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + StringParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + + public : + /** @brief set the default value, default is 0 */ + void setDefault(const std::string &v); + + /** @brief sets the kind of the string param, defaults to eStringSingleLine */ + void setStringType(StringTypeEnum v); + + /** @brief if the string param is a file path, say that we are picking an existing file, rather than posibly specifying a new one, defaults to true */ + void setFilePathExists(bool v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an integer param */ + class IntParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(IntParamDescriptor,ValueParamDescriptor); + IntParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + IntParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + + public : + /** @brief set the default value, default is 0 */ + void setDefault(int v); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(int min, int max); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(int min, int max); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an 2d integer param */ + class Int2DParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(Int2DParamDescriptor,ValueParamDescriptor); + Int2DParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Int2DParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + + public : + /** @brief set the dimension labels */ + void setDimensionLabels(const std::string &x, + const std::string &y); + + /** @brief set the default value, default is 0 */ + void setDefault(int x, int y); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(int minX, int minY, + int maxX, int maxY); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(int minX, int minY, + int maxX, int maxY); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an 3d integer param */ + class Int3DParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(Int3DParamDescriptor,ValueParamDescriptor); + Int3DParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Int3DParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + + public : + /** @brief set the dimension labels */ + void setDimensionLabels(const std::string &x, + const std::string &y, + const std::string &z); + + /** @brief set the default value, default is 0 */ + void setDefault(int x, int y, int z); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(int minX, int minY, int minZ, + int maxX, int maxY, int maxZ); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(int minX, int minY, int minZ, + int maxX, int maxY, int maxZ); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Common base to all double param types */ + class BaseDoubleParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(BaseDoubleParamDescriptor,ValueParamDescriptor); + BaseDoubleParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + BaseDoubleParamDescriptor(const std::string &name, ParamTypeEnum type, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + public : + /** @brief set the type of the double param, defaults to eDoubleTypePlain */ + void setDoubleType(DoubleTypeEnum v); + + /** @brief set the type of coordinate system for default values */ + void setDefaultCoordinateSystem(DefaultCoordinateSystemEnum v); + + /** @brief set the sensitivity of any gui slider */ + void setIncrement(double v); + + /** @brief set the number of digits printed after a decimal point in any gui */ + void setDigits(int v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a double param */ + class DoubleParamDescriptor : public BaseDoubleParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(DoubleParamDescriptor,BaseDoubleParamDescriptor); + DoubleParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + DoubleParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + + public : + /** @brief if the double type is Absolute time, show a time marker on the time line if possible */ + void setShowTimeMarker(bool v); + + /** @brief set the default value, default is 0 */ + void setDefault(double v); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(double min, double max); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double min, double max); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a 2D double param */ + class Double2DParamDescriptor : public BaseDoubleParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(Double2DParamDescriptor,BaseDoubleParamDescriptor); + Double2DParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Double2DParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + + public : + /** @brief set the dimension labels */ + void setDimensionLabels(const std::string &x, + const std::string &y); + + /** @brief set kOfxParamPropUseHostOverlayHandle */ + void setUseHostOverlayHandle(bool v); + + /** @brief set the default value, default is 0 */ + void setDefault(double x, double y); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(double minX, double minY, + double maxX, double maxY); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double minX, double minY, + double maxX, double maxY); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a 3D double param */ + class Double3DParamDescriptor : public BaseDoubleParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(Double3DParamDescriptor,BaseDoubleParamDescriptor); + Double3DParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Double3DParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + friend class ParamSetDescriptor; + + public : + /** @brief set the dimension labels */ + void setDimensionLabels(const std::string &x, + const std::string &y, + const std::string &z); + + /** @brief set the default value, default is 0 */ + void setDefault(double x, double y, double z); + + /** @brief set the hard min/max range, default is -DBL_MAX, DBL_MAX */ + void setRange(double minX, double minY, double minZ, + double maxX, double maxY, double maxZ); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double minX, double minY, double minZ, + double maxX, double maxY, double maxZ); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an RGB colour param */ + class RGBParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(RGBParamDescriptor,ValueParamDescriptor); + RGBParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + RGBParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + /** @brief set the dimension labels */ + void setDimensionLabels(const std::string &r, + const std::string &g, + const std::string &b); + + /** @brief set the default value */ + void setDefault(double r, double g, double b); + + /** @brief set the hard min/max range, default is 0., 1. */ + void setRange(double minR, double minG, double minB, + double maxR, double maxG, double maxB); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double minR, double minG, double minB, + double maxR, double maxG, double maxB); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an RGBA colour param */ + class RGBAParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(RGBAParamDescriptor,ValueParamDescriptor); + RGBAParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + RGBAParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + /** @brief set the dimension labels */ + void setDimensionLabels(const std::string &r, + const std::string &g, + const std::string &b, + const std::string &a); + + /** @brief set the default value */ + void setDefault(double r, double g, double b, double a); + + /** @brief set the hard min/max range, default is 0., 1. */ + void setRange(double minR, double minG, double minB, double minA, + double maxR, double maxG, double maxB, double maxA); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double minR, double minG, double minB, double minA, + double maxR, double maxG, double maxB, double maxA); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a boolean param */ + class BooleanParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(BooleanParamDescriptor,ValueParamDescriptor); + BooleanParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + BooleanParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + /** @brief set the default value */ + void setDefault(bool v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a choice param */ + class ChoiceParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(ChoiceParamDescriptor,ValueParamDescriptor); + ChoiceParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + ChoiceParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + /** @brief set the default value */ + void setDefault(int v); + + /** @brief append an option, default is to have not there */ + void appendOption(const std::string &v, const std::string& label = "", const int order = INT_MIN); + + /** @brief how many options do we have */ + int getNOptions(void); + + /** @brief clear all the options so as to add some new ones in */ + void resetOptions(void); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a string choice param */ + class StrChoiceParamDescriptor : public ValueParamDescriptor + { + protected : + mDeclareProtectedAssignAndCCBase(StrChoiceParamDescriptor, ValueParamDescriptor); + StrChoiceParamDescriptor() { assert(false); } + + protected : + /** @brief hidden constructor */ + StrChoiceParamDescriptor(const std::string& p_Name, OfxPropertySetHandle p_Props); + + // so it can make one + friend class ParamSetDescriptor; + + public : + /** @brief set the default value */ + void setDefault(const std::string& p_DefaultValue); + + /** @brief append an option */ + void appendOption(const std::string& p_Enum, const std::string& p_Option, int order = INT_MIN); + + /** @brief how many options do we have */ + int getNOptions(); + + /** @brief clear all the options so as to add some new ones in */ + void resetOptions(); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a group param, not much to it really */ + class GroupParamDescriptor : public ParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(GroupParamDescriptor,ParamDescriptor); + GroupParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + GroupParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + /** @brief whether the initial state of a group is open or closed in a hierarchical layout, defaults to false */ + void setOpen(const bool v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a page param, not much to it really */ + class PageParamDescriptor : public ParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(PageParamDescriptor,ParamDescriptor); + PageParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + PageParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + + /** @brief adds a child parameter. Note the two existing pseudo params, gColumnSkip and gRowSkip */ + void addChild(const ParamDescriptor &p); + + /** @brief dummy page positioning parameter to be passed to @ref OFX::PageParamDescriptor::addChild */ + static DummyParamDescriptor gSkipRow; + + /** @brief dummy page positioning parameter to be passed to @ref OFX::PageParamDescriptor::addChild */ + static DummyParamDescriptor gSkipColumn; + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a push button param, not much to it at all */ + class PushButtonParamDescriptor : public ParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(PushButtonParamDescriptor,ParamDescriptor); + PushButtonParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + PushButtonParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a push button param, not much to it at all */ + class ParametricParamDescriptor : public ParamDescriptor + { + protected: + mDeclareProtectedAssignAndCCBase(ParametricParamDescriptor,ParamDescriptor); + ParametricParamDescriptor(void) {assert(false);} + + protected: + /** @brief hidden constructor */ + ParametricParamDescriptor(const std::string& name, OfxPropertySetHandle props); + + OfxParamHandle _ofxParamHandle; + ParamSetDescriptor* _paramSet; + std::unique_ptr _interact; + + // so it can make one + friend class ParamSetDescriptor; + void setParamSet( ParamSetDescriptor& paramSet ); + + public: + void setDimension( const int dimension ); + + void setRange( const double min, const double max ); + + void setDimensionLabel( const std::string& label, const int id ); + + void setUIColour( const int id, const OfxRGBColourD& color ); + + void addControlPoint( const int id, const OfxTime time, const double x, const double y, const bool addKey ); + + void setIdentity( const int id ); + + void setIdentity(); + + void setInteractDescriptor( ParamInteractDescriptor* desc ); + + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a custom param, haven't added animation support yet */ + class CustomParamDescriptor : public ValueParamDescriptor { + protected : + mDeclareProtectedAssignAndCCBase(CustomParamDescriptor,ValueParamDescriptor); + CustomParamDescriptor(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + CustomParamDescriptor(const std::string &name, OfxPropertySetHandle props); + + // so it can make one + friend class ParamSetDescriptor; + public : + /** @brief set the default value of the param */ + void setDefault(const std::string &v); + + void setCustomInterpolation(bool v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Describes a set of properties */ + class ParamSetDescriptor { + protected : + mDeclareProtectedAssignAndCC(ParamSetDescriptor); + + /** @brief calls the raw OFX routine to define a param */ + void defineRawParam(const std::string &name, ParamTypeEnum paramType, OfxPropertySetHandle &props); + + /** @brief Define a param descriptor of the given type */ + template bool + defineParamDescriptor(const std::string &name, ParamTypeEnum paramType, T * ¶mPtr) + { + paramPtr = NULL; + + // have we made it already in this param set and is it of the correct type + if(ParamDescriptor *param = findPreviouslyDefinedParam(name)) { + if(param->getType() == paramType) { + paramPtr = (T *) param; // could be a dynamic cast here + return true; + } + else + return false; // SHOULD THROW SOMETHING HERE!!!!!!! + } + else { + // ok define one and add it in + OfxPropertySetHandle props; + defineRawParam(name, paramType, props); + + // make out support descriptor class + paramPtr = new T(name, props); + + // add it to our map of described ones + _definedParams[name] = paramPtr; + } + return true; + } + + protected : + /** @brief Properties that belong to this param set */ + PropertySet _paramSetProps; + + /** @brief Parameter set handle */ + OfxParamSetHandle _paramSetHandle; + + /** @brief Set of all previously defined parameters, defined on demand */ + std::map _definedParams; + + /** @brief Hidden ctor */ + ParamSetDescriptor(void); + + /** @brief set the param set handle */ + void setParamSetHandle(OfxParamSetHandle h); + + /** @brief find a param in the map */ + ParamDescriptor *findPreviouslyDefinedParam(const std::string &name); + + public : + OfxParamSetHandle getParamSetHandle() + { + return _paramSetHandle; + } + + virtual ~ParamSetDescriptor(); + /** @brief tries to fetch a ParamDescriptor, returns 0 if it isn't there*/ + ParamDescriptor* getParamDescriptor(const std::string& name) const; + + /** @brief estabilishes the order of page params. Do it by calling it in turn for each page */ + void setPageParamOrder(PageParamDescriptor &p); + + /** @brief Define an integer param */ + IntParamDescriptor *defineIntParam(const std::string &name); + + /** @brief Define a 2D integer param */ + Int2DParamDescriptor *defineInt2DParam(const std::string &name); + + /** @brief Define a 3D integer param */ + Int3DParamDescriptor *defineInt3DParam(const std::string &name); + + /** @brief Define an double param */ + DoubleParamDescriptor *defineDoubleParam(const std::string &name); + + /** @brief Define a 2D double param */ + Double2DParamDescriptor *defineDouble2DParam(const std::string &name); + + /** @brief Define a 3D double param */ + Double3DParamDescriptor *defineDouble3DParam(const std::string &name); + + /** @brief Define a string param */ + StringParamDescriptor *defineStringParam(const std::string &name); + + /** @brief Define a RGBA param */ + RGBAParamDescriptor *defineRGBAParam(const std::string &name); + + /** @brief Define an RGB param */ + RGBParamDescriptor *defineRGBParam(const std::string &name); + + /** @brief Define a Boolean param */ + BooleanParamDescriptor *defineBooleanParam(const std::string &name); + + /** @brief Define a Choice param */ + ChoiceParamDescriptor *defineChoiceParam(const std::string &name); + + /** @brief Define a String Choice param */ + StrChoiceParamDescriptor* defineStrChoiceParam(const std::string& p_Name); + + /** @brief Define a group param */ + GroupParamDescriptor *defineGroupParam(const std::string &name); + + /** @brief Define a Page param */ + PageParamDescriptor *definePageParam(const std::string &name); + + /** @brief Define a push button param */ + PushButtonParamDescriptor *definePushButtonParam(const std::string &name); + + /** @brief Define a parametric param */ + ParametricParamDescriptor* defineParametricParam(const std::string &name); + + /** @brief Define a custom param */ + CustomParamDescriptor *defineCustomParam(const std::string &name); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Base class for all param instances */ + class Param { + protected : + // don't ever use these! + Param &operator=(const Param &/*v1*/) {assert(false); return *this;} + Param(const Param &v) : _paramSet(v._paramSet) {assert(false); } + Param(void) {assert(false);} + + protected : + const ParamSet *_paramSet; // who do I belong to + std::string _paramName; + ParamTypeEnum _paramType; + PropertySet _paramProps; + OfxParamHandle _paramHandle; + + /** @brief hidden constructor */ + Param(const ParamSet *paramSet, const std::string &name, ParamTypeEnum type, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief dtor */ + virtual ~Param(); + + /** @brief get name */ + const std::string &getName(void) const; + + /** @brief, set the label property in a param */ + void setLabel(const std::string &label); + + /** @brief, set the label properties in a param */ + void setLabels(const std::string &label, const std::string &shortLabel, const std::string &longLabel); + + /** @brief return the derived type of this parameter */ + ParamTypeEnum getType(void) const {return _paramType;} + + /** @brief set the secretness of the param, defaults to false */ + void setIsSecret(bool v); + + /** @brief set the param hint */ + void setHint(const std::string &hint); + + /** @brief whether the param is enabled */ + void setEnabled(bool v); + + /** @brief set the param data ptr */ + void setDataPtr(void* ptr); + + /** @brief fetch the label */ + void getLabel(std::string &label) const; + + /** @brief fetch the labels */ + void getLabels(std::string &label, std::string &shortLabel, std::string &longLabel) const; + + /** @brief get whether the param is secret */ + bool getIsSecret(void) const; + + /** @brief whether the param is enabled */ + bool getIsEnable(void) const; + + /** @brief get the param data ptr */ + void* getDataPtr(void) const; + + /** @brief get the param hint */ + std::string getHint(void) const; + + /** @brief get the script name */ + std::string getScriptName(void) const; + + /** @brief get the group param that is the parent of this one */ + GroupParam *getParent(void) const; + + /** @brief get the icon file name (SVG or PNG) */ + std::string getIcon(bool pngFormat) const; + + bool getHostHasNativeOverlayHandle() const; + + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a value holding param */ + class ValueParam : public Param { + protected : + mDeclareProtectedAssignAndCCBase(ValueParam,Param); + ValueParam(void) {assert(false);} + protected : + /** @brief hidden constructor */ + ValueParam(const ParamSet *paramSet, const std::string &name, ParamTypeEnum type, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief dtor */ + ~ValueParam(); + + /** @brief Set's whether the value of the param is significant (ie: affects the rendered image) */ + void setEvaluateOnChange(bool v); + + /** @brief is the param animating */ + bool getIsAnimating(void) const; + + /** @brief is the param animating */ + bool getIsAutoKeying(void) const; + + /** @brief is the param animating */ + bool getIsPersistant(void) const; + + /** @brief Get's whether the value of the param is significant (ie: affects the rendered image) */ + bool getEvaluateOnChange(void) const; + + /** @brief Get's whether the value of the param is significant (ie: affects the rendered image) */ + CacheInvalidationEnum getCacheInvalidation(void) const; + + /** @brief if the param is animating, the number of keys in it, otherwise 0 */ + unsigned int getNumKeys(void); + + /** @brief get the time of the nth key, nth must be between 0 and getNumKeys-1 */ + double getKeyTime(int nthKey); + + /** @brief find the index of a key by a time */ + int getKeyIndex(double time, + KeySearchEnum searchDir); + + /** @brief deletes a key at the given time */ + void deleteKeyAtTime(double time); + + /** @brief delete all the keys */ + void deleteAllKeys(void); + + /** @brief copy parameter from another, including any animation etc... */ + void copyFrom(const ValueParam& from, OfxTime dstOffset, const OfxRangeD *frameRange); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an integer param */ + class IntParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(IntParam,ValueParam); + IntParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + IntParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value */ + void setDefault(int v); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(int min, int max); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(int min, int max); + + /** @brief get the default value */ + void getDefault(int &v); + + /** @brief get the default value */ + int getDefault(void) {int v; getDefault(v); return v;} + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void getRange(int &min, int &max); + + /** @brief set the display min and max, default is to be the same as the range param */ + void getDisplayRange(int &min, int &max); + + /** @brief get value */ + void getValue(int &v); + + /** @brief and a nicer one */ + int getValue(void) {int v; getValue(v); return v;} + + /** @brief get the value at a time */ + void getValueAtTime(double t, int &v); + + /** @brief and a nicer one */ + int getValueAtTime(double t) {int v; getValueAtTime(t, v); return v;} + + /** @brief set value */ + void setValue(int v); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, int v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an integer param */ + class Int2DParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(Int2DParam,ValueParam); + Int2DParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Int2DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value, default is 0 */ + void setDefault(int x, int y); + + /** @brief set the default value, default is 0 */ + void setDefault(const OfxPointI &v) {setDefault(v.x, v.y);} + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(int minX, int minY, + int maxX, int maxY); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(int minX, int minY, + int maxX, int maxY); + + /** @brief get the default value */ + void getDefault(int &x, int &y); + + /** @brief get the default value */ + OfxPointI getDefault(void) {OfxPointI v; getDefault(v.x, v.y); return v;} + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void getRange(int &minX, int &minY, + int& maxX, int &maxY); + + /** @brief set the display min and max, default is to be the same as the range param */ + void getDisplayRange(int &minX, int &minY, + int &maxX, int &maxY); + + /** @brief get value */ + void getValue(int &x, int &y); + + /** @brief get the value */ + OfxPointI getValue(void) {OfxPointI v; getValue(v.x, v.y); return v;} + + /** @brief get the value at a time */ + void getValueAtTime(double t, int &x, int &y); + + /** @brief get the value */ + OfxPointI getValueAtTime(double t) {OfxPointI v; getValueAtTime(t, v.x, v.y); return v;} + + /** @brief set value */ + void setValue(int x, int y); + + /** @brief set the current value */ + void setValue(const OfxPointI &v) {setValue(v.x, v.y);} + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, int x, int y); + + /** @brief set the current value */ + void setValueAtTime(double t, const OfxPointI &v) {setValueAtTime(t, v.x, v.y);} + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an integer param */ + class Int3DParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(Int3DParam,ValueParam); + Int3DParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Int3DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value, default is 0 */ + void setDefault(int x, int y, int z); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void setRange(int minX, int minY, int minZ, + int maxX, int maxY, int maxZ); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(int minX, int minY, int minZ, + int maxX, int maxY, int maxZ); + + /** @brief get the default value */ + void getDefault(int &x, int &y, int &z); + + /** @brief set the hard min/max range, default is INT_MIN, INT_MAX */ + void getRange(int &minX, int &minY, int &minZ, + int& maxX, int &maxY, int &maxZ); + + /** @brief set the display min and max, default is to be the same as the range param */ + void getDisplayRange(int &minX, int &minY, int &minZ, + int& maxX, int &maxY, int &maxZ); + + /** @brief get value */ + void getValue(int &x, int &y, int &z); + + /** @brief get the value at a time */ + void getValueAtTime(double t, int &x, int &y, int &z); + + /** @brief set value */ + void setValue(int x, int y, int z); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, int x, int y, int z); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Common base to all double param types */ + class BaseDoubleParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(BaseDoubleParam,ValueParam); + BaseDoubleParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + BaseDoubleParam(const ParamSet *paramSet, const std::string &name, ParamTypeEnum type, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the sensitivity of any gui slider */ + void setIncrement(double v); + + /** @brief set the number of digits printed after a decimal point in any gui */ + void setDigits(int v); + + /** @brief get the sensitivity of any gui slider */ + void getIncrement(double &v); + + /** @brief get the number of digits printed after a decimal point in any gui */ + void getDigits(int &v); + + /** @brief get the type of the double param */ + void getDoubleType(DoubleTypeEnum &v); + + /** @brief get the type of coordinate system for default values */ + void getDefaultCoordinateSystem(DefaultCoordinateSystemEnum &v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an doubleeger param */ + class DoubleParam : public BaseDoubleParam { + protected : + mDeclareProtectedAssignAndCCBase(DoubleParam,BaseDoubleParam); + DoubleParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + DoubleParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value */ + void setDefault(double v); + + /** @brief if the double type is Absolute time, show a time marker on the time line if possible */ + void setShowTimeMarker(bool v); + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void setRange(double min, double max); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double min, double max); + + /** @brief get the default value */ + void getDefault(double &v); + + /** @brief get the default value */ + double getDefault(void) {double v; getDefault(v); return v;} + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void getRange(double &min, double &max); + + /** @brief set the display min and max, default is to be the same as the range param */ + void getDisplayRange(double &min, double &max); + + /** @brief get value */ + void getValue(double &v); + + /** @brief get value */ + double getValue(void) {double v; getValue(v); return v;} + + /** @brief get the value at a time */ + void getValueAtTime(double t, double &v); + + /** @brief get value */ + double getValueAtTime(double t) {double v; getValueAtTime(t, v); return v;} + + /** @brief set value */ + void setValue(double v); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, double v); + + /** @brief differentiate the param */ + void differentiate(double t, double &v); + + /** @brief differentiate the param */ + double differentiate(double t) {double v; differentiate(t, v); return v;} + + /** @brief integrate the param */ + void integrate(double t1, double t2, double &v); + + /** @brief integrate the param */ + double integrate(double t1, double t2) {double v; integrate(t1, t2, v); return v;} + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an doubleeger param */ + class Double2DParam : public BaseDoubleParam { + protected : + mDeclareProtectedAssignAndCCBase(Double2DParam,BaseDoubleParam); + Double2DParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Double2DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value, default is 0 */ + void setDefault(double x, double y); + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void setRange(double minX, double minY, + double maxX, double maxY); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double minX, double minY, + double maxX, double maxY); + + /** @brief get the default value */ + void getDefault(double &x, double &y); + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void getRange(double &minX, double &minY, + double& maxX, double &maxY); + + /** @brief set the display min and max, default is to be the same as the range param */ + void getDisplayRange(double &minX, double &minY, + double &maxX, double &maxY); + + /** @brief get value */ + void getValue(double &x, double &y); + + /** @brief get the value at a time */ + void getValueAtTime(double t, double &x, double &y); + + /** @brief set value */ + void setValue(double x, double y); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, double x, double y); + + /** @brief differentiate the param */ + void differentiate(double t, double &x, double &y); + + /** @brief differentiate the param */ + OfxPointD differentiate(double t) {OfxPointD v; differentiate(t, v.x, v.y); return v;} + + /** @brief integrate the param */ + void integrate(double t1, double t2, double &x, double &y); + + /** @brief integrate the param */ + OfxPointD integrate(double t1, double t2) {OfxPointD v; integrate(t1, t2, v.x, v.y); return v;} + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an doubleeger param */ + class Double3DParam : public BaseDoubleParam { + protected : + mDeclareProtectedAssignAndCCBase(Double3DParam,BaseDoubleParam); + Double3DParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + Double3DParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value, default is 0 */ + void setDefault(double x, double y, double z); + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void setRange(double minX, double minY, double minZ, + double maxX, double maxY, double maxZ); + + /** @brief set the display min and max, default is to be the same as the range param */ + void setDisplayRange(double minX, double minY, double minZ, + double maxX, double maxY, double maxZ); + + /** @brief get the default value */ + void getDefault(double &x, double &y, double &z); + + /** @brief set the hard min/max range, default is DOUBLE_MIN, DOUBLE_MAX */ + void getRange(double &minX, double &minY, double &minZ, + double& maxX, double &maxY, double &maxZ); + + /** @brief set the display min and max, default is to be the same as the range param */ + void getDisplayRange(double &minX, double &minY, double &minZ, + double& maxX, double &maxY, double &maxZ); + + /** @brief get value */ + void getValue(double &x, double &y, double &z); + + /** @brief get the value at a time */ + void getValueAtTime(double t, double &x, double &y, double &z); + + /** @brief set value */ + void setValue(double x, double y, double z); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, double x, double y, double z); + + /** @brief differentiate the param */ + void differentiate(double t, double &x, double &y, double &z); + + /** @brief differentiate the param */ + Ofx3DPointD differentiate(double t) {Ofx3DPointD v; differentiate(t, v.x, v.y, v.z); return v;} + + /** @brief integrate the param */ + void integrate(double t1, double t2, double &x, double &y, double &z); + + /** @brief integrate the param */ + Ofx3DPointD integrate(double t1, double t2) {Ofx3DPointD v; integrate(t1, t2, v.x, v.y, v.z); return v;} + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an RGB param */ + class RGBParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(RGBParam,ValueParam); + RGBParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + RGBParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value, default is 0 */ + void setDefault(double r, double g, double b); + + /** @brief get default value */ + void getDefault(double &r, double &g, double &b); + + /** @brief get value */ + void getValue(double &r, double &g, double &b); + + /** @brief get the value at a time */ + void getValueAtTime(double t, double &r, double &g, double &b); + + /** @brief set value */ + void setValue(double r, double g, double b); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, double r, double g, double b); + }; + + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up an RGB param */ + class RGBAParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(RGBAParam,ValueParam); + RGBAParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + RGBAParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + public : + /** @brief set the default value, default is 0 */ + void setDefault(double r, double g, double b, double a); + + /** @brief get default value */ + void getDefault(double &r, double &g, double &b, double &a); + + /** @brief get value */ + void getValue(double &r, double &g, double &b, double &a); + + /** @brief get the value at a time */ + void getValueAtTime(double t, double &r, double &g, double &b, double &a); + + /** @brief set value */ + void setValue(double r, double g, double b, double a); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, double r, double g, double b, double a); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a string param */ + class StringParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(StringParam,ValueParam); + StringParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + StringParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + friend class ParamSet; + + public : + /** @brief set the default value */ + void setDefault(const std::string &v); + + /** @brief get the default value */ + void getDefault(std::string &v); + + /** @brief get value */ + void getValue(std::string &v); + + /** @brief get the value at a time */ + void getValueAtTime(double t, std::string &v); + + /** @brief set value */ + void setValue(const std::string &v); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, const std::string &v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a choice param */ + class ChoiceParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(ChoiceParam,ValueParam); + ChoiceParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + ChoiceParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + // so it can make one + friend class ParamSet; + public : + /** @brief set the default value */ + void setDefault(int v); + + /** @brief get the default value */ + void getDefault(int &v); + + /** @brief how many options do we have */ + int getNOptions(void); + + /** @brief append an option, default is to have not there */ + void appendOption(const std::string &v, const std::string& label = "", const int order = -1); + + /** @brief set an option */ + void setOption(int item, const std::string &str); + + /** @brief get the option value */ + void getOption(int ix, std::string &v); + + /** @brief clear all the options so as to add some new ones in */ + void resetOptions(void); + + /** @brief get value */ + void getValue(int &v); + + /** @brief get the value at a time */ + void getValueAtTime(double t, int &v); + + /** @brief set value */ + void setValue(int v); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, int v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a string choice param */ + class StrChoiceParam : public StringParam + { + protected : + mDeclareProtectedAssignAndCCBase(StrChoiceParam, StringParam); + StrChoiceParam() { assert(false); } + + protected : + /** @brief hidden constructor */ + StrChoiceParam(const ParamSet* p_ParamSet, const std::string& p_Name, OfxParamHandle p_Handle); + + // so it can make one + friend class ParamSet; + + public : + /** @brief how many options do we have */ + int getNOptions(); + + /** @brief append an option */ + void appendOption(const std::string& p_Enum, const std::string& p_Option, int order = INT_MIN); + + /** @brief set an option */ + void setOption(const std::string& p_Index, const std::string& p_Option); + + /** @brief get the option value */ + void getOption(const std::string& p_Index, std::string& p_Option); + + /** @brief clear all the options so as to add some new ones in */ + void resetOptions(); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a boolean param */ + class BooleanParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(BooleanParam,ValueParam); + BooleanParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + BooleanParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + // so it can make one + friend class ParamSet; + public : + /** @brief set the default value */ + void setDefault(bool v); + + /** @brief get the default value */ + void getDefault(bool &v); + + /** @brief get the default value */ + bool getDefault(void) {bool v; getDefault(v); return v;} + + /** @brief get value */ + void getValue(bool &v); + + /** @brief get value */ + bool getValue(void) {bool v; getValue(v); return v;} + + /** @brief get the value at a time */ + void getValueAtTime(double t, bool &v); + + /** @brief get value */ + bool getValueAtTime(double t) {bool v; getValueAtTime(t, v); return v;} + + /** @brief set value */ + void setValue(bool v); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, bool v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a group param */ + class GroupParam : public Param { + protected : + mDeclareProtectedAssignAndCCBase(GroupParam,Param); + GroupParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + GroupParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + // so it can make one + friend class ParamSet; + public : + /** @brief whether the initial state of a group is open or closed in a hierarchical layout, defaults to true */ + bool getIsOpen(); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a group param */ + class PageParam : public Param { + protected : + mDeclareProtectedAssignAndCCBase(PageParam,Param); + PageParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + PageParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + // so it can make one + friend class ParamSet; + public : + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a custom param, not animation support yet */ + class CustomParam : public ValueParam { + protected : + mDeclareProtectedAssignAndCCBase(CustomParam,ValueParam); + CustomParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + CustomParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + // so it can make one + friend class ParamSet; + public : + /** @brief set the default value of the param */ + void setDefault(const std::string &v); + + /** @brief get the default value of the param */ + void getDefault(std::string &v); + + /** @brief get value */ + void getValue(std::string &v); + + /** @brief get the value at a time */ + void getValueAtTime(double t, std::string &v); + + /** @brief set value */ + void setValue(const std::string &v); + + /** @brief set value */ + void setValue(const char* str); + + /** @brief set the value at a time, implicitly adds a keyframe */ + void setValueAtTime(double t, const std::string &v); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a push button param, not much to it at all */ + class PushButtonParam : public Param { + protected : + mDeclareProtectedAssignAndCCBase(PushButtonParam,Param); + PushButtonParam(void) {assert(false);} + + protected : + /** @brief hidden constructor */ + PushButtonParam(const ParamSet *paramSet, const std::string &name, OfxParamHandle handle); + + // so it can make one + friend class ParamSet; + public : + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief Wraps up a parametric param */ + class ParametricParam : public Param { + private: + mDeclareProtectedAssignAndCCBase(ParametricParam,Param); + ParametricParam(void) {assert( false);} + + protected: + /** @brief hidden constructor */ + ParametricParam(const ParamSet* paramSet, const std::string& name, OfxParamHandle handle); + + // so it can make one + friend class ParamSet; + + public: + double getValue(const int curveIndex, + const OfxTime time, + const double parametricPosition); + int getNControlPoints(const int curveIndex, + const OfxTime time); + std::pair getNthControlPoint(const int curveIndex, + const OfxTime time, + const int nthCtl); + void setNthControlPoints(const int curveIndex, + const OfxTime time, + const int nthCtl, + const double key, + const double value, + const bool addAnimationKey); + void setNthControlPoints(const int curveIndex, + const OfxTime time, + const int nthCtl, + const std::pair ctrlPoint, + const bool addAnimationKey); + void addControlPoint(const int curveIndex, + const OfxTime time, + const double key, + const double value, + const bool addAnimationKey); + void deleteControlPoint(const int curveIndex, + const int nthCtl); + void deleteControlPoint(const int curveIndex); + }; + + //////////////////////////////////////////////////////////////////////////////// + /** @brief A set of parameters in a plugin instance */ + class ParamSet { + protected : + mDeclareProtectedAssignAndCC(ParamSet); + ParamTypeEnum getParamType(const std::string& name) const; + private : + /** @brief Properties that belong to this param set */ + PropertySet _paramSetProps; + + /** @brief Parameter set handle */ + OfxParamSetHandle _paramSetHandle; + + /** @brief Set of all previously fetched parameters, created on demand */ + mutable std::map _fetchedParams; + + /** @brief see if we have a param of the given name in out map */ + Param *findPreviouslyFetchedParam(const std::string &name) const; + + /** @brief calls the raw OFX routine to define a param */ + void fetchRawParam(const std::string &name, ParamTypeEnum paramType, OfxParamHandle &handle) const; + + /** @brief Fetch a param of the given name and type */ + template void + fetchParam(const std::string &name, ParamTypeEnum paramType, T * ¶mPtr) const + { + paramPtr = NULL; + + // have we made it already in this param set and is it an int? + if(Param *param = findPreviouslyFetchedParam(name)) { + if(param->getType() == paramType) { + paramPtr = (T *) param; // could be a dynamic cast here + } + else + throw OFX::Exception::TypeRequest("Fetching param and attempting to return the wrong type"); + } + else { + // ok define one and add it in + OfxParamHandle paramHandle; + fetchRawParam(name, paramType, paramHandle); + + // make out support descriptor class + paramPtr = new T(this, name, paramHandle); + + // add it to our map of described ones + _fetchedParams[name] = paramPtr; + } + } + + protected: + // the following function should be specialized for each param type T + // (see example below with T = CameraParam) + template void + fetchAttribute(OfxImageEffectHandle /*pluginHandle*/, const std::string& /*name*/, T * &/*paramPtr*/) const + { + assert(false); + } + + protected : + /** @brief Hidden ctor */ + ParamSet(void); + + /** @brief set the param set handle */ + void setParamSetHandle(OfxParamSetHandle h); + + public : + virtual ~ParamSet(); + + bool paramExists(const std::string& name) const; + + /// open an undoblock + void beginEditBlock(const std::string &name); + + /// close an undoblock + void endEditBlock(); + + Param* getParam(const std::string& name) const; + + /** @brief Fetch an integer param */ + IntParam *fetchIntParam(const std::string &name) const; + + /** @brief Fetch a 2D integer param */ + Int2DParam *fetchInt2DParam(const std::string &name) const; + + /** @brief Fetch a 3D integer param */ + Int3DParam *fetchInt3DParam(const std::string &name) const; + + /** @brief Fetch an double param */ + DoubleParam *fetchDoubleParam(const std::string &name) const; + + /** @brief Fetch a 2D double param */ + Double2DParam *fetchDouble2DParam(const std::string &name) const; + + /** @brief Fetch a 3D double param */ + Double3DParam *fetchDouble3DParam(const std::string &name) const; + + /** @brief Fetch a string param */ + StringParam *fetchStringParam(const std::string &name) const; + + /** @brief Fetch a RGBA param */ + RGBAParam *fetchRGBAParam(const std::string &name) const; + + /** @brief Fetch an RGB param */ + RGBParam *fetchRGBParam(const std::string &name) const; + + /** @brief Fetch a Boolean param */ + BooleanParam *fetchBooleanParam(const std::string &name) const; + + /** @brief Fetch a Choice param */ + ChoiceParam *fetchChoiceParam(const std::string &name) const; + + /** @brief Fetch a String Choice param */ + StrChoiceParam* fetchStrChoiceParam(const std::string& p_Name) const; + + /** @brief Fetch a group param */ + GroupParam *fetchGroupParam(const std::string &name) const; + + /** @brief Fetch a page param */ + PageParam *fetchPageParam(const std::string &name) const; + + /** @brief Fetch a push button param */ + PushButtonParam *fetchPushButtonParam(const std::string &name) const; + + /** @brief Fetch a custom param */ + CustomParam *fetchCustomParam(const std::string &name) const; + + /** @brief Fetch a parametric param */ + ParametricParam* fetchParametricParam(const std::string &name) const; + }; +}; + +// undeclare the protected assign and CC macro +#undef mDeclareProtectedAssignAndCC +#undef mDeclareProtectedAssignAndCCBase + +#endif diff --git a/third_party/openfx/Support/include/ofxsProcessing.h b/third_party/openfx/Support/include/ofxsProcessing.h new file mode 100644 index 000000000..570788d14 --- /dev/null +++ b/third_party/openfx/Support/include/ofxsProcessing.h @@ -0,0 +1,230 @@ + + +#ifndef _ofxsProcessing_h_ +#define _ofxsProcessing_h_ + +/* + OFX Support Library, a library that skins the OFX plug-in API with C++ classes. + Copyright (C) 2005 The Open Effects Association Ltd + Author Bruno Nicoletti bruno@thefoundry.co.uk + +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 The Open Effects Association Ltd, 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. + +The Open Effects Association Ltd +1 Wardour St +London W1D 6PA +England + +*/ + +#include +#include + +#include "ofxsImageEffect.h" +#include "ofxsMultiThread.h" +#include "ofxsLog.h" + +/** @file This file contains a useful base class that can be used to process images + +The code below is not so much a skin on the base OFX classes, but code used in implementing +specific image processing algorithms. +*/ + +namespace OFX { + + //////////////////////////////////////////////////////////////////////////////// + // base class to process images with + class ImageProcessor : public OFX::MultiThread::Processor { + protected : + OFX::ImageEffect &_effect; /**< @brief effect to render with */ + OFX::Image *_dstImg; /**< @brief image to process into */ + OfxRectI _renderWindow; /**< @brief render window to use */ + bool _isEnabledOpenCLRender; /**< @brief is OpenCL Render Enabled */ + bool _isEnabledCudaRender; /**< @brief is Cuda Render Enabled */ + bool _isEnabledMetalRender; /**< @brief is Metal Render Enabled */ + void* _pOpenCLCmdQ; /**< @brief OpenCL Command Queue Handle */ + void* _pCudaStream; /**< @brief Cuda Stream Handle */ + void* _pMetalCmdQ; /**< @brief Metal Command Queue Handle */ + + public : + /** @brief ctor */ + ImageProcessor(OFX::ImageEffect &effect) + : _effect(effect) + , _dstImg(0) + , _isEnabledOpenCLRender(false) + , _isEnabledCudaRender(false) + , _isEnabledMetalRender(false) + , _pOpenCLCmdQ(NULL) + , _pCudaStream(NULL) + , _pMetalCmdQ(NULL) + { + _renderWindow.x1 = _renderWindow.y1 = _renderWindow.x2 = _renderWindow.y2 = 0; + } + + /** @brief set the destination image */ + void setDstImg(OFX::Image *v) {_dstImg = v; } + + /** @brief set OpenCL, CUDA render arguments */ + void setGPURenderArgs(const OFX::RenderArguments& args) + { + _isEnabledOpenCLRender = args.isEnabledOpenCLRender; + _isEnabledCudaRender = args.isEnabledCudaRender; + _isEnabledMetalRender = args.isEnabledMetalRender; + + if (_isEnabledOpenCLRender) + { + _pOpenCLCmdQ = args.pOpenCLCmdQ; + } + if (_isEnabledCudaRender) + { + _pCudaStream = args.pCudaStream; + } + if (_isEnabledMetalRender) + { + _pMetalCmdQ = args.pMetalCmdQ; + } + } + + /** @brief reset the render window */ + void setRenderWindow(OfxRectI rect) {_renderWindow = rect;} + + /** @brief overridden from OFX::MultiThread::Processor. This function is called once on each SMP thread by the base class */ + void multiThreadFunction(unsigned int threadId, unsigned int nThreads) + { + // slice the y range into the number of threads it has + unsigned int dy = _renderWindow.y2 - _renderWindow.y1; + // the following is equivalent to std::ceil(dy/(double)nThreads); + unsigned int h = (dy+nThreads-1)/nThreads; + if (h == 0) { + // there are more threads than lines to process + h = 1; + } + if (threadId * h >= dy) { + // empty render subwindow + return; + } + unsigned int y1 = _renderWindow.y1 + threadId * h; + + unsigned int step = (threadId + 1) * h; + unsigned int y2 = _renderWindow.y1 + (step < dy ? step : dy); + + OfxRectI win = _renderWindow; + win.y1 = y1; win.y2 = y2; + + // and render that thread on each + multiThreadProcessImages(win); + } + + /** @brief called before any MP is done */ + virtual void preProcess(void) {} + + /** @brief this is called by process to actually process images using OpenCL when isEnabledOpenCLRender is true, override in derived classes */ + virtual void processImagesOpenCL(void) + { + OFX::Log::print("processImagesOpenCL not implemented"); + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + }; + + /** @brief this is called by process to actually process images using CUDA when isEnabledCudaRender is true, override in derived classes */ + virtual void processImagesCuda(void) + { + OFX::Log::print("processImagesCuda not implemented"); + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + }; + + /** @brief this is called by process to actually process images using Metal when isEnabledMetalRender is true, override in derived classes */ + virtual void processImagesMetal(void) + { + OFX::Log::print("processImagesMetal not implemented"); + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + }; + + /** @brief this is called by multiThreadFunction to actually process images, override in derived classes */ + virtual void multiThreadProcessImages(OfxRectI window) + { + OFX::Log::print("multiThreadProcessImages not implemented"); + OFX::throwSuiteStatusException(kOfxStatErrUnsupported); + }; + + /** @brief called before any MP is done */ + virtual void postProcess(void) {} + + /** @brief called to process everything */ + virtual void process(void) + { + // If _dstImg was set, check that the _renderWindow is lying into dstBounds + if (_dstImg) { + const OfxRectI& dstBounds = _dstImg->getBounds(); + // is the renderWindow within dstBounds ? + assert(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 && + dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2); + // exit gracefully in case of error + if (!(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 && + dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2) || + (_renderWindow.x1 >= _renderWindow.x2) || + (_renderWindow.y1 >= _renderWindow.y2)) { + return; + } + } + + // call the pre MP pass + preProcess(); + + if (_isEnabledOpenCLRender) + { + OFX::Log::print("processing via OpenCL"); + processImagesOpenCL(); + } + else if (_isEnabledCudaRender) + { + OFX::Log::print("processing via CUDA"); + processImagesCuda(); + } + else if (_isEnabledMetalRender) + { + OFX::Log::print("processing via Metal"); + processImagesMetal(); + } + else // is CPU + { + OFX::Log::print("processing via CPU"); + // make sure there are at least 4096 pixels per CPU and at least 1 line par CPU + unsigned int nCPUs = (std::min(_renderWindow.x2 - _renderWindow.x1, 4096) * + (_renderWindow.y2 - _renderWindow.y1)) / 4096; + // make sure the number of CPUs is valid (and use at least 1 CPU) + nCPUs = std::max(1u, std::min(nCPUs, OFX::MultiThread::getNumCPUs())); + + // call the base multi threading code, should put a pre & post thread calls in too + multiThread(nCPUs); + } + + // call the post MP pass + postProcess(); + } + + }; + + +}; +#endif diff --git a/third_party/openfx/Support/include/osxDeploy.sh b/third_party/openfx/Support/include/osxDeploy.sh new file mode 100755 index 000000000..e4a002aec --- /dev/null +++ b/third_party/openfx/Support/include/osxDeploy.sh @@ -0,0 +1,172 @@ +#!/bin/bash + +# +# Olive Community Edition - Non-Linear Video Editor +# Copyright (C) 2025 Olive CE Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + + + + + + +# Package all local libraries into an application or plugin bundle on OSX +# +# Author: Frederic Devernay +# +# This script copies the .so, .la and .xml files needed to redistribute a mac application +# This file is strongly inspired from the osx-app.sh script from the Inkscape source code +# +# In the XCode project, the "Runtime search paths" of your binaries should be set to +# "@loader_path/../Frameworks @loader_path/../Libraries" so that it finds libraries +# and frameworks at runtime. +# If using a Makefile, you should add the following flags at link time: +# -Wl,-rpath,@loader_path/../Frameworks -Wl,-rpath,@loader_path/../Libraries +# +# References: +# http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html +# http://www.dribin.org/dave/blog/archives/2009/11/15/rpath/ + +# env LANG=C is necessary so that sed doesn't try to interpret the binary file with a specific encoding +LANG=C +export LANG + +if [ $# != 2 ]; then + echo "Usage: $0 AppName.app|Bundle.bundle Executablename" + echo "moves macports and local libraries into AppName.app" + exit 1 +fi + +MACPORTS=/opt/local +HOMEBREW=/brew2/local +LOCAL=/usr/local + +# add to PATH +PATH="$MACPORTS/bin:$HOMEBREW/bin:$LOCAL/bin:$PATH" + +if ! port help > /dev/null 2>&1; then + echo "Please make sure that MacPorts is installed in /opt/local" + exit 1 +fi + + +package="$1" +binary="$package/Contents/MacOS/$2" +libdir="Libraries" +pkglib="$package/Contents/$libdir" + +if [ ! -x "$binary" ]; then + echo "Error: $binary does not exist or is not an executable" + exit 1 +fi + +rpath=`otool -l $binary | grep -A 3 LC_RPATH |grep path|awk '{ print $2 }'` +if [[ ! ("$rpath" == *"@loader_path/../Libraries"*) ]]; then + echo "Error:: The runtime search path in $binary does not contain \"@loader_path/../Libraries\". Please set it in your Xcode project, or link the binary with the flags -Xlinker -rpath -Xlinker \"@loader_path/../Libraries\"" + exit 1 +fi +# Test dirs +test -d "$pkglib" || mkdir "$pkglib" +test -d "$pkglib/share/" || mkdir "$pkglib/share/" + +LIBADD= + +############################# +# test if ImageMagick is used +if otool -L "$binary" | fgrep libMagick > /dev/null; then + # Check that ImageMagick is properly installed + if ! pkg-config --modversion ImageMagick >/dev/null 2>&1; then + echo "Missing ImageMagick -- please install ImageMagick ('sudo port install ImageMagick +no_x11 +universal') and try again." >&2 + exit 1 + fi + + # Update the ImageMagick path in startup script. + IMAGEMAGICKVER=`pkg-config --modversion ImageMagick` + IMAGEMAGICKMAJ=${IMAGEMAGICKVER%.*.*} + IMAGEMAGICKLIB=`pkg-config --variable=libdir ImageMagick` + IMAGEMAGICKSHARE=`pkg-config --variable=prefix ImageMagick`/share + # if I get this right, sed substitutes in the exe the occurences of IMAGEMAGICKVER + # into the actual value retrieved from the package. + # We don't need this because we use MAGICKCORE_PACKAGE_VERSION declared in the + # sed -e "s,IMAGEMAGICKVER,$IMAGEMAGICKVER,g" -i "" $pkgbin/DisparityKillerM + + # copy the ImageMagick libraries (.la and .so) + cp -r "$IMAGEMAGICKLIB/ImageMagick-$IMAGEMAGICKVER" "$pkglib/" + cp -r "$IMAGEMAGICKSHARE/ImageMagick-$IMAGEMAGICKMAJ" "$pkglib/share/" + + LIBADD="$LIBADD $pkglib/ImageMagick-$IMAGEMAGICKVER/modules-*/*/*.so" + WITH_IMAGEMAGICK=yes +fi + +# expand glob patterns in LIBADD +LIBADD=`echo $LIBADD` + +# Find out the library dependencies +# (i.e. $LOCAL or $MACPORTS), then loop until no changes. +a=1 +nfiles=0 +alllibs="" +endl=true +while $endl; do + #echo -e "\033[1mLooking for dependencies.\033[0m Round" $a + libs="`otool -L $pkglib/* $LIBADD $binary 2>/dev/null | fgrep compatibility | cut -d\( -f1 | grep -e $LOCAL'\\|'$HOMEBREW'\\|'$MACPORTS | sort | uniq`" + if [ -n "$libs" ]; then + cp -f $libs $pkglib + alllibs="`ls $alllibs $libs | sort | uniq`" + fi + let "a+=1" + nnfiles=`ls $pkglib | wc -l` + if [ $nnfiles = $nfiles ]; then + endl=false + else + nfiles=$nnfiles + fi +done + +# all the libraries were copied, now change the names... +## We use @rpath instead of @executable_path/../$libdir because it's shorter +## than /opt/local, so it always works. The downside is that the XCode project +## has to link the binary with "Runtime search paths" set correctly +## (e.g. to "@loader_path/../Frameworks @loader_path/../Libraries" ). +if [ -n "$alllibs" ]; then + changes="" + for l in $alllibs; do + changes="$changes -change $l @rpath/`basename $l`" + done + + for f in $pkglib/* $LIBADD "$binary"; do + # avoid directories + if [ -f $f ]; then + if ! install_name_tool $changes $f; then + echo "Error: 'install_name_tool $changes $f' failed" + exit 1 + fi + fi + done +fi + +#if [ "$WITH_IMAGEMAGICK" = "yes" ]; then + # and now, obfuscate all the default paths in dynamic libraries + # and ImageMagick modules and config files + + # generate a pseudo-random string which has the same length as $MACPORTS + RANDSTR="R7bUU6jiFvqrPy6zLVPwIC3b93R2b1RG2qD3567t8hC3b93R2b1RG2qD3567t8h" + MACRAND=${RANDSTR:0:${#MACPORTS}} + HOMEBREWRAND=${RANDSTR:0:${#HOMEBREW}} + LOCALRAND=${RANDSTR:0:${#LOCAL}} + find $pkglib -type f -exec sed -e "s@$MACPORTS@$MACRAND@g" -e "s@$HOMEBREW@$HOMEBREWRAND@g" -e "s@$LOCAL@$LOCALRAND@g" -i "" {} \; + sed -e "s@$MACPORTS@$MACRAND@g" -e "s@$HOMEBREW@$HOMEBREWRAND@g" -e "s@$LOCAL@$LOCALRAND@g" -i "" "$binary" +#fi diff --git a/third_party/openfx/Support/support.doxy b/third_party/openfx/Support/support.doxy new file mode 100644 index 000000000..5aad5f2b5 --- /dev/null +++ b/third_party/openfx/Support/support.doxy @@ -0,0 +1,1074 @@ +# Doxyfile 1.3.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "OFX Support" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = "1.1" + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./doc + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = YES + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ./include ./Library + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs + +FILE_PATTERNS = *.cpp *.h *.H + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similiar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/third_party/openfx/include/DocSrc/footer.html b/third_party/openfx/include/DocSrc/footer.html new file mode 100644 index 000000000..b7846293e --- /dev/null +++ b/third_party/openfx/include/DocSrc/footer.html @@ -0,0 +1,35 @@ + + +
+ +Copyright OpenFX and contributors to the OpenFX project. +SPDX-License-Identifier: BSD-3-Clause + +Copying and redistribution with or without +modification, is permitted provided that the following conditions are met: +
    +
  1. Redistributions of the document must retain the above copyright notice + and this list of conditions.
  2. +
  3. Neither the name of The Open Effects Association Ltd nor names of its + contributors may be used to + endorse or promote products derived from this software without specific + prior written permission.
  4. +
+Automatic documentation generated by Doxygen.
+
diff --git a/third_party/openfx/include/DocSrc/ofx_footer.html b/third_party/openfx/include/DocSrc/ofx_footer.html new file mode 100644 index 000000000..0a2e2979e --- /dev/null +++ b/third_party/openfx/include/DocSrc/ofx_footer.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + diff --git a/third_party/openfx/include/DocSrc/ofx_header.html b/third_party/openfx/include/DocSrc/ofx_header.html new file mode 100644 index 000000000..560329d14 --- /dev/null +++ b/third_party/openfx/include/DocSrc/ofx_header.html @@ -0,0 +1,73 @@ + + + + + + + + + +$projectname: $title +$title + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ + diff --git a/third_party/openfx/include/DocSrc/ofx_style.css b/third_party/openfx/include/DocSrc/ofx_style.css new file mode 100644 index 000000000..18069aa7a --- /dev/null +++ b/third_party/openfx/include/DocSrc/ofx_style.css @@ -0,0 +1,1456 @@ + + +/* The standard CSS for doxygen 1.8.6 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +/* OFX Top level nav */ +.navbar-nav { + font-size: 13px; + background-color: #222; + border-color: #080808; + &>li>a{ + color: #999; + &:hover{ + color: #fff; + background-color: #000; + } + } +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 4px 6px; + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: bold; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('ftv2folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('ftv2folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('ftv2doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + margin-left: 0px; + padding-left: 0px; +} + +dl.note +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00D000; +} + +dl.deprecated +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #505050; +} + +dl.todo +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00C0E0; +} + +dl.test +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #3030E0; +} + +dl.bug +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + diff --git a/third_party/openfx/include/OFX_navheader.png b/third_party/openfx/include/OFX_navheader.png new file mode 100644 index 000000000..d2d3ff8f1 Binary files /dev/null and b/third_party/openfx/include/OFX_navheader.png differ diff --git a/third_party/openfx/include/ofx-native-v1.5_aces-v1.3_ocio-v2.3.h b/third_party/openfx/include/ofx-native-v1.5_aces-v1.3_ocio-v2.3.h new file mode 100644 index 000000000..538550be8 --- /dev/null +++ b/third_party/openfx/include/ofx-native-v1.5_aces-v1.3_ocio-v2.3.h @@ -0,0 +1,839 @@ + + +#ifndef _ofx_native_v1_5_aces_v1_3_ocio_v2_3_h_ +#define _ofx_native_v1_5_aces_v1_3_ocio_v2_3_h_ + +// Copyright OpenFX and contributors to the OpenFX project. +// SPDX-License-Identifier: BSD-3-Clause + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file ofx-native-v1.5_aces-v1.3_ocio-v2.3.h +Contains the list of supported colourspaces. +This file was auto-generated by scripts/genColour from ofx-native-v1.5_aces-v1.3_ocio-v2.3. +*/ + +// For use with kOfxImageEffectPropColourManagementAvailableConfigs +#define kOfxConfigIdentifier "ofx-native-v1.5_aces-v1.3_ocio-v2.3" + +// Basic Colourspaces +// These colourspaces are generic names for any colourspace with the correct attributes. + +/** @brief ofx_display_hdr +Any display-referred HDR video such as Rec. 2100 HLG or PQ. +*/ +#define kOfxColourspaceOfxDisplayHdr "ofx_display_hdr" +#define kOfxColourspaceOfxDisplayHdrLabel "OFX generic display HDR" +#define kOfxColourspaceOfxDisplayHdrEncoding "hdr-video" +#define kOfxColourspaceOfxDisplayHdrIsData false +#define kOfxColourspaceOfxDisplayHdrIsBasic true +#define kOfxColourspaceOfxDisplayHdrIsCore true +#define kOfxColourspaceOfxDisplayHdrIsDisplay true + +/** @brief ofx_display_sdr +Any display-referred SDR video such as Rec. 709. +*/ +#define kOfxColourspaceOfxDisplaySdr "ofx_display_sdr" +#define kOfxColourspaceOfxDisplaySdrLabel "OFX generic display SDR" +#define kOfxColourspaceOfxDisplaySdrEncoding "sdr-video" +#define kOfxColourspaceOfxDisplaySdrIsData false +#define kOfxColourspaceOfxDisplaySdrIsBasic true +#define kOfxColourspaceOfxDisplaySdrIsCore true +#define kOfxColourspaceOfxDisplaySdrIsDisplay true + +/** @brief ofx_raw +Image values should not be treated as colour, e.g. motion vectors or masks. +*/ +#define kOfxColourspaceOfxRaw "ofx_raw" +#define kOfxColourspaceOfxRawLabel "OFX generic raw" +#define kOfxColourspaceOfxRawEncoding "" +#define kOfxColourspaceOfxRawIsData true +#define kOfxColourspaceOfxRawIsBasic true +#define kOfxColourspaceOfxRawIsCore true +#define kOfxColourspaceOfxRawIsDisplay false + +/** @brief ofx_scene_linear +Any scene-referred linear colourspace. +*/ +#define kOfxColourspaceOfxSceneLinear "ofx_scene_linear" +#define kOfxColourspaceOfxSceneLinearLabel "OFX generic scene linear" +#define kOfxColourspaceOfxSceneLinearEncoding "scene-linear" +#define kOfxColourspaceOfxSceneLinearIsData false +#define kOfxColourspaceOfxSceneLinearIsBasic true +#define kOfxColourspaceOfxSceneLinearIsCore true +#define kOfxColourspaceOfxSceneLinearIsDisplay false + +/** @brief ofx_scene_log +Any scene-referred colourspace with a log transfer function. +*/ +#define kOfxColourspaceOfxSceneLog "ofx_scene_log" +#define kOfxColourspaceOfxSceneLogLabel "OFX generic scene log" +#define kOfxColourspaceOfxSceneLogEncoding "log" +#define kOfxColourspaceOfxSceneLogIsData false +#define kOfxColourspaceOfxSceneLogIsBasic true +#define kOfxColourspaceOfxSceneLogIsCore true +#define kOfxColourspaceOfxSceneLogIsDisplay false + +// Core Colourspaces + +// srgb_display +// Convert CIE XYZ (D65 white) to sRGB (piecewise EOTF) +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.RGBmonitor_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.RGBmonitor_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.RGBmonitor_D60sim_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.RGBmonitor_D60sim_100nits_dim.a1.0.3 +#define kOfxColourspaceSrgbDisplay "srgb_display" +#define kOfxColourspaceSrgbDisplayLabel "sRGB - Display" +#define kOfxColourspaceSrgbDisplayEncoding "sdr-video" +#define kOfxColourspaceSrgbDisplayIsData false +#define kOfxColourspaceSrgbDisplayIsBasic false +#define kOfxColourspaceSrgbDisplayIsCore true +#define kOfxColourspaceSrgbDisplayIsDisplay true + +// displayp3_display +// Convert CIE XYZ (D65 white) to Apple Display P3 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.DisplayP3_dim.a1.0.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.DisplayP3_dim.a1.0.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.DisplayP3_D60sim_dim.a1.0.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.DisplayP3_D60sim_dim.a1.0.0 +#define kOfxColourspaceDisplayp3Display "displayp3_display" +#define kOfxColourspaceDisplayp3DisplayLabel "Display P3 - Display" +#define kOfxColourspaceDisplayp3DisplayEncoding "sdr-video" +#define kOfxColourspaceDisplayp3DisplayIsData false +#define kOfxColourspaceDisplayp3DisplayIsBasic false +#define kOfxColourspaceDisplayp3DisplayIsCore true +#define kOfxColourspaceDisplayp3DisplayIsDisplay true + +// rec1886_rec709_display +// Convert CIE XYZ (D65 white) to Rec.1886/Rec.709 (HD video) +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec709_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec709_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec709_D60sim_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec709_D60sim_100nits_dim.a1.0.3 +#define kOfxColourspaceRec1886Rec709Display "rec1886_rec709_display" +#define kOfxColourspaceRec1886Rec709DisplayLabel "Rec.1886 Rec.709 - Display" +#define kOfxColourspaceRec1886Rec709DisplayEncoding "sdr-video" +#define kOfxColourspaceRec1886Rec709DisplayIsData false +#define kOfxColourspaceRec1886Rec709DisplayIsBasic false +#define kOfxColourspaceRec1886Rec709DisplayIsCore true +#define kOfxColourspaceRec1886Rec709DisplayIsDisplay true + +// rec1886_rec2020_display +// Convert CIE XYZ (D65 white) to Rec.1886/Rec.2020 (UHD video) +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec2020_100nits_dim.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_P3D65limited_100nits_dim.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_Rec709limited_100nits_dim.a1.1.0 +#define kOfxColourspaceRec1886Rec2020Display "rec1886_rec2020_display" +#define kOfxColourspaceRec1886Rec2020DisplayLabel "Rec.1886 Rec.2020 - Display" +#define kOfxColourspaceRec1886Rec2020DisplayEncoding "sdr-video" +#define kOfxColourspaceRec1886Rec2020DisplayIsData false +#define kOfxColourspaceRec1886Rec2020DisplayIsBasic false +#define kOfxColourspaceRec1886Rec2020DisplayIsCore true +#define kOfxColourspaceRec1886Rec2020DisplayIsDisplay true + +// rec2100_hlg_display +// Convert CIE XYZ (D65 white) to Rec.2100-HLG, 1000 nit +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_1000nits_15nits_HLG.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_1000nits_15nits_HLG.a1.1.0 +#define kOfxColourspaceRec2100HlgDisplay "rec2100_hlg_display" +#define kOfxColourspaceRec2100HlgDisplayLabel "Rec.2100-HLG - Display" +#define kOfxColourspaceRec2100HlgDisplayEncoding "hdr-video" +#define kOfxColourspaceRec2100HlgDisplayIsData false +#define kOfxColourspaceRec2100HlgDisplayIsBasic false +#define kOfxColourspaceRec2100HlgDisplayIsCore true +#define kOfxColourspaceRec2100HlgDisplayIsDisplay true + +// rec2100_pq_display +// Convert CIE XYZ (D65 white) to Rec.2100-PQ +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_1000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_1000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_2000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_2000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_4000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_4000nits_15nits_ST2084.a1.1.0 +#define kOfxColourspaceRec2100PqDisplay "rec2100_pq_display" +#define kOfxColourspaceRec2100PqDisplayLabel "Rec.2100-PQ - Display" +#define kOfxColourspaceRec2100PqDisplayEncoding "hdr-video" +#define kOfxColourspaceRec2100PqDisplayIsData false +#define kOfxColourspaceRec2100PqDisplayIsBasic false +#define kOfxColourspaceRec2100PqDisplayIsCore true +#define kOfxColourspaceRec2100PqDisplayIsDisplay true + +// st2084_p3d65_display +// Convert CIE XYZ (D65 white) to ST-2084 (PQ), P3-D65 primaries +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_1000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_1000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_2000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_2000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_4000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_4000nits_15nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_108nits_7point2nits_ST2084.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_108nits_7point2nits_ST2084.a1.1.0 +#define kOfxColourspaceSt2084P3d65Display "st2084_p3d65_display" +#define kOfxColourspaceSt2084P3d65DisplayLabel "ST2084-P3-D65 - Display" +#define kOfxColourspaceSt2084P3d65DisplayEncoding "hdr-video" +#define kOfxColourspaceSt2084P3d65DisplayIsData false +#define kOfxColourspaceSt2084P3d65DisplayIsBasic false +#define kOfxColourspaceSt2084P3d65DisplayIsCore true +#define kOfxColourspaceSt2084P3d65DisplayIsDisplay true + +// p3d65_display +// Convert CIE XYZ (D65 white) to Gamma 2.6, P3-D65 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_48nits.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D65_48nits.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_Rec709limited_48nits.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_D60sim_48nits.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D65_D60sim_48nits.a1.1.0 +#define kOfxColourspaceP3d65Display "p3d65_display" +#define kOfxColourspaceP3d65DisplayLabel "P3-D65 - Display" +#define kOfxColourspaceP3d65DisplayEncoding "sdr-video" +#define kOfxColourspaceP3d65DisplayIsData false +#define kOfxColourspaceP3d65DisplayIsBasic false +#define kOfxColourspaceP3d65DisplayIsCore true +#define kOfxColourspaceP3d65DisplayIsDisplay true + +// ACES2065-1 +// The "Academy Color Encoding System" reference colorspace. +#define kOfxColourspaceACES20651 "ACES2065-1" +#define kOfxColourspaceACES20651Label "ACES2065-1" +#define kOfxColourspaceACES20651Encoding "scene-linear" +#define kOfxColourspaceACES20651IsData false +#define kOfxColourspaceACES20651IsBasic false +#define kOfxColourspaceACES20651IsCore true +#define kOfxColourspaceACES20651IsDisplay false + +// ACEScc +// Convert ACEScc to ACES2065-1 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScc.a1.0.3 +#define kOfxColourspaceACEScc "ACEScc" +#define kOfxColourspaceACESccLabel "ACEScc" +#define kOfxColourspaceACESccEncoding "log" +#define kOfxColourspaceACESccIsData false +#define kOfxColourspaceACESccIsBasic false +#define kOfxColourspaceACESccIsCore true +#define kOfxColourspaceACESccIsDisplay false + +// ACEScct +// Convert ACEScct to ACES2065-1 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScct_to_ACES.a1.0.3 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScct.a1.0.3 +#define kOfxColourspaceACEScct "ACEScct" +#define kOfxColourspaceACEScctLabel "ACEScct" +#define kOfxColourspaceACEScctEncoding "log" +#define kOfxColourspaceACEScctIsData false +#define kOfxColourspaceACEScctIsBasic false +#define kOfxColourspaceACEScctIsCore true +#define kOfxColourspaceACEScctIsDisplay false + +// ACEScg +// Convert ACEScg to ACES2065-1 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScg_to_ACES.a1.0.3 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScg.a1.0.3 +#define kOfxColourspaceACEScg "ACEScg" +#define kOfxColourspaceACEScgLabel "ACEScg" +#define kOfxColourspaceACEScgEncoding "scene-linear" +#define kOfxColourspaceACEScgIsData false +#define kOfxColourspaceACEScgIsBasic false +#define kOfxColourspaceACEScgIsCore true +#define kOfxColourspaceACEScgIsDisplay false + +// lin_p3d65 +// Convert ACES2065-1 to linear P3 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Linear_P3-D65:1.0 +#define kOfxColourspaceLinP3d65 "lin_p3d65" +#define kOfxColourspaceLinP3d65Label "Linear P3-D65" +#define kOfxColourspaceLinP3d65Encoding "scene-linear" +#define kOfxColourspaceLinP3d65IsData false +#define kOfxColourspaceLinP3d65IsBasic false +#define kOfxColourspaceLinP3d65IsCore true +#define kOfxColourspaceLinP3d65IsDisplay false + +// lin_rec2020 +// Convert ACES2065-1 to linear Rec.2020 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Linear_Rec2020:1.0 +#define kOfxColourspaceLinRec2020 "lin_rec2020" +#define kOfxColourspaceLinRec2020Label "Linear Rec.2020" +#define kOfxColourspaceLinRec2020Encoding "scene-linear" +#define kOfxColourspaceLinRec2020IsData false +#define kOfxColourspaceLinRec2020IsBasic false +#define kOfxColourspaceLinRec2020IsCore true +#define kOfxColourspaceLinRec2020IsDisplay false + +// lin_rec709_srgb +// Convert ACES2065-1 to linear Rec.709 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Linear_Rec709:1.0 +#define kOfxColourspaceLinRec709Srgb "lin_rec709_srgb" +#define kOfxColourspaceLinRec709SrgbLabel "Linear Rec.709 (sRGB)" +#define kOfxColourspaceLinRec709SrgbEncoding "scene-linear" +#define kOfxColourspaceLinRec709SrgbIsData false +#define kOfxColourspaceLinRec709SrgbIsBasic false +#define kOfxColourspaceLinRec709SrgbIsCore true +#define kOfxColourspaceLinRec709SrgbIsDisplay false + +// g18_rec709_tx +// Convert ACES2065-1 to 1.8 gamma-corrected Rec.709 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma1.8_Rec709-Texture:1.0 +#define kOfxColourspaceG18Rec709Tx "g18_rec709_tx" +#define kOfxColourspaceG18Rec709TxLabel "Gamma 1.8 Rec.709 - Texture" +#define kOfxColourspaceG18Rec709TxEncoding "sdr-video" +#define kOfxColourspaceG18Rec709TxIsData false +#define kOfxColourspaceG18Rec709TxIsBasic false +#define kOfxColourspaceG18Rec709TxIsCore true +#define kOfxColourspaceG18Rec709TxIsDisplay false + +// g22_ap1_tx +// Convert ACES2065-1 to 2.2 gamma-corrected AP1 primaries, ACES ~=D60 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma2.2_AP1-Texture:1.0 +#define kOfxColourspaceG22Ap1Tx "g22_ap1_tx" +#define kOfxColourspaceG22Ap1TxLabel "Gamma 2.2 AP1 - Texture" +#define kOfxColourspaceG22Ap1TxEncoding "sdr-video" +#define kOfxColourspaceG22Ap1TxIsData false +#define kOfxColourspaceG22Ap1TxIsBasic false +#define kOfxColourspaceG22Ap1TxIsCore true +#define kOfxColourspaceG22Ap1TxIsDisplay false + +// g22_rec709_tx +// Convert ACES2065-1 to 2.2 gamma-corrected Rec.709 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma2.2_Rec709-Texture:1.0 +#define kOfxColourspaceG22Rec709Tx "g22_rec709_tx" +#define kOfxColourspaceG22Rec709TxLabel "Gamma 2.2 Rec.709 - Texture" +#define kOfxColourspaceG22Rec709TxEncoding "sdr-video" +#define kOfxColourspaceG22Rec709TxIsData false +#define kOfxColourspaceG22Rec709TxIsBasic false +#define kOfxColourspaceG22Rec709TxIsCore true +#define kOfxColourspaceG22Rec709TxIsDisplay false + +// g24_rec709_tx +// Convert ACES2065-1 to 2.4 gamma-corrected Rec.709 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma2.4_Rec709-Texture:1.0 +#define kOfxColourspaceG24Rec709Tx "g24_rec709_tx" +#define kOfxColourspaceG24Rec709TxLabel "Gamma 2.4 Rec.709 - Texture" +#define kOfxColourspaceG24Rec709TxEncoding "sdr-video" +#define kOfxColourspaceG24Rec709TxIsData false +#define kOfxColourspaceG24Rec709TxIsBasic false +#define kOfxColourspaceG24Rec709TxIsCore true +#define kOfxColourspaceG24Rec709TxIsDisplay false + +// srgb_encoded_ap1_tx +// Convert ACES2065-1 to sRGB Encoded AP1 primaries, ACES ~=D60 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_sRGB_Encoded_AP1-Texture:1.0 +#define kOfxColourspaceSrgbEncodedAp1Tx "srgb_encoded_ap1_tx" +#define kOfxColourspaceSrgbEncodedAp1TxLabel "sRGB Encoded AP1 - Texture" +#define kOfxColourspaceSrgbEncodedAp1TxEncoding "sdr-video" +#define kOfxColourspaceSrgbEncodedAp1TxIsData false +#define kOfxColourspaceSrgbEncodedAp1TxIsBasic false +#define kOfxColourspaceSrgbEncodedAp1TxIsCore true +#define kOfxColourspaceSrgbEncodedAp1TxIsDisplay false + +// srgb_encoded_p3d65_tx +// Convert ACES2065-1 to sRGB Encoded P3-D65 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_sRGB_Encoded_P3-D65-Texture:1.0 +#define kOfxColourspaceSrgbEncodedP3d65Tx "srgb_encoded_p3d65_tx" +#define kOfxColourspaceSrgbEncodedP3d65TxLabel "sRGB Encoded P3-D65 - Texture" +#define kOfxColourspaceSrgbEncodedP3d65TxEncoding "sdr-video" +#define kOfxColourspaceSrgbEncodedP3d65TxIsData false +#define kOfxColourspaceSrgbEncodedP3d65TxIsBasic false +#define kOfxColourspaceSrgbEncodedP3d65TxIsCore true +#define kOfxColourspaceSrgbEncodedP3d65TxIsDisplay false + +// srgb_tx +// Convert ACES2065-1 to sRGB +// CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_sRGB-Texture:1.0 +#define kOfxColourspaceSrgbTx "srgb_tx" +#define kOfxColourspaceSrgbTxLabel "sRGB - Texture" +#define kOfxColourspaceSrgbTxEncoding "sdr-video" +#define kOfxColourspaceSrgbTxIsData false +#define kOfxColourspaceSrgbTxIsBasic false +#define kOfxColourspaceSrgbTxIsCore true +#define kOfxColourspaceSrgbTxIsDisplay false + +// Raw +// The utility "Raw" colorspace. +#define kOfxColourspaceRaw "Raw" +#define kOfxColourspaceRawLabel "Raw" +#define kOfxColourspaceRawEncoding "" +#define kOfxColourspaceRawIsData true +#define kOfxColourspaceRawIsBasic false +#define kOfxColourspaceRawIsCore true +#define kOfxColourspaceRawIsDisplay false + +// Non-core Colourspaces + +// CIE-XYZ-D65 +// The "CIE XYZ (D65)" display connection colorspace. +#define kOfxColourspaceCIEXYZD65 "CIE-XYZ-D65" +#define kOfxColourspaceCIEXYZD65Label "CIE-XYZ-D65" +#define kOfxColourspaceCIEXYZD65Encoding "" +#define kOfxColourspaceCIEXYZD65IsData false +#define kOfxColourspaceCIEXYZD65IsBasic false +#define kOfxColourspaceCIEXYZD65IsCore false +#define kOfxColourspaceCIEXYZD65IsDisplay true + +// p3d60_display +// Convert CIE XYZ (D65 white) to Gamma 2.6, P3-D60 (Bradford adaptation) +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D60_48nits.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D60_48nits.a1.0.3 +#define kOfxColourspaceP3d60Display "p3d60_display" +#define kOfxColourspaceP3d60DisplayLabel "P3-D60 - Display" +#define kOfxColourspaceP3d60DisplayEncoding "sdr-video" +#define kOfxColourspaceP3d60DisplayIsData false +#define kOfxColourspaceP3d60DisplayIsBasic false +#define kOfxColourspaceP3d60DisplayIsCore false +#define kOfxColourspaceP3d60DisplayIsDisplay true + +// p3_dci_display +// Convert CIE XYZ (D65 white) to Gamma 2.6, P3-DCI (DCI white with Bradford adaptation) +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3DCI_48nits.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3DCI_48nits.a1.0.3 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3DCI_D65sim_48nits.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3DCI_D65sim_48nits.a1.1.0 +#define kOfxColourspaceP3DciDisplay "p3_dci_display" +#define kOfxColourspaceP3DciDisplayLabel "P3-DCI - Display" +#define kOfxColourspaceP3DciDisplayEncoding "sdr-video" +#define kOfxColourspaceP3DciDisplayIsData false +#define kOfxColourspaceP3DciDisplayIsBasic false +#define kOfxColourspaceP3DciDisplayIsCore false +#define kOfxColourspaceP3DciDisplayIsDisplay true + +// ADX10 +// Convert ADX10 to ACES2065-1 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ADX10_to_ACES.a1.0.3 +#define kOfxColourspaceADX10 "ADX10" +#define kOfxColourspaceADX10Label "ADX10" +#define kOfxColourspaceADX10Encoding "log" +#define kOfxColourspaceADX10IsData false +#define kOfxColourspaceADX10IsBasic false +#define kOfxColourspaceADX10IsCore false +#define kOfxColourspaceADX10IsDisplay false + +// ADX16 +// Convert ADX16 to ACES2065-1 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ADX16_to_ACES.a1.0.3 +#define kOfxColourspaceADX16 "ADX16" +#define kOfxColourspaceADX16Label "ADX16" +#define kOfxColourspaceADX16Encoding "log" +#define kOfxColourspaceADX16IsData false +#define kOfxColourspaceADX16IsBasic false +#define kOfxColourspaceADX16IsCore false +#define kOfxColourspaceADX16IsDisplay false + +// lin_arri_wide_gamut_3 +// Convert Linear ARRI Wide Gamut 3 to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:Linear_ARRI_Wide_Gamut_3_to_ACES2065-1:1.0 +#define kOfxColourspaceLinArriWideGamut3 "lin_arri_wide_gamut_3" +#define kOfxColourspaceLinArriWideGamut3Label "Linear ARRI Wide Gamut 3" +#define kOfxColourspaceLinArriWideGamut3Encoding "scene-linear" +#define kOfxColourspaceLinArriWideGamut3IsData false +#define kOfxColourspaceLinArriWideGamut3IsBasic false +#define kOfxColourspaceLinArriWideGamut3IsCore false +#define kOfxColourspaceLinArriWideGamut3IsDisplay false + +// arri_logc3_ei800 +// Convert ARRI LogC3 (EI800) to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:ARRI_LogC3_EI800_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.ARRI.Alexa-v3-logC-EI800.a1.v2 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_LogC_EI800_AWG.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.LogC_EI800_AWG_to_ACES.a1.1.0 +#define kOfxColourspaceArriLogc3Ei800 "arri_logc3_ei800" +#define kOfxColourspaceArriLogc3Ei800Label "ARRI LogC3 (EI800)" +#define kOfxColourspaceArriLogc3Ei800Encoding "log" +#define kOfxColourspaceArriLogc3Ei800IsData false +#define kOfxColourspaceArriLogc3Ei800IsBasic false +#define kOfxColourspaceArriLogc3Ei800IsCore false +#define kOfxColourspaceArriLogc3Ei800IsDisplay false + +// lin_arri_wide_gamut_4 +// Convert Linear ARRI Wide Gamut 4 to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:Linear_ARRI_Wide_Gamut_4_to_ACES2065-1:1.0 +#define kOfxColourspaceLinArriWideGamut4 "lin_arri_wide_gamut_4" +#define kOfxColourspaceLinArriWideGamut4Label "Linear ARRI Wide Gamut 4" +#define kOfxColourspaceLinArriWideGamut4Encoding "scene-linear" +#define kOfxColourspaceLinArriWideGamut4IsData false +#define kOfxColourspaceLinArriWideGamut4IsBasic false +#define kOfxColourspaceLinArriWideGamut4IsCore false +#define kOfxColourspaceLinArriWideGamut4IsDisplay false + +// arri_logc4 +// Convert ARRI LogC4 to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:ARRI_LogC4_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.ARRI.ARRI-LogC4.a1.v1 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.LogC4_to_ACES.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_LogC4.a1.1.0 +#define kOfxColourspaceArriLogc4 "arri_logc4" +#define kOfxColourspaceArriLogc4Label "ARRI LogC4" +#define kOfxColourspaceArriLogc4Encoding "log" +#define kOfxColourspaceArriLogc4IsData false +#define kOfxColourspaceArriLogc4IsBasic false +#define kOfxColourspaceArriLogc4IsCore false +#define kOfxColourspaceArriLogc4IsDisplay false + +// bmdfilm_widegamut_gen5 +// Convert Blackmagic Film Wide Gamut (Gen 5) to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:BMDFilm_WideGamut_Gen5_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.BlackmagicDesign.BMDFilm_WideGamut_Gen5.a1.v1 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_BMDFilm_WideGamut_Gen5.a1.v1 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.BMDFilm_WideGamut_Gen5_to_ACES.a1.v1 +#define kOfxColourspaceBmdfilmWidegamutGen5 "bmdfilm_widegamut_gen5" +#define kOfxColourspaceBmdfilmWidegamutGen5Label "BMDFilm WideGamut Gen5" +#define kOfxColourspaceBmdfilmWidegamutGen5Encoding "log" +#define kOfxColourspaceBmdfilmWidegamutGen5IsData false +#define kOfxColourspaceBmdfilmWidegamutGen5IsBasic false +#define kOfxColourspaceBmdfilmWidegamutGen5IsCore false +#define kOfxColourspaceBmdfilmWidegamutGen5IsDisplay false + +// davinci_intermediate_widegamut +// Convert DaVinci Intermediate Wide Gamut to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:DaVinci_Intermediate_WideGamut_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.DaVinci_Intermediate_WideGamut_to_ACES.a1.v1 +#define kOfxColourspaceDavinciIntermediateWidegamut "davinci_intermediate_widegamut" +#define kOfxColourspaceDavinciIntermediateWidegamutLabel "DaVinci Intermediate WideGamut" +#define kOfxColourspaceDavinciIntermediateWidegamutEncoding "log" +#define kOfxColourspaceDavinciIntermediateWidegamutIsData false +#define kOfxColourspaceDavinciIntermediateWidegamutIsBasic false +#define kOfxColourspaceDavinciIntermediateWidegamutIsCore false +#define kOfxColourspaceDavinciIntermediateWidegamutIsDisplay false + +// lin_bmd_widegamut_gen5 +// Convert Linear Blackmagic Wide Gamut (Gen 5) to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:Linear_BMD_WideGamut_Gen5_to_ACES2065-1:1.0 +#define kOfxColourspaceLinBmdWidegamutGen5 "lin_bmd_widegamut_gen5" +#define kOfxColourspaceLinBmdWidegamutGen5Label "Linear BMD WideGamut Gen5" +#define kOfxColourspaceLinBmdWidegamutGen5Encoding "scene-linear" +#define kOfxColourspaceLinBmdWidegamutGen5IsData false +#define kOfxColourspaceLinBmdWidegamutGen5IsBasic false +#define kOfxColourspaceLinBmdWidegamutGen5IsCore false +#define kOfxColourspaceLinBmdWidegamutGen5IsDisplay false + +// lin_davinci_widegamut +// Convert Linear DaVinci Wide Gamut to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:Linear_DaVinci_WideGamut_to_ACES2065-1:1.0 +#define kOfxColourspaceLinDavinciWidegamut "lin_davinci_widegamut" +#define kOfxColourspaceLinDavinciWidegamutLabel "Linear DaVinci WideGamut" +#define kOfxColourspaceLinDavinciWidegamutEncoding "scene-linear" +#define kOfxColourspaceLinDavinciWidegamutIsData false +#define kOfxColourspaceLinDavinciWidegamutIsBasic false +#define kOfxColourspaceLinDavinciWidegamutIsCore false +#define kOfxColourspaceLinDavinciWidegamutIsDisplay false + +// canonlog2_cinemagamut_d55 +// Convert Canon Log 2 Cinema Gamut (Daylight) to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:CanonLog2_CinemaGamut-D55_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CLog2_CGamut_to_ACES.a1.1.0 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_CLog2_CGamut.a1.1.0 +#define kOfxColourspaceCanonlog2CinemagamutD55 "canonlog2_cinemagamut_d55" +#define kOfxColourspaceCanonlog2CinemagamutD55Label "CanonLog2 CinemaGamut D55" +#define kOfxColourspaceCanonlog2CinemagamutD55Encoding "log" +#define kOfxColourspaceCanonlog2CinemagamutD55IsData false +#define kOfxColourspaceCanonlog2CinemagamutD55IsBasic false +#define kOfxColourspaceCanonlog2CinemagamutD55IsCore false +#define kOfxColourspaceCanonlog2CinemagamutD55IsDisplay false + +// canonlog3_cinemagamut_d55 +// Convert Canon Log 3 Cinema Gamut (Daylight) to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:CanonLog3_CinemaGamut-D55_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CLog3_CGamut_to_ACES.a1.1.0 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_CLog3_CGamut.a1.1.0 +#define kOfxColourspaceCanonlog3CinemagamutD55 "canonlog3_cinemagamut_d55" +#define kOfxColourspaceCanonlog3CinemagamutD55Label "CanonLog3 CinemaGamut D55" +#define kOfxColourspaceCanonlog3CinemagamutD55Encoding "log" +#define kOfxColourspaceCanonlog3CinemagamutD55IsData false +#define kOfxColourspaceCanonlog3CinemagamutD55IsBasic false +#define kOfxColourspaceCanonlog3CinemagamutD55IsCore false +#define kOfxColourspaceCanonlog3CinemagamutD55IsDisplay false + +// lin_cinemagamut_d55 +// Convert Linear Canon Cinema Gamut (Daylight) to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:Linear-CinemaGamut-D55_to_ACES2065-1:1.0 +#define kOfxColourspaceLinCinemagamutD55 "lin_cinemagamut_d55" +#define kOfxColourspaceLinCinemagamutD55Label "Linear CinemaGamut D55" +#define kOfxColourspaceLinCinemagamutD55Encoding "scene-linear" +#define kOfxColourspaceLinCinemagamutD55IsData false +#define kOfxColourspaceLinCinemagamutD55IsBasic false +#define kOfxColourspaceLinCinemagamutD55IsCore false +#define kOfxColourspaceLinCinemagamutD55IsDisplay false + +// lin_vgamut +// Convert Linear Panasonic V-Gamut to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Panasonic:Input:Linear_VGamut_to_ACES2065-1:1.0 +#define kOfxColourspaceLinVgamut "lin_vgamut" +#define kOfxColourspaceLinVgamutLabel "Linear V-Gamut" +#define kOfxColourspaceLinVgamutEncoding "scene-linear" +#define kOfxColourspaceLinVgamutIsData false +#define kOfxColourspaceLinVgamutIsBasic false +#define kOfxColourspaceLinVgamutIsCore false +#define kOfxColourspaceLinVgamutIsDisplay false + +// vlog_vgamut +// Convert Panasonic V-Log - V-Gamut to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Panasonic:Input:VLog_VGamut_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.VLog_VGamut_to_ACES.a1.1.0 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_VLog_VGamut.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Panasonic.VLog_VGamut.a1.v1 +#define kOfxColourspaceVlogVgamut "vlog_vgamut" +#define kOfxColourspaceVlogVgamutLabel "V-Log V-Gamut" +#define kOfxColourspaceVlogVgamutEncoding "log" +#define kOfxColourspaceVlogVgamutIsData false +#define kOfxColourspaceVlogVgamutIsBasic false +#define kOfxColourspaceVlogVgamutIsCore false +#define kOfxColourspaceVlogVgamutIsDisplay false + +// lin_redwidegamutrgb +// Convert Linear REDWideGamutRGB to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:RED:Input:Linear_REDWideGamutRGB_to_ACES2065-1:1.0 +#define kOfxColourspaceLinRedwidegamutrgb "lin_redwidegamutrgb" +#define kOfxColourspaceLinRedwidegamutrgbLabel "Linear REDWideGamutRGB" +#define kOfxColourspaceLinRedwidegamutrgbEncoding "scene-linear" +#define kOfxColourspaceLinRedwidegamutrgbIsData false +#define kOfxColourspaceLinRedwidegamutrgbIsBasic false +#define kOfxColourspaceLinRedwidegamutrgbIsCore false +#define kOfxColourspaceLinRedwidegamutrgbIsDisplay false + +// log3g10_redwidegamutrgb +// Convert RED Log3G10 REDWideGamutRGB to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:RED:Input:Log3G10_REDWideGamutRGB_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.RED.Log3G10_REDWideGamutRGB.a1.v1 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_Log3G10_RWG.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.Log3G10_RWG_to_ACES.a1.1.0 +#define kOfxColourspaceLog3g10Redwidegamutrgb "log3g10_redwidegamutrgb" +#define kOfxColourspaceLog3g10RedwidegamutrgbLabel "Log3G10 REDWideGamutRGB" +#define kOfxColourspaceLog3g10RedwidegamutrgbEncoding "log" +#define kOfxColourspaceLog3g10RedwidegamutrgbIsData false +#define kOfxColourspaceLog3g10RedwidegamutrgbIsBasic false +#define kOfxColourspaceLog3g10RedwidegamutrgbIsCore false +#define kOfxColourspaceLog3g10RedwidegamutrgbIsDisplay false + +// lin_sgamut3 +// Convert Linear S-Gamut3 to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_SGamut3_to_ACES2065-1:1.0 +#define kOfxColourspaceLinSgamut3 "lin_sgamut3" +#define kOfxColourspaceLinSgamut3Label "Linear S-Gamut3" +#define kOfxColourspaceLinSgamut3Encoding "scene-linear" +#define kOfxColourspaceLinSgamut3IsData false +#define kOfxColourspaceLinSgamut3IsBasic false +#define kOfxColourspaceLinSgamut3IsCore false +#define kOfxColourspaceLinSgamut3IsDisplay false + +// lin_sgamut3cine +// Convert Linear S-Gamut3.Cine to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_SGamut3Cine_to_ACES2065-1:1.0 +#define kOfxColourspaceLinSgamut3cine "lin_sgamut3cine" +#define kOfxColourspaceLinSgamut3cineLabel "Linear S-Gamut3.Cine" +#define kOfxColourspaceLinSgamut3cineEncoding "scene-linear" +#define kOfxColourspaceLinSgamut3cineIsData false +#define kOfxColourspaceLinSgamut3cineIsBasic false +#define kOfxColourspaceLinSgamut3cineIsCore false +#define kOfxColourspaceLinSgamut3cineIsDisplay false + +// lin_venice_sgamut3 +// Convert Linear Venice S-Gamut3 to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_Venice_SGamut3_to_ACES2065-1:1.0 +#define kOfxColourspaceLinVeniceSgamut3 "lin_venice_sgamut3" +#define kOfxColourspaceLinVeniceSgamut3Label "Linear Venice S-Gamut3" +#define kOfxColourspaceLinVeniceSgamut3Encoding "scene-linear" +#define kOfxColourspaceLinVeniceSgamut3IsData false +#define kOfxColourspaceLinVeniceSgamut3IsBasic false +#define kOfxColourspaceLinVeniceSgamut3IsCore false +#define kOfxColourspaceLinVeniceSgamut3IsDisplay false + +// lin_venice_sgamut3cine +// Convert Linear Venice S-Gamut3.Cine to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_Venice_SGamut3Cine_to_ACES2065-1:1.0 +#define kOfxColourspaceLinVeniceSgamut3cine "lin_venice_sgamut3cine" +#define kOfxColourspaceLinVeniceSgamut3cineLabel "Linear Venice S-Gamut3.Cine" +#define kOfxColourspaceLinVeniceSgamut3cineEncoding "scene-linear" +#define kOfxColourspaceLinVeniceSgamut3cineIsData false +#define kOfxColourspaceLinVeniceSgamut3cineIsBasic false +#define kOfxColourspaceLinVeniceSgamut3cineIsCore false +#define kOfxColourspaceLinVeniceSgamut3cineIsDisplay false + +// slog3_sgamut3 +// Convert Sony S-Log3 S-Gamut3 to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_SGamut3_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.SLog3_SGamut3.a1.v1 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_SGamut3.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_SGamut3_to_ACES.a1.1.0 +#define kOfxColourspaceSlog3Sgamut3 "slog3_sgamut3" +#define kOfxColourspaceSlog3Sgamut3Label "S-Log3 S-Gamut3" +#define kOfxColourspaceSlog3Sgamut3Encoding "log" +#define kOfxColourspaceSlog3Sgamut3IsData false +#define kOfxColourspaceSlog3Sgamut3IsBasic false +#define kOfxColourspaceSlog3Sgamut3IsCore false +#define kOfxColourspaceSlog3Sgamut3IsDisplay false + +// slog3_sgamut3cine +// Convert Sony S-Log3 S-Gamut3.Cine to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_SGamut3Cine_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.SLog3_SGamut3Cine.a1.v1 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_SGamut3Cine.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_SGamut3Cine_to_ACES.a1.1.0 +#define kOfxColourspaceSlog3Sgamut3cine "slog3_sgamut3cine" +#define kOfxColourspaceSlog3Sgamut3cineLabel "S-Log3 S-Gamut3.Cine" +#define kOfxColourspaceSlog3Sgamut3cineEncoding "log" +#define kOfxColourspaceSlog3Sgamut3cineIsData false +#define kOfxColourspaceSlog3Sgamut3cineIsBasic false +#define kOfxColourspaceSlog3Sgamut3cineIsCore false +#define kOfxColourspaceSlog3Sgamut3cineIsDisplay false + +// slog3_venice_sgamut3 +// Convert Sony S-Log3 Venice S-Gamut3 to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_Venice_SGamut3_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.Venice_SLog3_SGamut3.a1.v1 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_Venice_SGamut3.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_Venice_SGamut3_to_ACES.a1.1.0 +#define kOfxColourspaceSlog3VeniceSgamut3 "slog3_venice_sgamut3" +#define kOfxColourspaceSlog3VeniceSgamut3Label "S-Log3 Venice S-Gamut3" +#define kOfxColourspaceSlog3VeniceSgamut3Encoding "log" +#define kOfxColourspaceSlog3VeniceSgamut3IsData false +#define kOfxColourspaceSlog3VeniceSgamut3IsBasic false +#define kOfxColourspaceSlog3VeniceSgamut3IsCore false +#define kOfxColourspaceSlog3VeniceSgamut3IsDisplay false + +// slog3_venice_sgamut3cine +// Convert Sony S-Log3 Venice S-Gamut3.Cine to ACES2065-1 +// CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_Venice_SGamut3Cine_to_ACES2065-1:1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.Venice_SLog3_SGamut3Cine.a1.v1 +// AMF Components +// -------------- +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_Venice_SGamut3Cine.a1.1.0 +// ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_Venice_SGamut3Cine_to_ACES.a1.1.0 +#define kOfxColourspaceSlog3VeniceSgamut3cine "slog3_venice_sgamut3cine" +#define kOfxColourspaceSlog3VeniceSgamut3cineLabel "S-Log3 Venice S-Gamut3.Cine" +#define kOfxColourspaceSlog3VeniceSgamut3cineEncoding "log" +#define kOfxColourspaceSlog3VeniceSgamut3cineIsData false +#define kOfxColourspaceSlog3VeniceSgamut3cineIsBasic false +#define kOfxColourspaceSlog3VeniceSgamut3cineIsCore false +#define kOfxColourspaceSlog3VeniceSgamut3cineIsDisplay false + +// camera_rec709 +// Convert ACES2065-1 to Rec.709 camera OETF Rec.709 primaries, D65 white point +// CLFtransformID: urn:aswf:ocio:transformId:1.0:ITU:Utility:AP0_to_Camera_Rec709:1.0 +#define kOfxColourspaceCameraRec709 "camera_rec709" +#define kOfxColourspaceCameraRec709Label "Camera Rec.709" +#define kOfxColourspaceCameraRec709Encoding "sdr-video" +#define kOfxColourspaceCameraRec709IsData false +#define kOfxColourspaceCameraRec709IsBasic false +#define kOfxColourspaceCameraRec709IsCore false +#define kOfxColourspaceCameraRec709IsDisplay false + +/** @brief Roles - standard names used for compatibility with common OCIO configs. +*/ + +/** @brief aces_interchange +Guaranteed to be ACES2065-1. +*/ +#define kOfxColourspaceRoleAcesInterchange "aces_interchange" +#define kOfxColourspaceRoleAcesInterchangeIsBasic false +#define kOfxColourspaceRoleAcesInterchangeIsCore true + +/** @brief cie_xyz_d65_interchange +CIE XYZ colorimetry with the neutral axis at D65. +*/ +#define kOfxColourspaceRoleCieXyzD65Interchange "cie_xyz_d65_interchange" +#define kOfxColourspaceRoleCieXyzD65InterchangeIsBasic false +#define kOfxColourspaceRoleCieXyzD65InterchangeIsCore true + +/** @brief color_picking +The colourspace to use for colour pickers, typically a display colourspace. +*/ +#define kOfxColourspaceRoleColorPicking "color_picking" +#define kOfxColourspaceRoleColorPickingIsBasic false +#define kOfxColourspaceRoleColorPickingIsCore true + +/** @brief color_timing +A colourspace suitable for colour grading, typically a log colourspace. +*/ +#define kOfxColourspaceRoleColorTiming "color_timing" +#define kOfxColourspaceRoleColorTimingIsBasic false +#define kOfxColourspaceRoleColorTimingIsCore true + +/** @brief compositing_log +Any scene-referred colourspace with a log transfer function. +*/ +#define kOfxColourspaceRoleCompositingLog "compositing_log" +#define kOfxColourspaceRoleCompositingLogIsBasic false +#define kOfxColourspaceRoleCompositingLogIsCore true + +/** @brief data +Image values should not be treated as colour, e.g. motion vectors or masks. Mapped to the raw colourspace. +*/ +#define kOfxColourspaceRoleData "data" +#define kOfxColourspaceRoleDataIsBasic false +#define kOfxColourspaceRoleDataIsCore true + +/** @brief matte_paint +A colourspace suitable for matte painting. +*/ +#define kOfxColourspaceRoleMattePaint "matte_paint" +#define kOfxColourspaceRoleMattePaintIsBasic false +#define kOfxColourspaceRoleMattePaintIsCore true + +/** @brief scene_linear +Any scene-referred linear colourspace. +*/ +#define kOfxColourspaceRoleSceneLinear "scene_linear" +#define kOfxColourspaceRoleSceneLinearIsBasic false +#define kOfxColourspaceRoleSceneLinearIsCore true + +/** @brief texture_paint +A colourspace suitable for texture painting, typically sRGB. +*/ +#define kOfxColourspaceRoleTexturePaint "texture_paint" +#define kOfxColourspaceRoleTexturePaintIsBasic false +#define kOfxColourspaceRoleTexturePaintIsCore true + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/third_party/openfx/include/ofx-native-v1.5_aces-v1.3_ocio-v2.3.ocio b/third_party/openfx/include/ofx-native-v1.5_aces-v1.3_ocio-v2.3.ocio new file mode 100644 index 000000000..d071cf665 --- /dev/null +++ b/third_party/openfx/include/ofx-native-v1.5_aces-v1.3_ocio-v2.3.ocio @@ -0,0 +1,1549 @@ +ocio_profile_version: 2.3 + +environment: + {} +search_path: "" +strictparsing: true +luma: [0.2126, 0.7152, 0.0722] +name: ofx-native-v1.5_aces-v1.3_ocio-v2.3 +description: | + OpenFX 1.5 Native Mode Config + Based on: Academy Color Encoding System - Studio Config [COLORSPACES v2.1.0] [ACES v1.3] [OCIO v2.3] + ------------------------------------------------------------------------------------------ + + This "OpenColorIO" config is geared toward studios requiring a config that includes a wide variety of camera colorspaces, displays and looks. + +roles: + aces_interchange: ACES2065-1 + cie_xyz_d65_interchange: CIE-XYZ-D65 + color_picking: sRGB - Texture + color_timing: ACEScct + compositing_log: ACEScct + data: Raw + matte_paint: ACEScct + scene_linear: ACEScg + texture_paint: sRGB - Texture + +file_rules: + - ! {name: Default, colorspace: ACES2065-1} + +shared_views: + - ! {name: ACES 1.0 - SDR Video, view_transform: ACES 1.0 - SDR Video, display_colorspace: } + - ! {name: ACES 1.0 - SDR Video (D60 sim on D65), view_transform: ACES 1.0 - SDR Video (D60 sim on D65), display_colorspace: } + - ! {name: ACES 1.1 - SDR Video (P3 lim), view_transform: ACES 1.1 - SDR Video (P3 lim), display_colorspace: } + - ! {name: ACES 1.1 - SDR Video (Rec.709 lim), view_transform: ACES 1.1 - SDR Video (Rec.709 lim), display_colorspace: } + - ! {name: "ACES 1.1 - HDR Video (1000 nits & Rec.2020 lim)", view_transform: "ACES 1.1 - HDR Video (1000 nits & Rec.2020 lim)", display_colorspace: } + - ! {name: "ACES 1.1 - HDR Video (2000 nits & Rec.2020 lim)", view_transform: "ACES 1.1 - HDR Video (2000 nits & Rec.2020 lim)", display_colorspace: } + - ! {name: "ACES 1.1 - HDR Video (4000 nits & Rec.2020 lim)", view_transform: "ACES 1.1 - HDR Video (4000 nits & Rec.2020 lim)", display_colorspace: } + - ! {name: "ACES 1.1 - HDR Video (1000 nits & P3 lim)", view_transform: "ACES 1.1 - HDR Video (1000 nits & P3 lim)", display_colorspace: } + - ! {name: "ACES 1.1 - HDR Video (2000 nits & P3 lim)", view_transform: "ACES 1.1 - HDR Video (2000 nits & P3 lim)", display_colorspace: } + - ! {name: "ACES 1.1 - HDR Video (4000 nits & P3 lim)", view_transform: "ACES 1.1 - HDR Video (4000 nits & P3 lim)", display_colorspace: } + - ! {name: ACES 1.0 - SDR Cinema, view_transform: ACES 1.0 - SDR Cinema, display_colorspace: } + - ! {name: ACES 1.1 - SDR Cinema (Rec.709 lim), view_transform: ACES 1.1 - SDR Cinema (Rec.709 lim), display_colorspace: } + - ! {name: ACES 1.0 - SDR Cinema (D60 sim on DCI), view_transform: ACES 1.0 - SDR Cinema (D60 sim on DCI), display_colorspace: } + - ! {name: ACES 1.1 - SDR Cinema (D60 sim on D65), view_transform: ACES 1.1 - SDR Cinema (D60 sim on D65), display_colorspace: } + - ! {name: ACES 1.1 - SDR Cinema (D65 sim on DCI), view_transform: ACES 1.1 - SDR Cinema (D65 sim on DCI), display_colorspace: } + - ! {name: "ACES 1.1 - HDR Cinema (108 nits & P3 lim)", view_transform: "ACES 1.1 - HDR Cinema (108 nits & P3 lim)", display_colorspace: } + - ! {name: Un-tone-mapped, view_transform: Un-tone-mapped, display_colorspace: } + +displays: + sRGB - Display: + - ! {name: Raw, colorspace: Raw} + - ! [ACES 1.0 - SDR Video, ACES 1.0 - SDR Video (D60 sim on D65), Un-tone-mapped] + Display P3 - Display: + - ! {name: Raw, colorspace: Raw} + - ! [ACES 1.0 - SDR Video, ACES 1.0 - SDR Video (D60 sim on D65), Un-tone-mapped] + Rec.1886 Rec.709 - Display: + - ! {name: Raw, colorspace: Raw} + - ! [ACES 1.0 - SDR Video, ACES 1.0 - SDR Video (D60 sim on D65), Un-tone-mapped] + Rec.1886 Rec.2020 - Display: + - ! {name: Raw, colorspace: Raw} + - ! [ACES 1.0 - SDR Video, ACES 1.1 - SDR Video (P3 lim), ACES 1.1 - SDR Video (Rec.709 lim), Un-tone-mapped] + Rec.2100-HLG - Display: + - ! {name: Raw, colorspace: Raw} + - ! ["ACES 1.1 - HDR Video (1000 nits & Rec.2020 lim)", Un-tone-mapped] + Rec.2100-PQ - Display: + - ! {name: Raw, colorspace: Raw} + - ! ["ACES 1.1 - HDR Video (1000 nits & Rec.2020 lim)", "ACES 1.1 - HDR Video (2000 nits & Rec.2020 lim)", "ACES 1.1 - HDR Video (4000 nits & Rec.2020 lim)", Un-tone-mapped] + ST2084-P3-D65 - Display: + - ! {name: Raw, colorspace: Raw} + - ! ["ACES 1.1 - HDR Video (1000 nits & P3 lim)", "ACES 1.1 - HDR Video (2000 nits & P3 lim)", "ACES 1.1 - HDR Video (4000 nits & P3 lim)", "ACES 1.1 - HDR Cinema (108 nits & P3 lim)", Un-tone-mapped] + P3-D60 - Display: + - ! {name: Raw, colorspace: Raw} + - ! [ACES 1.0 - SDR Cinema, Un-tone-mapped] + P3-D65 - Display: + - ! {name: Raw, colorspace: Raw} + - ! [ACES 1.0 - SDR Cinema, ACES 1.1 - SDR Cinema (Rec.709 lim), ACES 1.1 - SDR Cinema (D60 sim on D65), Un-tone-mapped] + P3-DCI - Display: + - ! {name: Raw, colorspace: Raw} + - ! [ACES 1.0 - SDR Cinema (D60 sim on DCI), ACES 1.1 - SDR Cinema (D65 sim on DCI), Un-tone-mapped] + +active_displays: [sRGB - Display, Display P3 - Display, Rec.1886 Rec.709 - Display, Rec.1886 Rec.2020 - Display, Rec.2100-HLG - Display, Rec.2100-PQ - Display, ST2084-P3-D65 - Display, P3-D60 - Display, P3-D65 - Display, P3-DCI - Display] +active_views: [ACES 1.0 - SDR Video, ACES 1.0 - SDR Video (D60 sim on D65), ACES 1.1 - SDR Video (P3 lim), ACES 1.1 - SDR Video (Rec.709 lim), "ACES 1.1 - HDR Video (1000 nits & Rec.2020 lim)", "ACES 1.1 - HDR Video (2000 nits & Rec.2020 lim)", "ACES 1.1 - HDR Video (4000 nits & Rec.2020 lim)", "ACES 1.1 - HDR Video (1000 nits & P3 lim)", "ACES 1.1 - HDR Video (2000 nits & P3 lim)", "ACES 1.1 - HDR Video (4000 nits & P3 lim)", ACES 1.0 - SDR Cinema, ACES 1.1 - SDR Cinema (Rec.709 lim), ACES 1.0 - SDR Cinema (D60 sim on DCI), ACES 1.1 - SDR Cinema (D60 sim on D65), ACES 1.1 - SDR Cinema (D65 sim on DCI), "ACES 1.1 - HDR Cinema (108 nits & P3 lim)", Un-tone-mapped, Raw] + +looks: + - ! + name: ACES 1.3 Reference Gamut Compression + process_space: ACES2065-1 + description: | + LMT (applied in ACES2065-1) to compress scene-referred values from common cameras into the AP1 gamut + + ACEStransformID: urn:ampas:aces:transformId:v1.5:LMT.Academy.ReferenceGamutCompress.a1.v1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvLMT.Academy.ReferenceGamutCompress.a1.v1.0 + transform: ! {style: ACES-LMT - ACES 1.3 Reference Gamut Compression} + + +default_view_transform: Un-tone-mapped + +view_transforms: + - ! + name: ACES 1.0 - SDR Video + description: | + Component of ACES Output Transforms for SDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.RGBmonitor_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.DisplayP3_dim.a1.0.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec709_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_100nits_dim.a1.0.3 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.RGBmonitor_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.DisplayP3_dim.a1.0.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec709_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec2020_100nits_dim.a1.0.3 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0} + + - ! + name: ACES 1.0 - SDR Video (D60 sim on D65) + description: | + Component of ACES Output Transforms for SDR D65 video simulating D60 white + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.RGBmonitor_D60sim_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.DisplayP3_D60sim_dim.a1.0.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec709_D60sim_100nits_dim.a1.0.3 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.RGBmonitor_D60sim_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.DisplayP3_D60sim_dim.a1.0.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec709_D60sim_100nits_dim.a1.0.3 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-D60sim-D65_1.0} + + - ! + name: ACES 1.1 - SDR Video (P3 lim) + description: | + Component of ACES Output Transforms for SDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_P3D65limited_100nits_dim.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + + - ! + name: ACES 1.1 - SDR Video (Rec.709 lim) + description: | + Component of ACES Output Transforms for SDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_Rec709limited_100nits_dim.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-REC709lim_1.1} + + - ! + name: "ACES 1.1 - HDR Video (1000 nits & Rec.2020 lim)" + description: | + Component of ACES Output Transforms for 1000 nit HDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_1000nits_15nits_HLG.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_1000nits_15nits_ST2084.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_1000nits_15nits_HLG.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_1000nits_15nits_ST2084.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-VIDEO-1000nit-15nit-REC2020lim_1.1} + + - ! + name: "ACES 1.1 - HDR Video (2000 nits & Rec.2020 lim)" + description: | + Component of ACES Output Transforms for 2000 nit HDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_2000nits_15nits_ST2084.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_2000nits_15nits_ST2084.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-VIDEO-2000nit-15nit-REC2020lim_1.1} + + - ! + name: "ACES 1.1 - HDR Video (4000 nits & Rec.2020 lim)" + description: | + Component of ACES Output Transforms for 4000 nit HDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_4000nits_15nits_ST2084.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_4000nits_15nits_ST2084.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-VIDEO-4000nit-15nit-REC2020lim_1.1} + + - ! + name: "ACES 1.1 - HDR Video (1000 nits & P3 lim)" + description: | + Component of ACES Output Transforms for 1000 nit HDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_1000nits_15nits_ST2084.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_1000nits_15nits_ST2084.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-VIDEO-1000nit-15nit-P3lim_1.1} + + - ! + name: "ACES 1.1 - HDR Video (2000 nits & P3 lim)" + description: | + Component of ACES Output Transforms for 2000 nit HDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_2000nits_15nits_ST2084.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_2000nits_15nits_ST2084.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-VIDEO-2000nit-15nit-P3lim_1.1} + + - ! + name: "ACES 1.1 - HDR Video (4000 nits & P3 lim)" + description: | + Component of ACES Output Transforms for 4000 nit HDR D65 video + + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_4000nits_15nits_ST2084.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_4000nits_15nits_ST2084.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-VIDEO-4000nit-15nit-P3lim_1.1} + + - ! + name: ACES 1.0 - SDR Cinema + description: | + Component of ACES Output Transforms for SDR cinema + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D60_48nits.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_48nits.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D60_48nits.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D65_48nits.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-CINEMA_1.0} + + - ! + name: ACES 1.1 - SDR Cinema (Rec.709 lim) + description: | + Component of ACES Output Transforms for SDR cinema + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_Rec709limited_48nits.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-CINEMA-REC709lim_1.1} + + - ! + name: ACES 1.0 - SDR Cinema (D60 sim on DCI) + description: | + Component of ACES Output Transforms for SDR DCI cinema simulating D60 white + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3DCI_48nits.a1.0.3 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3DCI_48nits.a1.0.3 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-CINEMA-D60sim-DCI_1.0} + + - ! + name: ACES 1.1 - SDR Cinema (D60 sim on D65) + description: | + Component of ACES Output Transforms for SDR D65 cinema simulating D60 white + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_D60sim_48nits.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D65_D60sim_48nits.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-CINEMA-D60sim-D65_1.1} + + - ! + name: ACES 1.1 - SDR Cinema (D65 sim on DCI) + description: | + Component of ACES Output Transforms for SDR DCI cinema simulating D65 white + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3DCI_D65sim_48nits.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3DCI_D65sim_48nits.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-CINEMA-D65sim-DCI_1.1} + + - ! + name: "ACES 1.1 - HDR Cinema (108 nits & P3 lim)" + description: | + Component of ACES Output Transforms for 108 nit HDR D65 cinema + + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_108nits_7point2nits_ST2084.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_108nits_7point2nits_ST2084.a1.1.0 + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-CINEMA-108nit-7.2nit-P3lim_1.1} + + - ! + name: Un-tone-mapped + from_scene_reference: ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + +display_colorspaces: + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + family: "" + equalitygroup: "" + bitdepth: 32f + description: The "CIE XYZ (D65)" display connection colorspace. + isdata: false + allocation: uniform + + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to sRGB (piecewise EOTF) + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.RGBmonitor_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.RGBmonitor_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.RGBmonitor_D60sim_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.RGBmonitor_D60sim_100nits_dim.a1.0.3 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + + - ! + name: Display P3 - Display + aliases: [displayp3_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Apple Display P3 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.DisplayP3_dim.a1.0.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.DisplayP3_dim.a1.0.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.DisplayP3_D60sim_dim.a1.0.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.DisplayP3_D60sim_dim.a1.0.0 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_DisplayP3} + + - ! + name: Rec.1886 Rec.709 - Display + aliases: [rec1886_rec709_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Rec.1886/Rec.709 (HD video) + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec709_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec709_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec709_D60sim_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec709_D60sim_100nits_dim.a1.0.3 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_REC.1886-REC.709} + + - ! + name: Rec.1886 Rec.2020 - Display + aliases: [rec1886_rec2020_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Rec.1886/Rec.2020 (UHD video) + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.Rec2020_100nits_dim.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_P3D65limited_100nits_dim.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec2020_Rec709limited_100nits_dim.a1.1.0 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_REC.1886-REC.2020} + + - ! + name: Rec.2100-HLG - Display + aliases: [rec2100_hlg_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Rec.2100-HLG, 1000 nit + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_1000nits_15nits_HLG.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_1000nits_15nits_HLG.a1.1.0 + isdata: false + categories: [file-io] + encoding: hdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_REC.2100-HLG-1000nit} + + - ! + name: Rec.2100-PQ - Display + aliases: [rec2100_pq_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Rec.2100-PQ + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_1000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_1000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_2000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_2000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.Rec2020_4000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.Rec2020_4000nits_15nits_ST2084.a1.1.0 + isdata: false + categories: [file-io] + encoding: hdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_REC.2100-PQ} + + - ! + name: ST2084-P3-D65 - Display + aliases: [st2084_p3d65_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to ST-2084 (PQ), P3-D65 primaries + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_1000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_1000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_2000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_2000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_4000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_4000nits_15nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:RRTODT.Academy.P3D65_108nits_7point2nits_ST2084.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvRRTODT.Academy.P3D65_108nits_7point2nits_ST2084.a1.1.0 + isdata: false + categories: [file-io] + encoding: hdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_ST2084-P3-D65} + + - ! + name: P3-D60 - Display + aliases: [p3d60_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Gamma 2.6, P3-D60 (Bradford adaptation) + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D60_48nits.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D60_48nits.a1.0.3 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_G2.6-P3-D60-BFD} + + - ! + name: P3-D65 - Display + aliases: [p3d65_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Gamma 2.6, P3-D65 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_48nits.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D65_48nits.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_Rec709limited_48nits.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3D65_D60sim_48nits.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3D65_D60sim_48nits.a1.1.0 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_G2.6-P3-D65} + + - ! + name: P3-DCI - Display + aliases: [p3_dci_display] + family: Display + equalitygroup: "" + bitdepth: 32f + description: | + Convert CIE XYZ (D65 white) to Gamma 2.6, P3-DCI (DCI white with Bradford adaptation) + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3DCI_48nits.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3DCI_48nits.a1.0.3 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ODT.Academy.P3DCI_D65sim_48nits.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:InvODT.Academy.P3DCI_D65sim_48nits.a1.1.0 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_G2.6-P3-DCI-BFD} + +colorspaces: + - ! + name: ACES2065-1 + aliases: [aces2065_1, ACES - ACES2065-1, lin_ap0] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: The "Academy Color Encoding System" reference colorspace. + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + + - ! + name: ACEScc + aliases: [ACES - ACEScc, acescc_ap1] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACEScc to ACES2065-1 + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScc_to_ACES.a1.0.3 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScc.a1.0.3 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! {style: ACEScc_to_ACES2065-1} + + - ! + name: ACEScct + aliases: [ACES - ACEScct, acescct_ap1] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACEScct to ACES2065-1 + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScct_to_ACES.a1.0.3 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScct.a1.0.3 + isdata: false + categories: [file-io, working-space] + encoding: log + allocation: uniform + to_scene_reference: ! {style: ACEScct_to_ACES2065-1} + + - ! + name: ACEScg + aliases: [ACES - ACEScg, lin_ap1] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACEScg to ACES2065-1 + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScg_to_ACES.a1.0.3 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_ACEScg.a1.0.3 + isdata: false + categories: [file-io, working-space, texture] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: ADX10 + aliases: [Input - ADX - ADX10] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: | + Convert ADX10 to ACES2065-1 + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ADX10_to_ACES.a1.0.3 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! {style: ADX10_to_ACES2065-1} + + - ! + name: ADX16 + aliases: [Input - ADX - ADX16] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: | + Convert ADX16 to ACES2065-1 + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ADX16_to_ACES.a1.0.3 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! {style: ADX16_to_ACES2065-1} + + - ! + name: Linear ARRI Wide Gamut 3 + aliases: [lin_arri_wide_gamut_3, Input - ARRI - Linear - ALEXA Wide Gamut, lin_alexawide] + family: Input/ARRI + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear ARRI Wide Gamut 3 to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:Linear_ARRI_Wide_Gamut_3_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear ARRI Wide Gamut 3 to ACES2065-1 + children: + - ! {matrix: [0.680205505106279, 0.236136601606481, 0.0836578932872398, 0, 0.0854149797421404, 1.01747087860704, -0.102885858349182, 0, 0.00205652166929683, -0.0625625003847921, 1.06050597871549, 0, 0, 0, 0, 1]} + + - ! + name: ARRI LogC3 (EI800) + aliases: [arri_logc3_ei800, Input - ARRI - V3 LogC (EI800) - Wide Gamut, logc3ei800_alexawide] + family: Input/ARRI + equalitygroup: "" + bitdepth: 32f + description: | + Convert ARRI LogC3 (EI800) to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:ARRI_LogC3_EI800_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.ARRI.Alexa-v3-logC-EI800.a1.v2 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_LogC_EI800_AWG.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.LogC_EI800_AWG_to_ACES.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: ARRI LogC3 (EI800) to ACES2065-1 + children: + - ! {base: 10, log_side_slope: 0.247189638318671, log_side_offset: 0.385536998692443, lin_side_slope: 5.55555555555556, lin_side_offset: 0.0522722750251688, lin_side_break: 0.0105909904954696, direction: inverse} + - ! {matrix: [0.680205505106279, 0.236136601606481, 0.0836578932872398, 0, 0.0854149797421404, 1.01747087860704, -0.102885858349182, 0, 0.00205652166929683, -0.0625625003847921, 1.06050597871549, 0, 0, 0, 0, 1]} + + - ! + name: Linear ARRI Wide Gamut 4 + aliases: [lin_arri_wide_gamut_4, lin_awg4] + family: Input/ARRI + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear ARRI Wide Gamut 4 to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:Linear_ARRI_Wide_Gamut_4_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear ARRI Wide Gamut 4 to ACES2065-1 + children: + - ! {matrix: [0.750957362824734, 0.144422786709757, 0.104619850465509, 0, 0.000821837079380207, 1.007397584885, -0.00821942196438358, 0, -0.000499952143533471, -0.000854177231436971, 1.00135412937497, 0, 0, 0, 0, 1]} + + - ! + name: ARRI LogC4 + aliases: [arri_logc4] + family: Input/ARRI + equalitygroup: "" + bitdepth: 32f + description: | + Convert ARRI LogC4 to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:ARRI_LogC4_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.ARRI.ARRI-LogC4.a1.v1 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.LogC4_to_ACES.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_LogC4.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: ARRI LogC4 to ACES2065-1 + children: + - ! {log_side_slope: 0.0647954196341293, log_side_offset: -0.295908392682586, lin_side_slope: 2231.82630906769, lin_side_offset: 64, lin_side_break: -0.0180569961199113, direction: inverse} + - ! {matrix: [0.750957362824734, 0.144422786709757, 0.104619850465509, 0, 0.000821837079380207, 1.007397584885, -0.00821942196438358, 0, -0.000499952143533471, -0.000854177231436971, 1.00135412937497, 0, 0, 0, 0, 1]} + + - ! + name: BMDFilm WideGamut Gen5 + aliases: [bmdfilm_widegamut_gen5] + family: Input/BlackmagicDesign + equalitygroup: "" + bitdepth: 32f + description: | + Convert Blackmagic Film Wide Gamut (Gen 5) to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:BMDFilm_WideGamut_Gen5_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.BlackmagicDesign.BMDFilm_WideGamut_Gen5.a1.v1 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_BMDFilm_WideGamut_Gen5.a1.v1 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.BMDFilm_WideGamut_Gen5_to_ACES.a1.v1 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: Blackmagic Film Wide Gamut (Gen 5) to ACES2065-1 + children: + - ! {base: 2.71828182845905, log_side_slope: 0.0869287606549122, log_side_offset: 0.530013339229194, lin_side_offset: 0.00549407243225781, lin_side_break: 0.005, direction: inverse} + - ! {matrix: [0.647091325580708, 0.242595385134207, 0.110313289285085, 0, 0.0651915997328519, 1.02504756760476, -0.0902391673376125, 0, -0.0275570729194699, -0.0805887097177784, 1.10814578263725, 0, 0, 0, 0, 1]} + + - ! + name: DaVinci Intermediate WideGamut + aliases: [davinci_intermediate_widegamut] + family: Input/BlackmagicDesign + equalitygroup: "" + bitdepth: 32f + description: | + Convert DaVinci Intermediate Wide Gamut to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:DaVinci_Intermediate_WideGamut_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.DaVinci_Intermediate_WideGamut_to_ACES.a1.v1 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: DaVinci Intermediate Wide Gamut to ACES2065-1 + children: + - ! {log_side_slope: 0.07329248, log_side_offset: 0.51304736, lin_side_offset: 0.0075, lin_side_break: 0.00262409, linear_slope: 10.44426855, direction: inverse} + - ! {matrix: [0.748270290272981, 0.167694659554328, 0.0840350501726906, 0, 0.0208421234689102, 1.11190474268894, -0.132746866157851, 0, -0.0915122574225729, -0.127746712807307, 1.21925897022988, 0, 0, 0, 0, 1]} + + - ! + name: Linear BMD WideGamut Gen5 + aliases: [lin_bmd_widegamut_gen5] + family: Input/BlackmagicDesign + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear Blackmagic Wide Gamut (Gen 5) to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:Linear_BMD_WideGamut_Gen5_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear Blackmagic Wide Gamut (Gen 5) to ACES2065-1 + children: + - ! {matrix: [0.647091325580708, 0.242595385134207, 0.110313289285085, 0, 0.0651915997328519, 1.02504756760476, -0.0902391673376125, 0, -0.0275570729194699, -0.0805887097177784, 1.10814578263725, 0, 0, 0, 0, 1]} + + - ! + name: Linear DaVinci WideGamut + aliases: [lin_davinci_widegamut] + family: Input/BlackmagicDesign + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear DaVinci Wide Gamut to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:Linear_DaVinci_WideGamut_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear DaVinci Wide Gamut to ACES2065-1 + children: + - ! {matrix: [0.748270290272981, 0.167694659554328, 0.0840350501726906, 0, 0.0208421234689102, 1.11190474268894, -0.132746866157851, 0, -0.0915122574225729, -0.127746712807307, 1.21925897022988, 0, 0, 0, 0, 1]} + + - ! + name: CanonLog2 CinemaGamut D55 + aliases: [canonlog2_cinemagamut_d55, Input - Canon - Canon-Log2 - Cinema Gamut Daylight, canonlog2_cgamutday] + family: Input/Canon + equalitygroup: "" + bitdepth: 32f + description: | + Convert Canon Log 2 Cinema Gamut (Daylight) to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:CanonLog2_CinemaGamut-D55_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CLog2_CGamut_to_ACES.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_CLog2_CGamut.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! {style: CANON_CLOG2-CGAMUT_to_ACES2065-1} + + - ! + name: CanonLog3 CinemaGamut D55 + aliases: [canonlog3_cinemagamut_d55, Input - Canon - Canon-Log3 - Cinema Gamut Daylight, canonlog3_cgamutday] + family: Input/Canon + equalitygroup: "" + bitdepth: 32f + description: | + Convert Canon Log 3 Cinema Gamut (Daylight) to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:CanonLog3_CinemaGamut-D55_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.CLog3_CGamut_to_ACES.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_CLog3_CGamut.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! {style: CANON_CLOG3-CGAMUT_to_ACES2065-1} + + - ! + name: Linear CinemaGamut D55 + aliases: [lin_cinemagamut_d55, Input - Canon - Linear - Canon Cinema Gamut Daylight, lin_canoncgamutday] + family: Input/Canon + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear Canon Cinema Gamut (Daylight) to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:Linear-CinemaGamut-D55_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear Canon Cinema Gamut (Daylight) to ACES2065-1 + children: + - ! {matrix: [0.763064454775734, 0.14902116113706, 0.0879143840872056, 0, 0.00365745670512393, 1.10696038037622, -0.110617837081339, 0, -0.0094077940457189, -0.218383304989987, 1.22779109903571, 0, 0, 0, 0, 1]} + + - ! + name: Linear V-Gamut + aliases: [lin_vgamut, Input - Panasonic - Linear - V-Gamut] + family: Input/Panasonic + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear Panasonic V-Gamut to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Panasonic:Input:Linear_VGamut_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear Panasonic V-Gamut to ACES2065-1 + children: + - ! {matrix: [0.72461670413153, 0.166915288193706, 0.108468007674764, 0, 0.021390245413146, 0.984908155703054, -0.00629840111620089, 0, -0.00923556287076561, -0.00105690563900513, 1.01029246850977, 0, 0, 0, 0, 1]} + + - ! + name: V-Log V-Gamut + aliases: [vlog_vgamut, Input - Panasonic - V-Log - V-Gamut] + family: Input/Panasonic + equalitygroup: "" + bitdepth: 32f + description: | + Convert Panasonic V-Log - V-Gamut to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Panasonic:Input:VLog_VGamut_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.VLog_VGamut_to_ACES.a1.1.0 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_VLog_VGamut.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Panasonic.VLog_VGamut.a1.v1 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: Panasonic V-Log - V-Gamut to ACES2065-1 + children: + - ! {base: 10, log_side_slope: 0.241514, log_side_offset: 0.598206, lin_side_offset: 0.00873, lin_side_break: 0.01, direction: inverse} + - ! {matrix: [0.72461670413153, 0.166915288193706, 0.108468007674764, 0, 0.021390245413146, 0.984908155703054, -0.00629840111620089, 0, -0.00923556287076561, -0.00105690563900513, 1.01029246850977, 0, 0, 0, 0, 1]} + + - ! + name: Linear REDWideGamutRGB + aliases: [lin_redwidegamutrgb, Input - RED - Linear - REDWideGamutRGB, lin_rwg] + family: Input/RED + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear REDWideGamutRGB to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:RED:Input:Linear_REDWideGamutRGB_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear REDWideGamutRGB to ACES2065-1 + children: + - ! {matrix: [0.785058804068092, 0.0838587565440846, 0.131082439387823, 0, 0.0231738348454756, 1.08789754919233, -0.111071384037806, 0, -0.0737604353682082, -0.314590072290208, 1.38835050765842, 0, 0, 0, 0, 1]} + + - ! + name: Log3G10 REDWideGamutRGB + aliases: [log3g10_redwidegamutrgb, Input - RED - REDLog3G10 - REDWideGamutRGB, rl3g10_rwg] + family: Input/RED + equalitygroup: "" + bitdepth: 32f + description: | + Convert RED Log3G10 REDWideGamutRGB to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:RED:Input:Log3G10_REDWideGamutRGB_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.RED.Log3G10_REDWideGamutRGB.a1.v1 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_Log3G10_RWG.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.Log3G10_RWG_to_ACES.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: RED Log3G10 REDWideGamutRGB to ACES2065-1 + children: + - ! {base: 10, log_side_slope: 0.224282, lin_side_slope: 155.975327, lin_side_offset: 2.55975327, lin_side_break: -0.01, direction: inverse} + - ! {matrix: [0.785058804068092, 0.0838587565440846, 0.131082439387823, 0, 0.0231738348454756, 1.08789754919233, -0.111071384037806, 0, -0.0737604353682082, -0.314590072290208, 1.38835050765842, 0, 0, 0, 0, 1]} + + - ! + name: Linear S-Gamut3 + aliases: [lin_sgamut3, Input - Sony - Linear - S-Gamut3] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear S-Gamut3 to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_SGamut3_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear S-Gamut3 to ACES2065-1 + children: + - ! {matrix: [0.75298259539984, 0.143370216235557, 0.103647188364603, 0, 0.0217076974414429, 1.01531883550528, -0.0370265329467195, 0, -0.00941605274963355, 0.00337041785882367, 1.00604563489081, 0, 0, 0, 0, 1]} + + - ! + name: Linear S-Gamut3.Cine + aliases: [lin_sgamut3cine, Input - Sony - Linear - S-Gamut3.Cine] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear S-Gamut3.Cine to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_SGamut3Cine_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear S-Gamut3.Cine to ACES2065-1 + children: + - ! {matrix: [0.638788667185978, 0.272351433711262, 0.0888598991027595, 0, -0.00391590602528224, 1.0880732308974, -0.0841573248721177, 0, -0.0299072021239151, -0.0264325799101947, 1.05633978203411, 0, 0, 0, 0, 1]} + + - ! + name: Linear Venice S-Gamut3 + aliases: [lin_venice_sgamut3, Input - Sony - Linear - Venice S-Gamut3] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear Venice S-Gamut3 to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_Venice_SGamut3_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear Venice S-Gamut3 to ACES2065-1 + children: + - ! {matrix: [0.793329741146434, 0.0890786256206771, 0.117591633232888, 0, 0.0155810585252582, 1.03271230692988, -0.0482933654551394, 0, -0.0188647477991488, 0.0127694120973433, 1.0060953357018, 0, 0, 0, 0, 1]} + + - ! + name: Linear Venice S-Gamut3.Cine + aliases: [lin_venice_sgamut3cine, Input - Sony - Linear - Venice S-Gamut3.Cine] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Linear Venice S-Gamut3.Cine to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:Linear_Venice_SGamut3Cine_to_ACES2065-1:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + to_scene_reference: ! + name: Linear Venice S-Gamut3.Cine to ACES2065-1 + children: + - ! {matrix: [0.674257092126512, 0.220571735923397, 0.10517117195009, 0, -0.00931360607857167, 1.10595886142466, -0.0966452553460855, 0, -0.0382090673002312, -0.017938376600236, 1.05614744390047, 0, 0, 0, 0, 1]} + + - ! + name: S-Log3 S-Gamut3 + aliases: [slog3_sgamut3, Input - Sony - S-Log3 - S-Gamut3] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Sony S-Log3 S-Gamut3 to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_SGamut3_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.SLog3_SGamut3.a1.v1 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_SGamut3.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_SGamut3_to_ACES.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: Sony S-Log3 S-Gamut3 to ACES2065-1 + children: + - ! {base: 10, log_side_slope: 0.255620723362659, log_side_offset: 0.410557184750733, lin_side_slope: 5.26315789473684, lin_side_offset: 0.0526315789473684, lin_side_break: 0.01125, linear_slope: 6.62194371177582, direction: inverse} + - ! {matrix: [0.75298259539984, 0.143370216235557, 0.103647188364603, 0, 0.0217076974414429, 1.01531883550528, -0.0370265329467195, 0, -0.00941605274963355, 0.00337041785882367, 1.00604563489081, 0, 0, 0, 0, 1]} + + - ! + name: S-Log3 S-Gamut3.Cine + aliases: [slog3_sgamut3cine, Input - Sony - S-Log3 - S-Gamut3.Cine, slog3_sgamutcine] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Sony S-Log3 S-Gamut3.Cine to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_SGamut3Cine_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.SLog3_SGamut3Cine.a1.v1 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_SGamut3Cine.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_SGamut3Cine_to_ACES.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: Sony S-Log3 S-Gamut3.Cine to ACES2065-1 + children: + - ! {base: 10, log_side_slope: 0.255620723362659, log_side_offset: 0.410557184750733, lin_side_slope: 5.26315789473684, lin_side_offset: 0.0526315789473684, lin_side_break: 0.01125, linear_slope: 6.62194371177582, direction: inverse} + - ! {matrix: [0.638788667185978, 0.272351433711262, 0.0888598991027595, 0, -0.00391590602528224, 1.0880732308974, -0.0841573248721177, 0, -0.0299072021239151, -0.0264325799101947, 1.05633978203411, 0, 0, 0, 0, 1]} + + - ! + name: S-Log3 Venice S-Gamut3 + aliases: [slog3_venice_sgamut3, Input - Sony - S-Log3 - Venice S-Gamut3] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Sony S-Log3 Venice S-Gamut3 to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_Venice_SGamut3_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.Venice_SLog3_SGamut3.a1.v1 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_Venice_SGamut3.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_Venice_SGamut3_to_ACES.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: Sony S-Log3 Venice S-Gamut3 to ACES2065-1 + children: + - ! {base: 10, log_side_slope: 0.255620723362659, log_side_offset: 0.410557184750733, lin_side_slope: 5.26315789473684, lin_side_offset: 0.0526315789473684, lin_side_break: 0.01125, linear_slope: 6.62194371177582, direction: inverse} + - ! {matrix: [0.793329741146434, 0.089078625620677, 0.117591633232888, 0, 0.0155810585252582, 1.03271230692988, -0.0482933654551394, 0, -0.0188647477991488, 0.0127694120973433, 1.00609533570181, 0, 0, 0, 0, 1]} + + - ! + name: S-Log3 Venice S-Gamut3.Cine + aliases: [slog3_venice_sgamut3cine, Input - Sony - S-Log3 - Venice S-Gamut3.Cine, slog3_venice_sgamutcine] + family: Input/Sony + equalitygroup: "" + bitdepth: 32f + description: | + Convert Sony S-Log3 Venice S-Gamut3.Cine to ACES2065-1 + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3_Venice_SGamut3Cine_to_ACES2065-1:1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:IDT.Sony.Venice_SLog3_SGamut3Cine.a1.v1 + + AMF Components + -------------- + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACES_to_SLog3_Venice_SGamut3Cine.a1.1.0 + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.SLog3_Venice_SGamut3Cine_to_ACES.a1.1.0 + isdata: false + categories: [file-io] + encoding: log + allocation: uniform + to_scene_reference: ! + name: Sony S-Log3 Venice S-Gamut3.Cine to ACES2065-1 + children: + - ! {base: 10, log_side_slope: 0.255620723362659, log_side_offset: 0.410557184750733, lin_side_slope: 5.26315789473684, lin_side_offset: 0.0526315789473684, lin_side_break: 0.01125, linear_slope: 6.62194371177582, direction: inverse} + - ! {matrix: [0.674257092126512, 0.220571735923397, 0.10517117195009, 0, -0.00931360607857167, 1.10595886142466, -0.0966452553460855, 0, -0.0382090673002312, -0.017938376600236, 1.05614744390047, 0, 0, 0, 0, 1]} + + - ! + name: Camera Rec.709 + aliases: [camera_rec709, Utility - Rec.709 - Camera, rec709_camera] + family: Utility/ITU + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to Rec.709 camera OETF Rec.709 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ITU:Utility:AP0_to_Camera_Rec709:1.0 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to Camera Rec.709 + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.22222222222222, offset: 0.099, direction: inverse} + + - ! + name: Linear P3-D65 + aliases: [lin_p3d65, Utility - Linear - P3-D65, lin_displayp3, Linear Display P3] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to linear P3 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Linear_P3-D65:1.0 + isdata: false + categories: [file-io, working-space, texture] + encoding: scene-linear + allocation: uniform + from_scene_reference: ! + name: AP0 to Linear P3-D65 + children: + - ! {matrix: [2.02490528596679, -0.689069761034766, -0.335835524932019, 0, -0.183597032256178, 1.28950620775902, -0.105909175502841, 0, 0.00905856112234766, -0.0592796840575522, 1.0502211229352, 0, 0, 0, 0, 1]} + + - ! + name: Linear Rec.2020 + aliases: [lin_rec2020, Utility - Linear - Rec.2020] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to linear Rec.2020 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Linear_Rec2020:1.0 + isdata: false + categories: [file-io, texture] + encoding: scene-linear + allocation: uniform + from_scene_reference: ! + name: AP0 to Linear Rec.2020 + children: + - ! {matrix: [1.49040952054172, -0.26617091926613, -0.224238601275593, 0, -0.0801674998722558, 1.18216712109757, -0.10199962122531, 0, 0.00322763119162216, -0.0347764757450576, 1.03154884455344, 0, 0, 0, 0, 1]} + + - ! + name: Linear Rec.709 (sRGB) + aliases: [lin_rec709_srgb, Utility - Linear - Rec.709, lin_rec709, lin_srgb, Utility - Linear - sRGB] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to linear Rec.709 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Linear_Rec709:1.0 + isdata: false + categories: [file-io, working-space, texture] + encoding: scene-linear + allocation: uniform + from_scene_reference: ! + name: AP0 to Linear Rec.709 (sRGB) + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + + - ! + name: Gamma 1.8 Rec.709 - Texture + aliases: [g18_rec709_tx, Utility - Gamma 1.8 - Rec.709 - Texture, g18_rec709] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to 1.8 gamma-corrected Rec.709 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma1.8_Rec709-Texture:1.0 + isdata: false + categories: [file-io, texture] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to Gamma 1.8 Rec.709 - Texture + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {value: 1.8, style: pass_thru, direction: inverse} + + - ! + name: Gamma 2.2 AP1 - Texture + aliases: [g22_ap1_tx, g22_ap1] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to 2.2 gamma-corrected AP1 primaries, ACES ~=D60 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma2.2_AP1-Texture:1.0 + isdata: false + categories: [file-io, texture] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to Gamma 2.2 AP1 - Texture + children: + - ! {matrix: [1.45143931614567, -0.23651074689374, -0.214928569251925, 0, -0.0765537733960206, 1.17622969983357, -0.0996759264375522, 0, 0.00831614842569772, -0.00603244979102102, 0.997716301365323, 0, 0, 0, 0, 1]} + - ! {value: 2.2, style: pass_thru, direction: inverse} + + - ! + name: Gamma 2.2 Rec.709 - Texture + aliases: [g22_rec709_tx, Utility - Gamma 2.2 - Rec.709 - Texture, g22_rec709] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to 2.2 gamma-corrected Rec.709 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma2.2_Rec709-Texture:1.0 + isdata: false + categories: [file-io, texture] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to Gamma 2.2 Rec.709 - Texture + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {value: 2.2, style: pass_thru, direction: inverse} + + - ! + name: Gamma 2.4 Rec.709 - Texture + aliases: [g24_rec709_tx, g24_rec709, rec709_display, Utility - Rec.709 - Display] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to 2.4 gamma-corrected Rec.709 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma2.4_Rec709-Texture:1.0 + isdata: false + categories: [file-io, texture] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to Gamma 2.4 Rec.709 - Texture + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {value: 2.4, style: pass_thru, direction: inverse} + + - ! + name: sRGB Encoded AP1 - Texture + aliases: [srgb_encoded_ap1_tx, srgb_ap1] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to sRGB Encoded AP1 primaries, ACES ~=D60 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_sRGB_Encoded_AP1-Texture:1.0 + isdata: false + categories: [file-io, texture] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to sRGB Encoded AP1 - Texture + children: + - ! {matrix: [1.45143931614567, -0.23651074689374, -0.214928569251925, 0, -0.0765537733960206, 1.17622969983357, -0.0996759264375522, 0, 0.00831614842569772, -0.00603244979102102, 0.997716301365323, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: sRGB Encoded P3-D65 - Texture + aliases: [srgb_encoded_p3d65_tx, srgb_p3d65, srgb_displayp3] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to sRGB Encoded P3-D65 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_sRGB_Encoded_P3-D65-Texture:1.0 + isdata: false + categories: [file-io, texture] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to sRGB Encoded P3-D65 - Texture + children: + - ! {matrix: [2.02490528596679, -0.689069761034766, -0.335835524932019, 0, -0.183597032256178, 1.28950620775902, -0.105909175502841, 0, 0.00905856112234766, -0.0592796840575522, 1.0502211229352, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: sRGB - Texture + aliases: [srgb_tx, Utility - sRGB - Texture, srgb_texture, Input - Generic - sRGB - Texture] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to sRGB + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_sRGB-Texture:1.0 + isdata: false + categories: [file-io, texture] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to sRGB Rec.709 + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: Raw + aliases: [Utility - Raw] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io, texture] + allocation: uniform + +named_transforms: + - ! + name: ARRI LogC3 - Curve (EI800) + aliases: [arri_logc3_crv_ei800, Input - ARRI - Curve - V3 LogC (EI800), crv_logc3ei800] + description: | + Convert ARRI LogC3 Curve (EI800) to Relative Scene Linear + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:ARRI_LogC3_Curve_EI800_to_Linear:1.0 + family: Input/ARRI + categories: [file-io] + encoding: log + transform: ! + name: ARRI LogC3 Curve (EI800) to Relative Scene Linear + children: + - ! {base: 10, log_side_slope: 0.247189638318671, log_side_offset: 0.385536998692443, lin_side_slope: 5.55555555555556, lin_side_offset: 0.0522722750251688, lin_side_break: 0.0105909904954696, direction: inverse} + + - ! + name: ARRI LogC4 - Curve + aliases: [arri_logc4_crv] + description: | + Convert ARRI LogC4 Curve to Relative Scene Linear + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ARRI:Input:ARRI_LogC4_Curve_to_Linear:1.0 + family: Input/ARRI + categories: [file-io] + encoding: log + transform: ! + name: ARRI LogC4 Curve to Relative Scene Linear + children: + - ! {log_side_slope: 0.0647954196341293, log_side_offset: -0.295908392682586, lin_side_slope: 2231.82630906769, lin_side_offset: 64, lin_side_break: -0.0180569961199113, direction: inverse} + + - ! + name: BMDFilm Gen5 Log - Curve + aliases: [bmdfilm_gen5_log_crv] + description: | + Convert Blackmagic Film (Gen 5) Log to Blackmagic Film (Gen 5) Linear + + CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:BMDFilm_Gen5_Log-Curve_to_Linear:1.0 + family: Input/BlackmagicDesign + categories: [file-io] + encoding: log + transform: ! + name: Blackmagic Film (Gen 5) Log to Linear Curve + children: + - ! {base: 2.71828182845905, log_side_slope: 0.0869287606549122, log_side_offset: 0.530013339229194, lin_side_offset: 0.00549407243225781, lin_side_break: 0.005, direction: inverse} + + - ! + name: DaVinci Intermediate Log - Curve + aliases: [davinci_intermediate_log_crv] + description: | + Convert DaVinci Intermediate Log to DaVinci Intermediate Linear + + CLFtransformID: urn:aswf:ocio:transformId:1.0:BlackmagicDesign:Input:DaVinci_Intermediate_Log-Curve_to_Linear:1.0 + family: Input/BlackmagicDesign + categories: [file-io] + encoding: log + transform: ! + name: DaVinci Intermediate Log to Linear Curve + children: + - ! {log_side_slope: 0.07329248, log_side_offset: 0.51304736, lin_side_offset: 0.0075, lin_side_break: 0.00262409, linear_slope: 10.44426855, direction: inverse} + + - ! + name: C-Log2 - Curve + aliases: [clog2_crv, Input - Canon - Curve - Canon-Log2, crv_canonlog2] + description: | + Convert CLog2 Log (arbitrary primaries) to CLog2 Linear (arbitrary primaries) + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:CLog2-Curve_to_Linear:1.0 + family: Input/Canon + categories: [file-io] + encoding: log + transform: ! {style: CURVE - CANON_CLOG2_to_LINEAR} + + - ! + name: C-Log3 - Curve + aliases: [clog3_crv, Input - Canon - Curve - Canon-Log3, crv_canonlog3] + description: | + Convert CLog3 Log (arbitrary primaries) to CLog3 Linear (arbitrary primaries) + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Canon:Input:CLog3-Curve_to_Linear:1.0 + family: Input/Canon + categories: [file-io] + encoding: log + transform: ! {style: CURVE - CANON_CLOG3_to_LINEAR} + + - ! + name: V-Log - Curve + aliases: [vlog_crv, Input - Panasonic - Curve - V-Log, crv_vlog] + description: | + Convert Panasonic V-Log Log (arbitrary primaries) to Panasonic V-Log Linear (arbitrary primaries) + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Panasonic:Input:VLog-Curve_to_Linear:1.0 + family: Input/Panasonic + categories: [file-io] + encoding: log + transform: ! + name: Panasonic V-Log Log to Linear Curve + children: + - ! {base: 10, log_side_slope: 0.241514, log_side_offset: 0.598206, lin_side_offset: 0.00873, lin_side_break: 0.01, direction: inverse} + + - ! + name: Log3G10 - Curve + aliases: [log3g10_crv, Input - RED - Curve - REDLog3G10, crv_rl3g10] + description: | + Convert RED Log3G10 Log (arbitrary primaries) to RED Log3G10 Linear (arbitrary primaries) + + CLFtransformID: urn:aswf:ocio:transformId:1.0:RED:Input:Log3G10-Curve_to_Linear:1.0 + family: Input/RED + categories: [file-io] + encoding: log + transform: ! + name: RED Log3G10 Log to Linear Curve + children: + - ! {base: 10, log_side_slope: 0.224282, lin_side_slope: 155.975327, lin_side_offset: 2.55975327, lin_side_break: -0.01, direction: inverse} + + - ! + name: S-Log3 - Curve + aliases: [slog3_crv, Input - Sony - Curve - S-Log3, crv_slog3] + description: | + Convert S-Log3 Log (arbitrary primaries) to S-Log3 Linear (arbitrary primaries) + + CLFtransformID: urn:aswf:ocio:transformId:1.0:Sony:Input:SLog3-Curve_to_Linear:1.0 + family: Input/Sony + categories: [file-io] + encoding: log + transform: ! + name: S-Log3 Log to Linear Curve + children: + - ! {base: 10, log_side_slope: 0.255620723362659, log_side_offset: 0.410557184750733, lin_side_slope: 5.26315789473684, lin_side_offset: 0.0526315789473684, lin_side_break: 0.01125, linear_slope: 6.62194371177582, direction: inverse} + + - ! + name: Rec.1886 - Curve + aliases: [rec1886_crv, Utility - Curve - Rec.1886, crv_rec1886] + description: | + Convert generic linear RGB to Rec.1886 encoded RGB + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:Linear_to_Rec1886-Curve:1.0 + family: Utility + categories: [file-io] + encoding: sdr-video + inverse_transform: ! + name: Linear to Rec.1886 + children: + - ! {value: 2.4, style: pass_thru, direction: inverse} + + - ! + name: Rec.709 - Curve + aliases: [rec709_crv, Utility - Curve - Rec.709, crv_rec709] + description: | + Convert generic linear RGB to generic gamma-corrected RGB + + CLFtransformID: urn:aswf:ocio:transformId:1.0:ITU:Utility:Linear_to_Rec709-Curve:1.0 + family: Utility/ITU + categories: [file-io] + encoding: sdr-video + inverse_transform: ! + name: Linear to Rec.709 + children: + - ! {gamma: 2.22222222222222, offset: 0.099, direction: inverse} + + - ! + name: sRGB - Curve + aliases: [srgb_crv, Utility - Curve - sRGB, crv_srgb] + description: | + Convert generic linear RGB to sRGB encoded RGB + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:Linear_to_sRGB-Curve:1.0 + family: Utility + categories: [file-io] + encoding: sdr-video + inverse_transform: ! + name: Linear to sRGB + children: + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: ST-2084 - Curve + aliases: [st_2084_crv] + description: | + Convert generic linear RGB to generic ST.2084 (PQ) encoded RGB mapping 1.0 to 100nits + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:Linear_to_ST2084-Curve:1.0 + family: Utility + categories: [file-io] + encoding: hdr-video + inverse_transform: ! {style: CURVE - LINEAR_to_ST-2084} + diff --git a/third_party/openfx/include/ofx.doxy b/third_party/openfx/include/ofx.doxy new file mode 100644 index 000000000..7b145ce2a --- /dev/null +++ b/third_party/openfx/include/ofx.doxy @@ -0,0 +1,2379 @@ +# Doxyfile 1.8.17 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "OFX" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = "1.4+" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Open Effects API" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../Documentation/doxygen_build + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = NO + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = ./DocSrc/ofx_header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = ./DocSrc/ofx_footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = ./DocSrc/ofx_style.css + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = YES + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /