Fix MSYS2 issues
[xonotic/netradiant.git] / libs / pivot.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
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.
11
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.
16
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
20  */
21
22 #if !defined( INCLUDED_PIVOT_H )
23 #define INCLUDED_PIVOT_H
24
25 #include "math/matrix.h"
26
27
28 inline void billboard_viewplaneOriented( Matrix4& rotation, const Matrix4& world2screen ){
29 #if 1
30         rotation = g_matrix4_identity;
31         Vector3 x( vector3_normalised( vector4_to_vector3( world2screen.x() ) ) );
32         Vector3 y( vector3_normalised( vector4_to_vector3( world2screen.y() ) ) );
33         Vector3 z( vector3_normalised( vector4_to_vector3( world2screen.z() ) ) );
34         vector4_to_vector3( rotation.y() ) = Vector3( x.y(), y.y(), z.y() );
35         vector4_to_vector3( rotation.z() ) = vector3_negated( Vector3( x.z(), y.z(), z.z() ) );
36         vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) );
37         vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) );
38 #else
39         Matrix4 screen2world( matrix4_full_inverse( world2screen ) );
40
41         Vector3 near_(
42                 vector4_projected(
43                         matrix4_transformed_vector4(
44                                 screen2world,
45                                 Vector4( 0, 0, -1, 1 )
46                                 )
47                         )
48                 );
49
50         Vector3 far_(
51                 vector4_projected(
52                         matrix4_transformed_vector4(
53                                 screen2world,
54                                 Vector4( 0, 0, 1, 1 )
55                                 )
56                         )
57                 );
58
59         Vector3 up(
60                 vector4_projected(
61                         matrix4_transformed_vector4(
62                                 screen2world,
63                                 Vector4( 0, 1, -1, 1 )
64                                 )
65                         )
66                 );
67
68         rotation = g_matrix4_identity;
69         vector4_to_vector3( rotation.y() ) = vector3_normalised( vector3_subtracted( up, near_ ) );
70         vector4_to_vector3( rotation.z() ) = vector3_normalised( vector3_subtracted( near_, far_ ) );
71         vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) );
72         vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) );
73 #endif
74 }
75
76 inline void billboard_viewpointOriented( Matrix4& rotation, const Matrix4& world2screen ){
77         Matrix4 screen2world( matrix4_full_inverse( world2screen ) );
78
79 #if 1
80         rotation = g_matrix4_identity;
81         vector4_to_vector3( rotation.y() ) = vector3_normalised( vector4_to_vector3( screen2world.y() ) );
82         vector4_to_vector3( rotation.z() ) = vector3_negated( vector3_normalised( vector4_to_vector3( screen2world.z() ) ) );
83         vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) );
84         vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) );
85 #else
86         Vector3 near_(
87                 vector4_projected(
88                         matrix4_transformed_vector4(
89                                 screen2world,
90                                 Vector4( world2screen[12] / world2screen[15], world2screen[13] / world2screen[15], -1, 1 )
91                                 )
92                         )
93                 );
94
95         Vector3 far_(
96                 vector4_projected(
97                         matrix4_transformed_vector4(
98                                 screen2world,
99                                 Vector4( world2screen[12] / world2screen[15], world2screen[13] / world2screen[15], 1, 1 )
100                                 )
101                         )
102                 );
103
104         Vector3 up(
105                 vector4_projected(
106                         matrix4_transformed_vector4(
107                                 screen2world,
108                                 Vector4( world2screen[12] / world2screen[15], world2screen[13] / world2screen[15] + 1, -1, 1 )
109                                 )
110                         )
111                 );
112
113         rotation = g_matrix4_identity;
114         vector4_to_vector3( rotation.y() ) = vector3_normalised( vector3_subtracted( up, near_ ) );
115         vector4_to_vector3( rotation.z() ) = vector3_normalised( vector3_subtracted( near_, far_ ) );
116         vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) );
117         vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) );
118 #endif
119 }
120
121
122 inline void ConstructObject2Screen( Matrix4& object2screen, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device, const Matrix4& device2screen ){
123         object2screen = device2screen;
124         matrix4_multiply_by_matrix4( object2screen, view2device );
125         matrix4_multiply_by_matrix4( object2screen, world2view );
126         matrix4_multiply_by_matrix4( object2screen, object2world );
127 }
128
129 inline void ConstructObject2Device( Matrix4& object2screen, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device ){
130         object2screen = view2device;
131         matrix4_multiply_by_matrix4( object2screen, world2view );
132         matrix4_multiply_by_matrix4( object2screen, object2world );
133 }
134
135 inline void ConstructDevice2Object( Matrix4& device2object, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device ){
136         ConstructObject2Device( device2object, object2world, world2view, view2device );
137         matrix4_full_invert( device2object );
138 }
139
140 //! S =  ( Inverse(Object2Screen *post ScaleOf(Object2Screen) ) *post Object2Screen
141 inline void pivot_scale( Matrix4& scale, const Matrix4& pivot2screen ){
142         Matrix4 pre_scale( g_matrix4_identity );
143         pre_scale[0] = static_cast<float>( vector3_length( vector4_to_vector3( pivot2screen.x() ) ) );
144         pre_scale[5] = static_cast<float>( vector3_length( vector4_to_vector3( pivot2screen.y() ) ) );
145         pre_scale[10] = static_cast<float>( vector3_length( vector4_to_vector3( pivot2screen.z() ) ) );
146
147         scale = pivot2screen;
148         matrix4_multiply_by_matrix4( scale, pre_scale );
149         matrix4_full_invert( scale );
150         matrix4_multiply_by_matrix4( scale, pivot2screen );
151 }
152
153 // scale by (inverse) W
154 inline void pivot_perspective( Matrix4& scale, const Matrix4& pivot2screen ){
155         scale = g_matrix4_identity;
156         scale[0] = scale[5] = scale[10] = pivot2screen[15];
157 }
158
159 inline void ConstructDevice2Manip( Matrix4& device2manip, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device, const Matrix4& device2screen ){
160         Matrix4 pivot2screen;
161         ConstructObject2Screen( pivot2screen, object2world, world2view, view2device, device2screen );
162
163         ConstructObject2Device( device2manip, object2world, world2view, view2device );
164
165         Matrix4 scale;
166         pivot_scale( scale, pivot2screen );
167         matrix4_multiply_by_matrix4( device2manip, scale );
168         pivot_perspective( scale, pivot2screen );
169         matrix4_multiply_by_matrix4( device2manip, scale );
170
171         matrix4_full_invert( device2manip );
172 }
173
174 inline void Pivot2World_worldSpace( Matrix4& manip2world, const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport ){
175         manip2world = pivot2world;
176
177         Matrix4 pivot2screen;
178         ConstructObject2Screen( pivot2screen, pivot2world, modelview, projection, viewport );
179
180         Matrix4 scale;
181         pivot_scale( scale, pivot2screen );
182         matrix4_multiply_by_matrix4( manip2world, scale );
183         pivot_perspective( scale, pivot2screen );
184         matrix4_multiply_by_matrix4( manip2world, scale );
185 }
186
187 inline void Pivot2World_viewpointSpace( Matrix4& manip2world, Vector3& axis, const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport ){
188         manip2world = pivot2world;
189
190         Matrix4 pivot2screen;
191         ConstructObject2Screen( pivot2screen, pivot2world, modelview, projection, viewport );
192
193         Matrix4 scale;
194         pivot_scale( scale, pivot2screen );
195         matrix4_multiply_by_matrix4( manip2world, scale );
196
197         billboard_viewpointOriented( scale, pivot2screen );
198         axis = vector4_to_vector3( scale.z() );
199         matrix4_multiply_by_matrix4( manip2world, scale );
200
201         pivot_perspective( scale, pivot2screen );
202         matrix4_multiply_by_matrix4( manip2world, scale );
203 }
204
205 inline void Pivot2World_viewplaneSpace( Matrix4& manip2world, const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport ){
206         manip2world = pivot2world;
207
208         Matrix4 pivot2screen;
209         ConstructObject2Screen( pivot2screen, pivot2world, modelview, projection, viewport );
210
211         Matrix4 scale;
212         pivot_scale( scale, pivot2screen );
213         matrix4_multiply_by_matrix4( manip2world, scale );
214
215         billboard_viewplaneOriented( scale, pivot2screen );
216         matrix4_multiply_by_matrix4( manip2world, scale );
217
218         pivot_perspective( scale, pivot2screen );
219         matrix4_multiply_by_matrix4( manip2world, scale );
220 }
221
222
223 #include "renderable.h"
224 #include "cullable.h"
225 #include "render.h"
226
227 const Colour4b g_colour_x( 255, 0, 0, 255 );
228 const Colour4b g_colour_y( 0, 255, 0, 255 );
229 const Colour4b g_colour_z( 0, 0, 255, 255 );
230
231 class Shader;
232
233 class RenderablePivot : public OpenGLRenderable
234 {
235 VertexBuffer<PointVertex> m_vertices;
236 public:
237 mutable Matrix4 m_localToWorld;
238 typedef Static<Shader*> StaticShader;
239 static Shader* getShader(){
240         return StaticShader::instance();
241 }
242
243 RenderablePivot(){
244         m_vertices.reserve( 6 );
245
246         m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 0 ), g_colour_x ) );
247         m_vertices.push_back( PointVertex( Vertex3f( 16, 0, 0 ), g_colour_x ) );
248
249         m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 0 ), g_colour_y ) );
250         m_vertices.push_back( PointVertex( Vertex3f( 0, 16, 0 ), g_colour_y ) );
251
252         m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 0 ), g_colour_z ) );
253         m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 16 ), g_colour_z ) );
254 }
255
256 void render( RenderStateFlags state ) const {
257         if ( m_vertices.size() == 0 ) {
258                 return;
259         }
260         if ( m_vertices.data() == 0 ) {
261                 return;
262         }
263         glVertexPointer( 3, GL_FLOAT, sizeof( PointVertex ), &m_vertices.data()->vertex );
264         glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( PointVertex ), &m_vertices.data()->colour );
265         glDrawArrays( GL_LINES, 0, m_vertices.size() );
266 }
267
268 void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
269         renderer.PushState();
270
271         Pivot2World_worldSpace( m_localToWorld, localToWorld, volume.GetModelview(), volume.GetProjection(), volume.GetViewport() );
272
273         renderer.Highlight( Renderer::ePrimitive, false );
274         renderer.SetState( getShader(), Renderer::eWireframeOnly );
275         renderer.SetState( getShader(), Renderer::eFullMaterials );
276         renderer.addRenderable( *this, m_localToWorld );
277
278         renderer.PopState();
279 }
280 };
281
282
283
284 #endif