2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined(INCLUDED_DRAGPLANES_H)
23 #define INCLUDED_DRAGPLANES_H
25 #include "selectable.h"
26 #include "selectionlib.h"
27 #include "math/aabb.h"
28 #include "math/line.h"
30 // local must be a pure rotation
31 inline Vector3 translation_to_local(const Vector3& translation, const Matrix4& local)
33 return matrix4_get_translation_vec3(
34 matrix4_multiplied_by_matrix4(
35 matrix4_translated_by_vec3(matrix4_transposed(local), translation),
41 // local must be a pure rotation
42 inline Vector3 translation_from_local(const Vector3& translation, const Matrix4& local)
44 return matrix4_get_translation_vec3(
45 matrix4_multiplied_by_matrix4(
46 matrix4_translated_by_vec3(local, translation),
47 matrix4_transposed(local)
55 ObservedSelectable m_selectable_right; // +x
56 ObservedSelectable m_selectable_left; // -x
57 ObservedSelectable m_selectable_front; // +y
58 ObservedSelectable m_selectable_back; // -y
59 ObservedSelectable m_selectable_top; // +z
60 ObservedSelectable m_selectable_bottom; // -z
63 DragPlanes(const SelectionChangeCallback& onchanged) :
64 m_selectable_right(onchanged),
65 m_selectable_left(onchanged),
66 m_selectable_front(onchanged),
67 m_selectable_back(onchanged),
68 m_selectable_top(onchanged),
69 m_selectable_bottom(onchanged)
72 bool isSelected() const
74 return m_selectable_right.isSelected()
75 || m_selectable_left.isSelected()
76 || m_selectable_front.isSelected()
77 || m_selectable_back.isSelected()
78 || m_selectable_top.isSelected()
79 || m_selectable_bottom.isSelected();
81 void setSelected(bool selected)
83 m_selectable_right.setSelected(selected);
84 m_selectable_left.setSelected(selected);
85 m_selectable_front.setSelected(selected);
86 m_selectable_back.setSelected(selected);
87 m_selectable_top.setSelected(selected);
88 m_selectable_bottom.setSelected(selected);
90 void selectPlanes(const AABB& aabb, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback, const Matrix4& rotation = g_matrix4_identity)
92 Line line(test.getNear(), test.getFar());
94 aabb_corners_oriented(aabb, rotation, corners);
97 aabb_planes_oriented(aabb, rotation, planes);
99 for(Vector3* i = corners; i != corners + 8; ++i)
101 *i = vector3_subtracted(line_closest_point(line, *i), *i);
104 if(vector3_dot(planes[0].normal(), corners[1]) > 0
105 && vector3_dot(planes[0].normal(), corners[2]) > 0
106 && vector3_dot(planes[0].normal(), corners[5]) > 0
107 && vector3_dot(planes[0].normal(), corners[6]) > 0)
109 Selector_add(selector, m_selectable_right);
110 selectedPlaneCallback(planes[0]);
111 //globalOutputStream() << "right\n";
113 if(vector3_dot(planes[1].normal(), corners[0]) > 0
114 && vector3_dot(planes[1].normal(), corners[3]) > 0
115 && vector3_dot(planes[1].normal(), corners[4]) > 0
116 && vector3_dot(planes[1].normal(), corners[7]) > 0)
118 Selector_add(selector, m_selectable_left);
119 selectedPlaneCallback(planes[1]);
120 //globalOutputStream() << "left\n";
122 if(vector3_dot(planes[2].normal(), corners[0]) > 0
123 && vector3_dot(planes[2].normal(), corners[1]) > 0
124 && vector3_dot(planes[2].normal(), corners[4]) > 0
125 && vector3_dot(planes[2].normal(), corners[5]) > 0)
127 Selector_add(selector, m_selectable_front);
128 selectedPlaneCallback(planes[2]);
129 //globalOutputStream() << "front\n";
131 if(vector3_dot(planes[3].normal(), corners[2]) > 0
132 && vector3_dot(planes[3].normal(), corners[3]) > 0
133 && vector3_dot(planes[3].normal(), corners[6]) > 0
134 && vector3_dot(planes[3].normal(), corners[7]) > 0)
136 Selector_add(selector, m_selectable_back);
137 selectedPlaneCallback(planes[3]);
138 //globalOutputStream() << "back\n";
140 if(vector3_dot(planes[4].normal(), corners[0]) > 0
141 && vector3_dot(planes[4].normal(), corners[1]) > 0
142 && vector3_dot(planes[4].normal(), corners[2]) > 0
143 && vector3_dot(planes[4].normal(), corners[3]) > 0)
145 Selector_add(selector, m_selectable_top);
146 selectedPlaneCallback(planes[4]);
147 //globalOutputStream() << "top\n";
149 if(vector3_dot(planes[5].normal(), corners[4]) > 0
150 && vector3_dot(planes[5].normal(), corners[5]) > 0
151 && vector3_dot(planes[5].normal(), corners[6]) > 0
152 && vector3_dot(planes[5].normal(), corners[7]) > 0)
154 Selector_add(selector, m_selectable_bottom);
155 selectedPlaneCallback(planes[5]);
156 //globalOutputStream() << "bottom\n";
161 void selectReversedPlanes(const AABB& aabb, Selector& selector, const SelectedPlanes& selectedPlanes, const Matrix4& rotation = g_matrix4_identity)
164 aabb_planes_oriented(aabb, rotation, planes);
166 if(selectedPlanes.contains(plane3_flipped(planes[0])))
168 Selector_add(selector, m_selectable_right);
170 if(selectedPlanes.contains(plane3_flipped(planes[1])))
172 Selector_add(selector, m_selectable_left);
174 if(selectedPlanes.contains(plane3_flipped(planes[2])))
176 Selector_add(selector, m_selectable_front);
178 if(selectedPlanes.contains(plane3_flipped(planes[3])))
180 Selector_add(selector, m_selectable_back);
182 if(selectedPlanes.contains(plane3_flipped(planes[4])))
184 Selector_add(selector, m_selectable_top);
186 if(selectedPlanes.contains(plane3_flipped(planes[5])))
188 Selector_add(selector, m_selectable_bottom);
191 AABB evaluateResize(const Vector3& translation) const
193 Vector3 min = m_bounds.origin - m_bounds.extents;
194 Vector3 max = m_bounds.origin + m_bounds.extents;
195 if(m_bounds.extents[0] != 0)
197 if(m_selectable_right.isSelected())
199 max[0] += translation[0];
200 //globalOutputStream() << "moving right\n";
202 if(m_selectable_left.isSelected())
204 min[0] += translation[0];
205 //globalOutputStream() << "moving left\n";
208 if(m_bounds.extents[1] != 0)
210 if(m_selectable_front.isSelected())
212 max[1] += translation[1];
213 //globalOutputStream() << "moving front\n";
215 if(m_selectable_back.isSelected())
217 min[1] += translation[1];
218 //globalOutputStream() << "moving back\n";
221 if(m_bounds.extents[2] != 0)
223 if(m_selectable_top.isSelected())
225 max[2] += translation[2];
226 //globalOutputStream() << "moving top\n";
228 if(m_selectable_bottom.isSelected())
230 min[2] += translation[2];
231 //globalOutputStream() << "moving bottom\n";
235 return AABB(vector3_mid(min, max), vector3_scaled(vector3_subtracted(max, min), 0.5));
237 AABB evaluateResize(const Vector3& translation, const Matrix4& rotation) const
239 AABB aabb(evaluateResize(translation_to_local(translation, rotation)));
240 aabb.origin = m_bounds.origin + translation_from_local(aabb.origin - m_bounds.origin, rotation);
243 Matrix4 evaluateTransform(const Vector3& translation) const
245 AABB aabb(evaluateResize(translation));
247 m_bounds.extents[0] != 0 ? aabb.extents[0] / m_bounds.extents[0] : 1,
248 m_bounds.extents[1] != 0 ? aabb.extents[1] / m_bounds.extents[1] : 1,
249 m_bounds.extents[2] != 0 ? aabb.extents[2] / m_bounds.extents[2] : 1
252 Matrix4 matrix(matrix4_translation_for_vec3(aabb.origin - m_bounds.origin));
253 matrix4_pivoted_scale_by_vec3(matrix, scale, m_bounds.origin);