Commit Graph
7002 Commits
Author SHA1 Message Date
Mike-Solar d63131cb12 engine: add the playback family to the facade 2026-07-20 17:46:49 +08:00
Mike-Solar f5acf31b43 docs: refine the viewer migration mapping with frame-path reuse and facade refinements 2026-07-20 16:45:09 +08:00
Mike-Solar 9872c4f48f docs: record the icon cluster and core-boundary findings in the roadmap risks 2026-07-20 16:37:52 +08:00
Mike-Solar cc6105ddd0 docs: add a measurable engine-coupling metric to the roadmap acceptance list 2026-07-20 16:32:24 +08:00
Mike-Solar 8f3ae107b4 docs: detail the viewer panel migration mapping in the facade roadmap 2026-07-20 16:27:45 +08:00
Mike-Solar 245f204c81 engine: timeline panel leftover commands migrate to the facade (round 3)
- new primitives: clip_toggle_enabled (per-block flip), clip_set_linked,
  sequence_add_default_transition (config-driven, sequence timebase),
  node_set_label_many, node_set_color_label, plus observation getters
- toggle-links, default transitions, enable toggles, color labels, and
  block renaming now go through the facade; the stray empty undo entry
  from block renaming is gone along the way
- nest/multicam/waveform-sync stay as documented composites: they mix
  redo_now intermediate state, graph surgery, and app-side computation
  that a single primitive cannot express faithfully
- the timeline panel's command execution paths are now fully migrated
2026-07-20 16:17:37 +08:00
Mike-Solar 37aa859cd0 engine: keyframe properties dialog migrates; keyframeviewundo deleted
- new primitives: keyframes_set_time_many (conflict-safe batch time
  move), keyframes_set_value_many (captured or explicit old values),
  keyframes_set_bezier_many (double precision), and
  keyframe_set_bezier_point (single handle with NaN-capture fallback)
- dialog and curveview drag finalization go through the facade; the
  tests exercise the same global undo stack via oakengine_project_undo
- keyframeview/keyframeviewundo.{h,cpp} removed with zero remaining
  references
2026-07-20 15:41:36 +08:00
Mike-Solar 8311128f4c engine: node parameter panel migrates to the facade
- 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)
2026-07-20 14:42:00 +08:00
Mike-Solar 0fe37dba3c engine: timeline panel batch/composite commands migrate to the facade (part 2)
- new primitives: ripple_delete_in_to_out (ripple or gap fill plus
  work-area state, one undo command), trim_clips_to (batch edge trim
  returning a count), delete_empty_tracks (type-filtered batch), and
  marker_remove_many (sparse marker deletion by timestamp array)
- delete-in-to-out, edit-to, delete-all-empty-tracks, and sequence
  viewer marker deletion now go through the facade; empty operations
  no longer push empty undo entries
- footage viewer marker deletion keeps its app path deliberately
  (facade marker handles are Sequences, not generic viewers); the
  tentative subtitle track and pointer drag chain stay as documented
  leftovers
2026-07-20 13:37:10 +08:00
Mike-Solar 2aa7eec016 engine: timeline panel core edit commands migrate to the facade (part 1)
- new batch primitives: split_clips (link-preserving, single undo
  command), delete_clips (gap replace + optional ripple with explicit
  region support), ripple_delete_range, marker_add_ex with color
- razor/split-at-playhead, clip delete, ripple-to-point, track delete,
  and the non-dialog marker path now issue facade commands instead of
  the app's own undo command classes
- batch operations deliberately produce one undo command per user
  action (deleting twenty clips is one entry, not twenty); selection
  and transition removal stay UI-side as documented leftovers
2026-07-20 13:17:07 +08:00
Mike-Solar 0a25d43218 engine: sequence parameters dialog migrates to the facade
- new facade API: video params ex (dimensions/rate/par/interlacing/
  preview format/divider), audio params, preview divider, and
  undoable-flagged setters mirroring the dialog's dual undo/no-undo
  modes; label setting gains node_set_label_ex
- the dialog's own SequenceParamCommand is gone; accept now issues
  facade calls (per-field commands, unchanged fields skipped)
- preset system stays UI-side by design: its flat XML schema never
  touches engine objects
- the auto-cache checkbox maps to the engine's existing stub (no undo
  noise)
2026-07-20 12:42:54 +08:00
Mike-Solar 456060ef3e engine: footage properties and project explorer migrate to the facade
- new facade API: video stream overrides (colorspace/range/interlacing/
  premultiply), pixel aspect, image-sequence params, stream enable,
  source start time, and colorspace candidates - all undoable
- project explorer proxy actions now run through FacadeProxyTask and
  the facade media-management functions (ProxyManager references in
  projectexplorer.cpp drop from 5 call sites to a comment)
- footage properties dialog reads/writes through the facade; its two
  app-side undo command classes are gone
- handle-model fix: the footage handle is a heap state object, not a
  plain pointer cast - oakengine_footage_borrow() wraps app-held
  Footage nodes correctly (nine UB reinterpret_casts caught by the
  DialogFootageProperties tests)
2026-07-20 12:16:21 +08:00
Mike-Solar 62f18125cb export: dialog execution path now goes through the facade
- oakengine_export_render_ex covers the dialog's entire option surface
  (formats, codecs, pix fmts, audio params, ranges incl. still frame,
  subtitles, scaling, threads, custom OCIO color transform names,
  per-codec key/value options) - zero feature reduction
- the dialog's Start now creates a FacadeExportTask that drives
  oakengine_export_render_ex instead of constructing ExportTask in the
  UI; progress flows through the facade callback and cancel through
  oakengine_export_cancel (OAKENGINE_E_CANCELLED preserves the
  keep-dialog-open semantics)
- two real fixes: audio sample format 0 no longer means an
  AAC-unsupported u8_p (default is f32_p), and image-sequence exports
  use the engine's real [#####] placeholder instead of a made-up -%04d
2026-07-20 11:06:46 +08:00
Mike-Solar 1ea6527b80 engine: prewarm conforms before facade export
Drives ConformManager for every audio-streaming footage with the same
AudioParams the export will use, before starting ExportTask - matching
the app's preview prewarm semantics. Root-cause analysis showed the
export's own wait-for-conform path already worked; this remains as a
first-export speedup and a belt-and-braces guarantee
2026-07-20 09:55:27 +08:00
Mike-Solar bb17c59c0f engine: add the preview family to the C ABI facade
- clip-level loop mode (off/loop/clamp), undoable
- per-channel audio levels as one-frame RMS at a timestamp
- waveform min/max buckets over a footage range, rendered on demand
- two real fixes uncovered by this family: conform completion signals
  were starved by msleep-only waits (audio renders always came back
  empty), and incomplete tickets from conform-pending renders are now
  retried until the conform is ready
2026-07-20 09:28:47 +08:00
Mike-Solar 882ce8268c engine: add media management (relink/proxy) to the footage facade
- relink through Footage::set_filename with the engine's natural
  clear+reprobe cascade; find_offline_footage recovers offline media
  by exact filename match under a search directory
- synchronous proxy generate (event-loop driven like the export
  family), state query, enable/disable, path, and delete, mirroring
  the app's proxy dialog assembly
- documented as non-undoable, matching the app's existing semantics
2026-07-20 08:53:43 +08:00
Mike-Solar 71b1243ad8 engine: add sequence structure to the timeline facade
- undoable track removal (content restored on undo) and true-move
  track reordering assembled from the edge commands (the engine has
  no move-track API)
- track height/mute/lock getters and setters, documented as
  non-undoable to match the engine's current semantics
- undoable marker add/remove/rename; duplicate timestamps are
  rejected with E_STATE instead of hitting the engine's debug assert
2026-07-20 08:42:03 +08:00
Mike-Solar eaa301b755 engine: add the keyframe family to the node facade
- keyframed state, count, read (time in sequence timebase + mapped
  values), add/remove, easing read/write (linear/bezier/hold with
  control points), and clear - all undoable with full undo/redo
  assertions
- easing set commands are minimal capi-local UndoCommands matching
  the app-layer semantics (engine has none of its own); same-time
  duplicates are rejected with E_STATE instead of hitting the engine's
  debug assert
2026-07-20 08:31:24 +08:00
Mike-Solar e82011b0ee engine: add the node graph family to the C ABI facade
- project node enumeration, type/name/label metadata, input
  introspection (id, mapped value type, connection state)
- typed parameter read/write for the eight common NodeValue kinds
  (int/float/bool/rational/color/vec2-4/combo/string), undoable via
  NodeParamSetSplitStandardValueCommand - the split-track value path,
  chosen after proving the standard-value command stores whole
  variants into a single component track
- graph operations (add/remove/connect/disconnect) reusing the
  engine's undo commands, all covered by undo/redo assertions
2026-07-20 08:16:43 +08:00
Mike-Solar db355c28b9 docs: facade migration roadmap for the remaining UI migration work 2026-07-20 07:53:16 +08:00
Mike-Solar 1ab7fa49a0 engine: timeline edit primitives round 2 (split/ripple-delete/trim/move)
All four are undoable and reuse the timeline/ command classes verbatim
(BlockSplitCommand, TrackRippleRemoveAreaCommand, BlockTrimCommand,
ReplaceBlockWithGap+PlaceBlock), with undo/redo assertions covering
split halves, media-in alignment on trim, ripple shift amounts, and
full restoration on undo
2026-07-20 07:52:07 +08:00
Mike-Solar b9b5ad09f7 engine: add the export family to the C ABI facade; mp4 transcode
- oakengine_export_render drives ExportTask synchronously (offline
  render + encode) with a progress callback, codec probing, and a
  thread-local error channel; exporter.h keeps clear of the visibility
  macro header
- oak-cli transcode now defaults to mp4 (H.264/AAC) with --format ppm
  keeping the raw output path
- two real concurrency bugs found by the facade's own test: ExportTask
  deadlocks when start()ed synchronously (queued conform handshake
  needs an event loop), and the progress callback must be captured by
  value because it fires on the task thread
2026-07-20 07:34:21 +08:00
Mike-Solar c1ee784600 engine: timeline edit primitives and oak-cli transcode
- oakengine_sequence_add_track and add_footage_clip are the facade's
  first editing primitives: undoable track creation and clip placement
  with full range validation, clip enumeration, and gap filtering
- oak-cli transcode closes the loop: media file -> import -> clip ->
  render, producing scaled PPM frames and a WAV from just the C ABI
- engine fix uncovered by transcode: the render worker used an invalid
  empty AudioParams for IPC render frames, crashing any sequence that
  contains audio; it now derives them from the rendered node itself
- sequence_new hardens its defaults against missing audio config keys
2026-07-20 06:33:14 +08:00
Mike-Solar 1a7029fd8f engine: add the footage family to the C ABI facade; oak-cli probe
- oakengine_footage_probe inspects media without a project (decoder
  probe): stream counts, per-stream video info (dimensions, rate,
  duration, color tags, interlacing), audio info, duration, decoder
  name, source start time; thread_local last_error for the NULL-handle
  failure paths
- oakengine_project_import_footage adds probed footage to a project
  through the same undoable command path as the app
- oak-cli probe prints decoder/duration/per-stream details and runs as
  a ctest everywhere (no GL)
- dual ownership documented: probe handles are owned, imported footage
  is borrowed from its project
2026-07-20 06:03:16 +08:00
Mike-Solar 6118260e01 engine: expose sequence video dimensions in the timeline facade
- oakengine_sequence_get_video_params (width/height/pixel aspect) with
  assertions for the default 1920x1080 square-pixel sequence and the
  invalid-handle path
- oak-cli now renders at the sequence's real dimensions instead of the
  hardcoded 1920x1080
2026-07-20 05:51:53 +08:00
Mike-Solar 009af0ff3f cli: add oak-cli, the first pure C ABI consumer of liboakengine
- oak-cli info prints project/sequence/footage details; oak-cli render
  writes PPM frames and a PCM WAV through the facade only - no engine
  C++ headers, no Qt headers, links just liboakengine
- exit code 2 marks rendering-unavailable so ctest can skip cleanly on
  machines without a GL render backend; info test runs everywhere
- facade fix uncovered by the CLI: project load now absolutizes the
  path, so relative footage paths can't be mistaken for a moved
  project; the fixture project now carries probed footage wired into
  its sequence so it renders real content
- packaged like the other binaries (Linux bin install, macOS bundle,
  Windows DLL copies); DESTDIR-verified
2026-07-20 05:48:07 +08:00
Mike-Solar b26ffb7d64 engine: add the renderer family to the C ABI facade
- oakengine_renderer_create/set_mode/last_error, render_frame (sync,
  60s timeout, CPU frames via the existing worker pool),
  render_audio (planar float), cancel; frames and audio buffers are
  owned handles with borrowed data pointers
- output colorspace names map to OCIO display transforms, with
  graceful fallback to reference-space output
- oakengine_renderer_test: parameter validation and error paths need
  no GL and always run; render assertions gate on
  DynamicRenderer backend availability and SKIP cleanly otherwise
- fix a facade bug found by its own test: wait_for_ticket leaked a
  connected lambda capturing a stack reference, which a subsequent
  cancelled ticket could fire into reused stack memory
2026-07-20 05:26:42 +08:00
Mike-Solar 5db7aac058 engine: add init/project/timeline families to the C ABI facade
- oakengine_init/shutdown with HEADLESS/RENDER flags: headless boots
  Config, NodeFactory, ColorManager, task/conform/proxy/frame/disk
  managers and the serializer (plus an offscreen QGuiApplication that
  Qt requires for QAction); RENDER adds RenderManager. Idempotent and
  upgradable, no UI anywhere
- oakengine_project_* (17): create/load/save, modified state, name,
  footage enumeration with online check, undo/redo, sequence access
- oakengine_sequence_* (13): name, length (seconds and rational),
  frame rate, per-type track counts, playhead (timestamp and seconds),
  work area, markers; sequences are borrowed handles owned by their
  project
- pure-C oakengine_init_test covers init idempotency, save/load
  round-trip through a real fixture project, footage online checks,
  timeline parameters, and NULL/bounds safety - no GL required
2026-07-20 04:54:45 +08:00
Mike-Solar 37845302f9 engine: begin the liboakengine C ABI facade with the IPC subsystem
- oakengine/export.h establishes the OAKENGINE_API visibility macros;
  include/oakengine/ipc.h is the first pure-C surface (41 functions:
  shm, frame slot pool, and the worker IPC messages as POD<->JSON
  build/parse), implemented in engine/src/capi/
- the IPC implementations move to engine/src/oliveimpl (namespace
  olive::engine::internal::ipc); engine/render/ipc/*.h are rebuilt as
  same-name/same-API wrapper classes forwarding across the C boundary
- FrameSlotMeta is shared with the C header verbatim so the app/worker
  wire format (v1) is bit-identical; static_asserts pin sizeof and
  field offsets
- spscringbuffer.h moves to include/oakengine/ as an inline-only
  header (no symbols, not ABI)
- new pure-C test oakengine_ipc_test (make_oakengine_test, no GL)
  covers shm, frame pool, message round-trips and the layout asserts;
  full gtest suite stays green (1986 tests)
2026-07-20 04:12:58 +08:00
Mike-Solar 28c4426236 build: split the engine into liboakengine.so; worker drops the UI entirely
Physical split: app/{audio,cli,codec,common,config,node,pluginSupport,
render,task,timeline,undo,tool,shaders} plus coreengine, version and
ui/icons+colorcoding move to a new top-level engine/ tree, built as
liboakengine.so (shared). The render backends (oakgl/oakvulkan) move
with it and link the engine library instead of embedding a static
render-core subset (libolive-rendercore is gone).

- oak-render-worker now links liboakengine instead of the whole
  libolive-editor object set: 336MB -> 2.9MB, no Qt Widgets UI
- the editor links liboakengine for the engine and keeps only UI
  objects in libolive-editor
- install/packaging: GNUInstallDirs libdir on Linux, bundle copy on
  macOS, oakengine.dll staged for NSIS, AppImage validation entry
- fix backend lookup for the new layout: DynamicRenderer searched
  ../app but backends now live in engine/; a stale pre-split liboakgl
  in the build tree got dlopened instead, re-initialized and later
  destroyed the interposed engine statics (full-suite segfault at
  DialogSequenceParameterTab, found via gdb watchpoint)
2026-07-20 03:23:28 +08:00
Mike-Solar 026ff94b5e refactor: invert the last engine-to-UI dependencies
- 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
2026-07-20 02:05:01 +08:00
Mike-Solar bff06e00e5 refactor: split Core into EngineCore (engine) and Core (UI)
EngineCore (new app/coreengine.{h,cpp}) owns every engine-safe part of
the old Core singleton: CoreParams, lifecycle of the engine managers,
UndoStack, tool/snapping/timecode state, locale, autorecovery, recent
projects, footage filters, clipboard, project registry, type
declarations, and the proxy toggle. UI dependencies are inverted
through hooks instead: status-bar/cache-full signals and std::function
handlers for image-sequence confirmation, footage relink, OTIO import,
project save/close and layout load (same pattern as
Config::ErrorHandler).

Core (app/) now derives from EngineCore and keeps only UI behavior:
the main window, dialogs, panel heuristics, import/export flows and
project lifecycle presentation. Its public API is unchanged (all
inherited), and Core::instance() covariantly static_casts the engine
singleton. The render worker constructs EngineCore directly, making it
the first binary that no longer needs the UI side of Core.

~25 engine call sites move from core.h to coreengine.h; a dozen more
drop a vestigial core.h include (gaining direct includes for symbols
they were borrowing transitively). Full gtest suite green (1986 tests,
0 failures).
2026-07-20 01:38:42 +08:00
Mike-Solar 5109dd2995 refactor: move the ratio input dialog out of engine common/ into dialog/
get_float_ratio_from_user() is pure UI (QInputDialog/QMessageBox);
common/ stays dialog-free.
2026-07-20 01:04:57 +08:00
Mike-Solar 69cd8d3a75 refactor: move msg_box out of engine qtutils into the dialog layer
The engine-side QtUtils no longer references QMessageBox; the two
dialog call sites use the identical olive::msg_box() inline helper.
2026-07-20 01:01:18 +08:00
Mike-Solar 03d4087124 refactor: cut engine-to-UI include violations ahead of the liboakengine split
- slider DisplayType enums sink to node/sliderdisplaytype.h (canonical
  engine home); FloatSlider/RationalSlider alias them for compatibility
- DropWithoutSequenceBehavior enum sinks to common/dropworkflowbehavior.h
- Config errors now go through a registered ErrorHandler hook instead of
  QMessageBox with a MainWindow parent; the style default no longer
  depends on the UI style manager
- MainWindowLayoutInfo moves to node/project/serializer/ and its panel
  dependency is reduced to a plain std::map alias (PanelLayoutInfo),
  breaking the engine -> PanelWidget -> KDDockWidgets chain
- ProjectImportErrorDialog moves from task/ to dialog/projectimport/
- remove confirmed-redundant UI includes and give project.h/import.h/
  project.cpp the direct includes they were borrowing transitively
- project.h includes folder/sequence headers directly (it used both
  types in its own API all along)
2026-07-20 00:52:12 +08:00
Mike-Solar 98f2f3e224 build: install liboakcore from the default target set
core was added with EXCLUDE_FROM_ALL, which also excluded its install
rules, so liboakcore.so never made it into packages. It now installs to
the platform libdir (/usr/lib on this machine, verified via DESTDIR).
2026-07-19 23:52:59 +08:00
Mike-Solar 1128694257 core: restrict liboakcore exports to the C ABI via version script
Even statically linked runtime libraries must not leak symbols: the
linker version script now whitelists oakcore_* only. nm reports 188
oakcore_* exports and zero anything else.
2026-07-19 23:51:15 +08:00
Mike-Solar 4fc8b80d7e core: turn olivecore into liboakcore.so with a pure C ABI
liboakcore is now a shared library that exposes only a C ABI:
- every value class (Rational, TimeRange, Color, Bezier, AudioParams,
  SampleBuffer) and the free-function groups (StringUtils, fraction
  utils, Timecode) is wrapped in an opaque-handle C API under
  core/include/olive/core/oakcore/ (init/copy/free + self-first
  functions), implemented in core/src/capi/
- consumers keep the original C++ API unchanged through same-name
  wrapper classes that hold the handle and forward across the C
  boundary; original implementations moved to core/src/oliveimpl
  (namespace olive::core::internal) and are hidden from export
- TimeRangeList/TimeRangeListFrameIterator are reimplemented inline
  over the wrapper (iterators/containers don't cross C ABI)
- generic Value container stays internal (unused by consumers) and is
  no longer part of the public umbrella header
- hidden visibility + OAKCORE_BUILD export macro; nm shows zero
  olive::* symbols exported
- install into the platform's standard libdir (GNUInstallDirs);
  Windows DLLs next to the executables, macOS into the app bundle
- TimelineWorkArea::in/out/length now return by value: the wrapped
  TimeRange getters return values, and forwarding them through const
  references dangled (found via RenderWorkerFootageTest crash)
- tests: 9 new pure C ABI test executables (oakcore_*_test) covering
  every public C function; 4 stale legacy core tests removed (they
  targeted a long-renamed API and were never built due to a malformed
  option() that also kept OLIVECORE_BUILD_TESTS off)
- CI/CD: oakcore.dll staged for NSIS, liboakcore.so added to the
  AppImage validation list, build-tree DLL copies on Windows
2026-07-19 23:49:40 +08:00
Mike-Solar 52625f2b98 proxy: restore pdivider (de)serialization dropped in the commit split
The load/save of the per-footage custom divider attribute was lost when
the proxy changes were re-applied during the three-way commit split;
ProxyManager.FootagePersistsCustomProxyParams caught it.
2026-07-19 23:49:14 +08:00
Mike-Solar 7832cb30b3 build: move render worker out of app/ into top-level worker/
- oak-render-worker now builds from worker/ (own CMakeLists.txt) as a
  peer of app/; RenderWorkerPool resolves the new build-tree location
- deduplicated the Linux install() rules for the worker
- worker-spawning tests resolve build/worker instead of build/app
- cd.yml: Windows staging copies the worker from its new output path
2026-07-19 22:12:29 +08:00
Mike-Solar 76f5c2a65b color: input colorspace auto-detection, HDR export tags, LGG/white balance nodes, more LUT formats, waveform parade
- media color primaries/transfer tags now flow from the FFmpeg probe
  through VideoParams into Footage::get_colorspace_to_use(); precedence
  is user override > media tags > project default
- export nclc tags derive from the output colorspace (PQ/HLG/BT.2020,
  P3, sRGB, Rec.601, Rec.709) instead of hardcoded BT.709
- new OCIO Color Grading (Log) node (lift/gamma/gain) and White Balance
  node (kelvin temperature + tint, HDR-safe)
- LUT whitelist extended to 9 OCIO-supported formats
- waveform scope gains an RGB parade mode (GPU and software paths)
- tests updated for the new colorspace precedence
2026-07-19 21:45:51 +08:00
Mike-Solar a7ddc0f114 audio: master-clock playback timing, output clock compensation, buffer config, interpolated speed
- playback timer uses the audio output device as its master clock: the
  PortAudio callback counts consumed frames (including underrun
  zero-fill) so video cannot drift away from what is heard; wall clock
  remains as fallback when no clocked output is running
- output clock compensates for device output latency; new Preferences >
  Audio buffer size setting (0 = auto)
- SampleBuffer::speed() now uses linear interpolation instead of
  nearest-neighbor sampling
- regression tests: audio-clock driven timer (fwd/rev/speed), wall
  clock fallback, interpolation correctness
2026-07-19 21:44:34 +08:00
Mike-Solar 0c02ff0d77 proxy: isolate proxies from export renders and improve proxy workflow
- FootageJob::should_use_proxy() centralizes the proxy decision; worker
  pre-decode now honors the render mode so exports always decode the
  original media (previously every frame was pre-decoded from proxies)
- global Tools > Use Proxy Media toggle with footage invalidation
- ffmpeg -progress parsing for real percentage feedback while generating
- divider mode (1/2, 1/4, 1/8 of source resolution) with UI, proxy
  filename tags and per-footage persistence (pdivider)
- Media Offline warning slat rendered for missing footage
- regression tests: export isolation, relink invalidation, offline slat,
  progress parsing, divider arguments
2026-07-19 21:43:58 +08:00
Mike-Solar bb40b4923e style: unify identifier naming per updated conventions
Automated with clang-tidy readability-identifier-naming (config added to
.clang-tidy) plus scripted passes, per the updated rules now documented
in CONTRIBUTING.md:

- types (class/struct/enum/alias/template params): PascalCase
- functions, variables, members: snake_case (incl. rational -> Rational)
- private/protected members: trailing underscore; static member
  variables likewise (instance_, available_themes_)
- constants and enum values: snake_case (kLinear -> k_linear,
  F32P -> f32p); ALL_CAPS reserved for macros
- macros: OAK_ prefix (OLIVE_ADD_TEST/OLIVE_ASSERT/OLIVE_CONFIG ->
  OAK_ADD_TEST/OAK_ASSERT/OAK_CONFIG, GL_PREAMBLE -> OAK_GL_PREAMBLE,
  include guards -> OAK_*)
- file names: all lowercase (Current/Plugin/OliveHost/OliveClip/
  OlivePluginInstance -> current/plugin/olivehost/oliveclip/
  oliveplugininstance)
- getters share the member name sans underscore, setters set_foo()
- Qt and third-party (OpenFX) virtual overrides and framework callbacks
  keep their original names (exempt in .clang-tidy)

Manual follow-ups required where automation could not reach:
- string-based QMetaObject/SIGNAL/SLOT references updated to renamed
  methods (AddTask, CreatedFile, DeleteSpecificFile, moveSelectionUp, ...)
- macro bodies referencing renamed methods (OLIVE_CONFIG,
  NODE_DEFAULT_DESTRUCTOR, MANAGEDDISPLAYWIDGET_*)
- self-shadowing locals renamed where signals/methods became same-named
  (size_changed, worker_count, selected_items, import param, filters)
- third_party OFX member/namespace usages restored (OFX::Host::*,
  _created, _clipPrefsDirty, createInstance, clearPersistentMessage)
- STL protocol aliases restored (const_iterator) with .clang-tidy
  ignore rules; qHash overloads restored

Full build and test suite pass: ctest 4/4, ~1960 gtest cases green.
2026-07-19 16:10:54 +08:00
Mike-Solar cb1718a103 test: replace fake and duplicate tests with real assertions
Fake tests rewritten to assert real behavior:
- audio_smoke: conversion tests now actually Convert() samples and verify
  output; waveform length/summary assertions tightened to exact values
- plugin_format_conversion: RowBytes/U8ToU16/LoadImageFile now call real
  production code (VideoParams::GetBytesPerPixel, sws scaler, OIIO decode
  of tests/img.png with known pixel values)
- core_color: HSV round trip now verifies fromHsv(toHsv(c)) == c instead
  of comparing toHsv against its own accessors
- core_bezier/node_inputimmediate: expected values replaced with
  independently derived constants instead of re-running the code under test
- common_commandlineparser/common_debug/common_jobtime: capture
  stdout/stderr/qDebug and assert actual output content
- proxy_manager: ProxyFinished test now drives a real proxy job instead of
  emitting the signal itself; proxy_dialog/panel/proxy/preferences/timeruler
  tests assert real widget state
- viewer_smoke/preview_autocacher/render_misc: zero-assertion tests given
  observable-state assertions or removed where nothing is observable

Duplicates removed:
- plugin_smoke_test.cpp: 18 tests duplicated from plugin_paraminstance /
  plugin_support_* / plugin_renderer_readback (751 -> 180 lines)
- module_smoke HumanStrings tests covered precisely by ui_humanstrings_test
- render_misc duplicate kDefaultInterpolation constant check

Removed by policy (skip allowed, never disabled):
- all DISABLED_ prefixes: re-enabled as real offscreen tests or deleted
- ffmpeg_decoder_hw: hardcoded personal path replaced with
  OAK_TEST_HW_DECODE_FILE env var, GTEST_SKIP when unset

Also:
- config_test: restore Config defaults after run (cross-test pollution)
- render_worker_footage: drop /tmp debug-output scaffolding
- previewaudiodevice construction test asserts the real bugfix
2026-07-19 13:58:31 +08:00
Mike-Solar b0aa683499 fix: dangling OpenGL context crash and uninitialized audio frame size
- OpenGLRenderer: hold the viewer-owned QOpenGLContext in a QPointer so
  DestroyInternal() safely skips it when the context has already been
  destroyed by Qt's shared-context lifecycle. Fixes a SIGSEGV when the
  full gtest suite ran MainWindow.ConstructsOffscreenWithPanelsAndMenus
  after earlier viewer tests.
- PreviewAudioDevice: add SetParams() deriving bytes_per_frame from the
  audio format (bytes per sample * channel count) instead of staying 0.
2026-07-19 13:58:06 +08:00
Mike-Solar 842bc7632b update: Update build.md 2026-07-18 20:57:10 +08:00
Mike-Solar 64a250391c about: thank Enzo GD in the About and Welcome dialogs
Enzo GD, administrator of the Olive Facebook user group, gave this
project generous promotional support in its early days. The shared body
text now carries a special-thanks line in both the About dialog and the
first-run Welcome dialog; zh_CN translation included.
2026-07-18 20:13:58 +08:00
Mike-Solar fd93de42ca Merge remote-tracking branch 'origin/main' 2026-07-18 18:27:46 +08:00
Mike-Solar ca68005fc2 ci: switch to GitHub-hosted runners and add daily cache-warming build
- Runners: ubuntu-24.04, macos-15, windows-latest (free tier) instead
  of WarpBuild 8x/12x instances
- openfx-misc parallelism adapts to nproc (GitHub runners have fewer
  vCPUs than the WarpBuild instances)
- Schedule a daily 03:17 UTC run so ccache entries never hit GitHub's
  7-day cache expiry and system dependencies stay current
2026-07-18 14:29:14 +08:00