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