├── Copy Mask to Crop Center.cs ├── Copy Mask to PiP Corner.cs ├── Precise Adjust Mask.cs ├── README.md └── Show FX Names.cs /Copy Mask to Crop Center.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * LICENSE NOTICE FROM THE ORIGINAL AUTHOR: 3 | * As I want you to profit from this plugin, I don't want to bother you with restrictive Licenses. 4 | * That's why you're free to use this script even in any commercial product. 5 | * Of course I would be more than happy about you mentioning me in your final product, but you're not obliged to. 6 | * If you're modifying this script however, you have to credit me as the original author. 7 | * Furthermore, this license notice mustn't be emitted or changed. You can add your own notice to this section but you are not allowed to remove it. 8 | * If this script gets more attention than anticipated I will consider removing this notice altogether, but it's my decision to do so. 9 | * Also I am not to be held liable if you use my script and something bad happens. Use at your own risk! 10 | * 11 | * The original author is: 12 | * ======================= 13 | * David Holland 14 | * aka DustVoice 15 | * 16 | * info@dustvoice.de 17 | * https://dustvoice.de 18 | */ 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using System.Drawing; 23 | using System.Windows.Forms; 24 | using ScriptPortal.Vegas; 25 | 26 | public class EntryPoint { 27 | const string MOTION_TRACKING_FX_NAME = "VEGAS Bézier Masking"; 28 | 29 | const int MASK_0 = 1; 30 | const int MASK_1 = 2; 31 | const int MASK_2 = 4; 32 | const int MASK_3 = 8; 33 | const int MASK_4 = 16; 34 | int MASK_BITMASK = 0; 35 | 36 | public void FromVegas(Vegas vegas) { 37 | Project currProject = vegas.Project; 38 | Int32 videoWidth = currProject.Video.Width; 39 | Int32 videoHeight = currProject.Video.Height; 40 | 41 | TrackEvent[] tes = FindSelectedEvents(currProject); 42 | VideoEvent[] ves = GetVideoEvents(tes); 43 | 44 | if (ves.Length != 2) 45 | { 46 | MessageBox.Show("You have to select exactly 2 video events (in no particular order) in order for this script to work.\nOne of the events must contain the \"" + MOTION_TRACKING_FX_NAME + "\" effect with at least one mask enabled and populated with motion tracking data, the second event is the target event, where the pan and crop center will be populated with the motion track data. Then after clicking on this script you can select the mask to use. The script will copy the location values of the mask to the location values of the pan and crop setting (beginning from the cursor position till the end of the motion tracked clip, or within the selection range).\n\nTerminating...", "Not enough selections", MessageBoxButtons.OK, MessageBoxIcon.Information); 47 | return; 48 | } 49 | 50 | // foreach (VideoEvent ev in ves) 51 | // { 52 | // foreach (Effect ef in ev.Effects) 53 | // { 54 | // MessageBox.Show(ef.Description); 55 | // } 56 | // } 57 | 58 | VideoEvent ve = GetEventContainingEffect(ves, MOTION_TRACKING_FX_NAME); 59 | 60 | if (ve == null) 61 | { 62 | MessageBox.Show("No selected event with the \"" + MOTION_TRACKING_FX_NAME + "\" plugin found which holds the motion tracking data!\n\nTerminating...", "Not enough selections", MessageBoxButtons.OK, MessageBoxIcon.Warning); 63 | return; 64 | } 65 | 66 | OFXEffect fx = GetOFXFromEvent(ve, MOTION_TRACKING_FX_NAME); 67 | 68 | if (fx == null) 69 | { 70 | MessageBox.Show("Can't seem to grab the \"" + MOTION_TRACKING_FX_NAME + "\" effect!\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 71 | return; 72 | } 73 | 74 | PopulateMaskBitmask(fx); 75 | 76 | // show_fx_parameters(fx); 77 | 78 | int mask_to_use = PromptForMaskNumber(); 79 | 80 | if (mask_to_use == -1) 81 | { 82 | return; 83 | } 84 | 85 | VideoEvent ve2 = GetEventDifferentFrom(ves, ve); 86 | 87 | if (ve2 == null) 88 | { 89 | MessageBox.Show("No selected event different from the motion capture event found, which is the target for the motion tracking data!\n\nTerminating...", "Not enough selections", MessageBoxButtons.OK, MessageBoxIcon.Warning); 90 | return; 91 | } 92 | 93 | Timecode startingTime = null; 94 | Timecode endingTime = null; 95 | 96 | DialogResult dialogResult = MessageBox.Show("You have two methods to copy the keyframes:\nOne option is to copy from the current cursor position onwards, till the script runs into the ending of one of the events (yes).\nThe other option is to use the current selection. Note however that this produces unexpected behaviour, if no selection is currently active! (no).\n\nCopy from the cursor onwards?", "Processing Method", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); 97 | 98 | if (dialogResult == DialogResult.Cancel) 99 | { 100 | return; 101 | } 102 | else 103 | { 104 | Double motionStart = ve.Start.ToMilliseconds(); 105 | Double motionEnd = ve.End.ToMilliseconds(); 106 | 107 | Double cornerStart = ve2.Start.ToMilliseconds(); 108 | Double cornerEnd = ve2.End.ToMilliseconds(); 109 | 110 | if (dialogResult == DialogResult.Yes) 111 | { 112 | Double cursorStart = vegas.Transport.CursorPosition.ToMilliseconds(); 113 | 114 | Double max = Math.Max(motionStart, Math.Max(cornerStart, cursorStart)); 115 | Double min = Math.Min(motionEnd, Math.Min(cornerEnd, cursorStart)); 116 | 117 | if (max != cursorStart || min != cursorStart) 118 | { 119 | MessageBox.Show("The cursor must be placed at a position where it covers both selected events!\n\nTerminating...", "Invalid cursor position", MessageBoxButtons.OK, MessageBoxIcon.Warning); 120 | return; 121 | } 122 | 123 | startingTime = new Timecode(cursorStart); 124 | endingTime = new Timecode(Math.Min(motionEnd, cornerEnd)); 125 | } 126 | else if (dialogResult == DialogResult.No) 127 | { 128 | Double selectionStart = vegas.Transport.SelectionStart.ToMilliseconds(); 129 | Double selectionEnd = selectionStart + vegas.Transport.SelectionLength.ToMilliseconds(); 130 | 131 | Double max = Math.Max(motionStart, Math.Max(cornerStart, selectionStart)); 132 | Double min = Math.Min(motionEnd, Math.Min(cornerEnd, selectionEnd)); 133 | 134 | if (max != selectionStart || min != selectionEnd) 135 | { 136 | MessageBox.Show("The selection must be placed in a range where it covers both selected events!\n\nTerminating...", "Invalid selection", MessageBoxButtons.OK, MessageBoxIcon.Warning); 137 | return; 138 | } 139 | 140 | startingTime = new Timecode(selectionStart); 141 | endingTime = new Timecode(selectionEnd); 142 | } 143 | } 144 | 145 | // MessageBox.Show("Current time: " + fx2.CurrentTime.ToString() + "\nCursor pos: " + vegas.Transport.CursorPosition.ToString() + "\nCalculated current time: " + (fx2.CurrentTime + ve2.Start).ToString()); 146 | 147 | OFXDouble2DParameter motionParam = fx.FindParameterByName("Location_" + mask_to_use.ToString()) as OFXDouble2DParameter; 148 | 149 | if (startingTime == null || endingTime == null) 150 | { 151 | MessageBox.Show("Something went wrong as the script tried to use the method you decided...\n\nTerminating...", "Not enough selections", MessageBoxButtons.OK, MessageBoxIcon.Stop); 152 | return; 153 | } 154 | 155 | double deltaX = 0; 156 | double deltaY = 0; 157 | double lastX = 0; 158 | double lastY = 0; 159 | bool deltaPopulated = false; 160 | 161 | VideoMotion ve2vm = ve2.VideoMotion; 162 | 163 | VideoMotionKeyframe prevKeyframe = new VideoMotionKeyframe(currProject, (startingTime - ve2.Start)); 164 | ve2vm.Keyframes.Add(prevKeyframe); 165 | 166 | foreach (OFXDouble2DKeyframe motionKeyframe in motionParam.Keyframes) 167 | { 168 | Timecode keyframeTime = motionKeyframe.Time + ve.Start; 169 | 170 | if (startingTime <= keyframeTime && keyframeTime <= endingTime) 171 | { 172 | if (!deltaPopulated) 173 | { 174 | lastX = motionKeyframe.Value.X; 175 | lastY = motionKeyframe.Value.Y; 176 | 177 | deltaPopulated = true; 178 | } 179 | else 180 | { 181 | deltaX = motionKeyframe.Value.X - lastX; 182 | deltaY = motionKeyframe.Value.Y - lastY; 183 | 184 | lastX = motionKeyframe.Value.X; 185 | lastY = motionKeyframe.Value.Y; 186 | 187 | // TODO: Delete 188 | // MessageBox.Show("Delta X: " + deltaX.ToString() 189 | // + "\nDelta Y: " + deltaY.ToString() 190 | // + "\nLast X: " + lastX.ToString() 191 | // + "\nLast Y: " + lastY.ToString()); 192 | 193 | VideoMotionKeyframe vmKeyframe = new VideoMotionKeyframe(currProject, keyframeTime - ve2.Start); 194 | ve2vm.Keyframes.Add(vmKeyframe); 195 | 196 | // TODO: Delete 197 | // MessageBox.Show("Current Bounds: " + vmKeyframe.Bounds.ToString() 198 | // + "\nCurrent Rotation: " + vmKeyframe.Rotation.ToString() 199 | // + "\nCurrent Type: " + vmKeyframe.Type.ToString() 200 | // + "\nCurrent Smoothness: " + vmKeyframe.Smoothness.ToString() 201 | // + "\n\nPrevious Bounds: " + prevKeyframe.Bounds.ToString() 202 | // + "\nPrevious Rotation: " + prevKeyframe.Rotation.ToString() 203 | // + "\nPrevious Type: " + prevKeyframe.Type.ToString() 204 | // + "\nPrevious Smoothness: " + prevKeyframe.Smoothness.ToString()); 205 | 206 | // Duplicate previous keyframe values 207 | // vmKeyframe.Bounds = prevKeyframe.Bounds; 208 | // vmKeyframe.Rotation = prevKeyframe.Rotation; 209 | // vmKeyframe.Type = prevKeyframe.Type; 210 | // vmKeyframe.Smoothness = prevKeyframe.Smoothness; 211 | 212 | // bool kfGrabbed = false; 213 | // foreach (VideoMotionKeyframe kf in ve2vm.Keyframes) 214 | // { 215 | // if (kf.Position.Equals(vmKeyframe.Position)) 216 | // { 217 | // vmKeyframe = kf; 218 | // kfGrabbed = true; 219 | // break; 220 | // } 221 | // } 222 | 223 | // if (!kfGrabbed) 224 | // { 225 | // MessageBox.Show("Something went wrong as the script tried to regrab a created keyframe with the Timecode " + vmKeyframe.Position.ToString() + " ...\n\nTerminating...", "Error regrabbing keyframe", MessageBoxButtons.OK, MessageBoxIcon.Stop); 226 | // return; 227 | // } 228 | 229 | double convertedX = deltaX * videoWidth; 230 | double convertedY = -1 * (deltaY * videoHeight); 231 | 232 | vmKeyframe.MoveBy(new VideoMotionVertex(Convert.ToSingle(convertedX), Convert.ToSingle(convertedY))); 233 | 234 | // MessageBox.Show("Next Bounds: " + vmKeyframe.Bounds.ToString() 235 | // + "\nNext Rotation: " + vmKeyframe.Rotation.ToString() 236 | // + "\nNext Type: " + vmKeyframe.Type.ToString() 237 | // + "\nNext Smoothness: " + vmKeyframe.Smoothness.ToString()); 238 | 239 | prevKeyframe = vmKeyframe; 240 | } 241 | } 242 | } 243 | 244 | // TODO: Bother with interpolation shit? 245 | // dialogResult = MessageBox.Show("Do you also want to copy the interpolation data?", "Copy interpolation data?", MessageBoxButtons.YesNo); 246 | 247 | // if (dialogResult == DialogResult.Yes) 248 | // { 249 | // int curr = 0; 250 | // int end = cornerParam.Keyframes.Count; 251 | 252 | // foreach (OFXDouble2DKeyframe motionKeyframe in motionParam.Keyframes) 253 | // { 254 | // Timecode keyframeTime = motionKeyframe.Time + ve.Start; 255 | // if (curr < end && startingTime <= keyframeTime && keyframeTime <= endingTime) 256 | // { 257 | // Timecode calculatedTime = (keyframeTime - ve2.Start); 258 | 259 | // OFXDouble2DKeyframe cornerKeyframe = cornerParam.Keyframes[curr] as OFXDouble2DKeyframe; 260 | // if (cornerKeyframe.Time == calculatedTime) 261 | // { 262 | // cornerKeyframe.Interpolation = motionKeyframe.Interpolation; 263 | // } 264 | // else if (cornerKeyframe.Time < calculatedTime) 265 | // { 266 | // ++curr; 267 | // } 268 | // } 269 | // } 270 | // } 271 | 272 | // cornerParam.ParameterChanged(); 273 | } 274 | 275 | private TrackEvent[] FindSelectedEvents(Project project) 276 | { 277 | List selectedEvents = new List(); 278 | 279 | foreach (Track track in project.Tracks) 280 | { 281 | foreach (TrackEvent trackEvent in track.Events) 282 | { 283 | if (trackEvent.Selected) 284 | { 285 | selectedEvents.Add(trackEvent); 286 | } 287 | } 288 | } 289 | return selectedEvents.ToArray(); 290 | } 291 | 292 | private VideoEvent[] GetVideoEvents(TrackEvent[] te) 293 | { 294 | List videoEvents = new List(); 295 | 296 | foreach (TrackEvent trackEvent in te) 297 | { 298 | if (trackEvent.IsVideo()) 299 | { 300 | videoEvents.Add((VideoEvent) trackEvent); 301 | } 302 | } 303 | 304 | return videoEvents.ToArray(); 305 | } 306 | 307 | private VideoEvent GetEventContainingEffect(VideoEvent[] ve, string effect_name) 308 | { 309 | foreach (VideoEvent videoEvent in ve) 310 | { 311 | foreach (Effect fx in videoEvent.Effects) 312 | { 313 | if (fx.Description.Equals(effect_name)) 314 | { 315 | return videoEvent; 316 | } 317 | } 318 | } 319 | 320 | return null; 321 | } 322 | 323 | private VideoEvent GetEventDifferentFrom(VideoEvent[] ve, VideoEvent comparison) 324 | { 325 | foreach (VideoEvent videoEvent in ve) 326 | { 327 | if (!videoEvent.Equals(comparison)) 328 | { 329 | return videoEvent; 330 | } 331 | } 332 | 333 | return null; 334 | } 335 | 336 | private Effect GetEffectFromEvent(VideoEvent ve, string effect_name) 337 | { 338 | foreach (Effect fx in ve.Effects) 339 | { 340 | if (fx.Description.Equals(effect_name)) 341 | { 342 | return fx; 343 | } 344 | } 345 | 346 | return null; 347 | } 348 | 349 | private OFXEffect GetOFXFromEvent(VideoEvent ve, string effect_name) 350 | { 351 | foreach (Effect fx in ve.Effects) 352 | { 353 | if (fx.Description.Equals(effect_name)) 354 | { 355 | return fx.OFXEffect; 356 | } 357 | } 358 | 359 | return null; 360 | } 361 | 362 | private void PopulateMaskBitmask(OFXEffect fx) 363 | { 364 | string[] paramNames = { "Enable_0", "Enable_1", "Enable_2", "Enable_3", "Enable_4" }; 365 | 366 | for (int i = 0; i < paramNames.Length; ++i) 367 | { 368 | int BITMASK_NUMBER = (int) Math.Pow(2, i); 369 | 370 | OFXBooleanParameter param = fx.FindParameterByName(paramNames[i]) as OFXBooleanParameter; 371 | 372 | if (param.Value) 373 | { 374 | MASK_BITMASK += BITMASK_NUMBER; 375 | } 376 | } 377 | } 378 | 379 | private int PromptForMaskNumber() 380 | { 381 | Form QuestionForm = new Form(); 382 | QuestionForm.Text = "Mask Selection"; 383 | Label labelMaskChoice = new Label(); 384 | labelMaskChoice.Text = "Choose a Mask to copy from:"; 385 | labelMaskChoice.Location = new Point(1, 1); 386 | labelMaskChoice.Size = new Size(200, labelMaskChoice.Size.Height); 387 | 388 | ComboBox MaskChoices = new ComboBox(); 389 | 390 | MaskChoices.Location = new Point(1, labelMaskChoice.Location.Y + labelMaskChoice.Height + 5); 391 | 392 | string[] mask_choices = { "Mask 1", "Mask 2", "Mask 3", "Mask 4", "Mask 5" }; 393 | 394 | for (int i = 0; i < mask_choices.Length; ++i) 395 | { 396 | int BITMASK_NUMBER = (int) Math.Pow(2, i); 397 | 398 | if ((MASK_BITMASK & BITMASK_NUMBER) != 0) 399 | { 400 | MaskChoices.Items.Add(mask_choices[i]); 401 | } 402 | } 403 | MaskChoices.SelectedIndex = 0; 404 | 405 | Button Done = new Button(); 406 | Done.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); }; 407 | MaskChoices.KeyDown += (s, g) => { if (g.KeyCode == Keys.Enter) { ComboBox cb = (ComboBox)s; Form f = (Form)cb.Parent; f.Close(); } }; 408 | Done.Text = "Done"; 409 | Done.Location = new Point(1, MaskChoices.Location.Y + MaskChoices.Height + 5); ; 410 | QuestionForm.Controls.Add(MaskChoices); 411 | QuestionForm.Controls.Add(Done); 412 | QuestionForm.Controls.Add(labelMaskChoice); 413 | QuestionForm.FormBorderStyle = FormBorderStyle.FixedDialog; 414 | QuestionForm.AutoSize = true; 415 | QuestionForm.Height = Done.Location.Y + Done.Height + 5; //This is too small for the form, it autosizes to "big enough" 416 | QuestionForm.Width = MaskChoices.Location.X + MaskChoices.Width + 5; 417 | QuestionForm.ShowDialog(); 418 | 419 | if (MaskChoices.SelectedIndex >= 0) 420 | { 421 | string selectedText = MaskChoices.SelectedItem.ToString(); 422 | char last_char = selectedText[selectedText.Length - 1]; 423 | int selectedMask = int.Parse(last_char.ToString()) - 1; 424 | int BITMASK_NUMBER = (int) Math.Pow(2, (selectedMask)); 425 | 426 | /* 427 | * MessageBox.Show("Selected Index: " + MaskChoices.SelectedIndex.ToString() + "\n" 428 | * + "BITMASK_NUMBER: " + BITMASK_NUMBER.ToString() + "\n" 429 | * + "MASK_BITMASK: " + MASK_BITMASK + "\n" 430 | * + "MASK_BITMASK & BITMASK_NUMBER: " + (MASK_BITMASK & BITMASK_NUMBER)); 431 | */ 432 | 433 | if ((MASK_BITMASK & BITMASK_NUMBER) == 0) 434 | { 435 | MessageBox.Show("This Mask is not enabled, or you have selected this Mask twice!\n\nTerminating...", "Wrong Mask", MessageBoxButtons.OK, MessageBoxIcon.Warning); 436 | return -1; 437 | } 438 | 439 | MASK_BITMASK -= BITMASK_NUMBER; 440 | 441 | return selectedMask; 442 | } 443 | 444 | return -1; 445 | } 446 | 447 | private void show_fx_parameters(OFXEffect fx) 448 | { 449 | string paramNames = ""; 450 | foreach(OFXParameter param in fx.Parameters) 451 | { 452 | paramNames += param.Name + " -> " + param.Label + "\n"; 453 | } 454 | MessageBox.Show(paramNames); 455 | } 456 | } 457 | -------------------------------------------------------------------------------- /Copy Mask to PiP Corner.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * LICENSE NOTICE FROM THE ORIGINAL AUTHOR: 3 | * As I want you to profit from this plugin, I don't want to bother you with restrictive Licenses. 4 | * That's why you're free to use this script even in any commercial product. 5 | * Of course I would be more than happy about you mentioning me in your final product, but you're not obliged to. 6 | * If you're modifying this script however, you have to credit me as the original author. 7 | * Furthermore, this license notice mustn't be emitted or changed. You can add your own notice to this section but you are not allowed to remove it. 8 | * If this script gets more attention than anticipated I will consider removing this notice altogether, but it's my decision to do so. 9 | * Also I am not to be held liable if you use my script and something bad happens. Use at your own risk! 10 | * 11 | * The original author is: 12 | * ======================= 13 | * David Holland 14 | * aka DustVoice 15 | * 16 | * info@dustvoice.de 17 | * https://dustvoice.de 18 | */ 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using System.Drawing; 23 | using System.Windows.Forms; 24 | using ScriptPortal.Vegas; 25 | 26 | public class EntryPoint { 27 | const string MOTION_TRACKING_FX_NAME = "VEGAS Bézier Masking"; 28 | const string PIP_FX_NAME = "VEGAS Picture In Picture"; 29 | const string PIP_FX_MODE_NAME = "Free Form"; 30 | 31 | const int MASK_0 = 1; 32 | const int MASK_1 = 2; 33 | const int MASK_2 = 4; 34 | const int MASK_3 = 8; 35 | const int MASK_4 = 16; 36 | int MASK_BITMASK = 0; 37 | int CORNER_BITMASK = MASK_0 + MASK_1 + MASK_2 + MASK_3; 38 | 39 | public void FromVegas(Vegas vegas) { 40 | TrackEvent[] tes = FindSelectedEvents(vegas.Project); 41 | VideoEvent[] ves = GetVideoEvents(tes); 42 | 43 | if (ves.Length != 2) 44 | { 45 | MessageBox.Show("You have to select exactly 2 video events (in no particular order) in order for this script to work.\nOne of the events must contain the \"" + MOTION_TRACKING_FX_NAME + "\" effect with at least one mask enabled and populated with motion tracking data, the second event must contain the \"" + PIP_FX_NAME + "\" effect with the mode set to \"" + PIP_FX_MODE_NAME + "\".\nThen after clicking on this script you can select the mask and corner to use. The script will copy the location values of the mask to the location values of the pip corner (beginning from the cursor position till the end of the motion tracked clip, or within the selection range).\n\nTerminating...", "Not enough selections", MessageBoxButtons.OK, MessageBoxIcon.Information); 46 | return; 47 | } 48 | 49 | // foreach (VideoEvent ev in ves) 50 | // { 51 | // foreach (Effect ef in ev.Effects) 52 | // { 53 | // MessageBox.Show(ef.Description); 54 | // } 55 | // } 56 | 57 | VideoEvent ve = GetEventContainingEffect(ves, MOTION_TRACKING_FX_NAME); 58 | 59 | if (ve == null) 60 | { 61 | MessageBox.Show("No selected event with the \"" + MOTION_TRACKING_FX_NAME + "\" plugin found which holds the motion tracking data!\n\nTerminating...", "Not enough selections", MessageBoxButtons.OK, MessageBoxIcon.Warning); 62 | return; 63 | } 64 | 65 | OFXEffect fx = GetOFXFromEvent(ve, MOTION_TRACKING_FX_NAME); 66 | 67 | if (fx == null) 68 | { 69 | MessageBox.Show("Can't seem to grab the \"" + MOTION_TRACKING_FX_NAME + "\" effect!\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 70 | return; 71 | } 72 | 73 | PopulateMaskBitmask(fx); 74 | 75 | // show_fx_parameters(fx); 76 | 77 | VideoEvent ve2 = GetEventContainingEffect(ves, PIP_FX_NAME); 78 | 79 | if (ve2 == null) 80 | { 81 | MessageBox.Show("No selected event with the \"" + PIP_FX_NAME + "\" plugin found which is the target for the motion tracking data!\n\nTerminating...", "Not enough selections", MessageBoxButtons.OK, MessageBoxIcon.Warning); 82 | return; 83 | } 84 | 85 | OFXEffect fx2 = GetOFXFromEvent(ve2, PIP_FX_NAME); 86 | 87 | if (fx2 == null) 88 | { 89 | MessageBox.Show("Can't seem to grab the \"" + PIP_FX_NAME + "\" effect!\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 90 | return; 91 | } 92 | 93 | OFXChoiceParameter param = fx2.FindParameterByName("KeepProportions") as OFXChoiceParameter; 94 | 95 | OFXChoice choice = param.Value; 96 | 97 | if (!param.Value.Name.Equals(PIP_FX_MODE_NAME)) 98 | { 99 | MessageBox.Show("The Mode of the \"" + PIP_FX_NAME + "\" effect has to be set to \"" + PIP_FX_MODE_NAME + "\"!\n\nTerminating...", "Wrong effect mode", MessageBoxButtons.OK, MessageBoxIcon.Warning); 100 | return; 101 | } 102 | 103 | bool goOn = false; 104 | List masks_to_use = new List(); 105 | List corners_to_use = new List(); 106 | 107 | while (!goOn) 108 | { 109 | int mask_to_use = PromptForMaskNumber(); 110 | 111 | if (mask_to_use == -1) 112 | { 113 | MessageBox.Show("Something went wrong during the mask choosing process!\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 114 | return; 115 | } 116 | 117 | // show_fx_parameters(fx2); 118 | 119 | string corner_to_use = PromptForCorner(); 120 | 121 | if (corner_to_use == null) 122 | { 123 | MessageBox.Show("Something went wrong during the corner choosing process!\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 124 | return; 125 | } 126 | 127 | masks_to_use.Add(mask_to_use); 128 | corners_to_use.Add(corner_to_use); 129 | 130 | if (MASK_BITMASK == 0 || CORNER_BITMASK == 0) 131 | { 132 | goOn = true; 133 | continue; 134 | } 135 | 136 | DialogResult continueResult = MessageBox.Show("Do you want to choose another mask-corner pair?", "Another one?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); 137 | 138 | if (continueResult == DialogResult.Cancel) 139 | { 140 | return; 141 | } 142 | else if (continueResult == DialogResult.No ) 143 | { 144 | goOn = true; 145 | } 146 | } 147 | 148 | if (masks_to_use.Count != corners_to_use.Count) 149 | { 150 | MessageBox.Show("Something went wrong during the mask-corner choosing process!\nMask-count differs from Corner-count!\n\nMaybe you have selected the same Mask or corner twice?\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 151 | } 152 | 153 | Timecode startingTime = null; 154 | Timecode endingTime = null; 155 | 156 | DialogResult dialogResult = MessageBox.Show("You have two methods to copy the keyframes:\nOne option is to copy from the current cursor position onwards, till the script runs into the ending of one of the events (yes).\nThe other option is to use the current selection. Note however that this produces unexpected behaviour, if no selection is currently active! (no).\n\nCopy from the cursor onwards?", "Processing Method", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); 157 | 158 | if (dialogResult == DialogResult.Cancel) 159 | { 160 | return; 161 | } 162 | else 163 | { 164 | Double motionStart = ve.Start.ToMilliseconds(); 165 | Double motionEnd = ve.End.ToMilliseconds(); 166 | 167 | Double cornerStart = ve2.Start.ToMilliseconds(); 168 | Double cornerEnd = ve2.End.ToMilliseconds(); 169 | 170 | if (dialogResult == DialogResult.Yes) 171 | { 172 | Double cursorStart = vegas.Transport.CursorPosition.ToMilliseconds(); 173 | 174 | Double max = Math.Max(motionStart, Math.Max(cornerStart, cursorStart)); 175 | Double min = Math.Min(motionEnd, Math.Min(cornerEnd, cursorStart)); 176 | 177 | if (max != cursorStart || min != cursorStart) 178 | { 179 | MessageBox.Show("The cursor must be placed at a position where it covers both selected events!\n\nTerminating...", "Invalid cursor position", MessageBoxButtons.OK, MessageBoxIcon.Warning); 180 | return; 181 | } 182 | 183 | startingTime = new Timecode(cursorStart); 184 | endingTime = new Timecode(Math.Min(motionEnd, cornerEnd)); 185 | } 186 | else if (dialogResult == DialogResult.No) 187 | { 188 | Double selectionStart = vegas.Transport.SelectionStart.ToMilliseconds(); 189 | Double selectionEnd = selectionStart + vegas.Transport.SelectionLength.ToMilliseconds(); 190 | 191 | Double max = Math.Max(motionStart, Math.Max(cornerStart, selectionStart)); 192 | Double min = Math.Min(motionEnd, Math.Min(cornerEnd, selectionEnd)); 193 | 194 | if (max != selectionStart || min != selectionEnd) 195 | { 196 | MessageBox.Show("The selection must be placed in a range where it covers both selected events!\n\nTerminating...", "Invalid selection", MessageBoxButtons.OK, MessageBoxIcon.Warning); 197 | return; 198 | } 199 | 200 | startingTime = new Timecode(selectionStart); 201 | endingTime = new Timecode(selectionEnd); 202 | } 203 | } 204 | 205 | // MessageBox.Show("Current time: " + fx2.CurrentTime.ToString() + "\nCursor pos: " + vegas.Transport.CursorPosition.ToString() + "\nCalculated current time: " + (fx2.CurrentTime + ve2.Start).ToString()); 206 | 207 | if (startingTime == null || endingTime == null) 208 | { 209 | MessageBox.Show("Something went wrong as the script tried to use the method you decided...\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 210 | return; 211 | } 212 | 213 | PopulateMaskBitmask(fx); 214 | CORNER_BITMASK = MASK_0 + MASK_1 + MASK_2 + MASK_3; 215 | 216 | for (int i = 0; i < masks_to_use.Count; ++i) 217 | { 218 | OFXDouble2DParameter motionParam = fx.FindParameterByName("Location_" + masks_to_use[i].ToString()) as OFXDouble2DParameter; 219 | 220 | OFXDouble2DParameter cornerParam = fx2.FindParameterByName(corners_to_use[i]) as OFXDouble2DParameter; 221 | 222 | foreach (OFXDouble2DKeyframe motionKeyframe in motionParam.Keyframes) 223 | { 224 | Timecode keyframeTime = motionKeyframe.Time + ve.Start; 225 | if (startingTime <= keyframeTime && keyframeTime <= endingTime) 226 | { 227 | cornerParam.SetValueAtTime((keyframeTime - ve2.Start), motionKeyframe.Value); 228 | } 229 | } 230 | 231 | cornerParam.ParameterChanged(); 232 | } 233 | 234 | // dialogResult = MessageBox.Show("Do you also want to copy the interpolation data?", "Copy interpolation data?", MessageBoxButtons.YesNo); 235 | 236 | // if (dialogResult == DialogResult.Yes) 237 | // { 238 | // int curr = 0; 239 | // int end = cornerParam.Keyframes.Count; 240 | 241 | // foreach (OFXDouble2DKeyframe motionKeyframe in motionParam.Keyframes) 242 | // { 243 | // Timecode keyframeTime = motionKeyframe.Time + ve.Start; 244 | // if (curr < end && startingTime <= keyframeTime && keyframeTime <= endingTime) 245 | // { 246 | // Timecode calculatedTime = (keyframeTime - ve2.Start); 247 | 248 | // OFXDouble2DKeyframe cornerKeyframe = cornerParam.Keyframes[curr] as OFXDouble2DKeyframe; 249 | // if (cornerKeyframe.Time == calculatedTime) 250 | // { 251 | // cornerKeyframe.Interpolation = motionKeyframe.Interpolation; 252 | // } 253 | // else if (cornerKeyframe.Time < calculatedTime) 254 | // { 255 | // ++curr; 256 | // } 257 | // } 258 | // } 259 | // } 260 | 261 | // cornerParam.ParameterChanged(); 262 | } 263 | 264 | private TrackEvent[] FindSelectedEvents(Project project) 265 | { 266 | List selectedEvents = new List(); 267 | 268 | foreach (Track track in project.Tracks) 269 | { 270 | foreach (TrackEvent trackEvent in track.Events) 271 | { 272 | if (trackEvent.Selected) 273 | { 274 | selectedEvents.Add(trackEvent); 275 | } 276 | } 277 | } 278 | return selectedEvents.ToArray(); 279 | } 280 | 281 | private VideoEvent[] GetVideoEvents(TrackEvent[] te) 282 | { 283 | List videoEvents = new List(); 284 | 285 | foreach (TrackEvent trackEvent in te) 286 | { 287 | if (trackEvent.IsVideo()) 288 | { 289 | videoEvents.Add((VideoEvent) trackEvent); 290 | } 291 | } 292 | 293 | return videoEvents.ToArray(); 294 | } 295 | 296 | private VideoEvent GetEventContainingEffect(VideoEvent[] ve, string effect_name) 297 | { 298 | foreach (VideoEvent videoEvent in ve) 299 | { 300 | foreach (Effect fx in videoEvent.Effects) 301 | { 302 | if (fx.Description.Equals(effect_name)) 303 | { 304 | return videoEvent; 305 | } 306 | } 307 | } 308 | 309 | return null; 310 | } 311 | 312 | private Effect GetEffectFromEvent(VideoEvent ve, string effect_name) 313 | { 314 | foreach (Effect fx in ve.Effects) 315 | { 316 | if (fx.Description.Equals(effect_name)) 317 | { 318 | return fx; 319 | } 320 | } 321 | 322 | return null; 323 | } 324 | 325 | private OFXEffect GetOFXFromEvent(VideoEvent ve, string effect_name) 326 | { 327 | foreach (Effect fx in ve.Effects) 328 | { 329 | if (fx.Description.Equals(effect_name)) 330 | { 331 | return fx.OFXEffect; 332 | } 333 | } 334 | 335 | return null; 336 | } 337 | 338 | private void PopulateMaskBitmask(OFXEffect fx) 339 | { 340 | string[] paramNames = { "Enable_0", "Enable_1", "Enable_2", "Enable_3", "Enable_4" }; 341 | 342 | for (int i = 0; i < paramNames.Length; ++i) 343 | { 344 | int BITMASK_NUMBER = (int) Math.Pow(2, i); 345 | 346 | OFXBooleanParameter param = fx.FindParameterByName(paramNames[i]) as OFXBooleanParameter; 347 | 348 | if (param.Value) 349 | { 350 | MASK_BITMASK += BITMASK_NUMBER; 351 | } 352 | } 353 | } 354 | 355 | private int PromptForMaskNumber() 356 | { 357 | Form QuestionForm = new Form(); 358 | QuestionForm.Text = "Mask Selection"; 359 | Label labelMaskChoice = new Label(); 360 | labelMaskChoice.Text = "Choose a Mask to copy from:"; 361 | labelMaskChoice.Location = new Point(1, 1); 362 | labelMaskChoice.Size = new Size(200, labelMaskChoice.Size.Height); 363 | 364 | ComboBox MaskChoices = new ComboBox(); 365 | 366 | MaskChoices.Location = new Point(1, labelMaskChoice.Location.Y + labelMaskChoice.Height + 5); 367 | 368 | string[] mask_choices = { "Mask 1", "Mask 2", "Mask 3", "Mask 4", "Mask 5" }; 369 | 370 | for (int i = 0; i < mask_choices.Length; ++i) 371 | { 372 | int BITMASK_NUMBER = (int) Math.Pow(2, i); 373 | 374 | if ((MASK_BITMASK & BITMASK_NUMBER) != 0) 375 | { 376 | MaskChoices.Items.Add(mask_choices[i]); 377 | } 378 | } 379 | MaskChoices.SelectedIndex = 0; 380 | 381 | Button Done = new Button(); 382 | Done.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); }; 383 | MaskChoices.KeyDown += (s, g) => { if (g.KeyCode == Keys.Enter) { ComboBox cb = (ComboBox)s; Form f = (Form)cb.Parent; f.Close(); } }; 384 | Done.Text = "Done"; 385 | Done.Location = new Point(1, MaskChoices.Location.Y + MaskChoices.Height + 5); ; 386 | QuestionForm.Controls.Add(MaskChoices); 387 | QuestionForm.Controls.Add(Done); 388 | QuestionForm.Controls.Add(labelMaskChoice); 389 | QuestionForm.FormBorderStyle = FormBorderStyle.FixedDialog; 390 | QuestionForm.AutoSize = true; 391 | QuestionForm.Height = Done.Location.Y + Done.Height + 5; //This is too small for the form, it autosizes to "big enough" 392 | QuestionForm.Width = MaskChoices.Location.X + MaskChoices.Width + 5; 393 | QuestionForm.ShowDialog(); 394 | 395 | if (MaskChoices.SelectedIndex >= 0) 396 | { 397 | string selectedText = MaskChoices.SelectedItem.ToString(); 398 | char last_char = selectedText[selectedText.Length - 1]; 399 | int selectedMask = int.Parse(last_char.ToString()) - 1; 400 | int BITMASK_NUMBER = (int) Math.Pow(2, (selectedMask)); 401 | 402 | /* 403 | * MessageBox.Show("Selected Index: " + MaskChoices.SelectedIndex.ToString() + "\n" 404 | * + "BITMASK_NUMBER: " + BITMASK_NUMBER.ToString() + "\n" 405 | * + "MASK_BITMASK: " + MASK_BITMASK + "\n" 406 | * + "MASK_BITMASK & BITMASK_NUMBER: " + (MASK_BITMASK & BITMASK_NUMBER)); 407 | */ 408 | 409 | if ((MASK_BITMASK & BITMASK_NUMBER) == 0) 410 | { 411 | MessageBox.Show("This Mask is not enabled, or you have selected this Mask twice!\n\nTerminating...", "Wrong Mask", MessageBoxButtons.OK, MessageBoxIcon.Warning); 412 | return -1; 413 | } 414 | 415 | MASK_BITMASK -= BITMASK_NUMBER; 416 | 417 | return selectedMask; 418 | } 419 | 420 | return -1; 421 | } 422 | 423 | private string PromptForCorner() 424 | { 425 | Form QuestionForm = new Form(); 426 | QuestionForm.Text = "Corner Selection"; 427 | Label labelCornerChoice = new Label(); 428 | labelCornerChoice.Text = "Choose a corner to copy to:"; 429 | labelCornerChoice.Location = new Point(1, 1); 430 | labelCornerChoice.Size = new Size(200, labelCornerChoice.Size.Height); 431 | 432 | ComboBox CornerChoices = new ComboBox(); 433 | 434 | CornerChoices.Location = new Point(1, labelCornerChoice.Location.Y + labelCornerChoice.Height + 5); 435 | 436 | string[] corner_choices = { "Top Left", "Top Right", "Bottom Left", "Bottom Right" }; 437 | 438 | for (int i = 0; i < corner_choices.Length; ++i) 439 | { 440 | int BITMASK_NUMBER = (int) Math.Pow(2, i); 441 | 442 | if ((CORNER_BITMASK & BITMASK_NUMBER) != 0) 443 | { 444 | CornerChoices.Items.Add(corner_choices[i]); 445 | } 446 | } 447 | CornerChoices.SelectedIndex = 0; 448 | 449 | Button Done = new Button(); 450 | Done.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); }; 451 | CornerChoices.KeyDown += (s, g) => { if (g.KeyCode == Keys.Enter) { ComboBox cb = (ComboBox)s; Form f = (Form)cb.Parent; f.Close(); } }; 452 | Done.Text = "Done"; 453 | Done.Location = new Point(1, CornerChoices.Location.Y + CornerChoices.Height + 5); ; 454 | QuestionForm.Controls.Add(CornerChoices); 455 | QuestionForm.Controls.Add(Done); 456 | QuestionForm.Controls.Add(labelCornerChoice); 457 | QuestionForm.FormBorderStyle = FormBorderStyle.FixedDialog; 458 | QuestionForm.AutoSize = true; 459 | QuestionForm.Height = Done.Location.Y + Done.Height + 5; //This is too small for the form, it autosizes to "big enough" 460 | QuestionForm.Width = CornerChoices.Location.X + CornerChoices.Width + 5; 461 | QuestionForm.ShowDialog(); 462 | 463 | if (CornerChoices.SelectedIndex >= 0) 464 | { 465 | string selectedText = CornerChoices.SelectedItem.ToString(); 466 | 467 | int selectedCorner = -1; 468 | 469 | switch (selectedText) 470 | { 471 | case "Top Left": 472 | selectedCorner = 0; 473 | break; 474 | case "Top Right": 475 | selectedCorner = 1; 476 | break; 477 | case "Bottom Left": 478 | selectedCorner = 2; 479 | break; 480 | case "Bottom Right": 481 | selectedCorner = 3; 482 | break; 483 | default: 484 | break; 485 | } 486 | 487 | if (selectedCorner == -1) 488 | { 489 | MessageBox.Show("Couldn't grab ComboBox content. This could be a bug. Please try again!\n\nTerminating...", "Wrong Corner", MessageBoxButtons.OK, MessageBoxIcon.Warning); 490 | return null; 491 | } 492 | 493 | int BITMASK_NUMBER = (int) Math.Pow(2, (selectedCorner)); 494 | 495 | if ((CORNER_BITMASK & BITMASK_NUMBER) == 0) 496 | { 497 | MessageBox.Show("This corner has already be chosen!\n\nTerminating...", "Wrong Corner", MessageBoxButtons.OK, MessageBoxIcon.Warning); 498 | return null; 499 | } 500 | 501 | CORNER_BITMASK -= BITMASK_NUMBER; 502 | 503 | switch (selectedCorner) 504 | { 505 | case 0: 506 | return "CornerTL"; 507 | case 1: 508 | return "CornerTR"; 509 | case 2: 510 | return "CornerBL"; 511 | case 3: 512 | return "CornerBR"; 513 | default: 514 | return null; 515 | } 516 | } 517 | 518 | return null; 519 | } 520 | 521 | private void show_fx_parameters(OFXEffect fx) 522 | { 523 | string paramNames = ""; 524 | foreach(OFXParameter param in fx.Parameters) 525 | { 526 | paramNames += param.Name + " -> " + param.Label + "\n"; 527 | } 528 | MessageBox.Show(paramNames); 529 | } 530 | } 531 | -------------------------------------------------------------------------------- /Precise Adjust Mask.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * LICENSE NOTICE FROM THE ORIGINAL AUTHOR: 3 | * As I want you to profit from this plugin, I don't want to bother you with restrictive Licenses. 4 | * That's why you're free to use this script even in any commercial product. 5 | * Of course I would be more than happy about you mentioning me in your final product, but you're not obliged to. 6 | * If you're modifying this script however, you have to credit me as the original author. 7 | * Furthermore, this license notice mustn't be emitted or changed. You can add your own notice to this section but you are not allowed to remove it. 8 | * If this script gets more attention than anticipated I will consider removing this notice altogether, but it's my decision to do so. 9 | * Also I am not to be held liable if you use my script and something bad happens. Use at your own risk! 10 | * 11 | * The original author is: 12 | * ======================= 13 | * David Holland 14 | * aka DustVoice 15 | * 16 | * info@dustvoice.de 17 | * https://dustvoice.de 18 | */ 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using System.Drawing; 23 | using System.Windows.Forms; 24 | using ScriptPortal.Vegas; 25 | 26 | public class EntryPoint { 27 | const string MOTION_TRACKING_FX_NAME = "VEGAS Bézier Masking"; 28 | 29 | const int MASK_0 = 1; 30 | const int MASK_1 = 2; 31 | const int MASK_2 = 4; 32 | const int MASK_3 = 8; 33 | const int MASK_4 = 16; 34 | int MASK_BITMASK = 0; 35 | 36 | public void FromVegas(Vegas vegas) { 37 | Project currProject = vegas.Project; 38 | Int32 videoWidth = currProject.Video.Width; 39 | Int32 videoHeight = currProject.Video.Height; 40 | 41 | TrackEvent[] tes = FindSelectedEvents(currProject); 42 | VideoEvent[] ves = GetVideoEvents(tes); 43 | 44 | if (ves.Length != 1) 45 | { 46 | MessageBox.Show("You have to select exactly 1 video events in order for this script to work.\nThe events must contain the \"" + MOTION_TRACKING_FX_NAME + "\" effect with at least one mask enabled. You then zoom in, using pan and crop options. Then after clicking on this script, the pan and crop option will be reset and the point moved, so that it stays on the pixel you selected.\n\nTerminating...", "Wrong selection", MessageBoxButtons.OK, MessageBoxIcon.Information); 47 | return; 48 | } 49 | 50 | // foreach (VideoEvent ev in ves) 51 | // { 52 | // foreach (Effect ef in ev.Effects) 53 | // { 54 | // MessageBox.Show(ef.Description); 55 | // } 56 | // } 57 | 58 | VideoEvent ve = GetEventContainingEffect(ves, MOTION_TRACKING_FX_NAME); 59 | 60 | if (ve == null) 61 | { 62 | MessageBox.Show("No selected event with the \"" + MOTION_TRACKING_FX_NAME + "\" plugin found which holds the motion tracking data!\n\nTerminating...", "Wrong selection", MessageBoxButtons.OK, MessageBoxIcon.Warning); 63 | return; 64 | } 65 | 66 | OFXEffect fx = GetOFXFromEvent(ve, MOTION_TRACKING_FX_NAME); 67 | 68 | if (fx == null) 69 | { 70 | MessageBox.Show("Can't seem to grab the \"" + MOTION_TRACKING_FX_NAME + "\" effect!\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 71 | return; 72 | } 73 | 74 | PopulateMaskBitmask(fx); 75 | 76 | // show_fx_parameters(fx); 77 | 78 | int mask_to_use = PromptForMaskNumber(); 79 | 80 | if (mask_to_use == -1) 81 | { 82 | return; 83 | } 84 | 85 | Timecode cursorTime = null; 86 | 87 | Double motionStart = ve.Start.ToMilliseconds(); 88 | Double motionEnd = ve.End.ToMilliseconds(); 89 | 90 | Double cursorStart = vegas.Transport.CursorPosition.ToMilliseconds(); 91 | 92 | Double max = Math.Max(motionStart, cursorStart); 93 | Double min = Math.Min(motionEnd, cursorStart); 94 | 95 | if (max != cursorStart || min != cursorStart) 96 | { 97 | MessageBox.Show("The cursor must be placed within the event borders!\n\nTerminating...", "Invalid cursor position", MessageBoxButtons.OK, MessageBoxIcon.Warning); 98 | return; 99 | } 100 | 101 | cursorTime = new Timecode(cursorStart); 102 | 103 | OFXDouble2DParameter motionParam = fx.FindParameterByName("Location_" + mask_to_use.ToString()) as OFXDouble2DParameter; 104 | 105 | if (cursorTime == null) 106 | { 107 | MessageBox.Show("Something went wrong as the script tried to determine the cursor position...\n\nTerminating...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 108 | return; 109 | } 110 | 111 | VideoMotion vevm = ve.VideoMotion; 112 | 113 | VideoMotionKeyframe currKeyframe = new VideoMotionKeyframe(currProject, (cursorTime - ve.Start)); 114 | vevm.Keyframes.Add(currKeyframe); 115 | 116 | Single cutoutWidth = currKeyframe.TopRight.X - currKeyframe.TopLeft.X; 117 | Single cutoutHeight = currKeyframe.BottomLeft.Y - currKeyframe.TopLeft.Y; 118 | Single originX = currKeyframe.TopLeft.X; 119 | Single originY = currKeyframe.BottomLeft.Y; 120 | 121 | OFXDouble2D cursorValue = motionParam.GetValueAtTime(cursorTime - ve.Start); 122 | 123 | Double newCoordX = originX + (cutoutWidth * cursorValue.X); 124 | Double newCoordY = originY - (cutoutHeight * cursorValue.Y); 125 | cursorValue.X = newCoordX / videoWidth; 126 | cursorValue.Y = 1 - (newCoordY / videoHeight); 127 | motionParam.SetValueAtTime((cursorTime - ve.Start), cursorValue); 128 | 129 | DialogResult dialogResult = MessageBox.Show("If you choose to also adapt the mask scale, this would mean that the mask will be shrunk together with the video frame.\nIf you have zoomed in alot, it sometimes makes sense to not do this as the control handles would get so small that you can't grab them.\nIf you choose to also adjust the size, you can also later on change the width/height from the mask settings.\n\nWould you like to also adapt the mask scale?", "Also adjust mask scale?", MessageBoxButtons.YesNo, MessageBoxIcon.Question); 130 | 131 | if (dialogResult == DialogResult.Yes) 132 | { 133 | OFXDoubleParameter widthParam = fx.FindParameterByName("Width_" + mask_to_use.ToString()) as OFXDoubleParameter; 134 | OFXDoubleParameter heightParam = fx.FindParameterByName("Height_" + mask_to_use.ToString()) as OFXDoubleParameter; 135 | Double maskWidth = widthParam.GetValueAtTime(cursorTime - ve.Start); 136 | Double maskHeight = heightParam.GetValueAtTime(cursorTime - ve.Start); 137 | Double widthRelation = videoWidth / cutoutWidth; 138 | Double heightRelation = videoHeight / cutoutHeight; 139 | 140 | widthParam.SetValueAtTime((cursorTime - ve.Start), (maskWidth / widthRelation)); 141 | heightParam.SetValueAtTime((cursorTime - ve.Start), (maskHeight / heightRelation)); 142 | } 143 | 144 | VideoMotionBounds restoreBounds = new VideoMotionBounds( 145 | new VideoMotionVertex(0, 0), 146 | new VideoMotionVertex(videoWidth, 0), 147 | new VideoMotionVertex(videoWidth, videoHeight), 148 | new VideoMotionVertex(0, videoHeight) 149 | ); 150 | currKeyframe.Bounds = restoreBounds; 151 | currKeyframe.Center = new VideoMotionVertex((videoWidth / 2), (videoHeight / 2)); 152 | 153 | MessageBox.Show("Please select a different effect, or move the cursor to a differen event, in order to update the control handles of the mask", "Refresh control handles", MessageBoxButtons.OK, MessageBoxIcon.Information); 154 | 155 | fx.AllParametersChanged(); 156 | } 157 | 158 | private TrackEvent[] FindSelectedEvents(Project project) 159 | { 160 | List selectedEvents = new List(); 161 | 162 | foreach (Track track in project.Tracks) 163 | { 164 | foreach (TrackEvent trackEvent in track.Events) 165 | { 166 | if (trackEvent.Selected) 167 | { 168 | selectedEvents.Add(trackEvent); 169 | } 170 | } 171 | } 172 | return selectedEvents.ToArray(); 173 | } 174 | 175 | private VideoEvent[] GetVideoEvents(TrackEvent[] te) 176 | { 177 | List videoEvents = new List(); 178 | 179 | foreach (TrackEvent trackEvent in te) 180 | { 181 | if (trackEvent.IsVideo()) 182 | { 183 | videoEvents.Add((VideoEvent) trackEvent); 184 | } 185 | } 186 | 187 | return videoEvents.ToArray(); 188 | } 189 | 190 | private VideoEvent GetEventContainingEffect(VideoEvent[] ve, string effect_name) 191 | { 192 | foreach (VideoEvent videoEvent in ve) 193 | { 194 | foreach (Effect fx in videoEvent.Effects) 195 | { 196 | if (fx.Description.Equals(effect_name)) 197 | { 198 | return videoEvent; 199 | } 200 | } 201 | } 202 | 203 | return null; 204 | } 205 | 206 | private VideoEvent GetEventDifferentFrom(VideoEvent[] ve, VideoEvent comparison) 207 | { 208 | foreach (VideoEvent videoEvent in ve) 209 | { 210 | if (!videoEvent.Equals(comparison)) 211 | { 212 | return videoEvent; 213 | } 214 | } 215 | 216 | return null; 217 | } 218 | 219 | private Effect GetEffectFromEvent(VideoEvent ve, string effect_name) 220 | { 221 | foreach (Effect fx in ve.Effects) 222 | { 223 | if (fx.Description.Equals(effect_name)) 224 | { 225 | return fx; 226 | } 227 | } 228 | 229 | return null; 230 | } 231 | 232 | private OFXEffect GetOFXFromEvent(VideoEvent ve, string effect_name) 233 | { 234 | foreach (Effect fx in ve.Effects) 235 | { 236 | if (fx.Description.Equals(effect_name)) 237 | { 238 | return fx.OFXEffect; 239 | } 240 | } 241 | 242 | return null; 243 | } 244 | 245 | private void PopulateMaskBitmask(OFXEffect fx) 246 | { 247 | string[] paramNames = { "Enable_0", "Enable_1", "Enable_2", "Enable_3", "Enable_4" }; 248 | 249 | for (int i = 0; i < paramNames.Length; ++i) 250 | { 251 | int BITMASK_NUMBER = (int) Math.Pow(2, i); 252 | 253 | OFXBooleanParameter param = fx.FindParameterByName(paramNames[i]) as OFXBooleanParameter; 254 | 255 | if (param.Value) 256 | { 257 | MASK_BITMASK += BITMASK_NUMBER; 258 | } 259 | } 260 | } 261 | 262 | private int PromptForMaskNumber() 263 | { 264 | Form QuestionForm = new Form(); 265 | QuestionForm.Text = "Mask Selection"; 266 | Label labelMaskChoice = new Label(); 267 | labelMaskChoice.Text = "Choose a Mask to copy from:"; 268 | labelMaskChoice.Location = new Point(1, 1); 269 | labelMaskChoice.Size = new Size(200, labelMaskChoice.Size.Height); 270 | 271 | ComboBox MaskChoices = new ComboBox(); 272 | 273 | MaskChoices.Location = new Point(1, labelMaskChoice.Location.Y + labelMaskChoice.Height + 5); 274 | 275 | string[] mask_choices = { "Mask 1", "Mask 2", "Mask 3", "Mask 4", "Mask 5" }; 276 | 277 | for (int i = 0; i < mask_choices.Length; ++i) 278 | { 279 | int BITMASK_NUMBER = (int) Math.Pow(2, i); 280 | 281 | if ((MASK_BITMASK & BITMASK_NUMBER) != 0) 282 | { 283 | MaskChoices.Items.Add(mask_choices[i]); 284 | } 285 | } 286 | MaskChoices.SelectedIndex = 0; 287 | 288 | Button Done = new Button(); 289 | Done.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); }; 290 | MaskChoices.KeyDown += (s, g) => { if (g.KeyCode == Keys.Enter) { ComboBox cb = (ComboBox)s; Form f = (Form)cb.Parent; f.Close(); } }; 291 | Done.Text = "Done"; 292 | Done.Location = new Point(1, MaskChoices.Location.Y + MaskChoices.Height + 5); ; 293 | QuestionForm.Controls.Add(MaskChoices); 294 | QuestionForm.Controls.Add(Done); 295 | QuestionForm.Controls.Add(labelMaskChoice); 296 | QuestionForm.FormBorderStyle = FormBorderStyle.FixedDialog; 297 | QuestionForm.AutoSize = true; 298 | QuestionForm.Height = Done.Location.Y + Done.Height + 5; //This is too small for the form, it autosizes to "big enough" 299 | QuestionForm.Width = MaskChoices.Location.X + MaskChoices.Width + 5; 300 | QuestionForm.ShowDialog(); 301 | 302 | if (MaskChoices.SelectedIndex >= 0) 303 | { 304 | string selectedText = MaskChoices.SelectedItem.ToString(); 305 | char last_char = selectedText[selectedText.Length - 1]; 306 | int selectedMask = int.Parse(last_char.ToString()) - 1; 307 | int BITMASK_NUMBER = (int) Math.Pow(2, (selectedMask)); 308 | 309 | /* 310 | * MessageBox.Show("Selected Index: " + MaskChoices.SelectedIndex.ToString() + "\n" 311 | * + "BITMASK_NUMBER: " + BITMASK_NUMBER.ToString() + "\n" 312 | * + "MASK_BITMASK: " + MASK_BITMASK + "\n" 313 | * + "MASK_BITMASK & BITMASK_NUMBER: " + (MASK_BITMASK & BITMASK_NUMBER)); 314 | */ 315 | 316 | if ((MASK_BITMASK & BITMASK_NUMBER) == 0) 317 | { 318 | MessageBox.Show("This Mask is not enabled, or you have selected this Mask twice!\n\nTerminating...", "Wrong Mask", MessageBoxButtons.OK, MessageBoxIcon.Warning); 319 | return -1; 320 | } 321 | 322 | MASK_BITMASK -= BITMASK_NUMBER; 323 | 324 | return selectedMask; 325 | } 326 | 327 | return -1; 328 | } 329 | 330 | private void show_fx_parameters(OFXEffect fx) 331 | { 332 | string paramNames = ""; 333 | foreach(OFXParameter param in fx.Parameters) 334 | { 335 | paramNames += param.Name + " -> " + param.Label + "\n"; 336 | } 337 | MessageBox.Show(paramNames); 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VEGAS-Scripts 2 | Custom Scripts for Sony VEGAS Pro 17 3 | 4 | ## YouTube Tutorials 5 | 6 | [Copy Mask to PiP Corner.cs & Copy Mask to Crop Center.cs](https://www.youtube.com/watch?v=M_uxjhB3Ero&feature=youtu.be) 7 | 8 | [Precise Adjust Mask.cs](https://www.youtube.com/watch?v=M8jadIBpPZ8) 9 | -------------------------------------------------------------------------------- /Show FX Names.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * LICENSE NOTICE FROM THE ORIGINAL AUTHOR: 3 | * As I want you to profit from this plugin, I don't want to bother you with restrictive Licenses. 4 | * That's why you're free to use this script even in any commercial product. 5 | * Of course I would be more than happy about you mentioning me in your final product, but you're not obliged to. 6 | * If you're modifying this script however, you have to credit me as the original author. 7 | * Furthermore, this license notice mustn't be emitted or changed. You can add your own notice to this section but you are not allowed to remove it. 8 | * If this script gets more attention than anticipated I will consider removing this notice altogether, but it's my decision to do so. 9 | * Also I am not to be held liable if you use my script and something bad happens. Use at your own risk! 10 | * 11 | * The original author is: 12 | * ======================= 13 | * David Holland 14 | * aka DustVoice 15 | * 16 | * info@dustvoice.de 17 | * https://dustvoice.de 18 | */ 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using System.Drawing; 23 | using System.Windows.Forms; 24 | using ScriptPortal.Vegas; 25 | 26 | public class EntryPoint { 27 | public void FromVegas(Vegas vegas) { 28 | TrackEvent[] tes = FindSelectedEvents(vegas.Project); 29 | VideoEvent[] ves = GetVideoEvents(tes); 30 | 31 | if (ves.Length != 1) 32 | { 33 | MessageBox.Show("You have to select exactly 1 video events (in no particular order) in order for this script to work.\n\nTerminating...", "Wrong selections", MessageBoxButtons.OK, MessageBoxIcon.Information); 34 | return; 35 | } 36 | 37 | VideoEvent ve = ShowFXNames(ves); 38 | 39 | } 40 | 41 | private TrackEvent[] FindSelectedEvents(Project project) 42 | { 43 | List selectedEvents = new List(); 44 | 45 | foreach (Track track in project.Tracks) 46 | { 47 | foreach (TrackEvent trackEvent in track.Events) 48 | { 49 | if (trackEvent.Selected) 50 | { 51 | selectedEvents.Add(trackEvent); 52 | } 53 | } 54 | } 55 | return selectedEvents.ToArray(); 56 | } 57 | 58 | private VideoEvent[] GetVideoEvents(TrackEvent[] te) 59 | { 60 | List videoEvents = new List(); 61 | 62 | foreach (TrackEvent trackEvent in te) 63 | { 64 | if (trackEvent.IsVideo()) 65 | { 66 | videoEvents.Add((VideoEvent) trackEvent); 67 | } 68 | } 69 | 70 | return videoEvents.ToArray(); 71 | } 72 | 73 | private VideoEvent ShowFXNames(VideoEvent[] ve) 74 | { 75 | string effectNames = ""; 76 | foreach (VideoEvent videoEvent in ve) 77 | { 78 | foreach (Effect fx in videoEvent.Effects) 79 | { 80 | effectNames += fx.Description + "\n"; 81 | } 82 | } 83 | 84 | MessageBox.Show(effectNames, "Concrete effect names", MessageBoxButtons.OK, MessageBoxIcon.Information); 85 | 86 | return null; 87 | } 88 | } 89 | --------------------------------------------------------------------------------