CI / Build & test (Windows) (push) Failing after 7s
All crates take the oak-* kebab-case naming (oak-audio, oak-codec, oak-common, oak-core, oak-ffmpeg-link, oak-node, oak-otio, oak-plugin, oak-render, oak-storage, oak-task, oak-timeline, oak-undo), with the lib identifiers rewritten (oakrender:: -> oak_render::, oakcore_rs:: -> oak_core::, ...) across all 226 referencing files. The GUI application moves from the workspace root into crates/oak-app/: src/, build.rs (paths fixed for the new location) and tests/ travel with it, the root Cargo.toml becomes workspace-only ([workspace] + workspace.package + profiles), and the app package inherits the workspace version. The screenshots example becomes a standalone crate examples/simple_player/ with its own Cargo.toml. Every crate now inherits the single workspace version (version.workspace = true), and the workflows' crate paths and the build docs follow the renames. Validated with a clean cargo check --workspace.
144 lines
4.4 KiB
Rust
144 lines
4.4 KiB
Rust
// Oak Video Editor - Non-Linear Video Editor
|
|
// Copyright (C) 2026 Oak 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 <http://www.gnu.org/licenses/>.
|
|
|
|
//! Time generator node (C++ `src/node/src/input/time/timeinput.{h,cpp}`,
|
|
//! `olive::TimeInput`).
|
|
|
|
use crate::factory::NodeMeta;
|
|
use crate::node::{Category, NodeBehavior, NodeCore};
|
|
use crate::value::{NodeValue, NodeValueRow, NodeValueTable};
|
|
use oak_core::Rational;
|
|
|
|
/// Time input node. Emits the current time (in seconds) as a float.
|
|
/// The C++ class has no own members (no inputs, no caches of its own),
|
|
/// so this is a unit-like struct.
|
|
pub struct TimeInput;
|
|
|
|
impl NodeBehavior for TimeInput {
|
|
/// Human-readable name (C++ `name()`).
|
|
fn name(&self) -> &str {
|
|
"Time"
|
|
}
|
|
|
|
/// Stable type id (C++ `id()`).
|
|
fn type_id(&self) -> &str {
|
|
"org.olivevideoeditor.Olive.time"
|
|
}
|
|
|
|
/// Categories (C++ `category()` returns `{ k_category_time }`; the
|
|
/// Rust [`Category`] enum has no `Time` variant, so this returns an
|
|
/// empty slice — see the note on [`register`]).
|
|
fn categories(&self) -> &[Category] {
|
|
&[]
|
|
}
|
|
|
|
/// Description (C++ `description()`).
|
|
fn description(&self) -> &str {
|
|
"Generates the time (in seconds) at this frame."
|
|
}
|
|
|
|
/// Evaluate outputs (C++ `value()`): pushes the current global time
|
|
/// (`globals.time().in().to_double()`, here the `time` argument) as a
|
|
/// float value, not marked as a texture, with the push tag `"time"`.
|
|
fn value(
|
|
&self,
|
|
core: &NodeCore,
|
|
inputs: &NodeValueRow,
|
|
time: Rational,
|
|
table: &mut NodeValueTable,
|
|
) {
|
|
let _ = (core, inputs);
|
|
table.push(
|
|
crate::value::ValueType::Float,
|
|
NodeValue::Float(time.to_f64()),
|
|
Some("time".to_string()),
|
|
);
|
|
}
|
|
|
|
/// Deep copy (C++ `copy()` via `NODE_DEFAULT_FUNCTIONS`).
|
|
fn duplicate(&self, _core: &NodeCore) -> Option<Box<dyn NodeBehavior>> {
|
|
Some(Box::new(TimeInput))
|
|
}
|
|
}
|
|
|
|
/// Constructor (C++ `TimeInput::TimeInput()`): trivial — the node has no
|
|
/// inputs to wire up.
|
|
pub fn create() -> (NodeCore, Box<dyn NodeBehavior>) {
|
|
(NodeCore::new(), Box::new(TimeInput))
|
|
}
|
|
|
|
/// Register this node type (C++ `k_time` in
|
|
/// `factory.cpp::create_from_factory_index`). NOTE: the C++ category is
|
|
/// `k_category_time`, which has no counterpart in the Rust [`Category`]
|
|
/// enum, so the entry is registered with an empty category list.
|
|
pub fn register(meta: &mut Vec<NodeMeta>) {
|
|
meta.push(NodeMeta {
|
|
type_id: "org.olivevideoeditor.Olive.time",
|
|
name: "Time",
|
|
categories: &[],
|
|
create,
|
|
});
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::value::{NodeValueTable, ValueType};
|
|
use oak_core::Rational;
|
|
|
|
#[test]
|
|
fn value_pushes_current_time_as_float() {
|
|
let (core, behavior) = create();
|
|
let mut table = NodeValueTable::default();
|
|
behavior.value(
|
|
&core,
|
|
&crate::value::NodeValueRow::default(),
|
|
Rational::new(15, 2),
|
|
&mut table,
|
|
);
|
|
assert_eq!(table.get(ValueType::Float), Some(&NodeValue::Float(7.5)));
|
|
// The pushed row carries the "time" tag (C++ push tag).
|
|
let (_, _, tag) = &table.rows()[0];
|
|
assert_eq!(tag.as_deref(), Some("time"));
|
|
}
|
|
|
|
#[test]
|
|
fn value_ignores_inputs() {
|
|
let (core, behavior) = create();
|
|
let mut row = crate::value::NodeValueRow::default();
|
|
row.insert("some_in".to_string(), NodeValue::Float(99.0));
|
|
let mut table = NodeValueTable::default();
|
|
behavior.value(&core, &row, Rational::new(3, 1), &mut table);
|
|
assert_eq!(table.get(ValueType::Float), Some(&NodeValue::Float(3.0)));
|
|
}
|
|
|
|
#[test]
|
|
fn create_has_only_enabled_input() {
|
|
let (core, behavior) = create();
|
|
assert_eq!(behavior.type_id(), "org.olivevideoeditor.Olive.time");
|
|
assert_eq!(core.inputs.len(), 1);
|
|
assert_eq!(core.inputs[0].id, crate::node::ENABLED_INPUT);
|
|
}
|
|
|
|
#[test]
|
|
fn duplicate_copies_node() {
|
|
let (_core, behavior) = create();
|
|
let copy = behavior.duplicate(&_core).unwrap();
|
|
assert_eq!(copy.type_id(), "org.olivevideoeditor.Olive.time");
|
|
assert_eq!(copy.name(), "Time");
|
|
}
|
|
}
|