1 /*
2 Copyright (c) 2000-2003 Lee Thomason (www.grinninglizard.com)
3 Grinning Lizard Utilities.
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any
7 damages arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any
10 purpose, including commercial applications, and to alter it and
11 redistribute it freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must
14 not claim that you wrote the original software. If you use this
15 software in a product, an acknowledgment in the product documentation
16 would be appreciated but is not required.
17
18 2. Altered source versions must be plainly marked as such, and
19 must not be misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source
22 distribution.
23 */
24
25
26 #ifndef GRINLIZ_GEOMETRY_INCLUDED
27 #define GRINLIZ_GEOMETRY_INCLUDED
28
29 #include "glvector.h"
30 #include "glrectangle.h"
31 #include "glmatrix.h"
32 #include "glmemorypool.h"
33
34 #include <vector>
35
36 namespace grinliz {
37
38 /// Cross Product
39 template< class T>
CrossProduct(const Vector2<T> & u,const Vector2<T> & v,Vector3<T> * w)40 inline void CrossProduct( const Vector2<T>& u, const Vector2<T>& v, Vector3<T>* w )
41 {
42 w->x = 0.0f;
43 w->y = 0.0f;
44 w->z = u.x * v.y - u.y * v.x;
45 }
46
47
48 /// Dot Product
49 template< class T>
DotProduct(const Vector2<T> & v0,const Vector2<T> & v1)50 inline T DotProduct( const Vector2<T>& v0, const Vector2<T>& v1 )
51 {
52 return v0.x*v1.x + v0.y*v1.y;
53 }
54
55
56 /// Cross Product
57 template< class T>
CrossProduct(const Vector3<T> & u,const Vector3<T> & v,Vector3<T> * w)58 inline void CrossProduct( const Vector3<T>& u, const Vector3<T>& v, Vector3<T>* w )
59 {
60 GLASSERT( &u != w && &v != w );
61
62 w->x = u.y * v.z - u.z * v.y;
63 w->y = u.z * v.x - u.x * v.z;
64 w->z = u.x * v.y - u.y * v.x;
65 }
66
67
68 /// Cross Product
69 template< class T>
CrossProduct(const Vector3<T> & u,const Vector3<T> & v)70 inline Vector3<T> CrossProduct( const Vector3<T>& u, const Vector3<T>& v )
71 {
72 Vector3<T> w;
73
74 w.x = u.y * v.z - u.z * v.y;
75 w.y = u.z * v.x - u.x * v.z;
76 w.z = u.x * v.y - u.y * v.x;
77 return w;
78 }
79
80
81 /// Dot Product
82 template< class T>
DotProduct(const Vector3<T> & v0,const Vector3<T> & v1)83 inline T DotProduct( const Vector3<T>& v0, const Vector3<T>& v1 )
84 {
85 return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z;
86 }
87
88
89 struct BoundingSphere
90 {
91 Vector3F point;
92 float rad;
93
94 };
95
96
97 /** Used to define a ray with an origin, direction, and length.
98 */
99 struct Ray
100 {
101 Vector3F origin;
102 Vector3F direction; // should always have a length of 1.0f
103 float length;
104 };
105
106 /** Plane
107 n * p + d = 0
108 ax + by + cz + d = 0
109 */
110 struct Plane
111 {
112 /// Create a plane from 3 points.
113 static void CreatePlane( const Vector3F* vertices, Plane* plane );
114
115 Vector3F n; ///< normal
116 float d; ///< offset
117
ZPlane118 float Z( float x, float y ) const { return -( d + (n.x * x) + (n.y * y) ) / ( n.z ); }
119
NormalizePlane120 void Normalize()
121 {
122 float div = 1.0f / sqrtf( ( n.x * n.x ) + ( n.y * n.y ) + ( n.z * n.z ) );
123 n.x *= div;
124 n.y *= div;
125 n.z *= div;
126 d *= div;
127 }
128
129 // void Negative( Plane* p ) const
130 // {
131 // p->n.x = -n.x;
132 // p->n.y = -n.y;
133 // p->n.z = -n.z;
134 // p->d = -d;
135 // }
136
137 /// Projects the given vector onto the plain and creates a normal vector in the plane.
138 void ProjectToPlane( const Vector3F& vector, Vector3F* projected ) const;
139 };
140
141 float CalcSphereTexture( float x, float y, bool roundHigh );
142
143 enum TessellateSphereMode
144 {
145 TESS_SPHERE_NORMAL,
146 TESS_SPHERE_TOPHALF,
147 TESS_SPHERE_MIRROR,
148 };
149
150 /** Create a tessellation of a sphere by octrahedron subdivision. Creates a very smooth
151 sphere that is not biased to any axis.
152
153 @param iterations Number of subdivisions. Typically in the range of 1-3.
154 @param radius Radius of the sphere.
155 @param innerNormals If true, the normals will face inside, for rendering the sphere
156 around the camera. Useful for creating a skydome.
157 @param _vertex Pointer to a vector for vertices (required)
158 @param _index Pointer to a vector for indices (required)
159 @param _normal Pointer to a vector for normals (optional)
160 @param _texture Generate texture coordinates (optional)
161 @param mode Controls texture coordinate generation.
162 */
163 void TessellateSphere( int iterations, float radius, bool innerNormals,
164 std::vector< Vector3F >* _vertex,
165 std::vector< U32 >* _index,
166 std::vector< Vector3F >* _normal = 0,
167 std::vector< Vector2F >* _texture = 0,
168 TessellateSphereMode mode = TESS_SPHERE_NORMAL );
169
170
171 /** A point in a LineLoop. See LineLoop for a full description.
172 */
173 struct LineNode
174 {
175 grinliz::Vector2F point; // the point on the line
176 LineNode* prev;
177 LineNode* next;
178 float value; // optional interpolation info
179
LineNodeLineNode180 LineNode( const grinliz::Vector2F& p ) : point( p ), prev( 0 ), next( 0 ), value( 0.0f ) {}
LineNodeLineNode181 LineNode( float x, float y ) : prev( 0 ), next( 0 ), value( 0.0f ) { point.Set( x, y ); }
LineNodeLineNode182 LineNode( float x, float y, float val ) : prev( 0 ), next( 0 ), value( val ) { point.Set( x, y ); }
~LineNodeLineNode183 ~LineNode() {}
184
newLineNode185 void* operator new( size_t size ) {
186 GLASSERT( sizeof( LineNode ) == size );
187 return pool.Alloc();
188 }
189
deleteLineNode190 void operator delete( void* mem ) { pool.Free( mem ); }
191
192 static MemoryPool pool;
193 };
194
195
196 /** A representation of a closed 2D polygon as a series of points.
197 The "loop" is a true circular
198 list - there are no nulls or sentinels. The next pointer is positive
199 (counter-clock) and the prev pointer is negative (clock).
200 */
201 class LineLoop
202 {
203 public:
204 /// Construct an empty loop.
LineLoop()205 LineLoop() : first( 0 ) {}
~LineLoop()206 ~LineLoop() { Clear(); }
207
208 /// Clear the loop and free the memory for the lines.
209 void Clear();
210 /// Delete a point.
211 void Delete( LineNode* del );
212 /** Add a point at the end of the loop. Normally a loop is created by:
213
214 @vertabtim
215 frustum2D.Clear();
216 frustum2D.AddAtEnd( new LineNode( 0.0f, 0.0f ) );
217 frustum2D.AddAtEnd( new LineNode( (float)(VERTEXSIZE-1), 0.0f ) );
218 frustum2D.AddAtEnd( new LineNode( (float)(VERTEXSIZE-1), (float)(VERTEXSIZE-1) ) );
219 frustum2D.AddAtEnd( new LineNode( 0.0f, (float)(VERTEXSIZE-1) ) );
220 @endverbatim
221 */
222 void AddAtEnd( LineNode* node );
223 /// Add a pointer after the point specified.
224 void AddAfter( LineNode* me, LineNode* add );
225 /// Return the first point - null if empty.
First()226 LineNode* First() { return first; }
227 /// Return the first point - null if empty.
First()228 const LineNode* First() const { return first; }
229 /** Sort so the positive direction will the left edge,
230 and the negitive direction the right. First() will point
231 to the first left edge.
232 */
233 void SortToTop();
234 /// Compute the bounds of the loop.
235 void Bounds( grinliz::Rectangle2F* bounds );
236
237 /** Draw the lineloop to a floating point surface, using
238 'value' in the line node. Note that only fully included
239 points will be drawn.
240 */
241 void Render( float* surface, int width, int height, bool fill=false );
242
243 #ifdef DEBUG
244 void Dump();
245 #endif
246
247 private:
248 LineNode* first;
249 };
250
251
252 /**
253 Create a mini vertex array for a quad.
254 - The X0 term is the pattern: 0, 1, 1, 0
255 - The X1 term is the pattern: 0, 0, 1, 1
256 */
257 template< int X0, int X1, int XC >
258 struct Quad3F
259 {
260 enum { NUM_VERTEX = 4 };
261 Vector3F vertex[NUM_VERTEX];
262
Quad3FQuad3F263 Quad3F( float x0, float y0, float x1, float y1, float c )
264 {
265 vertex[0].X(X0) = x0; vertex[0].X(X1) = y0; vertex[0].X(XC) = c;
266 vertex[1].X(X0) = x1; vertex[1].X(X1) = y0; vertex[1].X(XC) = c;
267 vertex[2].X(X0) = x1; vertex[2].X(X1) = y1; vertex[2].X(XC) = c;
268 vertex[3].X(X0) = x0; vertex[3].X(X1) = y1; vertex[3].X(XC) = c;
269 }
270 };
271
272 typedef Quad3F< 0, 1, 2 > Quad3Fz;
273
274
275 /**
276 Create a mini vertex array for a quad.
277 - The X0 term is the pattern: 0, 1, 1, 0
278 - The X1 term is the pattern: 0, 0, 1, 1
279 */
280 template< int X0, int X1 >
281 struct Quad2F
282 {
283 enum { NUM_VERTEX = 4 };
284 Vector2F vertex[NUM_VERTEX];
285
Quad2FQuad2F286 Quad2F( float x0, float y0, float x1, float y1 )
287 {
288 vertex[0].X(X0) = x0; vertex[0].X(X1) = y0;
289 vertex[1].X(X0) = x1; vertex[1].X(X1) = y0;
290 vertex[2].X(X0) = x1; vertex[2].X(X1) = y1;
291 vertex[3].X(X0) = x0; vertex[3].X(X1) = y1;
292 }
293 };
294
295 typedef Quad2F< 0, 1 > Quad2Fz;
296
297
298
299 /** A quaternion class. Whether these are useful or not is still up to
300 debate, but they are certainly getting more common. Lilith uses
301 them for the camera.
302 */
303 class Quaternion
304 {
305 public:
Quaternion()306 Quaternion() : x( 0.0f ), y( 0.0f ), z( 0.0f ), w( 1.0f ) {}
307
308 void Normalize();
309
310 const void ToAxisAngle( Vector3F* axis, float* angleOut );
311 const void ToMatrix( Matrix4* matrix );
312 void FromRotationMatrix( const Matrix4& matrix );
313 void FromAxisAngle( const Vector3F& axis, float angle );
314
315 static void SLERP( const Quaternion& start, const Quaternion& end, float t, Quaternion* result );
316 static void Multiply( const Quaternion& a, const Quaternion& b, Quaternion* result );
317
318 float x, y, z, w;
319 };
320
321
322 enum
323 {
324 REJECT = 0, // No intersection.
325 INTERSECT, // Intersected
326 POSITIVE, // All comparison positive
327 NEGATIVE, // All Comparison negative
328 INSIDE, // An intersection, expected to be outside of the object, is originating inside
329 };
330
331 enum
332 {
333 // Reordering would be bad. x=0, y=1, z=2
334 YZ_PLANE,
335 XZ_PLANE,
336 XY_PLANE
337 };
338
339
340 /** @page intersection Intersection Functions
341
342 Intersection functions use the following conventions:
343
344 - Plane: an infinite 3D plane
345 - Ray: point and direction, possibly a length
346 - Gravray: point with direction in the -z only, possibly a length
347 - AABB: axis aligned bounding box
348 - Tri: triangle
349
350 Intersection functions return:
351 - REJECT No intersection.
352 - INTERSECT Intersected. Usually the point of intersection is written to a structure.
353 - POSITIVE, A comparison was positive.
354 - NEGATIVE, A Comparison was negative.
355 */
356
357 /** Compare a plane to a Axis-Aligned Bounding Box. Has more detailed return
358 types than IntersectPlaneAABB().
359 @return INTERSECT, POSITIVE, NEGATIVE
360 */
361 int ComparePlaneAABB( const Plane&, const Rectangle3F& aabb );
362
363 /** Compare a plane to a point.
364 @return POSITIVE, NEGATIVE, (very unlikely) INTERSECT
365 */
366 int ComparePlanePoint( const Plane&, const Vector3F& p );
367
368 /** Compare a plane to a Axis-Aligned Bounding Box.
369 @return REJECT or INTERSECT
370 */
IntersectPlaneAABB(const Plane & p,const Rectangle3F & aabb)371 inline int IntersectPlaneAABB( const Plane& p, const Rectangle3F& aabb )
372 {
373 return ( ComparePlaneAABB( p, aabb ) == INTERSECT ) ? INTERSECT : REJECT;
374 }
375
376
377 /** The very important triangle test. Will not return a back face intersection.
378 The "intersect" pointer is an optional parameter.
379 @return REJECT or INTERSECT
380 */
381 int IntersectRayTri( const Vector3F& point, const Vector3F& dir,
382 const Vector3F& vert0, const Vector3F& vert1, const Vector3F& vert2,
383 Vector3F* intersect );
384
385 /** Internect a ray and a plane. The planeType can be X, Y, or Z (0, 1, 2), and
386 have a corresponding location in space.
387 @return REJECT or INTERSECT
388 */
389 int IntersectRayAAPlane( const Vector3F& point, const Vector3F& dir,
390 int planeType, float planeLoc,
391 Vector3F* intersect,
392 float* t );
393
394 /** Intersect a ray with an Axis-Aligned Bounding Box. If the origin of the ray
395 is inside the box, the intersection point will be the origin and t=0.
396 @return REJECT, INTERSECT, or INSIDE.
397 */
398 int IntersectRayAABB( const Vector3F& origin, const Vector3F& dir,
399 const Rectangle3F& aabb,
400 Vector3F* intersect,
401 float* t );
402
403 /** The ray and a bounding box form an intersection that is another bounding
404 box. Very useful when you have a ray and a big box and want to know
405 the smaller box of interest.
406 @return REJECT, INTERSECT
407 */
408 int IntersectionRayAABB( const Ray& ray,
409 const Rectangle3F& aabb,
410 Rectangle3F* result );
411
412 /** Intersect a ray with the Z plane (at offset z.)
413 @return REJECT or INTERSECT
414 */
415 int IntersectRayZPlane( const Vector3F& origin, const Vector3F& dir,
416 float z,
417 Vector3F* intersect );
418
419 /** Intersection of a line and a plane (general case).
420 @return REJECT or INTERSECT. Note that INTERSECT may be true, but
421 the 't' parameter is <0 or >1
422 */
423 int IntersectLinePlane( const Vector3F& a0, const Vector3F& a1,
424 const Plane& plane,
425 Vector3F* out,
426 float* t );
427
428 /** Intersection of 3D lines. The return value is itself a line (out0 and out1)
429 that is the shortest line between a and b. The return value is not limited
430 by the endpoints.
431 @return REJECT or INTERSECT.
432 */
433 int IntersectLineLine( const Vector3F& a0, const Vector3F& a1,
434 const Vector3F& b0, const Vector3F& b1,
435 Vector3F* out0,
436 Vector3F* out1 );
437
438 /** Intersection of 2D lines. The return value is a point. If the
439 intersection is actually between the endpoints, t0 and t1 will
440 be in the range [0,1]
441 @return REJECT or INTERSECT.
442 */
443 int IntersectLineLine( const Vector2F& a0, const Vector2F& a1,
444 const Vector2F& b0, const Vector2F& b1,
445 Vector2F* out,
446 float* t0,
447 float* t1 );
448
449
450 /** Returns whether the point is in the *convex* polygon specified by vertex.
451 @return REJECT or INTERSECT.
452 */
453 int PointInPolygon( const Vector2F& p, const Vector2F* vertex, int numVertex );
454
455 /** This is assumes the point *is* on the line. Given this, returns
456 the parameterized distance (t) of pi between p0 and p1 )
457 */
458 float PointBetweenPoints( const Vector3F& p0, const Vector3F& p1, const Vector3F& pi );
459
460 /**
461 Intersection of 3 planes is a point. Returs INTERSECT if there is such
462 a point, or REJECT if planes are parallel.
463 */
464 int Intersect3Planes( const Plane& p0, const Plane& p1, const Plane& p2, Vector3F* intersection );
465
466 }; // namespace grinliz
467 #endif
468
469