Files
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

189 lines
4.8 KiB
C++

/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This 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/>.
***/
#include "timelineundosplit.h"
#include "node/block/clip/clip.h"
#include "node/block/transition/transition.h"
#include "node/nodeundo.h"
namespace olive
{
//
// BlockSplitCommand
//
void BlockSplitCommand::prepare()
{
reconnect_tree_command_ = new MultiUndoCommand();
new_block_ = static_cast<Block *>(
Node::copy_node_in_graph(block_, reconnect_tree_command_));
}
void BlockSplitCommand::redo()
{
old_length_ = block_->length();
Q_ASSERT(point_ > block_->in() && point_ < block_->out());
reconnect_tree_command_->redo_now();
// Determine our new lengths
Rational new_length = point_ - block_->in();
Rational new_part_length = block_->out() - point_;
// Begin an operation
Track *track = block_->track();
// Set lengths
block_->set_length_and_media_out(new_length);
new_block()->set_length_and_media_in(new_part_length);
// Insert new block
track->insert_block_after(new_block(), block_);
if (ClipBlock *new_clip = dynamic_cast<ClipBlock *>(new_block_)) {
ClipBlock *old_clip = static_cast<ClipBlock *>(block_);
new_clip->add_cache_passthrough_from(old_clip);
}
// If the block had an out transition, we move it to the new block
moved_transition_ = NodeInput();
TransitionBlock *potential_transition =
dynamic_cast<TransitionBlock *>(new_block()->next());
if (potential_transition) {
for (const Node::OutputConnection &output :
block_->output_connections()) {
if (output.second.node() == potential_transition) {
moved_transition_ = NodeInput(potential_transition,
TransitionBlock::k_out_block_input);
Node::disconnect_edge(block_, moved_transition_);
Node::connect_edge(new_block(), moved_transition_);
break;
}
}
}
}
void BlockSplitCommand::undo()
{
Track *track = block_->track();
if (moved_transition_.is_valid()) {
Node::disconnect_edge(new_block(), moved_transition_);
Node::connect_edge(block_, moved_transition_);
}
block_->set_length_and_media_out(old_length_);
track->ripple_remove_block(new_block());
// If we ran a reconnect command, disconnect now
reconnect_tree_command_->undo_now();
}
//
// BlockSplitPreservingLinksCommand
//
Block *BlockSplitPreservingLinksCommand::get_split(Block *original,
int time_index) const
{
if (time_index >= 0 && time_index < times_.size()) {
int original_index = blocks_.indexOf(original);
if (original_index != -1) {
return splits_.at(time_index).at(original_index);
}
}
return nullptr;
}
void BlockSplitPreservingLinksCommand::prepare()
{
splits_.resize(times_.size());
for (int i = 0; i < times_.size(); i++) {
const Rational &time = times_.at(i);
// FIXME: I realize this isn't going to work if the times aren't ordered. I'm lazy so rather
// than writing in a sorting algorithm here, I'll just put an assert as a reminder
// if this ever becomes an issue.
Q_ASSERT(i == 0 || time > times_.at(i - 1));
QVector<Block *> splits(blocks_.size());
for (int j = 0; j < blocks_.size(); j++) {
Block *b = blocks_.at(j);
if (b->in() < time && b->out() > time) {
BlockSplitCommand *split_command =
new BlockSplitCommand(b, time);
split_command->redo_now();
splits.replace(j, split_command->new_block());
commands_.append(split_command);
} else {
splits.replace(j, nullptr);
}
}
splits_.replace(i, splits);
}
// Now that we've determined all the splits, we can relink everything
for (int i = 0; i < blocks_.size(); i++) {
Block *a = blocks_.at(i);
for (int j = 0; j < blocks_.size(); j++) {
if (i == j) {
continue;
}
Block *b = blocks_.at(j);
if (Block::are_linked(a, b)) {
// These blocks are linked, ensure all the splits are linked too
foreach (const QVector<Block *> &split_list, splits_) {
NodeLinkCommand *blc = new NodeLinkCommand(
split_list.at(i), split_list.at(j), true);
blc->redo_now();
commands_.append(blc);
}
}
}
}
}
//
// TrackSplitAtTimeCommand
//
void TrackSplitAtTimeCommand::prepare()
{
// Find Block that contains this time
Block *b = track_->block_containing_time(point_);
if (b) {
command_ = new BlockSplitCommand(b, point_);
}
}
}