Compiler hygiene (all platforms):
- Silence warnings across the tree: missing override, -Wreorder ctor
init, -Wshadow, -Wsign-compare, missing switch cases, unused
functions/captures, Qt 6.11 deprecations (QMouseEvent/QDropEvent
accessors, qAsConst, Q_FOREACH over non-shared containers,
AA_UseHighDpiPixmaps) and the .bak/ backup tree removal.
- Fix regressions from the cleanup: missing clip decls in
capi/timeline.cpp, plugin.cpp rename fallout, panel setFocus
ambiguity, QGraphicsItem::pos vs event->position(), duplicate
k_push_button case, boolean test variable.
Windows:
- Qt portability: CommandLineParser is_set/add_option, QTimeZone
systemTimeZone (QTimeZone::LocalTime is 6.11-only), k_progress_* enum.
- Linking: stop adding oakengine to OLIVE_LIBRARIES (import lib plus
oakengine-obj caused multiple definitions); add OAKENGINE_STATIC so
internal consumers no longer reference __imp_* stubs.
- oakengine.ver: export olive::Renderer typeinfo so liboakgl.so can be
dlopened (Linux), DynamicRenderer no longer dlcloses backend libraries
(crash in RenderManager's dtor calling into unmapped memory).
- OTIO runtime: copy DLLs next to every binary on Windows instead of
relying on PATH (0xc0000135 in gtest discovery).
- Headless GL: the runner only has GDI OpenGL 1.1, killing every render
worker. Deploy Mesa llvmpipe as opengl32sw.dll (Qt's software-GL
channel) with QT_OPENGL=software, and let QT_OPENGL override the
AA_UseDesktopOpenGL default. ExportTask fails fast after 8 consecutive
undelivered frames instead of segfaulting or grinding forever;
FFmpegEncoder::write_frame tolerates null frames.
- Tests: GetTempPathA+PID temp dirs, GetLongPathNameA for 8.3 names,
forward-slash normalization when comparing project filenames.
Linux:
- Install libshaderc-dev so oakvulkan compiles GLSL (Vulkan tests).
- Accept UNORM floor-or-round (63/64) in the blit ping-pong test.
- Skip MainWindow construction test on the offscreen QPA (cannot paint
QOpenGLWidget).
Also: oak_cli_transcode gets a 300s ctest timeout, worker logs GL
context version and LoadGraph/render_frame stages, and
docs/plans/eliminate-event-bridge-issues.md (English translation).
- capi: oakengine_node_output_connection_at/_at_ex returned the source
node as the connection destination; the actual destination is
conn.second.node(). Out-edge enumeration was useless, so the node
view could only draw in-edges and randomly lost whichever edges
needed the out-edge path (random per context build order).
Regression test in oakengine_node_test
- project teardown: Project::clear() pre-notifies node removal while
nodes are fully constructed (observers used to crash on
half-destroyed nodes); childEvent suppresses the removal dance while
clearing; Node::disconnect_all/disconnect_edge get a silent mode for
teardown so no invalidation/events touch dying members
(is_being_cleared); ClipBlock marker disconnect guarded against
dead viewer/markers; ProjectCopier and PreviewAutoCacher drop
project references on Project::destroyed instead of disconnecting
dead objects at shutdown
- preview: add oakengine_preview_request_get_audio_sample_count; the
viewer queried sample count by passing nullptr to get_audio_samples
which rejects it, so all playback audio was silently dropped
- app: fix unterminated input-id memcpy in ResolveGroupInput
(nodeparamviewitem, widgetbridge) that corrupted every parameter id
- app: unsubscribe raw C-API event subscriptions in destructors of
NodeParamViewKeyframeControl, NodeParamViewConnectedLabel and
ExportDialog; playhead events used to fire into dead widgets
(crash when dragging the playhead)
- tests: preview request roundtrip (video frame + audio range) and
free-while-active teardown coverage; env-gated OAK_DEBUG_EDGES /
OAK_DEBUG_INVALID_INPUT diagnostics
- docs: investigation notes in docs/zh/
- nodeparamview: add visited set to get_distance_between_nodes, fixing
unbounded recursion (stack overflow) when the node graph has a cycle
- viewerdisplay: give texture_ a consistent owner via assign_texture();
borrowed queue textures are now retained, created ones freed, fixing
a dangling pointer that corrupted the heap and crashed in the GL driver
- playbackcache: resignal_requests() iterates a copy, handlers may
clear_request_range() while iterating (ASan container-overflow)
- preview C API: preview request ticket lambdas captured the request
state raw; after oakengine_preview_request_free the ticket outlived
the request and the finished callback wrote into freed memory
(heap-use-after-free). The finished flag is now a shared_ptr captured
weakly by the callbacks
- playback: oak_playback_frame regains a timestamp (num/den) filled
from olive::Frame; the viewer queue append no longer uses Rational()
for every frame, which made append_timewise drop all but the first
frame and froze the picture during playback
- mainwindow: open_node_in_viewer refuses sequence nodes; sequences
already have the Sequence Viewer, and saved layouts could otherwise
resurrect a redundant floating Viewer bound to the sequence
- app/ no longer includes engine C++ headers nor holds engine C++ types:
engine access goes through the oakengine C ABI plus C++ wrappers
(oakutil/oaknode.h, oakutil/oakvideo.h) and app-local mirror types
(tooltypes, trackreferencehandle, timelinecommonapp, keyframetypes,
subtitleapp, serializedlayoutinfoapp, nodevaluehandle, sliderdisplaytypeapp)
- engine: new C ABI functions for block/track/clip/transition navigation
and predicates, links, caches, waveform/playback, disk folder,
sequence_track_list, node_free, footage_is_valid, block_get_track,
get_brush; loadotio/saveotio ported to the current engine API
- OTIO is now a required dependency: CI and CD build it on every
platform, FindOpenTimelineIO fixed for OTIO 0.16/0.19 (the old deps
include requirement silently disabled OTIO everywhere), runtime
libraries are bundled into packages and copied next to macOS binaries
(oak_copy_otio_runtime)
- fix ProjectViewModel drag&drop mime read/write size mismatch (segfault)
- unify color label naming (k_olive -> "Oak") in the app-side mirror
- docs: OTIO required, FFmpeg minimum corrected to 6.0 (en/zh)
- gtest suite: 1925 passed, 0 failed
Move the pure-header utilities shared by app/ and engine/ out of
engine/common/ into a new shared/include/oakutil/ layer (define, lerp,
decibel, digit, range, crashpadutils, autoscroll, qtutils, filefunctions
declarations, and a trimmed xmlutils exposing a CancelAtom-free void*
overload). engine/common/ keeps forwarding headers so internal include
paths are unchanged; app/ now includes oakutil/* directly.
engine/node/project.h gains an explicit NodeGroup forward declaration
previously obtained transitively through the old xmlutils.h.
Every app module now reaches liboakengine exclusively through
oakengine_* C calls, EngineEventBridge subscriptions and app-side
handle headers (cliphandle/keyframehandle/nodevaluehandle/oakvaluehelper).
Direct C++ command construction, engine signal connect()s, and engine
type usage in MOC-visible signatures are gone: 557 -> 0 undefined
olive:: symbols in oak-editor.
- new facade API: set_input_at_time (element addressing, track=-1 for
all components at once), set_input_string_at_time, frame_time_base,
array_insert_at/remove_at, disconnect_ex (element-aware), and
keyframes_set_type_many (first cross-track keyframe op, addressed by
(time,track) pairs)
- the widget bridge's commit funnel, color path, array ops, label
disconnect, and keyframe set-type actions in keyframeview/curvewidget
now go through the facade; keyframeviewundo.h loses two consumers
- deliberate leftovers with rationale: keyframecontrol's multi-track
composite ops (documented track-0-only limitation of the keyframe
family), keyframeproperties dialog (needs a set_time primitive),
curveview's drag UX, and NodeInputDragger (already engine-side)
- NodeFactory's menu creation moves to UI-side widget/menu/factorymenu
(the factory only exposes its node library read-only now)
- DiskManager's cache-settings dialog is created through a registered
std::function handler (registered by Core at startup)
- OlivePluginInstance creates progress UIs through a
PluginProgressReporter interface (Null fallback headless) and queries
the active viewer through a provider callback, both registered by Core
- factory.h, diskmanager and pluginSupport no longer reference any
widget//dialog//panel//window headers or classes
- File inputs marked with the 'lut_library' property (currently the
OCIO LUT node) now show a combo box populated from the global LUT
library above the path field: pick a library LUT directly, or use
'Other (Custom File)...' with the regular path field; selections go
through the standard undoable input-change path
- Refresh zh_CN translations with lupdate and translate all strings
introduced by the proxy dialog, LUT library, LUT picker, waveform
sync and footage start time work
- Document the new per-footage custom <proxy> attributes and the
'manual' source-start-time origin in the project file reference
- Add LutFileField UI tests
- Add a global LUT library: user-configurable directories (new
Preferences > LUT tab) scanned recursively for .cube/.3dl files; LUT
node file pickers offer the library dirs as sidebar shortcuts via a
'lut_library' input property handled by the param view bridge
- OCIOLutNode no longer fails silently: missing files, unsupported
extensions and OCIO load errors are recorded in last_error() and
surfaced in the status bar (input still passes through for rendering
safety)
- ColorDialog: re-enable the display -> reference conversion using
ColorProcessor::kInverse with a validity guard, and re-enable the
Display tab in ColorValuesWidget; covered by a round-trip regression
test proving the old OCIO inverse crash no longer occurs
- OCIOGradingTransformLinearNode: enforce the OCIO clampWhite >
clampBlack invariant per frame in Value() so keyframed/connected
values cannot produce invalid grading transforms, and constrain the
white clamp UI minimum whenever the black clamp is static
- Regression tests for LUT extension checks, direction switching, node
error reporting, LUT library scanning, display inverse round-trip and
clamp enforcement
In NodeParamView::SetSelectedNodes, after locating the target node item,
expand and raise its containing NodeParamViewContext dock widget so the
active tab/folded section switches to the one that actually holds the node.
ColorCorrectOFX and similar plugins declare per-channel controls
(Gamma, Contrast, Saturation, Gain, Offset) as kOfxParamTypeRGBA.
Olive previously mapped every RGBA param to NodeValue::kColor and
rendered it as a ColorButton, which is semantically wrong for
adjustment sliders.
This commit adds heuristic semantic detection to distinguish
"true color" inputs (color pickers) from "per-channel scalar"
inputs (float sliders):
- label/hint/name keywords ("gamma", "contrast", "gain", ...)
- display range outside [0, 1]
- uniform default values across all channels
The detected semantic ("color" or "scalar") is stored as the
node input property "color_semantic". The display range and hint
are also persisted as "min" / "max" / "tooltip".
NodeParamViewWidgetBridge now branches on "color_semantic":
- "scalar" → 4× FloatSlider (reuses existing ProcessSlider /
keyframe-track logic, since kColor already splits into 4 tracks)
- otherwise → ColorButton (unchanged)
All 4 test suites pass.