1 // Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
2 //
3 // Permission to use, copy, modify, and distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 //
15 // Aegisub Project http://www.aegisub.org/
16 
17 /// @file visual_tool_rotatez.cpp
18 /// @brief 2D rotation in Z axis visual typesetting tool
19 /// @ingroup visual_ts
20 
21 #include "visual_tool_rotatez.h"
22 
23 #include "include/aegisub/context.h"
24 #include "selection_controller.h"
25 
26 #include <libaegisub/format.h>
27 
28 #include <cmath>
29 #include <wx/colour.h>
30 
31 static const float deg2rad = 3.1415926536f / 180.f;
32 static const float rad2deg = 180.f / 3.1415926536f;
33 
VisualToolRotateZ(VideoDisplay * parent,agi::Context * context)34 VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, agi::Context *context)
35 : VisualTool<VisualDraggableFeature>(parent, context)
36 , org(new Feature)
37 {
38 	features.push_back(*org);
39 	org->type = DRAG_BIG_TRIANGLE;
40 }
41 
Draw()42 void VisualToolRotateZ::Draw() {
43 	if (!active_line) return;
44 
45 	DrawAllFeatures();
46 
47 	float radius = (pos - org->pos).Len();
48 	float oRadius = radius;
49 	if (radius < 50)
50 		radius = 50;
51 
52 	// Set up the projection
53 	gl.SetOrigin(org->pos);
54 	gl.SetRotation(rotation_x, rotation_y, 0);
55 	gl.SetScale(scale);
56 
57 	// Draw the circle
58 	gl.SetLineColour(colour[0]);
59 	gl.SetFillColour(colour[1], 0.3f);
60 	gl.DrawRing(Vector2D(0, 0), radius + 4, radius - 4);
61 
62 	// Draw markers around circle
63 	int markers = 6;
64 	float markStart = -90.f / markers;
65 	float markEnd = markStart + (180.f / markers);
66 	for (int i = 0; i < markers; ++i) {
67 		float angle = i * (360.f / markers);
68 		gl.DrawRing(Vector2D(0, 0), radius+30, radius+12, 1.0, angle+markStart, angle+markEnd);
69 	}
70 
71 	// Draw the baseline through the origin showing current rotation
72 	Vector2D angle_vec(Vector2D::FromAngle(angle * deg2rad));
73 	gl.SetLineColour(colour[3], 1, 2);
74 	gl.DrawLine(angle_vec * -radius, angle_vec * radius);
75 
76 	if (org->pos != pos) {
77 		Vector2D rotated_pos = Vector2D::FromAngle(angle * deg2rad - (pos - org->pos).Angle()) * oRadius;
78 
79 		// Draw the line from origin to rotated position
80 		gl.DrawLine(Vector2D(), rotated_pos);
81 
82 		// Draw the line under the text
83 		gl.DrawLine(rotated_pos - angle_vec * 20, rotated_pos + angle_vec * 20);
84 	}
85 
86 	// Draw the fake features on the ring
87 	gl.SetLineColour(colour[0], 1.f, 1);
88 	gl.SetFillColour(colour[1], 0.3f);
89 	gl.DrawCircle(angle_vec * radius, 4);
90 	gl.DrawCircle(angle_vec * -radius, 4);
91 
92 	// Clear the projection
93 	gl.ResetTransform();
94 
95 	// Draw line to mouse if it isn't over the origin feature
96 	if (mouse_pos && (mouse_pos - org->pos).SquareLen() > 100) {
97 		gl.SetLineColour(colour[0]);
98 		gl.DrawLine(org->pos, mouse_pos);
99 	}
100 }
101 
InitializeHold()102 bool VisualToolRotateZ::InitializeHold() {
103 	orig_angle = angle + (org->pos - mouse_pos).Angle() * rad2deg;
104 	return true;
105 }
106 
UpdateHold()107 void VisualToolRotateZ::UpdateHold() {
108 	angle = orig_angle - (org->pos - mouse_pos).Angle() * rad2deg;
109 
110 	if (ctrl_down)
111 		angle = floorf(angle / 30.f + .5f) * 30.f;
112 
113 	angle = fmodf(angle + 360.f, 360.f);
114 
115 	SetSelectedOverride("\\frz", agi::format("%.4g", angle));
116 }
117 
UpdateDrag(Feature * feature)118 void VisualToolRotateZ::UpdateDrag(Feature *feature) {
119 	auto org = GetLineOrigin(active_line);
120 	if (!org) org = GetLinePosition(active_line);
121 	auto d = ToScriptCoords(feature->pos) - org;
122 
123 	for (auto line : c->selectionController->GetSelectedSet()) {
124 		org = GetLineOrigin(line);
125 		if (!org) org = GetLinePosition(line);
126 		SetOverride(line, "\\org", (d + org).PStr());
127 	}
128 }
129 
DoRefresh()130 void VisualToolRotateZ::DoRefresh() {
131 	if (!active_line) return;
132 
133 	pos = FromScriptCoords(GetLinePosition(active_line));
134 	if (!(org->pos = GetLineOrigin(active_line)))
135 		org->pos = pos;
136 	else
137 		org->pos = FromScriptCoords(org->pos);
138 
139 	GetLineRotation(active_line, rotation_x, rotation_y, angle);
140 	GetLineScale(active_line, scale);
141 }
142