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