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 ){
32 return matrix4_get_translation_vec3(
33 matrix4_multiplied_by_matrix4(
34 matrix4_translated_by_vec3( matrix4_transposed( local ), translation ),
40 // local must be a pure rotation
41 inline Vector3 translation_from_local( const Vector3& translation, const Matrix4& local ){
42 return matrix4_get_translation_vec3(
43 matrix4_multiplied_by_matrix4(
44 matrix4_translated_by_vec3( local, translation ),
45 matrix4_transposed( local )
53 ObservedSelectable m_selectable_right; // +x
54 ObservedSelectable m_selectable_left; // -x
55 ObservedSelectable m_selectable_front; // +y
56 ObservedSelectable m_selectable_back; // -y
57 ObservedSelectable m_selectable_top; // +z
58 ObservedSelectable m_selectable_bottom; // -z
61 DragPlanes( const SelectionChangeCallback& onchanged ) :
62 m_selectable_right( onchanged ),
63 m_selectable_left( onchanged ),
64 m_selectable_front( onchanged ),
65 m_selectable_back( onchanged ),
66 m_selectable_top( onchanged ),
67 m_selectable_bottom( onchanged ){
69 bool isSelected() const {
70 return m_selectable_right.isSelected()
71 || m_selectable_left.isSelected()
72 || m_selectable_front.isSelected()
73 || m_selectable_back.isSelected()
74 || m_selectable_top.isSelected()
75 || m_selectable_bottom.isSelected();
77 void setSelected( bool selected ){
78 m_selectable_right.setSelected( selected );
79 m_selectable_left.setSelected( selected );
80 m_selectable_front.setSelected( selected );
81 m_selectable_back.setSelected( selected );
82 m_selectable_top.setSelected( selected );
83 m_selectable_bottom.setSelected( selected );
85 void selectPlanes( const AABB& aabb, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback, const Matrix4& rotation = g_matrix4_identity ){
86 Line line( test.getNear(), test.getFar() );
88 aabb_corners_oriented( aabb, rotation, corners );
91 aabb_planes_oriented( aabb, rotation, planes );
93 for ( Vector3* i = corners; i != corners + 8; ++i )
95 *i = vector3_subtracted( line_closest_point( line, *i ), *i );
98 if ( vector3_dot( planes[0].normal(), corners[1] ) > 0
99 && vector3_dot( planes[0].normal(), corners[2] ) > 0
100 && vector3_dot( planes[0].normal(), corners[5] ) > 0
101 && vector3_dot( planes[0].normal(), corners[6] ) > 0 ) {
102 Selector_add( selector, m_selectable_right );
103 selectedPlaneCallback( planes[0] );
104 //globalOutputStream() << "right\n";
106 if ( vector3_dot( planes[1].normal(), corners[0] ) > 0
107 && vector3_dot( planes[1].normal(), corners[3] ) > 0
108 && vector3_dot( planes[1].normal(), corners[4] ) > 0
109 && vector3_dot( planes[1].normal(), corners[7] ) > 0 ) {
110 Selector_add( selector, m_selectable_left );
111 selectedPlaneCallback( planes[1] );
112 //globalOutputStream() << "left\n";
114 if ( vector3_dot( planes[2].normal(), corners[0] ) > 0
115 && vector3_dot( planes[2].normal(), corners[1] ) > 0
116 && vector3_dot( planes[2].normal(), corners[4] ) > 0
117 && vector3_dot( planes[2].normal(), corners[5] ) > 0 ) {
118 Selector_add( selector, m_selectable_front );
119 selectedPlaneCallback( planes[2] );
120 //globalOutputStream() << "front\n";
122 if ( vector3_dot( planes[3].normal(), corners[2] ) > 0
123 && vector3_dot( planes[3].normal(), corners[3] ) > 0
124 && vector3_dot( planes[3].normal(), corners[6] ) > 0
125 && vector3_dot( planes[3].normal(), corners[7] ) > 0 ) {
126 Selector_add( selector, m_selectable_back );
127 selectedPlaneCallback( planes[3] );
128 //globalOutputStream() << "back\n";
130 if ( vector3_dot( planes[4].normal(), corners[0] ) > 0
131 && vector3_dot( planes[4].normal(), corners[1] ) > 0
132 && vector3_dot( planes[4].normal(), corners[2] ) > 0
133 && vector3_dot( planes[4].normal(), corners[3] ) > 0 ) {
134 Selector_add( selector, m_selectable_top );
135 selectedPlaneCallback( planes[4] );
136 //globalOutputStream() << "top\n";
138 if ( vector3_dot( planes[5].normal(), corners[4] ) > 0
139 && vector3_dot( planes[5].normal(), corners[5] ) > 0
140 && vector3_dot( planes[5].normal(), corners[6] ) > 0
141 && vector3_dot( planes[5].normal(), corners[7] ) > 0 ) {
142 Selector_add( selector, m_selectable_bottom );
143 selectedPlaneCallback( planes[5] );
144 //globalOutputStream() << "bottom\n";
149 void selectReversedPlanes( const AABB& aabb, Selector& selector, const SelectedPlanes& selectedPlanes, const Matrix4& rotation = g_matrix4_identity ){
151 aabb_planes_oriented( aabb, rotation, planes );
153 if ( selectedPlanes.contains( plane3_flipped( planes[0] ) ) ) {
154 Selector_add( selector, m_selectable_right );
156 if ( selectedPlanes.contains( plane3_flipped( planes[1] ) ) ) {
157 Selector_add( selector, m_selectable_left );
159 if ( selectedPlanes.contains( plane3_flipped( planes[2] ) ) ) {
160 Selector_add( selector, m_selectable_front );
162 if ( selectedPlanes.contains( plane3_flipped( planes[3] ) ) ) {
163 Selector_add( selector, m_selectable_back );
165 if ( selectedPlanes.contains( plane3_flipped( planes[4] ) ) ) {
166 Selector_add( selector, m_selectable_top );
168 if ( selectedPlanes.contains( plane3_flipped( planes[5] ) ) ) {
169 Selector_add( selector, m_selectable_bottom );
172 AABB evaluateResize( const Vector3& translation ) const {
173 Vector3 min = m_bounds.origin - m_bounds.extents;
174 Vector3 max = m_bounds.origin + m_bounds.extents;
175 if ( m_bounds.extents[0] != 0 ) {
176 if ( m_selectable_right.isSelected() ) {
177 max[0] += translation[0];
178 //globalOutputStream() << "moving right\n";
180 if ( m_selectable_left.isSelected() ) {
181 min[0] += translation[0];
182 //globalOutputStream() << "moving left\n";
185 if ( m_bounds.extents[1] != 0 ) {
186 if ( m_selectable_front.isSelected() ) {
187 max[1] += translation[1];
188 //globalOutputStream() << "moving front\n";
190 if ( m_selectable_back.isSelected() ) {
191 min[1] += translation[1];
192 //globalOutputStream() << "moving back\n";
195 if ( m_bounds.extents[2] != 0 ) {
196 if ( m_selectable_top.isSelected() ) {
197 max[2] += translation[2];
198 //globalOutputStream() << "moving top\n";
200 if ( m_selectable_bottom.isSelected() ) {
201 min[2] += translation[2];
202 //globalOutputStream() << "moving bottom\n";
206 return AABB( vector3_mid( min, max ), vector3_scaled( vector3_subtracted( max, min ), 0.5 ) );
208 AABB evaluateResize( const Vector3& translation, const Matrix4& rotation ) const {
209 AABB aabb( evaluateResize( translation_to_local( translation, rotation ) ) );
210 aabb.origin = m_bounds.origin + translation_from_local( aabb.origin - m_bounds.origin, rotation );
213 Matrix4 evaluateTransform( const Vector3& translation ) const {
214 AABB aabb( evaluateResize( translation ) );
216 m_bounds.extents[0] != 0 ? aabb.extents[0] / m_bounds.extents[0] : 1,
217 m_bounds.extents[1] != 0 ? aabb.extents[1] / m_bounds.extents[1] : 1,
218 m_bounds.extents[2] != 0 ? aabb.extents[2] / m_bounds.extents[2] : 1
221 Matrix4 matrix( matrix4_translation_for_vec3( aabb.origin - m_bounds.origin ) );
222 matrix4_pivoted_scale_by_vec3( matrix, scale, m_bounds.origin );