--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * This 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "automation.inc"
+#include "clip.h"
+#include "edl.h"
+#include "localsession.h"
+#include "maskauto.h"
+#include "maskautos.h"
+#include "track.h"
+#include "transportque.inc"
+
+MaskAutos::MaskAutos(EDL *edl,
+ Track *track)
+ : Autos(edl, track)
+{
+ type = AUTOMATION_TYPE_MASK;
+}
+
+MaskAutos::~MaskAutos()
+{
+}
+
+
+
+
+void MaskAutos::update_parameter(MaskAuto *src)
+{
+ double selection_start = edl->local_session->get_selectionstart(0);
+ double selection_end = edl->local_session->get_selectionend(0);
+
+// Selection is always aligned to frame for masks
+
+// Create new keyframe if auto keyframes or replace entire keyframe.
+ if(selection_start == selection_end)
+ {
+// Search for keyframe to write to
+ MaskAuto *dst = (MaskAuto*)get_auto_for_editing();
+
+ dst->copy_data(src);
+ }
+ else
+// Replace changed parameter in all selected keyframes.
+ {
+// Search all keyframes in selection but don't create a new one.
+ int64_t start = track->to_units(selection_start, 0);
+ int64_t end = track->to_units(selection_end, 0);
+ Auto *current_auto = 0;
+ MaskAuto *current = 0;
+ current = (MaskAuto*)get_prev_auto(start,
+ PLAY_FORWARD,
+ current_auto,
+ 1);
+
+// The first one determines the changed parameters since it is the one displayed
+// in the GUI.
+ MaskAuto *first = current;
+
+// Update the first one last, so it is available for comparisons to the changed one.
+ for(current = (MaskAuto*)NEXT;
+ current && current->position < end;
+ current = (MaskAuto*)NEXT)
+ {
+ current->update_parameter(first,
+ src);
+ }
+ first->copy_data(src);
+ }
+}
+
+
+
+void MaskAutos::get_points(ArrayList<MaskPoint*> *points,
+ int submask,
+ int64_t position,
+ int direction)
+{
+ MaskAuto *begin = 0, *end = 0;
+ position = (direction == PLAY_FORWARD) ? position : (position - 1);
+
+// Get auto before and after position
+ for(MaskAuto* current = (MaskAuto*)last;
+ current;
+ current = (MaskAuto*)PREVIOUS)
+ {
+ if(current->position <= position)
+ {
+ begin = current;
+ end = NEXT ? (MaskAuto*)NEXT : current;
+ break;
+ }
+ }
+
+// Nothing before position found
+ if(!begin)
+ {
+ begin = end = (MaskAuto*)first;
+ }
+
+// Nothing after position found
+ if(!begin)
+ {
+ begin = end = (MaskAuto*)default_auto;
+ }
+
+
+ SubMask *mask1 = begin->get_submask(submask);
+ SubMask *mask2 = end->get_submask(submask);
+
+ points->remove_all_objects();
+ int total_points = MAX(mask1->points.size(), mask2->points.size());
+ for(int i = 0; i < total_points; i++)
+ {
+ MaskPoint *point = new MaskPoint;
+ MaskPoint point1;
+ int need_point1 = 1;
+ MaskPoint point2;
+ int need_point2 = 1;
+
+ if(i < mask1->points.size())
+ {
+ point1.copy_from(*mask1->points.get(i));
+ need_point1 = 0;
+ }
+
+ if(i < mask2->points.size())
+ {
+ point2.copy_from(*mask2->points.get(i));
+ need_point2 = 0;
+ }
+
+ if(need_point1) point1.copy_from(point2);
+ if(need_point2) point2.copy_from(point1);
+
+ avg_points(point,
+ &point1,
+ &point2,
+ position,
+ begin->position,
+ end->position);
+ points->append(point);
+ }
+}
+
+
+float MaskAutos::get_feather(int64_t position, int direction)
+{
+ Auto *begin = 0, *end = 0;
+ position = (direction == PLAY_FORWARD) ? position : (position - 1);
+
+ get_prev_auto(position, PLAY_FORWARD, begin, 1);
+ get_next_auto(position, PLAY_FORWARD, end, 1);
+
+ double weight = 0.0;
+ if(end->position != begin->position)
+ weight = (double)(position - begin->position) / (end->position - begin->position);
+
+ return ((MaskAuto*)begin)->feather * (1.0 - weight) + ((MaskAuto*)end)->feather * weight;
+}
+
+int MaskAutos::get_value(int64_t position, int direction)
+{
+ Auto *begin = 0, *end = 0;
+ position = (direction == PLAY_FORWARD) ? position : (position - 1);
+
+ get_prev_auto(position, PLAY_FORWARD, begin, 1);
+ get_next_auto(position, PLAY_FORWARD, end, 1);
+
+ double weight = 0.0;
+ if(end->position != begin->position)
+ weight = (double)(position - begin->position) / (end->position - begin->position);
+
+ int result = (int)((double)((MaskAuto*)begin)->value * (1.0 - weight) +
+ (double)((MaskAuto*)end)->value * weight + 0.5);
+// printf("MaskAutos::get_value %d %d %f %d %f %d\n",
+// __LINE__,
+// ((MaskAuto*)begin)->value,
+// 1.0 - weight,
+// ((MaskAuto*)end)->value,
+// weight,
+// result);
+ return result;
+}
+
+
+void MaskAutos::avg_points(MaskPoint *output,
+ MaskPoint *input1,
+ MaskPoint *input2,
+ int64_t output_position,
+ int64_t position1,
+ int64_t position2)
+{
+ if(position2 == position1)
+ {
+ *output = *input1;
+ }
+ else
+ {
+ float fraction2 = (float)(output_position - position1) / (position2 - position1);
+ float fraction1 = 1 - fraction2;
+ output->x = input1->x * fraction1 + input2->x * fraction2;
+ output->y = input1->y * fraction1 + input2->y * fraction2;
+ output->control_x1 = input1->control_x1 * fraction1 + input2->control_x1 * fraction2;
+ output->control_y1 = input1->control_y1 * fraction1 + input2->control_y1 * fraction2;
+ output->control_x2 = input1->control_x2 * fraction1 + input2->control_x2 * fraction2;
+ output->control_y2 = input1->control_y2 * fraction1 + input2->control_y2 * fraction2;
+ }
+
+}
+
+
+Auto* MaskAutos::new_auto()
+{
+ return new MaskAuto(edl, this);
+}
+
+void MaskAutos::dump()
+{
+ printf(" MaskAutos::dump %p\n", this);
+ printf(" Default: position %jd submasks %d\n",
+ default_auto->position,
+ ((MaskAuto*)default_auto)->masks.total);
+ ((MaskAuto*)default_auto)->dump();
+ for(Auto* current = first; current; current = NEXT)
+ {
+ printf(" position %jd masks %d\n",
+ current->position,
+ ((MaskAuto*)current)->masks.total);
+ ((MaskAuto*)current)->dump();
+ }
+}
+
+int MaskAutos::mask_exists(int64_t position, int direction)
+{
+ Auto *current = 0;
+ position = (direction == PLAY_FORWARD) ? position : (position - 1);
+
+ MaskAuto* keyframe = (MaskAuto*)get_prev_auto(position, direction, current);
+
+
+
+ for(int i = 0; i < keyframe->masks.total; i++)
+ {
+ SubMask *mask = keyframe->get_submask(i);
+ if(mask->points.total > 1)
+ return 1;
+ }
+ return 0;
+}
+
+int MaskAutos::total_submasks(int64_t position, int direction)
+{
+ position = (direction == PLAY_FORWARD) ? position : (position - 1);
+ for(MaskAuto* current = (MaskAuto*)last;
+ current;
+ current = (MaskAuto*)PREVIOUS)
+ {
+ if(current->position <= position)
+ {
+ return current->masks.total;
+ }
+ }
+
+ return ((MaskAuto*)default_auto)->masks.total;
+}
+
+
+void MaskAutos::translate_masks(float translate_x, float translate_y)
+{
+ ((MaskAuto *)default_auto)->translate_submasks(translate_x, translate_y);
+ for(MaskAuto* current = (MaskAuto*)first;
+ current;
+ current = (MaskAuto*)NEXT)
+ {
+ current->translate_submasks(translate_x, translate_y);
+ }
+}
+
+