]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/math/expression.h
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / libs / math / expression.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_EXPRESSION_H )
23 #define INCLUDED_EXPRESSION_H
24
25 #include <math/matrix.h>
26
27 template<typename Value>
28 class Literal
29 {
30 Value m_value;
31 public:
32 typedef Value value_type;
33
34 Literal( const Value& value )
35         : m_value( value ){
36 }
37 const value_type& eval() const {
38         return m_value;
39 }
40 };
41
42 template<typename Value>
43 inline Literal<Value> float_literal( const Value& value ){
44         return Literal<Value>( value );
45 }
46
47 template<typename Expression>
48 inline float float_for_expression( const Expression& expression ){
49         return expression.eval();
50 }
51
52
53 template<typename First, typename Second>
54 class ScalarDivided
55 {
56 First first;
57 Second second;
58 public:
59 typedef typename First::value_type value_type;
60
61 ScalarDivided( const First& first_, const Second& second_ ) : first( first_ ), second( second_ ){
62 }
63 value_type eval() const {
64         return static_cast<value_type>( first.eval() / second.eval() );
65 }
66 };
67
68 template<typename First, typename Second>
69 inline ScalarDivided<First, Second> float_divided( const First& first, const Second& second ){
70         return ScalarDivided<First, Second>( first, second );
71 }
72
73 template<typename First>
74 inline ScalarDivided<Literal<typename First::value_type>, First> float_reciprocal( const First& first ){
75         typedef typename First::value_type first_value_type;
76         return ScalarDivided<Literal<first_value_type>, First>( float_literal( first_value_type( 1.0 ) ), first );
77 }
78
79 template<typename First>
80 class SquareRoot
81 {
82 First first;
83 public:
84 typedef typename First::value_type value_type;
85
86 SquareRoot( const First& first_ ) : first( first_ ){
87 }
88 value_type eval() const {
89         return static_cast<value_type>( sqrt( first.eval() ) );
90 }
91 };
92
93 template<typename First>
94 inline SquareRoot<First> float_square_root( const First& first ){
95         return SquareRoot<First>( first );
96 }
97
98
99 template<typename Element>
100 class BasicVector3Literal
101 {
102 const BasicVector3<Element> m_value;
103 public:
104 typedef Element value_type;
105 typedef IntegralConstant<3> dimension;
106
107 BasicVector3Literal( const BasicVector3<Element>& value )
108         : m_value( value ){
109 }
110 const value_type& eval( unsigned int i ) const {
111         return m_value[i];
112 }
113 };
114
115 template<typename Element>
116 inline BasicVector3Literal<Element> vector3_literal( const BasicVector3<Element>& value ){
117         return BasicVector3Literal<Element>( value );
118 }
119
120 typedef BasicVector3Literal<float> Vector3Literal;
121
122 template<typename Element>
123 class BasicVector3Identity
124 {
125 const BasicVector3<Element>& m_value;
126 public:
127 typedef Element value_type;
128 typedef IntegralConstant<3> dimension;
129
130 BasicVector3Identity( const BasicVector3<Element>& value )
131         : m_value( value ){
132 }
133 const value_type& eval( unsigned int i ) const {
134         return m_value[i];
135 }
136 };
137
138 template<typename Element>
139 inline BasicVector3Identity<Element> vector3_identity( const BasicVector3<Element>& value ){
140         return BasicVector3Identity<Element>( value );
141 }
142
143 typedef BasicVector3Identity<float> Vector3Identity;
144
145 template<typename Expression>
146 inline BasicVector3<typename Expression::value_type> vector3_for_expression( const Expression& expression ){
147         return Vector3( expression.eval( 0 ), expression.eval( 1 ), expression.eval( 2 ) );
148 }
149
150
151 template<typename Operation, typename First, typename Second>
152 class VectorScalar
153 {
154 First first;
155 Literal<typename Second::value_type> second;
156 public:
157 typedef typename First::value_type value_type;
158 typedef typename First::dimension dimension;
159
160 VectorScalar( const First& first_, const Second& second_ )
161         : first( first_ ), second( second_.eval() ){
162 }
163 value_type eval( unsigned int i ) const {
164         return Operation::apply( first.eval( i ), second.eval() );
165 }
166 };
167
168
169
170 template<typename Operation, typename First, typename Second>
171 class VectorVector
172 {
173 First first;
174 Second second;
175 public:
176 typedef typename First::value_type value_type;
177 typedef typename First::dimension dimension;
178
179 VectorVector( const First& first_, const Second& second_ )
180         : first( first_ ), second( second_ ){
181 }
182 value_type eval( unsigned int i ) const {
183         return Operation::apply( first.eval( i ), second.eval( i ) );
184 }
185 };
186
187 template<typename First, typename Second>
188 class Added
189 {
190 public:
191 typedef First value_type;
192
193 static value_type apply( const First& first, const Second& second ){
194         return static_cast<value_type>( first + second );
195 }
196 };
197
198 template<typename First, typename Second>
199 inline VectorVector<Added<typename First::value_type, typename Second::value_type>, First, Second>
200 vector_added( const First& first, const Second& second ){
201         typedef typename First::value_type first_value_type;
202         typedef typename Second::value_type second_value_type;
203         return VectorVector<Added<first_value_type, second_value_type>, First, Second>( first, second );
204 }
205
206 template<typename First, typename Second>
207 class Multiplied
208 {
209 public:
210 typedef First value_type;
211
212 static value_type apply( const First& first, const Second& second ){
213         return static_cast<value_type>( first * second );
214 }
215 };
216
217 template<typename First, typename Second>
218 inline VectorVector<Multiplied<typename First::value_type, typename Second::value_type>, First, Second>
219 vector_multiplied( const First& first, const Second& second ){
220         typedef typename First::value_type first_value_type;
221         typedef typename Second::value_type second_value_type;
222         return VectorVector<Multiplied<first_value_type, second_value_type>, First, Second>( first, second );
223 }
224
225 template<typename First, typename Second>
226 inline VectorScalar<Multiplied<typename First::value_type, typename Second::value_type>, First, Second>
227 vector_scaled( const First& first, const Second& second ){
228         typedef typename First::value_type first_value_type;
229         typedef typename Second::value_type second_value_type;
230         return VectorScalar<Multiplied<first_value_type, second_value_type>, First, Second>( first, second );
231 }
232
233 template<typename First>
234 class Negated
235 {
236 public:
237 typedef First value_type;
238
239 static value_type apply( const First& first ){
240         return -first;
241 }
242 };
243
244 template<typename First, typename Operation>
245 class VectorUnary
246 {
247 First first;
248 public:
249 typedef typename First::value_type value_type;
250 typedef typename First::dimension dimension;
251
252 VectorUnary( const First& first_ ) : first( first_ ){
253 }
254 value_type eval( unsigned int i ) const {
255         return Operation::apply( first.eval( i ) );
256 }
257 };
258
259 template<typename First>
260 inline VectorUnary<First, Negated<typename First::value_type> >
261 vector_negated( const First& first ){
262         typedef typename First::value_type first_value_type;
263         return VectorUnary<First, Negated<first_value_type> >( first );
264 }
265
266 template<typename First, typename Second>
267 class VectorCross
268 {
269 First first;
270 Second second;
271 public:
272 typedef typename First::value_type value_type;
273 typedef typename First::dimension dimension;
274
275 VectorCross( const First& first_, const Second& second_ )
276         : first( first_ ), second( second_ ){
277 }
278 value_type eval( unsigned int i ) const {
279         return first.eval( ( i + 1 ) % 3 ) * second.eval( ( i + 2 ) % 3 ) - first.eval( ( i + 2 ) % 3 ) * second.eval( ( i + 1 ) % 3 );
280 }
281 };
282
283 template<typename First, typename Second>
284 inline VectorCross<First, Second>
285 vector_cross( const First& first, const Second& second ){
286         return VectorCross<First, Second>( first, second );
287 }
288
289
290 template<typename First, typename Second>
291 class VectorDot
292 {
293 First first;
294 Second second;
295 public:
296 typedef typename First::value_type value_type;
297 typedef typename First::dimension dimension;
298
299 VectorDot( const First& first_, const Second& second_ )
300         : first( first_ ), second( second_ ){
301 }
302
303 template<typename Index>
304 struct eval_dot
305 {
306         static value_type apply( const First& first, const Second& second ){
307                 return static_cast<value_type>(
308                                    first.eval( Index::VALUE ) * second.eval( Index::VALUE )
309                                    + eval_dot< IntegralConstant<Index::VALUE - 1> >::apply( first, second )
310                                    );
311         }
312 };
313
314 template<>
315 struct eval_dot< IntegralConstant<0> >
316 {
317         static value_type apply( const First& first, const Second& second ){
318                 return first.eval( 0 ) * second.eval( 0 );
319         }
320 };
321
322 value_type eval() const {
323         return eval_dot< IntegralConstant<dimension::VALUE - 1> >::apply( first, second );
324 }
325 };
326
327
328 template<typename First, typename Second>
329 inline VectorDot<First, Second> vector_dot( const First& first, const Second& second ){
330         return VectorDot<First, Second>( first, second );
331 }
332
333 template<typename First>
334 class VectorLengthSquared
335 {
336 First first;
337 public:
338 typedef typename First::value_type value_type;
339 typedef typename First::dimension dimension;
340
341 VectorLengthSquared( const First& first_ )
342         : first( first_ ){
343 }
344
345 static value_type squared( const value_type& value ){
346         return value * value;
347 }
348
349 template<typename Index>
350 struct eval_squared
351 {
352         static value_type apply( const First& first ){
353                 return static_cast<value_type>(
354                                    squared( first.eval( Index::VALUE ) )
355                                    + eval_squared< IntegralConstant<Index::VALUE - 1> >::apply( first )
356                                    );
357         }
358 };
359
360 template<>
361 struct eval_squared< IntegralConstant<0> >
362 {
363         static value_type apply( const First& first ){
364                 return squared( first.eval( 0 ) );
365         }
366 };
367
368 value_type eval() const {
369         return eval_squared< IntegralConstant<dimension::VALUE - 1> >::apply( first );
370 }
371 };
372
373 template<typename First>
374 inline VectorLengthSquared<First> vector_length_squared( const First& first ){
375         return VectorLengthSquared<First>( first );
376 }
377
378 template<typename First>
379 inline SquareRoot< VectorLengthSquared<First> > vector_length( const First& first ){
380         return float_square_root( vector_length_squared( first ) );
381 }
382
383 #if 1
384 template<typename First>
385 inline VectorScalar<
386         Multiplied<typename First::value_type, typename First::value_type>,
387         First,
388     // multiple evaulations of subexpression
389         ScalarDivided<
390                 Literal<typename First::value_type>,
391                 SquareRoot<
392                         VectorLengthSquared<First>
393                         >
394                 >
395         > vector_normalised( const First& first ){
396         typedef typename First::value_type first_value_type;
397         return vector_scaled( first, float_reciprocal( vector_length( first ) ) );
398 }
399 #else
400 template<typename First>
401 inline VectorScalar<
402         Multiplied<typename First::value_type, typename First::value_type>,
403         First,
404     // single evaluation of subexpression
405         Literal<typename First::value_type>
406         >
407 vector_normalised( const First& first ){
408         typedef typename First::value_type first_value_type;
409         return vector_scaled( first, float_literal( static_cast<first_value_type>( first_value_type( 1.0 ) / vector_length( first ).eval() ) ) );
410 }
411 #endif
412
413
414 class Matrix4Literal
415 {
416 const Matrix4 m_value;
417 public:
418 typedef float value_type;
419 typedef IntegralConstant<4> dimension0;
420 typedef IntegralConstant<4> dimension1;
421
422 Matrix4Literal( const Matrix4& value )
423         : m_value( value ){
424 }
425 const value_type& eval( unsigned int r, unsigned int c ) const {
426         return m_value[r * 4 + c];
427 }
428 };
429
430 inline Matrix4Literal matrix4_literal( const Matrix4& value ){
431         return Matrix4Literal( value );
432 }
433
434 class Matrix4Identity
435 {
436 const Matrix4& m_value;
437 public:
438 typedef float value_type;
439 typedef IntegralConstant<4> dimension0;
440 typedef IntegralConstant<4> dimension1;
441
442 Matrix4Identity( const Matrix4& value )
443         : m_value( value ){
444 }
445 const value_type& eval( unsigned int r, unsigned int c ) const {
446         return m_value[r * 4 + c];
447 }
448 };
449
450 inline Matrix4Identity matrix4_identity( const Matrix4& value ){
451         return Matrix4Identity( value );
452 }
453
454 template<typename Expression>
455 inline Matrix4 matrix4_for_expression( const Expression& expression ){
456         return Matrix4(
457                            expression.eval( 0, 0 ), expression.eval( 0, 1 ), expression.eval( 0, 2 ), expression.eval( 0, 3 ),
458                            expression.eval( 1, 0 ), expression.eval( 1, 1 ), expression.eval( 1, 2 ), expression.eval( 1, 3 ),
459                            expression.eval( 2, 0 ), expression.eval( 2, 1 ), expression.eval( 2, 2 ), expression.eval( 2, 3 ),
460                            expression.eval( 3, 0 ), expression.eval( 3, 1 ), expression.eval( 3, 2 ), expression.eval( 3, 3 )
461                            );
462 }
463
464 template<typename Expression>
465 inline Matrix4 matrix4_affine_for_expression( const Expression& expression ){
466         return Matrix4(
467                            expression.eval( 0, 0 ), expression.eval( 0, 1 ), expression.eval( 0, 2 ), 0,
468                            expression.eval( 1, 0 ), expression.eval( 1, 1 ), expression.eval( 1, 2 ), 0,
469                            expression.eval( 2, 0 ), expression.eval( 2, 1 ), expression.eval( 2, 2 ), 0,
470                            expression.eval( 3, 0 ), expression.eval( 3, 1 ), expression.eval( 3, 2 ), 1
471                            );
472 }
473
474
475 template<typename First, typename Second>
476 class PointMultiplied
477 {
478 const First& first;
479 const Second& second;
480 public:
481 typedef typename First::value_type value_type;
482 typedef typename First::dimension dimension;
483
484 PointMultiplied( const First& first_, const Second& second_ )
485         : first( first_ ), second( second_ ){
486 }
487 value_type eval( unsigned int i ) const {
488         return static_cast<value_type>( second.eval( 0, i ) * first.eval( 0 )
489                                                                         + second.eval( 1, i ) * first.eval( 1 )
490                                                                         + second.eval( 2, i ) * first.eval( 2 )
491                                                                         + second.eval( 3, i ) );
492 }
493 };
494
495 template<typename First, typename Second>
496 inline PointMultiplied<First, Second> point_multiplied( const First& point, const Second& matrix ){
497         return PointMultiplied<First, Second>( point, matrix );
498 }
499
500 template<typename First, typename Second>
501 class Matrix4Multiplied
502 {
503 const First& first;
504 const Second& second;
505 public:
506 typedef typename First::value_type value_type;
507 typedef typename First::dimension0 dimension0;
508 typedef typename First::dimension1 dimension1;
509
510 Matrix4Multiplied( const First& first_, const Second& second_ )
511         : first( first_ ), second( second_ ){
512 }
513
514 value_type eval( unsigned int r, unsigned int c ) const {
515         return static_cast<value_type>(
516                            second.eval( r, 0 ) * first.eval( 0, c )
517                            + second.eval( r, 1 ) * first.eval( 1, c )
518                            + second.eval( r, 2 ) * first.eval( 2, c )
519                            + second.eval( r, 3 ) * first.eval( 3, c )
520                            );
521 }
522 };
523
524 template<typename First, typename Second>
525 inline Matrix4Multiplied<First, Second> matrix4_multiplied( const First& first, const Second& second ){
526         return Matrix4Multiplied<First, Second>( first, second );
527 }
528
529 template<typename First>
530 class MatrixTransposed
531 {
532 const First& first;
533 public:
534 typedef typename First::value_type value_type;
535 typedef typename First::dimension0 dimension0;
536 typedef typename First::dimension1 dimension1;
537
538 MatrixTransposed( const First& first_ )
539         : first( first_ ){
540 }
541
542 value_type eval( unsigned int r, unsigned int c ) const {
543         return first.eval( c, r );
544 }
545 };
546
547 template<typename First>
548 inline MatrixTransposed<First> matrix_transposed( const First& first ){
549         return MatrixTransposed<First>( first );
550 }
551
552 #endif