aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmath
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llmath')
-rw-r--r--linden/indra/llmath/camera.h28
-rw-r--r--linden/indra/llmath/coordframe.h28
-rw-r--r--linden/indra/llmath/files.lst23
-rw-r--r--linden/indra/llmath/llbboxlocal.cpp56
-rw-r--r--linden/indra/llmath/llbboxlocal.h69
-rw-r--r--linden/indra/llmath/llcamera.cpp610
-rw-r--r--linden/indra/llmath/llcamera.h188
-rw-r--r--linden/indra/llmath/llcoord.h97
-rw-r--r--linden/indra/llmath/llcoordframe.cpp748
-rw-r--r--linden/indra/llmath/llcoordframe.h175
-rw-r--r--linden/indra/llmath/llcrc.cpp206
-rw-r--r--linden/indra/llmath/llcrc.h69
-rw-r--r--linden/indra/llmath/llinterp.h419
-rw-r--r--linden/indra/llmath/llmath.h421
-rw-r--r--linden/indra/llmath/llmath.vcproj322
-rw-r--r--linden/indra/llmath/llmd5.cpp574
-rw-r--r--linden/indra/llmath/llmd5.h145
-rw-r--r--linden/indra/llmath/lloctree.h712
-rw-r--r--linden/indra/llmath/llperlin.cpp295
-rw-r--r--linden/indra/llmath/llperlin.h47
-rw-r--r--linden/indra/llmath/llplane.h68
-rw-r--r--linden/indra/llmath/llquantize.h122
-rw-r--r--linden/indra/llmath/llquaternion.cpp849
-rw-r--r--linden/indra/llmath/llquaternion.h461
-rw-r--r--linden/indra/llmath/llrand.cpp74
-rw-r--r--linden/indra/llmath/llrand.h88
-rw-r--r--linden/indra/llmath/llrect.cpp29
-rw-r--r--linden/indra/llmath/llrect.h289
-rw-r--r--linden/indra/llmath/lltreenode.h180
-rw-r--r--linden/indra/llmath/lluuid.cpp864
-rw-r--r--linden/indra/llmath/lluuid.h321
-rw-r--r--linden/indra/llmath/llvolume.cpp4576
-rw-r--r--linden/indra/llmath/llvolume.h901
-rw-r--r--linden/indra/llmath/llvolumemgr.cpp314
-rw-r--r--linden/indra/llmath/llvolumemgr.h101
-rw-r--r--linden/indra/llmath/m3math.cpp549
-rw-r--r--linden/indra/llmath/m3math.h217
-rw-r--r--linden/indra/llmath/m4math.cpp813
-rw-r--r--linden/indra/llmath/m4math.h384
-rw-r--r--linden/indra/llmath/raytrace.cpp1275
-rw-r--r--linden/indra/llmath/raytrace.h233
-rw-r--r--linden/indra/llmath/v2math.cpp111
-rw-r--r--linden/indra/llmath/v2math.h326
-rw-r--r--linden/indra/llmath/v3color.cpp63
-rw-r--r--linden/indra/llmath/v3color.h381
-rw-r--r--linden/indra/llmath/v3dmath.cpp148
-rw-r--r--linden/indra/llmath/v3dmath.h437
-rw-r--r--linden/indra/llmath/v3math.cpp232
-rw-r--r--linden/indra/llmath/v3math.h465
-rw-r--r--linden/indra/llmath/v4color.cpp580
-rw-r--r--linden/indra/llmath/v4color.h558
-rw-r--r--linden/indra/llmath/v4coloru.cpp121
-rw-r--r--linden/indra/llmath/v4coloru.h520
-rw-r--r--linden/indra/llmath/v4math.cpp143
-rw-r--r--linden/indra/llmath/v4math.h404
-rw-r--r--linden/indra/llmath/xform.cpp115
-rw-r--r--linden/indra/llmath/xform.h288
57 files changed, 22832 insertions, 0 deletions
diff --git a/linden/indra/llmath/camera.h b/linden/indra/llmath/camera.h
new file mode 100644
index 0000000..e9963e9
--- /dev/null
+++ b/linden/indra/llmath/camera.h
@@ -0,0 +1,28 @@
1/**
2 * @file camera.h
3 * @brief Legacy wrapper header.
4 *
5 * Copyright (c) 2000-2007 Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llcamera.h"
diff --git a/linden/indra/llmath/coordframe.h b/linden/indra/llmath/coordframe.h
new file mode 100644
index 0000000..81d630e
--- /dev/null
+++ b/linden/indra/llmath/coordframe.h
@@ -0,0 +1,28 @@
1/**
2 * @file coordframe.h
3 * @brief Legacy wrapper header.
4 *
5 * Copyright (c) 2000-2007 Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llcoordframe.h"
diff --git a/linden/indra/llmath/files.lst b/linden/indra/llmath/files.lst
new file mode 100644
index 0000000..cfd635a
--- /dev/null
+++ b/linden/indra/llmath/files.lst
@@ -0,0 +1,23 @@
1llmath/llbboxlocal.cpp
2llmath/llcamera.cpp
3llmath/llcoordframe.cpp
4llmath/llcrc.cpp
5llmath/llmd5.cpp
6llmath/llperlin.cpp
7llmath/llquaternion.cpp
8llmath/llrand.cpp
9llmath/llrect.cpp
10llmath/lluuid.cpp
11llmath/llvolume.cpp
12llmath/llvolumemgr.cpp
13llmath/m3math.cpp
14llmath/m4math.cpp
15llmath/raytrace.cpp
16llmath/v2math.cpp
17llmath/v3color.cpp
18llmath/v3dmath.cpp
19llmath/v3math.cpp
20llmath/v4color.cpp
21llmath/v4coloru.cpp
22llmath/v4math.cpp
23llmath/xform.cpp
diff --git a/linden/indra/llmath/llbboxlocal.cpp b/linden/indra/llmath/llbboxlocal.cpp
new file mode 100644
index 0000000..b197241
--- /dev/null
+++ b/linden/indra/llmath/llbboxlocal.cpp
@@ -0,0 +1,56 @@
1/**
2 * @file llbboxlocal.cpp
3 * @brief General purpose bounding box class (Not axis aligned).
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llbboxlocal.h"
31#include "m4math.h"
32
33void LLBBoxLocal::addPoint(const LLVector3& p)
34{
35 mMin.mV[VX] = llmin( p.mV[VX], mMin.mV[VX] );
36 mMin.mV[VY] = llmin( p.mV[VY], mMin.mV[VY] );
37 mMin.mV[VZ] = llmin( p.mV[VZ], mMin.mV[VZ] );
38 mMax.mV[VX] = llmax( p.mV[VX], mMax.mV[VX] );
39 mMax.mV[VY] = llmax( p.mV[VY], mMax.mV[VY] );
40 mMax.mV[VZ] = llmax( p.mV[VZ], mMax.mV[VZ] );
41}
42
43void LLBBoxLocal::expand( F32 delta )
44{
45 mMin.mV[VX] -= delta;
46 mMin.mV[VY] -= delta;
47 mMin.mV[VZ] -= delta;
48 mMax.mV[VX] += delta;
49 mMax.mV[VY] += delta;
50 mMax.mV[VZ] += delta;
51}
52
53LLBBoxLocal operator*(const LLBBoxLocal &a, const LLMatrix4 &b)
54{
55 return LLBBoxLocal( a.mMin * b, a.mMax * b );
56}
diff --git a/linden/indra/llmath/llbboxlocal.h b/linden/indra/llmath/llbboxlocal.h
new file mode 100644
index 0000000..cb71a4f
--- /dev/null
+++ b/linden/indra/llmath/llbboxlocal.h
@@ -0,0 +1,69 @@
1/**
2 * @file llbboxlocal.h
3 * @brief General purpose bounding box class.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_BBOXLOCAL_H
29#define LL_BBOXLOCAL_H
30
31#include "v3math.h"
32
33class LLMatrix4;
34
35class LLBBoxLocal
36{
37public:
38 LLBBoxLocal() {}
39 LLBBoxLocal( const LLVector3& min, const LLVector3& max ) : mMin( min ), mMax( max ) {}
40 // Default copy constructor is OK.
41
42 const LLVector3& getMin() const { return mMin; }
43 void setMin( const LLVector3& min ) { mMin = min; }
44
45 const LLVector3& getMax() const { return mMax; }
46 void setMax( const LLVector3& max ) { mMax = max; }
47
48 LLVector3 getCenter() const { return (mMax - mMin) * 0.5f + mMin; }
49 LLVector3 getExtent() const { return mMax - mMin; }
50
51 BOOL containsPoint(const LLVector3& p) const;
52 BOOL intersects(const LLBBoxLocal& b) const;
53
54 void addPoint(const LLVector3& p);
55 void addBBox(const LLBBoxLocal& b) { addPoint( b.mMin ); addPoint( b.mMax ); }
56
57 void expand( F32 delta );
58
59 friend LLBBoxLocal operator*(const LLBBoxLocal& a, const LLMatrix4& b);
60
61private:
62 LLVector3 mMin;
63 LLVector3 mMax;
64};
65
66LLBBoxLocal operator*(const LLBBoxLocal &a, const LLMatrix4 &b);
67
68
69#endif // LL_BBOXLOCAL_H
diff --git a/linden/indra/llmath/llcamera.cpp b/linden/indra/llmath/llcamera.cpp
new file mode 100644
index 0000000..13666ba
--- /dev/null
+++ b/linden/indra/llmath/llcamera.cpp
@@ -0,0 +1,610 @@
1/**
2 * @file llcamera.cpp
3 * @brief Implementation of the LLCamera class.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llmath.h"
31#include "llcamera.h"
32
33// ---------------- Constructors and destructors ----------------
34
35LLCamera::LLCamera() :
36 LLCoordFrame(),
37 mView(DEFAULT_FIELD_OF_VIEW),
38 mAspect(DEFAULT_ASPECT_RATIO),
39 mViewHeightInPixels( -1 ), // invalid height
40 mNearPlane(DEFAULT_NEAR_PLANE),
41 mFarPlane(DEFAULT_FAR_PLANE),
42 mFixedDistance(-1.f)
43{
44 calculateFrustumPlanes();
45}
46
47
48LLCamera::LLCamera(F32 z_field_of_view, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) :
49 LLCoordFrame(),
50 mView(z_field_of_view),
51 mAspect(aspect_ratio),
52 mViewHeightInPixels(view_height_in_pixels),
53 mNearPlane(near_plane),
54 mFarPlane(far_plane),
55 mFixedDistance(-1.f)
56{
57 if (mView < MIN_FIELD_OF_VIEW) { mView = MIN_FIELD_OF_VIEW; }
58 else if (mView > MAX_FIELD_OF_VIEW) { mView = MAX_FIELD_OF_VIEW; }
59
60 if (mAspect < MIN_ASPECT_RATIO) { mAspect = MIN_ASPECT_RATIO; }
61 else if (mAspect > MAX_ASPECT_RATIO) { mAspect = MAX_ASPECT_RATIO; }
62
63 if (mNearPlane < MIN_NEAR_PLANE) { mNearPlane = MIN_NEAR_PLANE; }
64 else if (mNearPlane > MAX_NEAR_PLANE) { mNearPlane = MAX_NEAR_PLANE; }
65
66 if (mFarPlane < 0) { mFarPlane = DEFAULT_FAR_PLANE; }
67 else if (mFarPlane < MIN_FAR_PLANE) { mFarPlane = MIN_FAR_PLANE; }
68 else if (mFarPlane > MAX_FAR_PLANE) { mFarPlane = MAX_FAR_PLANE; }
69
70 calculateFrustumPlanes();
71}
72
73
74
75// ---------------- LLCamera::setFoo() member functions ----------------
76
77void LLCamera::setView(F32 field_of_view)
78{
79 mView = field_of_view;
80 if (mView < MIN_FIELD_OF_VIEW) { mView = MIN_FIELD_OF_VIEW; }
81 else if (mView > MAX_FIELD_OF_VIEW) { mView = MAX_FIELD_OF_VIEW; }
82 calculateFrustumPlanes();
83}
84
85void LLCamera::setViewHeightInPixels(S32 height)
86{
87 mViewHeightInPixels = height;
88
89 // Don't really need to do this, but update the pixel meter ratio with it.
90 calculateFrustumPlanes();
91}
92
93void LLCamera::setAspect(F32 aspect_ratio)
94{
95 mAspect = aspect_ratio;
96 if (mAspect < MIN_ASPECT_RATIO) { mAspect = MIN_ASPECT_RATIO; }
97 else if (mAspect > MAX_ASPECT_RATIO) { mAspect = MAX_ASPECT_RATIO; }
98 calculateFrustumPlanes();
99}
100
101
102void LLCamera::setNear(F32 near_plane)
103{
104 mNearPlane = near_plane;
105 if (mNearPlane < MIN_NEAR_PLANE) { mNearPlane = MIN_NEAR_PLANE; }
106 else if (mNearPlane > MAX_NEAR_PLANE) { mNearPlane = MAX_NEAR_PLANE; }
107 calculateFrustumPlanes();
108}
109
110
111void LLCamera::setFar(F32 far_plane)
112{
113 mFarPlane = far_plane;
114 if (mFarPlane < MIN_FAR_PLANE) { mFarPlane = MIN_FAR_PLANE; }
115 else if (mFarPlane > MAX_FAR_PLANE) { mFarPlane = MAX_FAR_PLANE; }
116 calculateFrustumPlanes();
117}
118
119
120// ---------------- read/write to buffer ----------------
121
122size_t LLCamera::writeFrustumToBuffer(char *buffer) const
123{
124 memcpy(buffer, &mView, sizeof(F32));
125 buffer += sizeof(F32);
126 memcpy(buffer, &mAspect, sizeof(F32));
127 buffer += sizeof(F32);
128 memcpy(buffer, &mNearPlane, sizeof(F32));
129 buffer += sizeof(F32);
130 memcpy(buffer, &mFarPlane, sizeof(F32));
131 return 4*sizeof(F32);
132}
133
134size_t LLCamera::readFrustumFromBuffer(const char *buffer)
135{
136 memcpy(&mView, buffer, sizeof(F32));
137 buffer += sizeof(F32);
138 memcpy(&mAspect, buffer, sizeof(F32));
139 buffer += sizeof(F32);
140 memcpy(&mNearPlane, buffer, sizeof(F32));
141 buffer += sizeof(F32);
142 memcpy(&mFarPlane, buffer, sizeof(F32));
143 return 4*sizeof(F32);
144}
145
146
147// ---------------- test methods ----------------
148
149int LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
150{
151 static const LLVector3 scaler[] = {
152 LLVector3(-1,-1,-1),
153 LLVector3( 1,-1,-1),
154 LLVector3(-1, 1,-1),
155 LLVector3( 1, 1,-1),
156 LLVector3(-1,-1, 1),
157 LLVector3( 1,-1, 1),
158 LLVector3(-1, 1, 1),
159 LLVector3( 1, 1, 1)
160 };
161
162 U8 mask = 0;
163 S32 result = 2;
164
165 for (int i = 0; i < 6; i++)
166 {
167 mask = mAgentPlaneMask[i];
168 LLPlane p = mAgentPlanes[i];
169 LLVector3 n = LLVector3(p);
170 float d = p.mV[3];
171 LLVector3 rscale = radius.scaledVec(scaler[mask]);
172
173 LLVector3 minp = center - rscale;
174 LLVector3 maxp = center + rscale;
175
176 if (n * minp > -d)
177 {
178 return 0;
179 }
180
181 if (n * maxp > -d)
182 {
183 result = 1;
184 }
185 }
186
187 return result;
188}
189
190int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
191{
192 LLVector3 dist = sphere_center-mFrustCenter;
193 float dsq = dist * dist;
194 float rsq = mFarPlane*0.5f + radius;
195 rsq *= rsq;
196
197 if (dsq < rsq)
198 {
199 return 1;
200 }
201
202 return 0;
203}
204
205// HACK: This version is still around because the version below doesn't work
206// unless the agent planes are initialized.
207// Return 1 if sphere is in frustum, 2 if fully in frustum, otherwise 0.
208// NOTE: 'center' is in absolute frame.
209int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radius) const
210{
211 // Returns 1 if sphere is in frustum, 0 if not.
212 // modified so that default view frust is along X with Z vertical
213 F32 x, y, z, rightDist, leftDist, topDist, bottomDist;
214
215 // Subtract the view position
216 //LLVector3 relative_center;
217 //relative_center = sphere_center - getOrigin();
218 LLVector3 rel_center(sphere_center);
219 rel_center -= mOrigin;
220
221 bool all_in = TRUE;
222
223 // Transform relative_center.x to camera frame
224 x = mXAxis * rel_center;
225 if (x < MIN_NEAR_PLANE - radius)
226 {
227 return 0;
228 }
229 else if (x < MIN_NEAR_PLANE + radius)
230 {
231 all_in = FALSE;
232 }
233
234 if (x > mFarPlane + radius)
235 {
236 return 0;
237 }
238 else if (x > mFarPlane - radius)
239 {
240 all_in = FALSE;
241 }
242
243 // Transform relative_center.y to camera frame
244 y = mYAxis * rel_center;
245
246 // distance to plane is the dot product of (x, y, 0) * plane_normal
247 rightDist = x * mLocalPlanes[PLANE_RIGHT][VX] + y * mLocalPlanes[PLANE_RIGHT][VY];
248 if (rightDist < -radius)
249 {
250 return 0;
251 }
252 else if (rightDist < radius)
253 {
254 all_in = FALSE;
255 }
256
257 leftDist = x * mLocalPlanes[PLANE_LEFT][VX] + y * mLocalPlanes[PLANE_LEFT][VY];
258 if (leftDist < -radius)
259 {
260 return 0;
261 }
262 else if (leftDist < radius)
263 {
264 all_in = FALSE;
265 }
266
267 // Transform relative_center.y to camera frame
268 z = mZAxis * rel_center;
269
270 topDist = x * mLocalPlanes[PLANE_TOP][VX] + z * mLocalPlanes[PLANE_TOP][VZ];
271 if (topDist < -radius)
272 {
273 return 0;
274 }
275 else if (topDist < radius)
276 {
277 all_in = FALSE;
278 }
279
280 bottomDist = x * mLocalPlanes[PLANE_BOTTOM][VX] + z * mLocalPlanes[PLANE_BOTTOM][VZ];
281 if (bottomDist < -radius)
282 {
283 return 0;
284 }
285 else if (bottomDist < radius)
286 {
287 all_in = FALSE;
288 }
289
290 if (all_in)
291 {
292 return 2;
293 }
294
295 return 1;
296}
297
298
299// HACK: This (presumably faster) version only currently works if you set up the
300// frustum planes using GL. At some point we should get those planes through another
301// mechanism, and then we can get rid of the "old" version above.
302
303// Return 1 if sphere is in frustum, 2 if fully in frustum, otherwise 0.
304// NOTE: 'center' is in absolute frame.
305int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const
306{
307 // Returns 1 if sphere is in frustum, 0 if not.
308 int res = 2;
309 for (int i = 0; i < 6; i++)
310 {
311 float d = mAgentPlanes[i].dist(sphere_center);
312
313 if (d > radius)
314 {
315 return 0;
316 }
317
318 if (d > -radius)
319 {
320 res = 1;
321 }
322 }
323
324 return res;
325}
326
327
328// return height of a sphere of given radius, located at center, in pixels
329F32 LLCamera::heightInPixels(const LLVector3 &center, F32 radius ) const
330{
331 if (radius == 0.f) return 0.f;
332
333 // If height initialized
334 if (mViewHeightInPixels > -1)
335 {
336 // Convert sphere to coord system with 0,0,0 at camera
337 LLVector3 vec = center - mOrigin;
338
339 // Compute distance to sphere
340 F32 dist = vec.magVec();
341
342 // Calculate angle of whole object
343 F32 angle = 2.0f * (F32) atan2(radius, dist);
344
345 // Calculate fraction of field of view
346 F32 fraction_of_fov = angle / mView;
347
348 // Compute number of pixels tall, based on vertical field of view
349 return (fraction_of_fov * mViewHeightInPixels);
350 }
351 else
352 {
353 // return invalid height
354 return -1.0f;
355 }
356}
357
358// If pos is visible, return the distance from pos to the camera.
359// Use fudge distance to scale rad against top/bot/left/right planes
360// Otherwise, return -distance
361F32 LLCamera::visibleDistance(const LLVector3 &pos, F32 rad, F32 fudgedist, U32 planemask) const
362{
363 if (mFixedDistance > 0)
364 {
365 return mFixedDistance;
366 }
367 LLVector3 dvec = pos - mOrigin;
368 // Check visibility
369 F32 dist = dvec.magVec();
370 if (dist > rad)
371 {
372 F32 dp,tdist;
373 dp = dvec * mXAxis;
374 if (dp < -rad)
375 return -dist;
376
377 rad *= fudgedist;
378 LLVector3 tvec(pos);
379 for (int p=0; p<PLANE_NUM; p++)
380 {
381 if (!(planemask & (1<<p)))
382 continue;
383 tdist = -(mWorldPlanes[p].dist(tvec));
384 if (tdist > rad)
385 return -dist;
386 }
387 }
388 return dist;
389}
390
391// Like visibleDistance, except uses mHorizPlanes[], which are left and right
392// planes perpindicular to (0,0,1) in world space
393F32 LLCamera::visibleHorizDistance(const LLVector3 &pos, F32 rad, F32 fudgedist, U32 planemask) const
394{
395 if (mFixedDistance > 0)
396 {
397 return mFixedDistance;
398 }
399 LLVector3 dvec = pos - mOrigin;
400 // Check visibility
401 F32 dist = dvec.magVec();
402 if (dist > rad)
403 {
404 rad *= fudgedist;
405 LLVector3 tvec(pos);
406 for (int p=0; p<HORIZ_PLANE_NUM; p++)
407 {
408 if (!(planemask & (1<<p)))
409 continue;
410 F32 tdist = -(mHorizPlanes[p].dist(tvec));
411 if (tdist > rad)
412 return -dist;
413 }
414 }
415 return dist;
416}
417
418// ---------------- friends and operators ----------------
419
420std::ostream& operator<<(std::ostream &s, const LLCamera &C)
421{
422 s << "{ \n";
423 s << " Center = " << C.getOrigin() << "\n";
424 s << " AtAxis = " << C.getXAxis() << "\n";
425 s << " LeftAxis = " << C.getYAxis() << "\n";
426 s << " UpAxis = " << C.getZAxis() << "\n";
427 s << " View = " << C.getView() << "\n";
428 s << " Aspect = " << C.getAspect() << "\n";
429 s << " NearPlane = " << C.mNearPlane << "\n";
430 s << " FarPlane = " << C.mFarPlane << "\n";
431 s << " TopPlane = " << C.mLocalPlanes[LLCamera::PLANE_TOP][VX] << " "
432 << C.mLocalPlanes[LLCamera::PLANE_TOP][VY] << " "
433 << C.mLocalPlanes[LLCamera::PLANE_TOP][VZ] << "\n";
434 s << " BottomPlane = " << C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VX] << " "
435 << C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VY] << " "
436 << C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VZ] << "\n";
437 s << " LeftPlane = " << C.mLocalPlanes[LLCamera::PLANE_LEFT][VX] << " "
438 << C.mLocalPlanes[LLCamera::PLANE_LEFT][VY] << " "
439 << C.mLocalPlanes[LLCamera::PLANE_LEFT][VZ] << "\n";
440 s << " RightPlane = " << C.mLocalPlanes[LLCamera::PLANE_RIGHT][VX] << " "
441 << C.mLocalPlanes[LLCamera::PLANE_RIGHT][VY] << " "
442 << C.mLocalPlanes[LLCamera::PLANE_RIGHT][VZ] << "\n";
443 s << "}";
444 return s;
445}
446
447
448
449// ---------------- private member functions ----------------
450
451void LLCamera::calculateFrustumPlanes()
452{
453 // The planes only change when any of the frustum descriptions change.
454 // They are not affected by changes of the position of the Frustum
455 // because they are known in the view frame and the position merely
456 // provides information on how to get from the absolute frame to the
457 // view frame.
458
459 F32 left,right,top,bottom;
460 top = mFarPlane * (F32)tanf(0.5f * mView);
461 bottom = -top;
462 left = top * mAspect;
463 right = -left;
464
465 calculateFrustumPlanes(left, right, top, bottom);
466}
467
468LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3)
469{
470 LLVector3 n = ((p2-p1)%(p3-p1));
471 n.normVec();
472
473 return LLPlane(p1, n);
474}
475
476
477void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
478{
479
480 for (int i = 0; i < 8; i++)
481 {
482 mAgentFrustum[i] = frust[i];
483 }
484
485 //frust contains the 8 points of the frustum, calculate 6 planes
486
487 //order of planes is important, keep most likely to fail in the front of the list
488
489 //near - frust[0], frust[1], frust[2]
490 mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]);
491
492 //far
493 mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]);
494
495 //left
496 mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]);
497
498 //right
499 mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]);
500
501 //top
502 mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]);
503
504 //bottom
505 mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]);
506
507 //cache plane octant facing mask for use in AABBInFrustum
508 for (int i = 0; i < 8; i++)
509 {
510 U8 mask = 0;
511 LLPlane p = mAgentPlanes[i];
512 LLVector3 n = LLVector3(p);
513
514 if (n.mV[0] >= 0)
515 {
516 mask |= 1;
517 }
518 if (n.mV[1] >= 0)
519 {
520 mask |= 2;
521 }
522 if (n.mV[2] >= 0)
523 {
524 mask |= 4;
525 }
526 mAgentPlaneMask[i] = mask;
527 }
528}
529
530void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom)
531{
532 LLVector3 a, b, c;
533
534 // For each plane we need to define 3 points (LLVector3's) in camera view space.
535 // The order in which we pass the points to planeFromPoints() matters, because the
536 // plane normal has a degeneracy of 2; we want it pointing _into_ the frustum.
537
538 a.setVec(0.0f, 0.0f, 0.0f);
539 b.setVec(mFarPlane, right, top);
540 c.setVec(mFarPlane, right, bottom);
541 mLocalPlanes[PLANE_RIGHT].setVec(a, b, c);
542
543 c.setVec(mFarPlane, left, top);
544 mLocalPlanes[PLANE_TOP].setVec(a, c, b);
545
546 b.setVec(mFarPlane, left, bottom);
547 mLocalPlanes[PLANE_LEFT].setVec(a, b, c);
548
549 c.setVec(mFarPlane, right, bottom);
550 mLocalPlanes[PLANE_BOTTOM].setVec( a, c, b);
551
552 //calculate center and radius squared of frustum in world absolute coordinates
553 mFrustCenter = X_AXIS*mFarPlane*0.5f;
554 mFrustCenter = transformToAbsolute(mFrustCenter);
555 mFrustRadiusSquared = mFarPlane*0.5f;
556 mFrustRadiusSquared *= mFrustRadiusSquared * 1.05f; //pad radius squared by 5%
557}
558
559// x and y are in WINDOW space, so x = Y-Axis (left/right), y= Z-Axis(Up/Down)
560void LLCamera::calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2)
561{
562 F32 bottom, top, left, right;
563 F32 view_height = (F32)tanf(0.5f * mView) * mFarPlane;
564 F32 view_width = view_height * mAspect;
565
566 left = x1 * -2.f * view_width;
567 right = x2 * -2.f * view_width;
568 bottom = y1 * 2.f * view_height;
569 top = y2 * 2.f * view_height;
570
571 calculateFrustumPlanes(left, right, top, bottom);
572}
573
574void LLCamera::calculateWorldFrustumPlanes()
575{
576 F32 d;
577 LLVector3 center = mOrigin - mXAxis*mNearPlane;
578 mWorldPlanePos = center;
579 for (int p=0; p<4; p++)
580 {
581 LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
582 LLVector3 norm = rotateToAbsolute(pnorm);
583 norm.normVec();
584 d = -(center * norm);
585 mWorldPlanes[p] = LLPlane(norm, d);
586 }
587 // horizontal planes, perpindicular to (0,0,1);
588 LLVector3 zaxis(0, 0, 1.0f);
589 F32 yaw = getYaw();
590 {
591 LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
592 tnorm.rotVec(yaw, zaxis);
593 d = -(mOrigin * tnorm);
594 mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
595 }
596 {
597 LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
598 tnorm.rotVec(yaw, zaxis);
599 d = -(mOrigin * tnorm);
600 mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
601 }
602}
603
604// NOTE: this is the OpenGL matrix that will transform the default OpenGL view
605// (-Z=at, Y=up) to the default view of the LLCamera class (X=at, Z=up):
606//
607// F32 cfr_transform = { 0.f, 0.f, -1.f, 0.f, // -Z becomes X
608// -1.f, 0.f, 0.f, 0.f, // -X becomes Y
609// 0.f, 1.f, 0.f, 0.f, // Y becomes Z
610// 0.f, 0.f, 0.f, 1.f };
diff --git a/linden/indra/llmath/llcamera.h b/linden/indra/llmath/llcamera.h
new file mode 100644
index 0000000..82b6130
--- /dev/null
+++ b/linden/indra/llmath/llcamera.h
@@ -0,0 +1,188 @@
1/**
2 * @file llcamera.h
3 * @brief Header file for the LLCamera class.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_CAMERA_H
29#define LL_CAMERA_H
30
31
32#include "llmath.h"
33#include "llcoordframe.h"
34#include "llplane.h"
35
36const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
37const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
38const F32 DEFAULT_NEAR_PLANE = 0.25f;
39const F32 DEFAULT_FAR_PLANE = 64.f; // far reaches across two horizontal, not diagonal, regions
40
41const F32 MAX_FIELD_OF_VIEW = F_PI;
42const F32 MAX_ASPECT_RATIO = 50.0f;
43const F32 MAX_NEAR_PLANE = 10.f;
44const F32 MAX_FAR_PLANE = 100000.0f; //1000000.0f; // Max allowed. Not good Z precision though.
45const F32 MAX_FAR_CLIP = 1024.0f;
46
47const F32 MIN_FIELD_OF_VIEW = 0.1f;
48const F32 MIN_ASPECT_RATIO = 0.02f;
49const F32 MIN_NEAR_PLANE = 0.1f;
50const F32 MIN_FAR_PLANE = 0.2f;
51
52static const LLVector3 X_AXIS(1.f,0.f,0.f);
53static const LLVector3 Y_AXIS(0.f,1.f,0.f);
54static const LLVector3 Z_AXIS(0.f,0.f,1.f);
55
56static const LLVector3 NEG_X_AXIS(-1.f,0.f,0.f);
57static const LLVector3 NEG_Y_AXIS(0.f,-1.f,0.f);
58static const LLVector3 NEG_Z_AXIS(0.f,0.f,-1.f);
59
60
61// An LLCamera is an LLCoorFrame with a view frustum.
62// This means that it has several methods for moving it around
63// that are inherited from the LLCoordFrame() class :
64//
65// setOrigin(), setAxes()
66// translate(), rotate()
67// roll(), pitch(), yaw()
68// etc...
69
70
71class LLCamera
72: public LLCoordFrame
73{
74public:
75 enum {
76 PLANE_LEFT = 0,
77 PLANE_RIGHT = 1,
78 PLANE_BOTTOM = 2,
79 PLANE_TOP = 3,
80 PLANE_NUM = 4
81 };
82 enum {
83 PLANE_LEFT_MASK = (1<<PLANE_LEFT),
84 PLANE_RIGHT_MASK = (1<<PLANE_RIGHT),
85 PLANE_BOTTOM_MASK = (1<<PLANE_BOTTOM),
86 PLANE_TOP_MASK = (1<<PLANE_TOP),
87 PLANE_ALL_MASK = 0xf
88 };
89 enum {
90 HORIZ_PLANE_LEFT = 0,
91 HORIZ_PLANE_RIGHT = 1,
92 HORIZ_PLANE_NUM = 2
93 };
94 enum {
95 HORIZ_PLANE_LEFT_MASK = (1<<HORIZ_PLANE_LEFT),
96 HORIZ_PLANE_RIGHT_MASK = (1<<HORIZ_PLANE_RIGHT),
97 HORIZ_PLANE_ALL_MASK = 0x3
98 };
99
100protected:
101 F32 mView; // angle between top and bottom frustum planes in radians.
102 F32 mAspect; // width/height
103 S32 mViewHeightInPixels; // for ViewHeightInPixels() only
104 F32 mNearPlane;
105 F32 mFarPlane;
106 LLPlane mLocalPlanes[4];
107 F32 mFixedDistance; // Always return this distance, unless < 0
108 LLVector3 mFrustCenter; // center of frustum and radius squared for ultra-quick exclusion test
109 F32 mFrustRadiusSquared;
110
111 LLPlane mWorldPlanes[PLANE_NUM];
112 LLPlane mHorizPlanes[HORIZ_PLANE_NUM];
113 LLPlane mAgentPlanes[6]; //frustum in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
114 U8 mAgentPlaneMask[6];
115 LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera)
116public:
117 LLVector3 mAgentFrustum[8];
118
119public:
120 LLCamera();
121 LLCamera(F32 z_field_of_view, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);
122
123 void setView(F32 new_view);
124 void setViewHeightInPixels(S32 height);
125 void setAspect(F32 new_aspect);
126 void setNear(F32 new_near);
127 void setFar(F32 new_far);
128
129 F32 getView() const { return mView; } // vertical FOV in radians
130 S32 getViewHeightInPixels() const { return mViewHeightInPixels; }
131 F32 getAspect() const { return mAspect; } // width / height
132 F32 getNear() const { return mNearPlane; } // meters
133 F32 getFar() const { return mFarPlane; } // meters
134
135 F32 getYaw() const
136 {
137 return atan2f(mXAxis[VY], mXAxis[VX]);
138 }
139 F32 getPitch() const
140 {
141 F32 xylen = sqrtf(mXAxis[VX]*mXAxis[VX] + mXAxis[VY]*mXAxis[VY]);
142 return atan2f(mXAxis[VZ], xylen);
143 }
144
145 const LLPlane& getWorldPlane(S32 index) const { return mWorldPlanes[index]; }
146 const LLVector3& getWorldPlanePos() const { return mWorldPlanePos; }
147
148 // Copy mView, mAspect, mNearPlane, and mFarPlane to buffer.
149 // Return number of bytes copied.
150 size_t writeFrustumToBuffer(char *buffer) const;
151
152 // Copy mView, mAspect, mNearPlane, and mFarPlane from buffer.
153 // Return number of bytes copied.
154 size_t readFrustumFromBuffer(const char *buffer);
155 void calcAgentFrustumPlanes(LLVector3* frust);
156 // Returns 1 if partly in, 2 if fully in.
157 // NOTE: 'center' is in absolute frame.
158 S32 sphereInFrustumOld(const LLVector3 &center, const F32 radius) const;
159 S32 sphereInFrustum(const LLVector3 &center, const F32 radius) const;
160 S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
161 S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
162 S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
163 //does a quick 'n dirty sphere-sphere check
164 S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
165
166 // Returns height of object in pixels (must be height because field of view
167 // is based on window height).
168 F32 heightInPixels(const LLVector3 &center, F32 radius ) const;
169
170 // return the distance from pos to camera if visible (-distance if not visible)
171 F32 visibleDistance(const LLVector3 &pos, F32 rad, F32 fudgescale = 1.0f, U32 planemask = PLANE_ALL_MASK) const;
172 F32 visibleHorizDistance(const LLVector3 &pos, F32 rad, F32 fudgescale = 1.0f, U32 planemask = HORIZ_PLANE_ALL_MASK) const;
173 void setFixedDistance(F32 distance) { mFixedDistance = distance; }
174
175 friend std::ostream& operator<<(std::ostream &s, const LLCamera &C);
176
177protected:
178 void calculateFrustumPlanes();
179 void calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom);
180 void calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2);
181 void calculateWorldFrustumPlanes();
182};
183
184
185#endif
186
187
188
diff --git a/linden/indra/llmath/llcoord.h b/linden/indra/llmath/llcoord.h
new file mode 100644
index 0000000..6aa6b64
--- /dev/null
+++ b/linden/indra/llmath/llcoord.h
@@ -0,0 +1,97 @@
1/**
2 * @file llcoord.h
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_LLCOORD_H
28#define LL_LLCOORD_H
29
30// A two-dimensional pixel value
31class LLCoord
32{
33public:
34 S32 mX;
35 S32 mY;
36
37 LLCoord(): mX(0), mY(0)
38 {}
39 LLCoord(S32 x, S32 y): mX(x), mY(y)
40 {}
41 virtual ~LLCoord()
42 {}
43
44 virtual void set(S32 x, S32 y) { mX = x; mY = y; }
45};
46
47
48// GL coordinates start in the client region of a window,
49// with left, bottom = 0, 0
50class LLCoordGL : public LLCoord
51{
52public:
53 LLCoordGL() : LLCoord()
54 {}
55 LLCoordGL(S32 x, S32 y) : LLCoord(x, y)
56 {}
57};
58
59
60// Window coords include things like window borders,
61// menu regions, etc.
62class LLCoordWindow : public LLCoord
63{
64public:
65 LLCoordWindow() : LLCoord()
66 {}
67 LLCoordWindow(S32 x, S32 y) : LLCoord(x, y)
68 {}
69};
70
71
72// Screen coords start at left, top = 0, 0
73class LLCoordScreen : public LLCoord
74{
75public:
76 LLCoordScreen() : LLCoord()
77 {}
78 LLCoordScreen(S32 x, S32 y) : LLCoord(x, y)
79 {}
80};
81
82class LLCoordFont : public LLCoord
83{
84public:
85 F32 mZ;
86
87 LLCoordFont() : LLCoord(), mZ(0.f)
88 {}
89 LLCoordFont(S32 x, S32 y, F32 z = 0) : LLCoord(x,y), mZ(z)
90 {}
91
92 void set(S32 x, S32 y) { LLCoord::set(x,y); mZ = 0.f; }
93 void set(S32 x, S32 y, F32 z) { mX = x; mY = y; mZ = z; }
94};
95
96
97#endif
diff --git a/linden/indra/llmath/llcoordframe.cpp b/linden/indra/llmath/llcoordframe.cpp
new file mode 100644
index 0000000..552854d
--- /dev/null
+++ b/linden/indra/llmath/llcoordframe.cpp
@@ -0,0 +1,748 @@
1/**
2 * @file llcoordframe.cpp
3 * @brief LLCoordFrame class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30//#include "vmath.h"
31#include "v3math.h"
32#include "m3math.h"
33#include "v4math.h"
34#include "m4math.h"
35#include "llquaternion.h"
36#include "llcoordframe.h"
37
38#ifndef X_AXIS
39 #define X_AXIS 1.0f,0.0f,0.0f
40 #define Y_AXIS 0.0f,1.0f,0.0f
41 #define Z_AXIS 0.0f,0.0f,1.0f
42#endif
43
44// Constructors
45
46LLCoordFrame::LLCoordFrame() :
47 mOrigin(0.f, 0.f, 0.f),
48 mXAxis(X_AXIS),
49 mYAxis(Y_AXIS),
50 mZAxis(Z_AXIS)
51{
52}
53
54LLCoordFrame::LLCoordFrame(const LLVector3 &origin) :
55 mOrigin(origin),
56 mXAxis(X_AXIS),
57 mYAxis(Y_AXIS),
58 mZAxis(Z_AXIS)
59{
60 if( !mOrigin.isFinite() )
61 {
62 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
63 }
64}
65
66LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLVector3 &direction) :
67 mOrigin(origin)
68{
69 lookDir(direction);
70
71 if( !isFinite() )
72 {
73 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
74 }
75}
76
77LLCoordFrame::LLCoordFrame(const LLVector3 &x_axis,
78 const LLVector3 &y_axis,
79 const LLVector3 &z_axis) :
80 mOrigin(0.f, 0.f, 0.f),
81 mXAxis(x_axis),
82 mYAxis(y_axis),
83 mZAxis(z_axis)
84{
85 if( !isFinite() )
86 {
87 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
88 }
89}
90
91LLCoordFrame::LLCoordFrame(const LLVector3 &origin,
92 const LLVector3 &x_axis,
93 const LLVector3 &y_axis,
94 const LLVector3 &z_axis) :
95 mOrigin(origin),
96 mXAxis(x_axis),
97 mYAxis(y_axis),
98 mZAxis(z_axis)
99{
100 if( !isFinite() )
101 {
102 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
103 }
104}
105
106
107LLCoordFrame::LLCoordFrame(const LLVector3 &origin,
108 const LLMatrix3 &rotation) :
109 mOrigin(origin),
110 mXAxis(rotation.mMatrix[VX]),
111 mYAxis(rotation.mMatrix[VY]),
112 mZAxis(rotation.mMatrix[VZ])
113{
114 if( !isFinite() )
115 {
116 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
117 }
118}
119
120LLCoordFrame::LLCoordFrame(const LLQuaternion &q) :
121 mOrigin(0.f, 0.f, 0.f)
122{
123 LLMatrix3 rotation_matrix(q);
124 mXAxis.setVec(rotation_matrix.mMatrix[VX]);
125 mYAxis.setVec(rotation_matrix.mMatrix[VY]);
126 mZAxis.setVec(rotation_matrix.mMatrix[VZ]);
127
128 if( !isFinite() )
129 {
130 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
131 }
132}
133
134LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLQuaternion &q) :
135 mOrigin(origin)
136{
137 LLMatrix3 rotation_matrix(q);
138 mXAxis.setVec(rotation_matrix.mMatrix[VX]);
139 mYAxis.setVec(rotation_matrix.mMatrix[VY]);
140 mZAxis.setVec(rotation_matrix.mMatrix[VZ]);
141
142 if( !isFinite() )
143 {
144 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
145 }
146}
147
148LLCoordFrame::LLCoordFrame(const LLMatrix4 &mat) :
149 mOrigin(mat.mMatrix[VW]),
150 mXAxis(mat.mMatrix[VX]),
151 mYAxis(mat.mMatrix[VY]),
152 mZAxis(mat.mMatrix[VZ])
153{
154 if( !isFinite() )
155 {
156 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
157 }
158}
159
160
161// The folowing two constructors are dangerous due to implicit casting and have been disabled - SJB
162/*
163LLCoordFrame::LLCoordFrame(const F32 *origin, const F32 *rotation) :
164 mOrigin(origin),
165 mXAxis(rotation+3*VX),
166 mYAxis(rotation+3*VY),
167 mZAxis(rotation+3*VZ)
168{
169 if( !isFinite() )
170 {
171 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
172 }
173}
174*/
175
176/*
177LLCoordFrame::LLCoordFrame(const F32 *origin_and_rotation) :
178 mOrigin(origin_and_rotation),
179 mXAxis(origin_and_rotation + 3*(VX+1)),
180 mYAxis(origin_and_rotation + 3*(VY+1)),
181 mZAxis(origin_and_rotation + 3*(VZ+1))
182{
183 if( !isFinite() )
184 {
185 llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
186 }
187}
188*/
189
190
191void LLCoordFrame::reset()
192{
193 mOrigin.setVec(0.0f, 0.0f, 0.0f);
194 resetAxes();
195}
196
197
198void LLCoordFrame::resetAxes()
199{
200 mXAxis.setVec(1.0f, 0.0f, 0.0f);
201 mYAxis.setVec(0.0f, 1.0f, 0.0f);
202 mZAxis.setVec(0.0f, 0.0f, 1.0f);
203}
204
205// setOrigin() member functions set mOrigin
206
207void LLCoordFrame::setOrigin(F32 x, F32 y, F32 z)
208{
209 mOrigin.setVec(x, y, z);
210
211 if( !mOrigin.isFinite() )
212 {
213 llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
214 }
215}
216
217void LLCoordFrame::setOrigin(const LLVector3 &new_origin)
218{
219 mOrigin = new_origin;
220 if( !mOrigin.isFinite() )
221 {
222 llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
223 }
224}
225
226void LLCoordFrame::setOrigin(const F32 *origin)
227{
228 mOrigin.mV[VX] = *(origin + VX);
229 mOrigin.mV[VY] = *(origin + VY);
230 mOrigin.mV[VZ] = *(origin + VZ);
231
232 if( !mOrigin.isFinite() )
233 {
234 llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
235 }
236}
237
238void LLCoordFrame::setOrigin(const LLCoordFrame &frame)
239{
240 mOrigin = frame.getOrigin();
241
242 if( !mOrigin.isFinite() )
243 {
244 llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
245 }
246}
247
248// setAxes() member functions set the axes, and assume that
249// the arguments are orthogonal and normalized.
250
251void LLCoordFrame::setAxes(const LLVector3 &x_axis,
252 const LLVector3 &y_axis,
253 const LLVector3 &z_axis)
254{
255 mXAxis = x_axis;
256 mYAxis = y_axis;
257 mZAxis = z_axis;
258 if( !isFinite() )
259 {
260 llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
261 }
262}
263
264
265void LLCoordFrame::setAxes(const LLMatrix3 &rotation_matrix)
266{
267 mXAxis.setVec(rotation_matrix.mMatrix[VX]);
268 mYAxis.setVec(rotation_matrix.mMatrix[VY]);
269 mZAxis.setVec(rotation_matrix.mMatrix[VZ]);
270 if( !isFinite() )
271 {
272 llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
273 }
274}
275
276
277void LLCoordFrame::setAxes(const LLQuaternion &q )
278{
279 LLMatrix3 rotation_matrix(q);
280 setAxes(rotation_matrix);
281 if( !isFinite() )
282 {
283 llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
284 }
285}
286
287
288void LLCoordFrame::setAxes( const F32 *rotation_matrix )
289{
290 mXAxis.mV[VX] = *(rotation_matrix + 3*VX + VX);
291 mXAxis.mV[VY] = *(rotation_matrix + 3*VX + VY);
292 mXAxis.mV[VZ] = *(rotation_matrix + 3*VX + VZ);
293 mYAxis.mV[VX] = *(rotation_matrix + 3*VY + VX);
294 mYAxis.mV[VY] = *(rotation_matrix + 3*VY + VY);
295 mYAxis.mV[VZ] = *(rotation_matrix + 3*VY + VZ);
296 mZAxis.mV[VX] = *(rotation_matrix + 3*VZ + VX);
297 mZAxis.mV[VY] = *(rotation_matrix + 3*VZ + VY);
298 mZAxis.mV[VZ] = *(rotation_matrix + 3*VZ + VZ);
299
300 if( !isFinite() )
301 {
302 llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
303 }
304}
305
306
307void LLCoordFrame::setAxes(const LLCoordFrame &frame)
308{
309 mXAxis = frame.getXAxis();
310 mYAxis = frame.getYAxis();
311 mZAxis = frame.getZAxis();
312
313 if( !isFinite() )
314 {
315 llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
316 }
317}
318
319
320// translate() member functions move mOrigin to a relative position
321
322void LLCoordFrame::translate(F32 x, F32 y, F32 z)
323{
324 mOrigin.mV[VX] += x;
325 mOrigin.mV[VY] += y;
326 mOrigin.mV[VZ] += z;
327
328 if( !mOrigin.isFinite() )
329 {
330 llerrs << "Non Finite in LLCoordFrame::translate()" << llendl;
331 }
332}
333
334
335void LLCoordFrame::translate(const LLVector3 &v)
336{
337 mOrigin += v;
338
339 if( !mOrigin.isFinite() )
340 {
341 llerrs << "Non Finite in LLCoordFrame::translate()" << llendl;
342 }
343}
344
345
346void LLCoordFrame::translate(const F32 *origin)
347{
348 mOrigin.mV[VX] += *(origin + VX);
349 mOrigin.mV[VY] += *(origin + VY);
350 mOrigin.mV[VZ] += *(origin + VZ);
351
352 if( !mOrigin.isFinite() )
353 {
354 llerrs << "Non Finite in LLCoordFrame::translate()" << llendl;
355 }
356}
357
358
359// Rotate move the axes to a relative rotation
360
361void LLCoordFrame::rotate(F32 angle, F32 x, F32 y, F32 z)
362{
363 LLQuaternion q(angle, LLVector3(x,y,z));
364 rotate(q);
365}
366
367
368void LLCoordFrame::rotate(F32 angle, const LLVector3 &rotation_axis)
369{
370 LLQuaternion q(angle, rotation_axis);
371 rotate(q);
372}
373
374
375void LLCoordFrame::rotate(const LLQuaternion &q)
376{
377 LLMatrix3 rotation_matrix(q);
378 rotate(rotation_matrix);
379}
380
381
382void LLCoordFrame::rotate(const LLMatrix3 &rotation_matrix)
383{
384 mXAxis.rotVec(rotation_matrix);
385 mYAxis.rotVec(rotation_matrix);
386 orthonormalize();
387
388 if( !isFinite() )
389 {
390 llerrs << "Non Finite in LLCoordFrame::rotate()" << llendl;
391 }
392}
393
394
395void LLCoordFrame::roll(F32 angle)
396{
397 LLQuaternion q(angle, mXAxis);
398 LLMatrix3 rotation_matrix(q);
399 rotate(rotation_matrix);
400
401 if( !mYAxis.isFinite() || !mZAxis.isFinite() )
402 {
403 llerrs << "Non Finite in LLCoordFrame::roll()" << llendl;
404 }
405}
406
407void LLCoordFrame::pitch(F32 angle)
408{
409 LLQuaternion q(angle, mYAxis);
410 LLMatrix3 rotation_matrix(q);
411 rotate(rotation_matrix);
412
413 if( !mXAxis.isFinite() || !mZAxis.isFinite() )
414 {
415 llerrs << "Non Finite in LLCoordFrame::pitch()" << llendl;
416 }
417}
418
419void LLCoordFrame::yaw(F32 angle)
420{
421 LLQuaternion q(angle, mZAxis);
422 LLMatrix3 rotation_matrix(q);
423 rotate(rotation_matrix);
424
425 if( !mXAxis.isFinite() || !mYAxis.isFinite() )
426 {
427 llerrs << "Non Finite in LLCoordFrame::yaw()" << llendl;
428 }
429}
430
431// get*() routines
432
433
434LLQuaternion LLCoordFrame::getQuaternion() const
435{
436 LLQuaternion quat(mXAxis, mYAxis, mZAxis);
437 return quat;
438}
439
440
441void LLCoordFrame::getMatrixToLocal(LLMatrix4& mat) const
442{
443 mat.setFwdCol(mXAxis);
444 mat.setLeftCol(mYAxis);
445 mat.setUpCol(mZAxis);
446
447 mat.mMatrix[3][0] = -(mOrigin * LLVector3(mat.mMatrix[0][0], mat.mMatrix[1][0], mat.mMatrix[2][0]));
448 mat.mMatrix[3][1] = -(mOrigin * LLVector3(mat.mMatrix[0][1], mat.mMatrix[1][1], mat.mMatrix[2][1]));
449 mat.mMatrix[3][2] = -(mOrigin * LLVector3(mat.mMatrix[0][2], mat.mMatrix[1][2], mat.mMatrix[2][2]));
450}
451
452
453void LLCoordFrame::getRotMatrixToParent(LLMatrix4& mat) const
454{
455 // Note: moves into CFR
456 mat.setFwdRow( -mYAxis );
457 mat.setLeftRow( mZAxis );
458 mat.setUpRow( -mXAxis );
459}
460
461size_t LLCoordFrame::writeOrientation(char *buffer) const
462{
463 memcpy(buffer, mOrigin.mV, 3*sizeof(F32));
464 buffer += 3*sizeof(F32);
465 memcpy(buffer, mXAxis.mV, 3*sizeof(F32));
466 buffer += 3*sizeof(F32);
467 memcpy(buffer, mYAxis.mV, 3*sizeof(F32));
468 buffer += 3*sizeof(F32);
469 memcpy(buffer, mZAxis.mV, 3*sizeof(F32));
470 return 12*sizeof(F32);
471}
472
473
474size_t LLCoordFrame::readOrientation(const char *buffer)
475{
476 memcpy(mOrigin.mV, buffer, 3*sizeof(F32));
477 buffer += 3*sizeof(F32);
478 memcpy(mXAxis.mV, buffer, 3*sizeof(F32));
479 buffer += 3*sizeof(F32);
480 memcpy(mYAxis.mV, buffer, 3*sizeof(F32));
481 buffer += 3*sizeof(F32);
482 memcpy(mZAxis.mV, buffer, 3*sizeof(F32));
483
484 if( !isFinite() )
485 {
486 llerrs << "Non Finite in LLCoordFrame::readOrientation()" << llendl;
487 }
488
489 return 12*sizeof(F32);
490}
491
492
493// rotation and transform vectors between reference frames
494
495LLVector3 LLCoordFrame::rotateToLocal(const LLVector3 &absolute_vector) const
496{
497 LLVector3 local_vector(mXAxis * absolute_vector,
498 mYAxis * absolute_vector,
499 mZAxis * absolute_vector);
500 return local_vector;
501}
502
503
504LLVector4 LLCoordFrame::rotateToLocal(const LLVector4 &absolute_vector) const
505{
506 LLVector4 local_vector;
507 local_vector.mV[VX] = mXAxis.mV[VX] * absolute_vector.mV[VX] +
508 mXAxis.mV[VY] * absolute_vector.mV[VY] +
509 mXAxis.mV[VZ] * absolute_vector.mV[VZ];
510 local_vector.mV[VY] = mYAxis.mV[VX] * absolute_vector.mV[VX] +
511 mYAxis.mV[VY] * absolute_vector.mV[VY] +
512 mYAxis.mV[VZ] * absolute_vector.mV[VZ];
513 local_vector.mV[VZ] = mZAxis.mV[VX] * absolute_vector.mV[VX] +
514 mZAxis.mV[VY] * absolute_vector.mV[VY] +
515 mZAxis.mV[VZ] * absolute_vector.mV[VZ];
516 local_vector.mV[VW] = absolute_vector.mV[VW];
517 return local_vector;
518}
519
520
521LLVector3 LLCoordFrame::rotateToAbsolute(const LLVector3 &local_vector) const
522{
523 LLVector3 absolute_vector;
524 absolute_vector.mV[VX] = mXAxis.mV[VX] * local_vector.mV[VX] +
525 mYAxis.mV[VX] * local_vector.mV[VY] +
526 mZAxis.mV[VX] * local_vector.mV[VZ];
527 absolute_vector.mV[VY] = mXAxis.mV[VY] * local_vector.mV[VX] +
528 mYAxis.mV[VY] * local_vector.mV[VY] +
529 mZAxis.mV[VY] * local_vector.mV[VZ];
530 absolute_vector.mV[VZ] = mXAxis.mV[VZ] * local_vector.mV[VX] +
531 mYAxis.mV[VZ] * local_vector.mV[VY] +
532 mZAxis.mV[VZ] * local_vector.mV[VZ];
533 return absolute_vector;
534}
535
536
537LLVector4 LLCoordFrame::rotateToAbsolute(const LLVector4 &local_vector) const
538{
539 LLVector4 absolute_vector;
540 absolute_vector.mV[VX] = mXAxis.mV[VX] * local_vector.mV[VX] +
541 mYAxis.mV[VX] * local_vector.mV[VY] +
542 mZAxis.mV[VX] * local_vector.mV[VZ];
543 absolute_vector.mV[VY] = mXAxis.mV[VY] * local_vector.mV[VX] +
544 mYAxis.mV[VY] * local_vector.mV[VY] +
545 mZAxis.mV[VY] * local_vector.mV[VZ];
546 absolute_vector.mV[VZ] = mXAxis.mV[VZ] * local_vector.mV[VX] +
547 mYAxis.mV[VZ] * local_vector.mV[VY] +
548 mZAxis.mV[VZ] * local_vector.mV[VZ];
549 absolute_vector.mV[VW] = local_vector[VW];
550 return absolute_vector;
551}
552
553
554void LLCoordFrame::orthonormalize()
555// Makes sure the axes are orthogonal and normalized.
556{
557 mXAxis.normVec(); // X is renormalized
558 mYAxis -= mXAxis * (mXAxis * mYAxis); // Y remains in X-Y plane
559 mYAxis.normVec(); // Y is normalized
560 mZAxis = mXAxis % mYAxis; // Z = X cross Y
561}
562
563
564LLVector3 LLCoordFrame::transformToLocal(const LLVector3 &absolute_vector) const
565{
566 return rotateToLocal(absolute_vector - mOrigin);
567}
568
569
570LLVector4 LLCoordFrame::transformToLocal(const LLVector4 &absolute_vector) const
571{
572 LLVector4 local_vector(absolute_vector);
573 local_vector.mV[VX] -= mOrigin.mV[VX];
574 local_vector.mV[VY] -= mOrigin.mV[VY];
575 local_vector.mV[VZ] -= mOrigin.mV[VZ];
576 return rotateToLocal(local_vector);
577}
578
579
580LLVector3 LLCoordFrame::transformToAbsolute(const LLVector3 &local_vector) const
581{
582 return (rotateToAbsolute(local_vector) + mOrigin);
583}
584
585
586LLVector4 LLCoordFrame::transformToAbsolute(const LLVector4 &local_vector) const
587{
588 LLVector4 absolute_vector;
589 absolute_vector = rotateToAbsolute(local_vector);
590 absolute_vector.mV[VX] += mOrigin.mV[VX];
591 absolute_vector.mV[VY] += mOrigin.mV[VY];
592 absolute_vector.mV[VZ] += mOrigin.mV[VZ];
593 return absolute_vector;
594}
595
596
597// This is how you combine a translation and rotation of a
598// coordinate frame to get an OpenGL transformation matrix:
599//
600// translation * rotation = transformation matrix
601//
602// (i)->
603// (j)| 1 0 0 0 | | a d g 0 | | a d g 0 |
604// | | 0 1 0 0 | * | b e h 0 | = | b e h 0 |
605// V | 0 0 1 0 | | c f i 0 | | c f i 0 |
606// |-x -y -z 1 | | 0 0 0 1 | |-(ax+by+cz) -(dx+ey+fz) -(gx+hy+iz) 1 |
607//
608// where {a,b,c} = x-axis
609// {d,e,f} = y-axis
610// {g,h,i} = z-axis
611// {x,y,z} = origin
612
613void LLCoordFrame::getOpenGLTranslation(F32 *ogl_matrix) const
614{
615 *(ogl_matrix + 0) = 1.0f;
616 *(ogl_matrix + 1) = 0.0f;
617 *(ogl_matrix + 2) = 0.0f;
618 *(ogl_matrix + 3) = 0.0f;
619
620 *(ogl_matrix + 4) = 0.0f;
621 *(ogl_matrix + 5) = 1.0f;
622 *(ogl_matrix + 6) = 0.0f;
623 *(ogl_matrix + 7) = 0.0f;
624
625 *(ogl_matrix + 8) = 0.0f;
626 *(ogl_matrix + 9) = 0.0f;
627 *(ogl_matrix + 10) = 1.0f;
628 *(ogl_matrix + 11) = 0.0f;
629
630 *(ogl_matrix + 12) = -mOrigin.mV[VX];
631 *(ogl_matrix + 13) = -mOrigin.mV[VY];
632 *(ogl_matrix + 14) = -mOrigin.mV[VZ];
633 *(ogl_matrix + 15) = 1.0f;
634}
635
636
637void LLCoordFrame::getOpenGLRotation(F32 *ogl_matrix) const
638{
639 *(ogl_matrix + 0) = mXAxis.mV[VX];
640 *(ogl_matrix + 4) = mXAxis.mV[VY];
641 *(ogl_matrix + 8) = mXAxis.mV[VZ];
642
643 *(ogl_matrix + 1) = mYAxis.mV[VX];
644 *(ogl_matrix + 5) = mYAxis.mV[VY];
645 *(ogl_matrix + 9) = mYAxis.mV[VZ];
646
647 *(ogl_matrix + 2) = mZAxis.mV[VX];
648 *(ogl_matrix + 6) = mZAxis.mV[VY];
649 *(ogl_matrix + 10) = mZAxis.mV[VZ];
650
651 *(ogl_matrix + 3) = 0.0f;
652 *(ogl_matrix + 7) = 0.0f;
653 *(ogl_matrix + 11) = 0.0f;
654
655 *(ogl_matrix + 12) = 0.0f;
656 *(ogl_matrix + 13) = 0.0f;
657 *(ogl_matrix + 14) = 0.0f;
658 *(ogl_matrix + 15) = 1.0f;
659}
660
661
662void LLCoordFrame::getOpenGLTransform(F32 *ogl_matrix) const
663{
664 *(ogl_matrix + 0) = mXAxis.mV[VX];
665 *(ogl_matrix + 4) = mXAxis.mV[VY];
666 *(ogl_matrix + 8) = mXAxis.mV[VZ];
667 *(ogl_matrix + 12) = -mOrigin * mXAxis;
668
669 *(ogl_matrix + 1) = mYAxis.mV[VX];
670 *(ogl_matrix + 5) = mYAxis.mV[VY];
671 *(ogl_matrix + 9) = mYAxis.mV[VZ];
672 *(ogl_matrix + 13) = -mOrigin * mYAxis;
673
674 *(ogl_matrix + 2) = mZAxis.mV[VX];
675 *(ogl_matrix + 6) = mZAxis.mV[VY];
676 *(ogl_matrix + 10) = mZAxis.mV[VZ];
677 *(ogl_matrix + 14) = -mOrigin * mZAxis;
678
679 *(ogl_matrix + 3) = 0.0f;
680 *(ogl_matrix + 7) = 0.0f;
681 *(ogl_matrix + 11) = 0.0f;
682 *(ogl_matrix + 15) = 1.0f;
683}
684
685
686// at and up_direction are presumed to be normalized
687void LLCoordFrame::lookDir(const LLVector3 &at, const LLVector3 &up_direction)
688{
689 // Make sure 'at' and 'up_direction' are not parallel
690 // and that neither are zero-length vectors
691 LLVector3 left(up_direction % at);
692 if (left.isNull())
693 {
694 //tweak lookat pos so we don't get a degenerate matrix
695 LLVector3 tempat(at[VX] + 0.01f, at[VY], at[VZ]);
696 tempat.normVec();
697 left = (up_direction % tempat);
698 }
699 left.normVec();
700
701 LLVector3 up = at % left;
702 setAxes(at, left, up);
703}
704
705void LLCoordFrame::lookDir(const LLVector3 &xuv)
706{
707 static LLVector3 up_direction(0.0f, 0.0f, 1.0f);
708 lookDir(xuv, up_direction);
709}
710
711void LLCoordFrame::lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest, const LLVector3 &up_direction)
712{
713 setOrigin(origin);
714 LLVector3 at(point_of_interest - origin);
715 at.normVec();
716 lookDir(at, up_direction);
717}
718
719void LLCoordFrame::lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest)
720{
721 static LLVector3 up_direction(0.0f, 0.0f, 1.0f);
722
723 setOrigin(origin);
724 LLVector3 at(point_of_interest - origin);
725 at.normVec();
726 lookDir(at, up_direction);
727}
728
729
730// Operators and friends
731
732std::ostream& operator<<(std::ostream &s, const LLCoordFrame &C)
733{
734 s << "{ "
735 << " origin = " << C.mOrigin
736 << " x_axis = " << C.mXAxis
737 << " y_axis = " << C.mYAxis
738 << " z_axis = " << C.mZAxis
739 << " }";
740 return s;
741}
742
743
744
745// Private member functions
746
747
748//EOF
diff --git a/linden/indra/llmath/llcoordframe.h b/linden/indra/llmath/llcoordframe.h
new file mode 100644
index 0000000..d15f3e5
--- /dev/null
+++ b/linden/indra/llmath/llcoordframe.h
@@ -0,0 +1,175 @@
1/**
2 * @file llcoordframe.h
3 * @brief LLCoordFrame class header file.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_COORDFRAME_H
29#define LL_COORDFRAME_H
30
31#include "v3math.h"
32#include "v4math.h"
33#include "llerror.h"
34
35// XXX : The constructors of the LLCoordFrame class assume that all vectors
36// and quaternion being passed as arguments are normalized, and all matrix
37// arguments are unitary. VERY BAD things will happen if these assumptions fail.
38// Also, segfault hazzards exist in methods that accept F32* arguments.
39
40
41class LLCoordFrame
42{
43public:
44 LLCoordFrame(); // Inits at zero with identity rotation
45 explicit LLCoordFrame(const LLVector3 &origin); // Sets origin, and inits rotation = Identity
46 LLCoordFrame(const LLVector3 &x_axis,
47 const LLVector3 &y_axis,
48 const LLVector3 &z_axis); // Sets coordinate axes and inits origin at zero
49 LLCoordFrame(const LLVector3 &origin,
50 const LLVector3 &x_axis,
51 const LLVector3 &y_axis,
52 const LLVector3 &z_axis); // Sets the origin and coordinate axes
53 LLCoordFrame(const LLVector3 &origin,
54 const LLMatrix3 &rotation); // Sets axes to 3x3 matrix
55 LLCoordFrame(const LLVector3 &origin,
56 const LLVector3 &direction); // Sets origin and calls lookDir(direction)
57 explicit LLCoordFrame(const LLQuaternion &q); // Sets axes using q and inits mOrigin to zero
58 LLCoordFrame(const LLVector3 &origin,
59 const LLQuaternion &q); // Uses quaternion to init axes
60 explicit LLCoordFrame(const LLMatrix4 &mat); // Extracts frame from a 4x4 matrix
61 // The folowing two constructors are dangerous due to implicit casting and have been disabled - SJB
62 //LLCoordFrame(const F32 *origin, const F32 *rotation); // Assumes "origin" is 1x3 and "rotation" is 1x9 array
63 //LLCoordFrame(const F32 *origin_and_rotation); // Assumes "origin_and_rotation" is 1x12 array
64
65 BOOL isFinite() { return mOrigin.isFinite() && mXAxis.isFinite() && mYAxis.isFinite() && mZAxis.isFinite(); }
66
67 void reset();
68 void resetAxes();
69
70 void setOrigin(F32 x, F32 y, F32 z); // Set mOrigin
71 void setOrigin(const LLVector3 &origin);
72 void setOrigin(const F32 *origin);
73 void setOrigin(const LLCoordFrame &frame);
74
75 inline void setOriginX(F32 x) { mOrigin.mV[VX] = x; }
76 inline void setOriginY(F32 y) { mOrigin.mV[VY] = y; }
77 inline void setOriginZ(F32 z) { mOrigin.mV[VZ] = z; }
78
79 void setAxes(const LLVector3 &x_axis, // Set axes
80 const LLVector3 &y_axis,
81 const LLVector3 &z_axis);
82 void setAxes(const LLMatrix3 &rotation_matrix);
83 void setAxes(const LLQuaternion &q);
84 void setAxes(const F32 *rotation_matrix);
85 void setAxes(const LLCoordFrame &frame);
86
87 void translate(F32 x, F32 y, F32 z); // Move mOrgin
88 void translate(const LLVector3 &v);
89 void translate(const F32 *origin);
90
91 void rotate(F32 angle, F32 x, F32 y, F32 z); // Move axes
92 void rotate(F32 angle, const LLVector3 &rotation_axis);
93 void rotate(const LLQuaternion &q);
94 void rotate(const LLMatrix3 &m);
95
96 void orthonormalize(); // Makes sure axes are unitary and orthogonal.
97
98 // These methods allow rotations in the LLCoordFrame's frame
99 void roll(F32 angle); // RH rotation about mXAxis, radians
100 void pitch(F32 angle); // RH rotation about mYAxis, radians
101 void yaw(F32 angle); // RH rotation about mZAxis, radians
102
103 inline const LLVector3 &getOrigin() const { return mOrigin; }
104
105 inline const LLVector3 &getXAxis() const { return mXAxis; }
106 inline const LLVector3 &getYAxis() const { return mYAxis; }
107 inline const LLVector3 &getZAxis() const { return mZAxis; }
108
109 inline const LLVector3 &getAtAxis() const { return mXAxis; }
110 inline const LLVector3 &getLeftAxis() const { return mYAxis; }
111 inline const LLVector3 &getUpAxis() const { return mZAxis; }
112
113 // These return representations of the rotation or orientation of the LLFrame
114 // it its absolute frame. That is, these rotations acting on the X-axis {1,0,0}
115 // will produce the mXAxis.
116 // LLMatrix3 getMatrix3() const; // Returns axes in 3x3 matrix
117 LLQuaternion getQuaternion() const; // Returns axes in quaternion form
118
119 // Same as above, except it also includes the translation of the LLFrame
120 // LLMatrix4 getMatrix4() const; // Returns position and axes in 4x4 matrix
121
122 // Returns matrix which expresses point in local frame in the parent frame
123 void getMatrixToParent(LLMatrix4 &mat) const;
124 // Returns matrix which expresses point in parent frame in the local frame
125 void getMatrixToLocal(LLMatrix4 &mat) const; // Returns matrix which expresses point in parent frame in the local frame
126
127 void getRotMatrixToParent(LLMatrix4 &mat) const;
128
129 // Copies mOrigin, then the three axes to buffer, returns number of bytes copied.
130 size_t writeOrientation(char *buffer) const;
131
132 // Copies mOrigin, then the three axes from buffer, returns the number of bytes copied.
133 // Assumes the data in buffer is correct.
134 size_t readOrientation(const char *buffer);
135
136 LLVector3 rotateToLocal(const LLVector3 &v) const; // Returns v' rotated to local
137 LLVector4 rotateToLocal(const LLVector4 &v) const; // Returns v' rotated to local
138 LLVector3 rotateToAbsolute(const LLVector3 &v) const; // Returns v' rotated to absolute
139 LLVector4 rotateToAbsolute(const LLVector4 &v) const; // Returns v' rotated to absolute
140
141 LLVector3 transformToLocal(const LLVector3 &v) const; // Returns v' in local coord
142 LLVector4 transformToLocal(const LLVector4 &v) const; // Returns v' in local coord
143 LLVector3 transformToAbsolute(const LLVector3 &v) const; // Returns v' in absolute coord
144 LLVector4 transformToAbsolute(const LLVector4 &v) const; // Returns v' in absolute coord
145
146 // Write coord frame orientation into provided array in OpenGL matrix format.
147 void getOpenGLTranslation(F32 *ogl_matrix) const;
148 void getOpenGLRotation(F32 *ogl_matrix) const;
149 void getOpenGLTransform(F32 *ogl_matrix) const;
150
151 // lookDir orients to (xuv, presumed normalized) and does not affect origin
152 void lookDir(const LLVector3 &xuv, const LLVector3 &up);
153 void lookDir(const LLVector3 &xuv); // up = 0,0,1
154 // lookAt orients to (point_of_interest - origin) and sets origin
155 void lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest, const LLVector3 &up);
156 void lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest); // up = 0,0,1
157
158 // deprecated
159 void setOriginAndLookAt(const LLVector3 &origin, const LLVector3 &up, const LLVector3 &point_of_interest)
160 {
161 lookAt(origin, point_of_interest, up);
162 }
163
164 friend std::ostream& operator<<(std::ostream &s, const LLCoordFrame &C);
165
166 // These vectors are in absolute frame
167 LLVector3 mOrigin;
168 LLVector3 mXAxis;
169 LLVector3 mYAxis;
170 LLVector3 mZAxis;
171};
172
173
174#endif
175
diff --git a/linden/indra/llmath/llcrc.cpp b/linden/indra/llmath/llcrc.cpp
new file mode 100644
index 0000000..4194432
--- /dev/null
+++ b/linden/indra/llmath/llcrc.cpp
@@ -0,0 +1,206 @@
1/**
2 * @file llcrc.cpp
3 * @brief implementation of the crc class.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llcrc.h"
31#include "llerror.h"
32
33#include <stdio.h>
34
35/* Copyright (C) 1986 Gary S. Brown. You may use this program, or
36 code or tables extracted from it, as desired without restriction.*/
37
38/* First, the polynomial itself and its table of feedback terms. The */
39/* polynomial is */
40/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
41/* Note that we take it "backwards" and put the highest-order term in */
42/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
43/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
44/* the MSB being 1. */
45
46/* Note that the usual hardware shift register implementation, which */
47/* is what we're using (we're merely optimizing it by doing eight-bit */
48/* chunks at a time) shifts bits into the lowest-order term. In our */
49/* implementation, that means shifting towards the right. Why do we */
50/* do it this way? Because the calculated CRC must be transmitted in */
51/* order from highest-order term to lowest-order term. UARTs transmit */
52/* characters in order from LSB to MSB. By storing the CRC this way, */
53/* we hand it to the UART in the order low-byte to high-byte; the UART */
54/* sends each low-bit to hight-bit; and the result is transmission bit */
55/* by bit from highest- to lowest-order term without requiring any bit */
56/* shuffling on our part. Reception works similarly. */
57
58/* The feedback terms table consists of 256, 32-bit entries. Notes: */
59/* */
60/* 1. The table can be generated at runtime if desired; code to do so */
61/* is shown later. It might not be obvious, but the feedback */
62/* terms simply represent the results of eight shift/xor opera- */
63/* tions for all combinations of data and CRC register values. */
64/* */
65/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
66/* be they sixteen or thirty-two bits wide. You simply choose the */
67/* appropriate table. Alternatively, because the table can be */
68/* generated at runtime, you can start by generating the table for */
69/* the polynomial in question and use exactly the same "updcrc", */
70/* if your application needn't simultaneously handle two CRC */
71/* polynomials. (Note, however, that XMODEM is strange.) */
72/* */
73/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
74/* of course, 32-bit entries work OK if the high 16 bits are zero. */
75/* */
76/* 4. The values must be right-shifted by eight bits by the "updcrc" */
77/* logic; the shift must be unsigned (bring in zeroes). On some */
78/* hardware you could probably optimize the shift in assembler by */
79/* using byte-swap instructions. */
80
81///----------------------------------------------------------------------------
82/// Local function declarations, constants, enums, and typedefs
83///----------------------------------------------------------------------------
84
85#define UPDC32(octet,crc) (crc_32_tab[((crc) \
86 ^ ((U8)octet)) & 0xff] ^ ((crc) >> 8))
87
88
89static U32 crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
900x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
910xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
920x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
930xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
940x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
950xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
960x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
970xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
980x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
990xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1000x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
1010x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1020x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
1030x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1040x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1050x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1060x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
1070xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1080x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
1090xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1100x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
1110xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1120xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
1130x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1140xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1150x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1160xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
1170x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1180xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
1190x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1200xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
1210x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1220x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
1230x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1240x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1250x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1260x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
1270x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1280xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
1290x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1300xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
1310x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1320xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
133};
134
135
136///----------------------------------------------------------------------------
137/// Class llcrc
138///----------------------------------------------------------------------------
139
140// Default constructor
141LLCRC::LLCRC() : mCurrent(0xffffffff)
142{
143}
144
145
146U32 LLCRC::getCRC() const
147{
148 return ~mCurrent;
149}
150
151void LLCRC::update(U8 next_byte)
152{
153 mCurrent = UPDC32(next_byte, mCurrent);
154}
155
156void LLCRC::update(const U8* buffer, U32 buffer_size)
157{
158 for ( ; buffer_size; --buffer_size, ++buffer)
159 {
160 mCurrent = UPDC32(*buffer, mCurrent);
161 }
162}
163
164void LLCRC::update(const char *filename)
165{
166 FILE *fp = LLFile::fopen(filename, "rb");
167
168 if (fp)
169 {
170 fseek(fp, 0, SEEK_END);
171 U32 size = ftell(fp);
172
173 fseek(fp, 0, SEEK_SET);
174
175 U8 *data = new U8[size];
176 fread(data, size, 1, fp);
177 fclose(fp);
178
179 update(data, size);
180 delete[] data;
181 }
182}
183
184
185#ifdef _DEBUG
186BOOL LLCRC::testHarness()
187{
188 const S32 TEST_BUFFER_SIZE = 16;
189 const char TEST_BUFFER[TEST_BUFFER_SIZE] = "hello &#$)$&Nd0";
190 LLCRC c1, c2;
191 c1.update((U8*)TEST_BUFFER, TEST_BUFFER_SIZE - 1);
192 char* rh = (char*)TEST_BUFFER;
193 while(*rh != '\0')
194 {
195 c2.update(*rh);
196 ++rh;
197 }
198 return(c1.getCRC() == c2.getCRC());
199}
200#endif
201
202
203
204///----------------------------------------------------------------------------
205/// Local function definitions
206///----------------------------------------------------------------------------
diff --git a/linden/indra/llmath/llcrc.h b/linden/indra/llmath/llcrc.h
new file mode 100644
index 0000000..7c267d6
--- /dev/null
+++ b/linden/indra/llmath/llcrc.h
@@ -0,0 +1,69 @@
1/**
2 * @file llcrc.h
3 * @brief LLCRC class header file.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLCRC_H
29#define LL_LLCRC_H
30
31//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32// Class llcrc
33//
34// Simple 32 bit crc. To use, instantiate an LLCRC instance and feed
35// it the bytes you want to check. It will update the internal crc as
36// you go, and you can qery it at the end. As a horribly inefficient
37// example (don't try this at work kids):
38//
39// LLCRC crc;
40// FILE* fp = LLFile::fopen(filename,"rb");
41// while(!feof(fp)) {
42// crc.update(fgetc(fp));
43// }
44// fclose(fp);
45// llinfos << "File crc: " << crc.getCRC() << llendl;
46//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47
48class LLCRC
49{
50protected:
51 U32 mCurrent;
52
53public:
54 LLCRC();
55
56 U32 getCRC() const;
57 void update(U8 next_byte);
58 void update(const U8* buffer, U32 buffer_size);
59 void update(const char *filename);
60
61#ifdef _DEBUG
62 // This function runs tests to make sure the crc is
63 // working. Returns TRUE if it is.
64 static BOOL testHarness();
65#endif
66};
67
68
69#endif // LL_LLCRC_H
diff --git a/linden/indra/llmath/llinterp.h b/linden/indra/llmath/llinterp.h
new file mode 100644
index 0000000..3cc0b18
--- /dev/null
+++ b/linden/indra/llmath/llinterp.h
@@ -0,0 +1,419 @@
1/**
2 * @file llinterp.h
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_LLINTERP_H
28#define LL_LLINTERP_H
29
30#include "math.h"
31
32// Class from which different types of interpolators can be derived
33
34class LLInterpVal
35{
36public:
37 virtual ~LLInterpVal() {}
38 virtual void interp(LLInterpVal &target, const F32 frac); // Linear interpolation for each type
39};
40
41template <typename Type>
42class LLInterp
43{
44public:
45 LLInterp();
46 virtual ~LLInterp() {}
47
48 virtual void start();
49 void update(const F32 time);
50 const Type &getCurVal() const;
51
52 void setStartVal(const Type &start_val);
53 const Type &getStartVal() const;
54
55 void setEndVal(const Type &target_val);
56 const Type &getEndVal() const;
57
58 void setStartTime(const F32 time);
59 F32 getStartTime() const;
60
61 void setEndTime(const F32 time);
62 F32 getEndTime() const;
63
64 BOOL isActive() const;
65 BOOL isDone() const;
66
67protected:
68 F32 mStartTime;
69 F32 mEndTime;
70 F32 mDuration;
71 BOOL mActive;
72 BOOL mDone;
73
74 Type mStartVal;
75 Type mEndVal;
76
77 F32 mCurTime;
78 Type mCurVal;
79};
80
81template <typename Type>
82class LLInterpLinear : public LLInterp<Type>
83{
84public:
85 /*virtual*/ void start();
86 void update(const F32 time);
87 F32 getCurFrac() const;
88protected:
89 F32 mCurFrac;
90};
91
92template <typename Type>
93class LLInterpExp : public LLInterpLinear<Type>
94{
95public:
96 void update(const F32 time);
97protected:
98};
99
100template <typename Type>
101class LLInterpAttractor : public LLInterp<Type>
102{
103public:
104 LLInterpAttractor();
105 /*virtual*/ void start();
106 void setStartVel(const Type &vel);
107 void setForce(const F32 force);
108 void update(const F32 time);
109protected:
110 F32 mForce;
111 Type mStartVel;
112 Type mVelocity;
113};
114
115template <typename Type>
116class LLInterpFunc : public LLInterp<Type>
117{
118public:
119 LLInterpFunc();
120 void update(const F32 time);
121
122 void setFunc(Type (*)(const F32, void *data), void *data);
123protected:
124 Type (*mFunc)(const F32 time, void *data);
125 void *mData;
126};
127
128
129///////////////////////////////////
130//
131// Implementation
132//
133//
134
135/////////////////////////////////
136//
137// LLInterp base class implementation
138//
139
140template <typename Type>
141LLInterp<Type>::LLInterp()
142{
143 mStartTime = 0.f;
144 mEndTime = 1.f;
145 mDuration = 1.f;
146 mCurTime = 0.f;
147 mDone = FALSE;
148 mActive = FALSE;
149}
150
151template <class Type>
152void LLInterp<Type>::setStartVal(const Type &start_val)
153{
154 mStartVal = start_val;
155}
156
157template <class Type>
158void LLInterp<Type>::start()
159{
160 mCurVal = mStartVal;
161 mCurTime = mStartTime;
162 mDone = FALSE;
163 mActive = FALSE;
164}
165
166template <class Type>
167const Type &LLInterp<Type>::getStartVal() const
168{
169 return mStartVal;
170}
171
172template <class Type>
173void LLInterp<Type>::setEndVal(const Type &end_val)
174{
175 mEndVal = end_val;
176}
177
178template <class Type>
179const Type &LLInterp<Type>::getEndVal() const
180{
181 return mEndVal;
182}
183
184template <class Type>
185const Type &LLInterp<Type>::getCurVal() const
186{
187 return mCurVal;
188}
189
190
191template <class Type>
192void LLInterp<Type>::setStartTime(const F32 start_time)
193{
194 mStartTime = start_time;
195 mDuration = mEndTime - mStartTime;
196}
197
198template <class Type>
199F32 LLInterp<Type>::getStartTime() const
200{
201 return mStartTime;
202}
203
204
205template <class Type>
206void LLInterp<Type>::setEndTime(const F32 end_time)
207{
208 mEndTime = end_time;
209 mDuration = mEndTime - mStartTime;
210}
211
212
213template <class Type>
214F32 LLInterp<Type>::getEndTime() const
215{
216 return mEndTime;
217}
218
219
220template <class Type>
221BOOL LLInterp<Type>::isDone() const
222{
223 return mDone;
224}
225
226template <class Type>
227BOOL LLInterp<Type>::isActive() const
228{
229 return mActive;
230}
231
232//////////////////////////////
233//
234// LLInterpLinear derived class implementation.
235//
236template <typename Type>
237void LLInterpLinear<Type>::start()
238{
239 LLInterp<Type>::start();
240 mCurFrac = 0.f;
241}
242
243template <typename Type>
244void LLInterpLinear<Type>::update(const F32 time)
245{
246 F32 target_frac = (time - this->mStartTime) / this->mDuration;
247 F32 dfrac = target_frac - this->mCurFrac;
248 if (target_frac >= 0.f)
249 {
250 this->mActive = TRUE;
251 }
252
253 if (target_frac > 1.f)
254 {
255 this->mCurVal = this->mEndVal;
256 this->mCurFrac = 1.f;
257 this->mCurTime = time;
258 this->mDone = TRUE;
259 return;
260 }
261
262 target_frac = llmin(1.f, target_frac);
263 target_frac = llmax(0.f, target_frac);
264
265 if (dfrac >= 0.f)
266 {
267 F32 total_frac = 1.f - this->mCurFrac;
268 F32 inc_frac = dfrac / total_frac;
269 this->mCurVal = inc_frac * this->mEndVal + (1.f - inc_frac) * this->mCurVal;
270 this->mCurTime = time;
271 }
272 else
273 {
274 F32 total_frac = this->mCurFrac - 1.f;
275 F32 inc_frac = dfrac / total_frac;
276 this->mCurVal = inc_frac * this->mStartVal + (1.f - inc_frac) * this->mCurVal;
277 this->mCurTime = time;
278 }
279 mCurFrac = target_frac;
280}
281
282template <class Type>
283F32 LLInterpLinear<Type>::getCurFrac() const
284{
285 return mCurFrac;
286}
287
288
289//////////////////////////////
290//
291// LLInterpAttractor derived class implementation.
292//
293
294
295template <class Type>
296LLInterpAttractor<Type>::LLInterpAttractor() : LLInterp<Type>()
297{
298 mForce = 0.1f;
299 mVelocity *= 0.f;
300 mStartVel *= 0.f;
301}
302
303template <class Type>
304void LLInterpAttractor<Type>::start()
305{
306 LLInterp<Type>::start();
307 mVelocity = mStartVel;
308}
309
310
311template <class Type>
312void LLInterpAttractor<Type>::setStartVel(const Type &vel)
313{
314 mStartVel = vel;
315}
316
317template <class Type>
318void LLInterpAttractor<Type>::setForce(const F32 force)
319{
320 mForce = force;
321}
322
323template <class Type>
324void LLInterpAttractor<Type>::update(const F32 time)
325{
326 if (time > this->mStartTime)
327 {
328 this->mActive = TRUE;
329 }
330 else
331 {
332 return;
333 }
334 if (time > this->mEndTime)
335 {
336 this->mDone = TRUE;
337 return;
338 }
339
340 F32 dt = time - this->mCurTime;
341 Type dist_val = this->mEndVal - this->mCurVal;
342 Type dv = 0.5*dt*dt*this->mForce*dist_val;
343 this->mVelocity += dv;
344 this->mCurVal += this->mVelocity * dt;
345 this->mCurTime = time;
346}
347
348
349//////////////////////////////
350//
351// LLInterpFucn derived class implementation.
352//
353
354
355template <class Type>
356LLInterpFunc<Type>::LLInterpFunc() : LLInterp<Type>()
357{
358 mFunc = NULL;
359 mData = NULL;
360}
361
362template <class Type>
363void LLInterpFunc<Type>::setFunc(Type (*func)(const F32, void *data), void *data)
364{
365 mFunc = func;
366 mData = data;
367}
368
369template <class Type>
370void LLInterpFunc<Type>::update(const F32 time)
371{
372 if (time > this->mStartTime)
373 {
374 this->mActive = TRUE;
375 }
376 else
377 {
378 return;
379 }
380 if (time > this->mEndTime)
381 {
382 this->mDone = TRUE;
383 return;
384 }
385
386 this->mCurVal = (*mFunc)(time - this->mStartTime, mData);
387 this->mCurTime = time;
388}
389
390//////////////////////////////
391//
392// LLInterpExp derived class implementation.
393//
394
395template <class Type>
396void LLInterpExp<Type>::update(const F32 time)
397{
398 F32 target_frac = (time - this->mStartTime) / this->mDuration;
399 if (target_frac >= 0.f)
400 {
401 this->mActive = TRUE;
402 }
403
404 if (target_frac > 1.f)
405 {
406 this->mCurVal = this->mEndVal;
407 this->mCurFrac = 1.f;
408 this->mCurTime = time;
409 this->mDone = TRUE;
410 return;
411 }
412
413 this->mCurFrac = 1.f - (F32)(exp(-2.f*target_frac));
414 this->mCurVal = this->mStartVal + this->mCurFrac * (this->mEndVal - this->mStartVal);
415 this->mCurTime = time;
416}
417
418#endif // LL_LLINTERP_H
419
diff --git a/linden/indra/llmath/llmath.h b/linden/indra/llmath/llmath.h
new file mode 100644
index 0000000..7009557
--- /dev/null
+++ b/linden/indra/llmath/llmath.h
@@ -0,0 +1,421 @@
1/**
2 * @file llmath.h
3 * @brief Useful math constants and macros.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LLMATH_H
29#define LLMATH_H
30
31#include <cmath>
32#include <math.h>
33#include <stdlib.h>
34
35#include "lldefs.h"
36
37// work around for Windows & older gcc non-standard function names.
38#if LL_WINDOWS
39#define llisnan(val) _isnan(val)
40#define llfinite(val) _finite(val)
41#elif (LL_LINUX && __GNUC__ <= 2)
42#define llisnan(val) isnan(val)
43#define llfinite(val) isfinite(val)
44#else
45#define llisnan(val) std::isnan(val)
46#define llfinite(val) std::isfinite(val)
47#endif
48
49// Single Precision Floating Point Routines
50#ifndef fsqrtf
51#define fsqrtf(x) ((F32)sqrt((F64)(x)))
52#endif
53#ifndef sqrtf
54#define sqrtf(x) ((F32)sqrt((F64)(x)))
55#endif
56
57#ifndef cosf
58#define cosf(x) ((F32)cos((F64)(x)))
59#endif
60#ifndef sinf
61#define sinf(x) ((F32)sin((F64)(x)))
62#endif
63#ifndef tanf
64#define tanf(x) ((F32)tan((F64)(x)))
65#endif
66#ifndef acosf
67#define acosf(x) ((F32)acos((F64)(x)))
68#endif
69
70#ifndef powf
71#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
72#endif
73
74const F32 GRAVITY = -9.8f;
75
76// mathematical constants
77const F32 F_PI = 3.1415926535897932384626433832795f;
78const F32 F_TWO_PI = 6.283185307179586476925286766559f;
79const F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f;
80const F32 F_SQRT2 = 1.4142135623730950488016887242097f;
81const F32 F_SQRT3 = 1.73205080756888288657986402541f;
82const F32 OO_SQRT2 = 0.7071067811865475244008443621049f;
83const F32 DEG_TO_RAD = 0.017453292519943295769236907684886f;
84const F32 RAD_TO_DEG = 57.295779513082320876798154814105f;
85const F32 F_APPROXIMATELY_ZERO = 0.00001f;
86const F32 F_LN2 = 0.69314718056f;
87const F32 OO_LN2 = 1.4426950408889634073599246810019f;
88
89// BUG: Eliminate in favor of F_APPROXIMATELY_ZERO above?
90const F32 FP_MAG_THRESHOLD = 0.0000001f;
91
92// TODO: Replace with logic like is_approx_equal
93inline BOOL is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); }
94
95inline BOOL is_approx_equal(F32 x, F32 y)
96{
97 const S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02;
98 return (abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT);
99}
100
101inline S32 llabs(const S32 a)
102{
103 return S32(labs(a));
104}
105
106inline F32 llabs(const F32 a)
107{
108 return F32(fabs(a));
109}
110
111inline F64 llabs(const F64 a)
112{
113 return F64(fabs(a));
114}
115
116inline S32 lltrunc( F32 f )
117{
118#if LL_WINDOWS && !defined( __INTEL_COMPILER )
119 // Avoids changing the floating point control word.
120 // Add or subtract 0.5 - epsilon and then round
121 const static U32 zpfp[] = { 0xBEFFFFFF, 0x3EFFFFFF };
122 S32 result;
123 __asm {
124 fld f
125 mov eax, f
126 shr eax, 29
127 and eax, 4
128 fadd dword ptr [zpfp + eax]
129 fistp result
130 }
131 return result;
132#else
133 return (S32)f;
134#endif
135}
136
137inline S32 lltrunc( F64 f )
138{
139 return (S32)f;
140}
141
142inline S32 llfloor( F32 f )
143{
144#if LL_WINDOWS && !defined( __INTEL_COMPILER )
145 // Avoids changing the floating point control word.
146 // Accurate (unlike Stereopsis version) for all values between S32_MIN and S32_MAX and slightly faster than Stereopsis version.
147 // Add -(0.5 - epsilon) and then round
148 const U32 zpfp = 0xBEFFFFFF;
149 S32 result;
150 __asm {
151 fld f
152 fadd dword ptr [zpfp]
153 fistp result
154 }
155 return result;
156#else
157 return (S32)floor(f);
158#endif
159}
160
161
162inline S32 llceil( F32 f )
163{
164 // This could probably be optimized, but this works.
165 return (S32)ceil(f);
166}
167
168
169#ifndef BOGUS_ROUND
170// Use this round. Does an arithmetic round (0.5 always rounds up)
171inline S32 llround(const F32 val)
172{
173 return llfloor(val + 0.5f);
174}
175
176#else // BOGUS_ROUND
177// Old llround implementation - does banker's round (toward nearest even in the case of a 0.5.
178// Not using this because we don't have a consistent implementation on both platforms, use
179// llfloor(val + 0.5f), which is consistent on all platforms.
180inline S32 llround(const F32 val)
181{
182 #if LL_WINDOWS
183 // Note: assumes that the floating point control word is set to rounding mode (the default)
184 S32 ret_val;
185 _asm fld val
186 _asm fistp ret_val;
187 return ret_val;
188 #elif LL_LINUX
189 // Note: assumes that the floating point control word is set
190 // to rounding mode (the default)
191 S32 ret_val;
192 __asm__ __volatile__( "flds %1 \n\t"
193 "fistpl %0 \n\t"
194 : "=m" (ret_val)
195 : "m" (val) );
196 return ret_val;
197 #else
198 return llfloor(val + 0.5f);
199 #endif
200}
201
202// A fast arithmentic round on intel, from Laurent de Soras http://ldesoras.free.fr
203inline int round_int(double x)
204{
205 const float round_to_nearest = 0.5f;
206 int i;
207 __asm
208 {
209 fld x
210 fadd st, st (0)
211 fadd round_to_nearest
212 fistp i
213 sar i, 1
214 }
215 return (i);
216}
217#endif // BOGUS_ROUND
218
219inline F32 llround( F32 val, F32 nearest )
220{
221 return F32(floor(val * (1.0f / nearest) + 0.5f)) * nearest;
222}
223
224inline F64 llround( F64 val, F64 nearest )
225{
226 return F64(floor(val * (1.0 / nearest) + 0.5)) * nearest;
227}
228
229// these provide minimum peak error
230//
231// avg error = -0.013049
232// peak error = -31.4 dB
233// RMS error = -28.1 dB
234
235const F32 FAST_MAG_ALPHA = 0.960433870103f;
236const F32 FAST_MAG_BETA = 0.397824734759f;
237
238// these provide minimum RMS error
239//
240// avg error = 0.000003
241// peak error = -32.6 dB
242// RMS error = -25.7 dB
243//
244//const F32 FAST_MAG_ALPHA = 0.948059448969f;
245//const F32 FAST_MAG_BETA = 0.392699081699f;
246
247inline F32 fastMagnitude(F32 a, F32 b)
248{
249 a = (a > 0) ? a : -a;
250 b = (b > 0) ? b : -b;
251 return(FAST_MAG_ALPHA * llmax(a,b) + FAST_MAG_BETA * llmin(a,b));
252}
253
254
255
256////////////////////
257//
258// Fast F32/S32 conversions
259//
260// Culled from www.stereopsis.com/FPU.html
261
262const F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor
263const S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point representation,
264
265// Endian dependent code
266#ifdef LL_LITTLE_ENDIAN
267 #define LL_EXP_INDEX 1
268 #define LL_MAN_INDEX 0
269#else
270 #define LL_EXP_INDEX 0
271 #define LL_MAN_INDEX 1
272#endif
273
274/* Deprecated: use llround(), lltrunc(), or llfloor() instead
275// ================================================================================================
276// Real2Int
277// ================================================================================================
278inline S32 F64toS32(F64 val)
279{
280 val = val + LL_DOUBLE_TO_FIX_MAGIC;
281 return ((S32*)&val)[LL_MAN_INDEX] >> LL_SHIFT_AMOUNT;
282}
283
284// ================================================================================================
285// Real2Int
286// ================================================================================================
287inline S32 F32toS32(F32 val)
288{
289 return F64toS32 ((F64)val);
290}
291*/
292
293////////////////////////////////////////////////
294//
295// Fast exp and log
296//
297
298// Implementation of fast exp() approximation (from a paper by Nicol N. Schraudolph
299// http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
300static union
301{
302 double d;
303 struct
304 {
305#ifdef LL_LITTLE_ENDIAN
306 S32 j, i;
307#else
308 S32 i, j;
309#endif
310 } n;
311} LLECO; // not sure what the name means
312
313#define LL_EXP_A (1048576 * OO_LN2) // use 1512775 for integer
314#define LL_EXP_C (60801) // this value of C good for -4 < y < 4
315
316#define LL_FAST_EXP(y) (LLECO.n.i = llround(F32(LL_EXP_A*(y))) + (1072693248 - LL_EXP_C), LLECO.d)
317
318
319
320inline F32 llfastpow(const F32 x, const F32 y)
321{
322 return (F32)(LL_FAST_EXP(y * log(x)));
323}
324
325
326inline F32 snap_to_sig_figs(F32 foo, S32 sig_figs)
327{
328 // compute the power of ten
329 F32 bar = 1.f;
330 for (S32 i = 0; i < sig_figs; i++)
331 {
332 bar *= 10.f;
333 }
334
335 foo = (F32)llround(foo * bar);
336
337 // shift back
338 foo /= bar;
339 return foo;
340}
341
342inline F32 lerp(F32 a, F32 b, F32 u)
343{
344 return a + ((b - a) * u);
345}
346
347inline F32 lerp2d(F32 x00, F32 x01, F32 x10, F32 x11, F32 u, F32 v)
348{
349 F32 a = x00 + (x01-x00)*u;
350 F32 b = x10 + (x11-x10)*u;
351 F32 r = a + (b-a)*v;
352 return r;
353}
354
355inline F32 ramp(F32 x, F32 a, F32 b)
356{
357 return (a == b) ? 0.0f : ((a - x) / (a - b));
358}
359
360inline F32 rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2)
361{
362 return lerp(y1, y2, ramp(x, x1, x2));
363}
364
365inline F32 clamp_rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2)
366{
367 if (y1 < y2)
368 {
369 return llclamp(rescale(x,x1,x2,y1,y2),y1,y2);
370 }
371 else
372 {
373 return llclamp(rescale(x,x1,x2,y1,y2),y2,y1);
374 }
375}
376
377
378inline F32 cubic_step( F32 x, F32 x0, F32 x1, F32 s0, F32 s1 )
379{
380 if (x <= x0)
381 return s0;
382
383 if (x >= x1)
384 return s1;
385
386 F32 f = (x - x0) / (x1 - x0);
387
388 return s0 + (s1 - s0) * (f * f) * (3.0f - 2.0f * f);
389}
390
391inline F32 cubic_step( F32 x )
392{
393 x = llclampf(x);
394
395 return (x * x) * (3.0f - 2.0f * x);
396}
397
398inline F32 quadratic_step( F32 x, F32 x0, F32 x1, F32 s0, F32 s1 )
399{
400 if (x <= x0)
401 return s0;
402
403 if (x >= x1)
404 return s1;
405
406 F32 f = (x - x0) / (x1 - x0);
407 F32 f_squared = f * f;
408
409 return (s0 * (1.f - f_squared)) + ((s1 - s0) * f_squared);
410}
411
412inline F32 llsimple_angle(F32 angle)
413{
414 while(angle <= -F_PI)
415 angle += F_TWO_PI;
416 while(angle > F_PI)
417 angle -= F_TWO_PI;
418 return angle;
419}
420
421#endif
diff --git a/linden/indra/llmath/llmath.vcproj b/linden/indra/llmath/llmath.vcproj
new file mode 100644
index 0000000..9b6047d
--- /dev/null
+++ b/linden/indra/llmath/llmath.vcproj
@@ -0,0 +1,322 @@
1<?xml version="1.0" encoding="Windows-1252"?>
2<VisualStudioProject
3 ProjectType="Visual C++"
4 Version="7.10"
5 Name="llmath"
6 ProjectGUID="{E87FD9BE-BE42-4EA3-BF4D-D992223046D9}"
7 Keyword="Win32Proj">
8 <Platforms>
9 <Platform
10 Name="Win32"/>
11 </Platforms>
12 <Configurations>
13 <Configuration
14 Name="Debug|Win32"
15 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
16 IntermediateDirectory="$(ConfigurationName)"
17 ConfigurationType="4"
18 CharacterSet="1">
19 <Tool
20 Name="VCCLCompilerTool"
21 Optimization="0"
22 AdditionalIncludeDirectories="..\llcommon;..\..\libraries\i686-win32\include;..\..\libraries\include\"
23 PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;LL_DEBUG"
24 MinimalRebuild="TRUE"
25 BasicRuntimeChecks="3"
26 RuntimeLibrary="1"
27 StructMemberAlignment="4"
28 ForceConformanceInForLoopScope="TRUE"
29 UsePrecompiledHeader="0"
30 WarningLevel="3"
31 WarnAsError="TRUE"
32 Detect64BitPortabilityProblems="FALSE"
33 DebugInformationFormat="4"/>
34 <Tool
35 Name="VCCustomBuildTool"/>
36 <Tool
37 Name="VCLibrarianTool"
38 OutputFile="$(OutDir)/llmath.lib"/>
39 <Tool
40 Name="VCMIDLTool"/>
41 <Tool
42 Name="VCPostBuildEventTool"/>
43 <Tool
44 Name="VCPreBuildEventTool"/>
45 <Tool
46 Name="VCPreLinkEventTool"/>
47 <Tool
48 Name="VCResourceCompilerTool"/>
49 <Tool
50 Name="VCWebServiceProxyGeneratorTool"/>
51 <Tool
52 Name="VCXMLDataGeneratorTool"/>
53 <Tool
54 Name="VCManagedWrapperGeneratorTool"/>
55 <Tool
56 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
57 </Configuration>
58 <Configuration
59 Name="Release|Win32"
60 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
61 IntermediateDirectory="$(ConfigurationName)"
62 ConfigurationType="4"
63 CharacterSet="1">
64 <Tool
65 Name="VCCLCompilerTool"
66 AdditionalIncludeDirectories="..\llcommon;..\..\libraries\i686-win32\include;..\..\libraries\include\"
67 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
68 RuntimeLibrary="0"
69 StructMemberAlignment="0"
70 ForceConformanceInForLoopScope="TRUE"
71 UsePrecompiledHeader="0"
72 WarningLevel="3"
73 WarnAsError="TRUE"
74 Detect64BitPortabilityProblems="FALSE"
75 DebugInformationFormat="3"/>
76 <Tool
77 Name="VCCustomBuildTool"/>
78 <Tool
79 Name="VCLibrarianTool"
80 OutputFile="$(OutDir)/llmath.lib"/>
81 <Tool
82 Name="VCMIDLTool"/>
83 <Tool
84 Name="VCPostBuildEventTool"/>
85 <Tool
86 Name="VCPreBuildEventTool"/>
87 <Tool
88 Name="VCPreLinkEventTool"/>
89 <Tool
90 Name="VCResourceCompilerTool"/>
91 <Tool
92 Name="VCWebServiceProxyGeneratorTool"/>
93 <Tool
94 Name="VCXMLDataGeneratorTool"/>
95 <Tool
96 Name="VCManagedWrapperGeneratorTool"/>
97 <Tool
98 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
99 </Configuration>
100 <Configuration
101 Name="ReleaseNoOpt|Win32"
102 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
103 IntermediateDirectory="$(ConfigurationName)"
104 ConfigurationType="4"
105 CharacterSet="1">
106 <Tool
107 Name="VCCLCompilerTool"
108 Optimization="0"
109 AdditionalIncludeDirectories="..\llcommon;..\..\libraries\i686-win32\include;..\..\libraries\include\"
110 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
111 RuntimeLibrary="0"
112 StructMemberAlignment="0"
113 ForceConformanceInForLoopScope="TRUE"
114 UsePrecompiledHeader="0"
115 BrowseInformation="0"
116 WarningLevel="3"
117 WarnAsError="TRUE"
118 Detect64BitPortabilityProblems="FALSE"
119 DebugInformationFormat="3"/>
120 <Tool
121 Name="VCCustomBuildTool"/>
122 <Tool
123 Name="VCLibrarianTool"
124 OutputFile="$(OutDir)/llmath.lib"/>
125 <Tool
126 Name="VCMIDLTool"/>
127 <Tool
128 Name="VCPostBuildEventTool"/>
129 <Tool
130 Name="VCPreBuildEventTool"/>
131 <Tool
132 Name="VCPreLinkEventTool"/>
133 <Tool
134 Name="VCResourceCompilerTool"/>
135 <Tool
136 Name="VCWebServiceProxyGeneratorTool"/>
137 <Tool
138 Name="VCXMLDataGeneratorTool"/>
139 <Tool
140 Name="VCManagedWrapperGeneratorTool"/>
141 <Tool
142 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
143 </Configuration>
144 </Configurations>
145 <References>
146 </References>
147 <Files>
148 <Filter
149 Name="Source Files"
150 Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
151 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
152 <File
153 RelativePath=".\llbboxlocal.cpp">
154 </File>
155 <File
156 RelativePath=".\llcamera.cpp">
157 </File>
158 <File
159 RelativePath=".\llcoordframe.cpp">
160 </File>
161 <File
162 RelativePath=".\llcrc.cpp">
163 </File>
164 <File
165 RelativePath=".\llmd5.cpp">
166 </File>
167 <File
168 RelativePath=".\llperlin.cpp">
169 </File>
170 <File
171 RelativePath=".\llquaternion.cpp">
172 </File>
173 <File
174 RelativePath=".\llrand.cpp">
175 </File>
176 <File
177 RelativePath=".\llrect.cpp">
178 </File>
179 <File
180 RelativePath=".\lluuid.cpp">
181 </File>
182 <File
183 RelativePath=".\llvolume.cpp">
184 </File>
185 <File
186 RelativePath=".\llvolumemgr.cpp">
187 </File>
188 <File
189 RelativePath=".\m3math.cpp">
190 </File>
191 <File
192 RelativePath=".\m4math.cpp">
193 </File>
194 <File
195 RelativePath=".\raytrace.cpp">
196 </File>
197 <File
198 RelativePath=".\v2math.cpp">
199 </File>
200 <File
201 RelativePath=".\v3color.cpp">
202 </File>
203 <File
204 RelativePath=".\v3dmath.cpp">
205 </File>
206 <File
207 RelativePath=".\v3math.cpp">
208 </File>
209 <File
210 RelativePath=".\v4color.cpp">
211 </File>
212 <File
213 RelativePath=".\v4coloru.cpp">
214 </File>
215 <File
216 RelativePath=".\v4math.cpp">
217 </File>
218 <File
219 RelativePath=".\xform.cpp">
220 </File>
221 </Filter>
222 <Filter
223 Name="Header Files"
224 Filter="h;hpp;hxx;hm;inl;inc;xsd"
225 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
226 <File
227 RelativePath=".\llbboxlocal.h">
228 </File>
229 <File
230 RelativePath=".\llcamera.h">
231 </File>
232 <File
233 RelativePath=".\llcoord.h">
234 </File>
235 <File
236 RelativePath=".\llcoordframe.h">
237 </File>
238 <File
239 RelativePath=".\llcrc.h">
240 </File>
241 <File
242 RelativePath=".\llinterp.h">
243 </File>
244 <File
245 RelativePath=".\llmath.h">
246 </File>
247 <File
248 RelativePath=".\llmd5.h">
249 </File>
250 <File
251 RelativePath=".\lloctree.h">
252 </File>
253 <File
254 RelativePath=".\llperlin.h">
255 </File>
256 <File
257 RelativePath=".\llquantize.h">
258 </File>
259 <File
260 RelativePath=".\llquaternion.h">
261 </File>
262 <File
263 RelativePath=".\llrand.h">
264 </File>
265 <File
266 RelativePath=".\llrect.h">
267 </File>
268 <File
269 RelativePath=".\lltreenode.h">
270 </File>
271 <File
272 RelativePath=".\lluuid.h">
273 </File>
274 <File
275 RelativePath=".\llvolume.h">
276 </File>
277 <File
278 RelativePath=".\llvolumemgr.h">
279 </File>
280 <File
281 RelativePath=".\m3math.h">
282 </File>
283 <File
284 RelativePath=".\m4math.h">
285 </File>
286 <File
287 RelativePath=".\raytrace.h">
288 </File>
289 <File
290 RelativePath=".\v2math.h">
291 </File>
292 <File
293 RelativePath=".\v3color.h">
294 </File>
295 <File
296 RelativePath=".\v3dmath.h">
297 </File>
298 <File
299 RelativePath=".\v3math.h">
300 </File>
301 <File
302 RelativePath=".\v4color.h">
303 </File>
304 <File
305 RelativePath=".\v4coloru.h">
306 </File>
307 <File
308 RelativePath=".\v4math.h">
309 </File>
310 <File
311 RelativePath=".\xform.h">
312 </File>
313 </Filter>
314 <Filter
315 Name="Resource Files"
316 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
317 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
318 </Filter>
319 </Files>
320 <Globals>
321 </Globals>
322</VisualStudioProject>
diff --git a/linden/indra/llmath/llmd5.cpp b/linden/indra/llmath/llmd5.cpp
new file mode 100644
index 0000000..19174af
--- /dev/null
+++ b/linden/indra/llmath/llmd5.cpp
@@ -0,0 +1,574 @@
1/**
2 * @file llmd5.cpp
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27// llMD5.CC - source code for the C++/object oriented translation and
28// modification of MD5.
29//
30// Adapted to Linden Lab by Frank Filipanits, 6/25/2002
31// Fixed potential memory leak, James Cook, 6/27/2002
32
33// Translation and modification (c) 1995 by Mordechai T. Abzug
34
35// This translation/ modification is provided "as is," without express or
36// implied warranty of any kind.
37
38// The translator/ modifier does not claim (1) that MD5 will do what you think
39// it does; (2) that this translation/ modification is accurate; or (3) that
40// this software is "merchantible." (Language for this disclaimer partially
41// copied from the disclaimer below).
42
43/* based on:
44
45 MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
46 MDDRIVER.C - test driver for MD2, MD4 and MD5
47
48
49 Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
50rights reserved.
51
52License to copy and use this software is granted provided that it
53is identified as the "RSA Data Security, Inc. MD5 Message-Digest
54Algorithm" in all material mentioning or referencing this software
55or this function.
56
57License is also granted to make and use derivative works provided
58that such works are identified as "derived from the RSA Data
59Security, Inc. MD5 Message-Digest Algorithm" in all material
60mentioning or referencing the derived work.
61
62RSA Data Security, Inc. makes no representations concerning either
63the merchantability of this software or the suitability of this
64software for any particular purpose. It is provided "as is"
65without express or implied warranty of any kind.
66
67These notices must be retained in any copies of any part of this
68documentation and/or software.
69
70 */
71
72
73
74
75
76#include "linden_common.h"
77
78#include "llmd5.h"
79
80#include <assert.h>
81#include <string.h>
82#include <fstream>
83#include <iostream>
84
85
86// LLMD5 simple initialization method
87
88LLMD5::LLMD5()
89{
90 init();
91}
92
93
94
95
96// MD5 block update operation. Continues an MD5 message-digest
97// operation, processing another message block, and updating the
98// context.
99
100void LLMD5::update (const uint1 *input, const uint4 input_length) {
101
102 uint4 input_index, buffer_index;
103 uint4 buffer_space; // how much space is left in buffer
104
105 if (finalized){ // so we can't update!
106 std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl;
107 return;
108 }
109
110 // Compute number of bytes mod 64
111 buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
112
113 // Update number of bits
114 if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
115 count[1]++;
116
117 count[1] += ((uint4)input_length >> 29);
118
119
120 buffer_space = 64 - buffer_index; // how much space is left in buffer
121
122 // Transform as many times as possible.
123 if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
124 // fill the rest of the buffer and transform
125 memcpy (buffer + buffer_index, input, buffer_space);
126 transform (buffer);
127
128 // now, transform each 64-byte piece of the input, bypassing the buffer
129 for (input_index = buffer_space; input_index + 63 < input_length;
130 input_index += 64)
131 transform (input+input_index);
132
133 buffer_index = 0; // so we can buffer remaining
134 }
135 else
136 input_index=0; // so we can buffer the whole input
137
138
139 // and here we do the buffering:
140 memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
141}
142
143
144
145// MD5 update for files.
146// Like above, except that it works on files (and uses above as a primitive.)
147
148void LLMD5::update(FILE *file){
149
150 unsigned char buffer[1024];
151 int len;
152
153 while ( (len=(int)fread(buffer, 1, 1024, file)) )
154 update(buffer, len);
155
156 fclose (file);
157
158}
159
160
161
162
163
164
165// MD5 update for istreams.
166// Like update for files; see above.
167
168void LLMD5::update(std::istream& stream){
169
170 unsigned char buffer[1024];
171 int len;
172
173 while (stream.good()){
174 stream.read( (char*)buffer, 1024); // note that return value of read is unusable.
175 len=stream.gcount();
176 update(buffer, len);
177 }
178
179}
180
181
182
183
184
185
186// MD5 update for ifstreams.
187// Like update for files; see above.
188
189void LLMD5::update(llifstream& stream){
190
191 unsigned char buffer[1024];
192 int len;
193
194 while (stream.good()){
195 stream.read( (char*)buffer, 1024); // note that return value of read is unusable.
196 len=stream.gcount();
197 update(buffer, len);
198 }
199
200}
201
202
203
204
205
206
207// MD5 finalization. Ends an MD5 message-digest operation, writing the
208// the message digest and zeroizing the context.
209
210
211void LLMD5::finalize (){
212
213 unsigned char bits[8];
214 unsigned int index, padLen;
215 static uint1 PADDING[64]={
216 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
219 };
220
221 if (finalized){
222 std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl;
223 return;
224 }
225
226 // Save number of bits
227 encode (bits, count, 8);
228
229 // Pad out to 56 mod 64.
230 index = (uint4) ((count[0] >> 3) & 0x3f);
231 padLen = (index < 56) ? (56 - index) : (120 - index);
232 update (PADDING, padLen);
233
234 // Append length (before padding)
235 update (bits, 8);
236
237 // Store state in digest
238 encode (digest, state, 16);
239
240 // Zeroize sensitive information
241 memset (buffer, 0, sizeof(*buffer));
242
243 finalized=1;
244
245}
246
247
248
249
250LLMD5::LLMD5(FILE *file){
251
252 init(); // must be called be all constructors
253 update(file);
254 finalize ();
255}
256
257
258
259
260LLMD5::LLMD5(std::istream& stream){
261
262 init(); // must called by all constructors
263 update (stream);
264 finalize();
265}
266
267
268
269LLMD5::LLMD5(llifstream& stream)
270{
271 init(); // must called by all constructors
272 update (stream);
273 finalize();
274}
275
276// Digest a string of the format ("%s:%i" % (s, number))
277LLMD5::LLMD5(const unsigned char *string, const unsigned int number)
278{
279 const char *colon = ":";
280 char tbuf[16];
281 init();
282 update(string, (U32)strlen((const char *) string));
283 update((const unsigned char *) colon, (U32)strlen(colon));
284 sprintf(tbuf, "%i", number);
285 update((const unsigned char *) tbuf, (U32)strlen(tbuf));
286 finalize();
287}
288
289// Digest a string
290LLMD5::LLMD5(const unsigned char *s)
291{
292 init();
293 update(s, (U32)strlen((const char *) s));
294 finalize();
295}
296
297void LLMD5::raw_digest(unsigned char *s)
298{
299 if (!finalized)
300 {
301 std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<<
302 "finalized the digest!" << std::endl;
303 s[0] = '\0';
304 return;
305 }
306
307 memcpy(s, digest, 16);
308 return;
309}
310
311
312
313void LLMD5::hex_digest(char *s)
314{
315 int i;
316
317 if (!finalized)
318 {
319 std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<<
320 "finalized the digest!" <<std::endl;
321 s[0] = '\0';
322 return;
323 }
324
325 for (i=0; i<16; i++)
326 {
327 sprintf(s+i*2, "%02x", digest[i]);
328 }
329
330 s[32]='\0';
331
332 return;
333}
334
335
336
337
338
339std::ostream& operator<<(std::ostream &stream, LLMD5 context)
340{
341 char s[33];
342 context.hex_digest(s);
343 stream << s;
344 return stream;
345}
346
347
348
349
350// PRIVATE METHODS:
351
352
353
354void LLMD5::init(){
355 finalized=0; // we just started!
356
357 // Nothing counted, so count=0
358 count[0] = 0;
359 count[1] = 0;
360
361 // Load magic initialization constants.
362 state[0] = 0x67452301;
363 state[1] = 0xefcdab89;
364 state[2] = 0x98badcfe;
365 state[3] = 0x10325476;
366}
367
368
369
370// Constants for MD5Transform routine.
371// Although we could use C++ style constants, defines are actually better,
372// since they let us easily evade scope clashes.
373
374#define S11 7
375#define S12 12
376#define S13 17
377#define S14 22
378#define S21 5
379#define S22 9
380#define S23 14
381#define S24 20
382#define S31 4
383#define S32 11
384#define S33 16
385#define S34 23
386#define S41 6
387#define S42 10
388#define S43 15
389#define S44 21
390
391
392
393
394// LLMD5 basic transformation. Transforms state based on block.
395void LLMD5::transform (const uint1 block[64]){
396
397 uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
398
399 decode (x, block, 64);
400
401 assert(!finalized); // not just a user error, since the method is private
402
403 /* Round 1 */
404 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
405 FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
406 FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
407 FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
408 FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
409 FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
410 FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
411 FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
412 FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
413 FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
414 FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
415 FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
416 FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
417 FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
418 FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
419 FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
420
421 /* Round 2 */
422 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
423 GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
424 GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
425 GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
426 GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
427 GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
428 GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
429 GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
430 GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
431 GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
432 GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
433 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
434 GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
435 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
436 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
437 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
438
439 /* Round 3 */
440 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
441 HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
442 HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
443 HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
444 HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
445 HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
446 HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
447 HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
448 HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
449 HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
450 HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
451 HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
452 HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
453 HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
454 HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
455 HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
456
457 /* Round 4 */
458 II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
459 II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
460 II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
461 II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
462 II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
463 II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
464 II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
465 II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
466 II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
467 II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
468 II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
469 II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
470 II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
471 II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
472 II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
473 II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
474
475 state[0] += a;
476 state[1] += b;
477 state[2] += c;
478 state[3] += d;
479
480 // Zeroize sensitive information.
481 memset ( (uint1 *) x, 0, sizeof(x));
482
483}
484
485
486
487// Encodes input (UINT4) into output (unsigned char). Assumes len is
488// a multiple of 4.
489void LLMD5::encode (uint1 *output, const uint4 *input, const uint4 len) {
490
491 unsigned int i, j;
492
493 for (i = 0, j = 0; j < len; i++, j += 4) {
494 output[j] = (uint1) (input[i] & 0xff);
495 output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
496 output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
497 output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
498 }
499}
500
501
502
503
504// Decodes input (unsigned char) into output (UINT4). Assumes len is
505// a multiple of 4.
506void LLMD5::decode (uint4 *output, const uint1 *input, const uint4 len){
507
508 unsigned int i, j;
509
510 for (i = 0, j = 0; j < len; i++, j += 4)
511 output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
512 (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
513}
514
515
516
517
518
519// ROTATE_LEFT rotates x left n bits.
520
521inline unsigned int LLMD5::rotate_left (uint4 x, uint4 n){
522 return (x << n) | (x >> (32-n)) ;
523}
524
525
526
527
528// F, G, H and I are basic MD5 functions.
529
530inline unsigned int LLMD5::F (uint4 x, uint4 y, uint4 z){
531 return (x & y) | (~x & z);
532}
533
534inline unsigned int LLMD5::G (uint4 x, uint4 y, uint4 z){
535 return (x & z) | (y & ~z);
536}
537
538inline unsigned int LLMD5::H (uint4 x, uint4 y, uint4 z){
539 return x ^ y ^ z;
540}
541
542inline unsigned int LLMD5::I (uint4 x, uint4 y, uint4 z){
543 return y ^ (x | ~z);
544}
545
546
547
548// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
549// Rotation is separate from addition to prevent recomputation.
550
551
552inline void LLMD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
553 uint4 s, uint4 ac){
554 a += F(b, c, d) + x + ac;
555 a = rotate_left (a, s) +b;
556}
557
558inline void LLMD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
559 uint4 s, uint4 ac){
560 a += G(b, c, d) + x + ac;
561 a = rotate_left (a, s) +b;
562}
563
564inline void LLMD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
565 uint4 s, uint4 ac){
566 a += H(b, c, d) + x + ac;
567 a = rotate_left (a, s) +b;
568}
569
570inline void LLMD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
571 uint4 s, uint4 ac){
572 a += I(b, c, d) + x + ac;
573 a = rotate_left (a, s) +b;
574}
diff --git a/linden/indra/llmath/llmd5.h b/linden/indra/llmath/llmd5.h
new file mode 100644
index 0000000..1874b45
--- /dev/null
+++ b/linden/indra/llmath/llmd5.h
@@ -0,0 +1,145 @@
1/**
2 * @file llmd5.h
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_LLMD5_H
28#define LL_LLMD5_H
29
30// LLMD5.CC - source code for the C++/object oriented translation and
31// modification of MD5.
32
33// Translation and modification (c) 1995 by Mordechai T. Abzug
34
35// This translation/ modification is provided "as is," without express or
36// implied warranty of any kind.
37
38// The translator/ modifier does not claim (1) that MD5 will do what you think
39// it does; (2) that this translation/ modification is accurate; or (3) that
40// this software is "merchantible." (Language for this disclaimer partially
41// copied from the disclaimer below).
42
43/* based on:
44
45 MD5.H - header file for MD5C.C
46 MDDRIVER.C - test driver for MD2, MD4 and MD5
47
48 Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
49rights reserved.
50
51License to copy and use this software is granted provided that it
52is identified as the "RSA Data Security, Inc. MD5 Message-Digest
53Algorithm" in all material mentioning or referencing this software
54or this function.
55
56License is also granted to make and use derivative works provided
57that such works are identified as "derived from the RSA Data
58Security, Inc. MD5 Message-Digest Algorithm" in all material
59mentioning or referencing the derived work.
60
61RSA Data Security, Inc. makes no representations concerning either
62the merchantability of this software or the suitability of this
63software for any particular purpose. It is provided "as is"
64without express or implied warranty of any kind.
65
66These notices must be retained in any copies of any part of this
67documentation and/or software.
68
69*/
70
71#include <stdio.h>
72#include <iosfwd>
73
74// use for the raw digest output
75const int MD5RAW_BYTES = 16;
76
77// use for outputting hex digests
78const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
79const int MD5HEX_STR_BYTES = 32; // message system fixed size
80
81class LLMD5 {
82// first, some types:
83 typedef unsigned int uint4; // assumes integer is 4 words long
84 typedef unsigned short int uint2; // assumes short integer is 2 words long
85 typedef unsigned char uint1; // assumes char is 1 word long
86
87public:
88// methods for controlled operation:
89 LLMD5 (); // simple initializer
90 void update (const uint1 *input, const uint4 input_length);
91 void update (std::istream& stream);
92 void update (FILE *file);
93 void update (llifstream& stream);
94 void finalize ();
95
96// constructors for special circumstances. All these constructors finalize
97// the MD5 context.
98 LLMD5 (const unsigned char *string); // digest string, finalize
99 LLMD5 (std::istream& stream); // digest stream, finalize
100 LLMD5 (FILE *file); // digest file, close, finalize
101 LLMD5 (llifstream& stream); // digest stream, close, finalize
102 LLMD5 (const unsigned char *string, const unsigned int number);
103
104// methods to acquire finalized result
105 void raw_digest(unsigned char *array); // provide 16-byte array for binary data
106 void hex_digest(char *string); // provide 33-byte array for ascii-hex string
107 friend std::ostream& operator<< (std::ostream&, LLMD5 context);
108
109
110
111private:
112
113
114// next, the private data:
115 uint4 state[4];
116 uint4 count[2]; // number of *bits*, mod 2^64
117 uint1 buffer[64]; // input buffer
118 uint1 digest[16];
119 uint1 finalized;
120
121// last, the private methods, mostly static:
122 void init (); // called by all constructors
123 void transform (const uint1 *buffer); // does the real update work. Note
124 // that length is implied to be 64.
125
126 static void encode (uint1 *dest, const uint4 *src, const uint4 length);
127 static void decode (uint4 *dest, const uint1 *src, const uint4 length);
128
129 static inline uint4 rotate_left (uint4 x, uint4 n);
130 static inline uint4 F (uint4 x, uint4 y, uint4 z);
131 static inline uint4 G (uint4 x, uint4 y, uint4 z);
132 static inline uint4 H (uint4 x, uint4 y, uint4 z);
133 static inline uint4 I (uint4 x, uint4 y, uint4 z);
134 static inline void FF (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
135 uint4 s, uint4 ac);
136 static inline void GG (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
137 uint4 s, uint4 ac);
138 static inline void HH (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
139 uint4 s, uint4 ac);
140 static inline void II (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
141 uint4 s, uint4 ac);
142
143};
144
145#endif // LL_LLMD5_H
diff --git a/linden/indra/llmath/lloctree.h b/linden/indra/llmath/lloctree.h
new file mode 100644
index 0000000..6e068cd
--- /dev/null
+++ b/linden/indra/llmath/lloctree.h
@@ -0,0 +1,712 @@
1/**
2 * @file lloctree.h
3 * @brief Octree declaration.
4 *
5 * Copyright (c) 2005-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLOCTREE_H
29#define LL_LLOCTREE_H
30
31#include "lltreenode.h"
32#include "v3math.h"
33#include <vector>
34#include <set>
35
36#ifdef LL_RELEASE_FOR_DOWNLOAD
37#define OCT_ERRS llwarns
38#else
39#define OCT_ERRS llerrs
40#endif
41
42#define LL_OCTREE_PARANOIA_CHECK 0
43
44template <class T> class LLOctreeState;
45template <class T> class LLOctreeNode;
46
47template <class T>
48class LLOctreeListener: public LLTreeListener<T>
49{
50public:
51 typedef LLTreeListener<T> BaseType;
52 typedef LLOctreeNode<T> oct_node;
53
54 virtual ~LLOctreeListener() { };
55 virtual void handleChildAddition(const oct_node* parent, oct_node* child) = 0;
56 virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0;
57};
58
59
60template <class T>
61class LLOctreeNode : public LLTreeNode<T>
62{
63public:
64
65 typedef LLTreeNode<T> BaseType;
66 typedef LLTreeState<T> tree_state;
67 typedef LLOctreeState<T> oct_state;
68 typedef LLOctreeNode<T> oct_node;
69 typedef LLOctreeListener<T> oct_listener;
70
71 static const U8 OCTANT_POSITIVE_X = 0x01;
72 static const U8 OCTANT_POSITIVE_Y = 0x02;
73 static const U8 OCTANT_POSITIVE_Z = 0x04;
74
75 LLOctreeNode( LLVector3d center,
76 LLVector3d size,
77 tree_state* state,
78 BaseType* parent,
79 U8 octant = 255)
80 : BaseType(state),
81 mParent((oct_node*)parent),
82 mCenter(center),
83 mSize(size),
84 mOctant(octant)
85 {
86 updateMinMax();
87 if ((mOctant == 255) && mParent)
88 {
89 mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
90 }
91 }
92
93 virtual ~LLOctreeNode() { BaseType::destroyListeners(); delete this->mState; }
94
95 virtual const BaseType* getParent() const { return mParent; }
96 virtual void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
97 virtual const LLVector3d& getCenter() const { return mCenter; }
98 virtual const LLVector3d& getSize() const { return mSize; }
99 virtual void setCenter(LLVector3d center) { mCenter = center; }
100 virtual void setSize(LLVector3d size) { mSize = size; }
101 virtual bool balance() { return getOctState()->balance(); }
102 virtual void validate() { getOctState()->validate(); }
103 virtual U32 getChildCount() const { return getOctState()->getChildCount(); }
104 virtual oct_node* getChild(U32 index) { return getOctState()->getChild(index); }
105 virtual const oct_node* getChild(U32 index) const { return getOctState()->getChild(index); }
106 virtual U32 getElementCount() const { return getOctState()->getElementCount(); }
107 virtual void removeByAddress(T* data) { getOctState()->removeByAddress(data); }
108 virtual bool hasLeafState() const { return getOctState()->isLeaf(); }
109 virtual void destroy() { getOctState()->destroy(); }
110 virtual oct_node* getNodeAt(T* data) { return getOctState()->getNodeAt(data); }
111 virtual U8 getOctant() const { return mOctant; }
112 virtual void setOctant(U8 octant) { mOctant = octant; }
113 virtual const oct_state* getOctState() const { return (const oct_state*) BaseType::mState; }
114 virtual oct_state* getOctState() { return (oct_state*) BaseType::mState; }
115 virtual const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
116 virtual oct_node* getOctParent() { return (oct_node*) getParent(); }
117 virtual void deleteChild(oct_node* child) { getOctState()->deleteChild(child); }
118
119 virtual U8 getOctant(const F64 pos[]) const //get the octant pos is in
120 {
121 U8 ret = 0;
122
123 if (pos[0] > mCenter.mdV[0])
124 {
125 ret |= OCTANT_POSITIVE_X;
126 }
127 if (pos[1] > mCenter.mdV[1])
128 {
129 ret |= OCTANT_POSITIVE_Y;
130 }
131 if (pos[2] > mCenter.mdV[2])
132 {
133 ret |= OCTANT_POSITIVE_Z;
134 }
135
136 return ret;
137 }
138
139 virtual bool isInside(T* data) const
140 {
141 return data->getBinRadius() <= mSize.mdV[0]*2.0 && isInside(data->getPositionGroup());
142 }
143
144 virtual bool isInside(const LLVector3d& pos) const
145 {
146 const F64& x = pos.mdV[0];
147 const F64& y = pos.mdV[1];
148 const F64& z = pos.mdV[2];
149
150 if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
151 y > mMax.mdV[1] || y <= mMin.mdV[1] ||
152 z > mMax.mdV[2] || z <= mMin.mdV[2])
153 {
154 return false;
155 }
156
157 return true;
158 }
159
160 virtual void updateMinMax()
161 {
162 for (U32 i = 0; i < 3; i++)
163 {
164 mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
165 mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
166 mCenter.mdV[i] = mCenter.mdV[i];
167 }
168 }
169
170 virtual oct_listener* getOctListener(U32 index)
171 {
172 return (oct_listener*) BaseType::getListener(index);
173 }
174
175 bool contains(T* xform)
176 {
177 if (mParent == NULL)
178 { //root node contains nothing
179 return false;
180 }
181
182 F64 size = mSize.mdV[0];
183 F64 p_size = size * 2.0;
184 F64 radius = xform->getBinRadius();
185
186 return (radius <= 0.001 && size <= 0.001) ||
187 (radius <= p_size && radius > size);
188 }
189
190 static void pushCenter(LLVector3d &center, LLVector3d &size, T* data)
191 {
192 LLVector3 pos(data->getPositionGroup());
193 F64 p[] =
194 {
195 (F64) pos.mV[0],
196 (F64) pos.mV[1],
197 (F64) pos.mV[2]
198 };
199
200 for (U32 i = 0; i < 3; i++)
201 {
202 if (p[i] > center.mdV[i])
203 {
204 center.mdV[i] += size.mdV[i];
205 }
206 else
207 {
208 center.mdV[i] -= size.mdV[i];
209 }
210 }
211 }
212
213protected:
214 oct_node* mParent;
215 LLVector3d mCenter;
216 LLVector3d mSize;
217 LLVector3d mMax;
218 LLVector3d mMin;
219 U8 mOctant;
220};
221
222template <class T>
223class LLOctreeTraveler : public LLTreeTraveler<T>
224{
225public:
226 virtual void traverse(const LLTreeNode<T>* node);
227 virtual void visit(const LLTreeState<T>* state) { }
228 virtual void visit(const LLOctreeState<T>* branch) = 0;
229};
230
231//will pass requests to a child, might make a new child
232template <class T>
233class LLOctreeState : public LLTreeState<T>
234{
235public:
236 typedef LLTreeState<T> BaseType;
237 typedef LLOctreeTraveler<T> oct_traveler;
238 typedef LLOctreeNode<T> oct_node;
239 typedef LLOctreeListener<T> oct_listener;
240 typedef LLTreeTraveler<T> tree_traveler;
241 typedef typename std::set<LLPointer<T> > element_list;
242 typedef typename std::set<LLPointer<T> >::iterator element_iter;
243 typedef typename std::set<LLPointer<T> >::const_iterator const_element_iter;
244 typedef typename std::vector<LLTreeListener<T>*>::iterator tree_listener_iter;
245 typedef typename std::vector<LLOctreeNode<T>* > child_list;
246
247 LLOctreeState(oct_node* node = NULL): BaseType(node) { this->clearChildren(); }
248 virtual ~LLOctreeState()
249 {
250 for (U32 i = 0; i < getChildCount(); i++)
251 {
252 delete getChild(i);
253 }
254 }
255
256
257 virtual void accept(oct_traveler* visitor) { visitor->visit(this); }
258 virtual bool isLeaf() const { return mChild.empty(); }
259
260 virtual U32 getElementCount() const { return mData.size(); }
261 virtual element_list& getData() { return mData; }
262 virtual const element_list& getData() const { return mData; }
263
264 virtual U32 getChildCount() const { return mChild.size(); }
265 virtual oct_node* getChild(U32 index) { return mChild[index]; }
266 virtual const oct_node* getChild(U32 index) const { return mChild[index]; }
267 virtual child_list& getChildren() { return mChild; }
268 virtual const child_list& getChildren() const { return mChild; }
269
270 virtual void accept(tree_traveler* visitor) const { visitor->visit(this); }
271 virtual void accept(oct_traveler* visitor) const { visitor->visit(this); }
272 const oct_node* getOctNode() const { return (const oct_node*) BaseType::getNode(); }
273 oct_node* getOctNode() { return (oct_node*) BaseType::getNode(); }
274
275 virtual oct_node* getNodeAt(T* data)
276 {
277 const LLVector3d& pos = data->getPositionGroup();
278 LLOctreeNode<T>* node = getOctNode();
279
280 if (node->isInside(data))
281 {
282 //do a quick search by octant
283 U8 octant = node->getOctant(pos.mdV);
284 BOOL keep_going = TRUE;
285
286 //traverse the tree until we find a node that has no node
287 //at the appropriate octant or is smaller than the object.
288 //by definition, that node is the smallest node that contains
289 // the data
290 while (keep_going && node->getSize().mdV[0] >= data->getBinRadius())
291 {
292 keep_going = FALSE;
293 for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
294 {
295 if (node->getChild(i)->getOctant() == octant)
296 {
297 node = node->getChild(i);
298 octant = node->getOctant(pos.mdV);
299 keep_going = TRUE;
300 }
301 }
302 }
303 }
304 else if (!node->contains(data) && node->getParent())
305 { //if we got here, data does not exist in this node
306 return ((LLOctreeNode<T>*) node->getParent())->getNodeAt(data);
307 }
308
309 return node;
310 }
311
312 virtual bool insert(T* data)
313 {
314 if (data == NULL)
315 {
316 OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
317 return false;
318 }
319 LLOctreeNode<T>* node = getOctNode();
320
321 if (data->getBinRadius() <= node->getSize().mdV[0])
322 {
323 oct_node* dest = getNodeAt(data);
324
325 if (dest != node)
326 {
327 dest->insert(data);
328 return false;
329 }
330 }
331
332 //no kid found, is it even here?
333 if (node->isInside(data))
334 {
335 if (node->contains(data))
336 { //it belongs here
337 if (data == NULL)
338 {
339 OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE LEAF !!!" << llendl;
340 return false;
341 }
342
343#if LL_OCTREE_PARANOIA_CHECK
344 //if this is a redundant insertion, error out (should never happen)
345 if (mData.find(data) != mData.end())
346 {
347 llwarns << "Redundant octree insertion detected. " << data << llendl;
348 return false;
349 }
350#endif
351
352 mData.insert(data);
353 return true;
354 }
355 else
356 {
357 //it's here, but no kids are in the right place, make a new kid
358 LLVector3d center(node->getCenter());
359 LLVector3d size(node->getSize()*0.5);
360
361 //push center in direction of data
362 LLOctreeNode<T>::pushCenter(center, size, data);
363
364#if LL_OCTREE_PARANOIA_CHECK
365 if (getChildCount() == 8)
366 {
367 //this really isn't possible, something bad has happened
368 OCT_ERRS << "Octree detected floating point error and gave up." << llendl;
369 //bool check = node->isInside(data);
370 return false;
371 }
372
373 //make sure no existing node matches this position
374 for (U32 i = 0; i < getChildCount(); i++)
375 {
376 if (mChild[i]->getCenter() == center)
377 {
378 OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
379 //bool check = node->isInside(data);
380 //check = getChild(i)->isInside(data);
381 return false;
382 }
383 }
384#endif
385
386 //make the new kid
387 LLOctreeState<T>* newstate = new LLOctreeState<T>();
388 oct_node* child = new LLOctreeNode<T>(center, size, newstate, node);
389 addChild(child);
390
391 child->insert(data);
392 }
393 }
394 else
395 {
396 //it's not in here, give it to the parent
397 node->getOctParent()->insert(data);
398 }
399
400 return false;
401 }
402
403 virtual bool remove(T* data)
404 {
405 oct_node* node = getOctNode();
406
407 if (mData.find(data) != mData.end())
408 { //we have data
409 mData.erase(data);
410 node->notifyRemoval(data);
411 checkAlive();
412 return true;
413 }
414 else if (node->isInside(data))
415 {
416 oct_node* dest = getNodeAt(data);
417
418 if (dest != node)
419 {
420 return dest->remove(data);
421 }
422 }
423
424 //SHE'S GONE MISSING...
425 //none of the children have it, let's just brute force this bastard out
426 //starting with the root node (UGLY CODE COMETH!)
427 oct_node* parent = node->getOctParent();
428 while (parent != NULL)
429 {
430 node = parent;
431 parent = node->getOctParent();
432 }
433
434 //node is now root
435 llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
436 node->removeByAddress(data);
437 return true;
438 }
439
440 virtual void removeByAddress(T* data)
441 {
442 if (mData.find(data) != mData.end())
443 {
444 mData.erase(data);
445 getOctNode()->notifyRemoval(data);
446 llwarns << "FOUND!" << llendl;
447 checkAlive();
448 return;
449 }
450
451 for (U32 i = 0; i < getChildCount(); i++)
452 { //we don't contain data, so pass this guy down
453 LLOctreeNode<T>* child = (LLOctreeNode<T>*) getChild(i);
454 child->removeByAddress(data);
455 }
456 }
457
458 virtual void clearChildren()
459 {
460 mChild.clear();
461 }
462
463 virtual void validate()
464 {
465#if LL_OCTREE_PARANOIA_CHECK
466 LLOctreeNode<T>* node = this->getOctNode();
467
468 for (U32 i = 0; i < getChildCount(); i++)
469 {
470 mChild[i]->validate();
471 if (mChild[i]->getParent() != node)
472 {
473 llerrs << "Octree child has invalid parent." << llendl;
474 }
475 }
476#endif
477 }
478
479 virtual bool balance()
480 {
481 return false;
482 }
483
484 virtual void destroy()
485 {
486 for (U32 i = 0; i < getChildCount(); i++)
487 {
488 mChild[i]->destroy();
489 delete mChild[i];
490 }
491 }
492
493 virtual void addChild(oct_node* child, BOOL silent = FALSE)
494 {
495#if LL_OCTREE_PARANOIA_CHECK
496 for (U32 i = 0; i < getChildCount(); i++)
497 {
498 if(mChild[i]->getSize() != child->getSize())
499 {
500 OCT_ERRS <<"Invalid octree child size." << llendl;
501 }
502 if (mChild[i]->getCenter() == child->getCenter())
503 {
504 OCT_ERRS <<"Duplicate octree child position." << llendl;
505 }
506 }
507
508 if (mChild.size() >= 8)
509 {
510 OCT_ERRS <<"Octree node has too many children... why?" << llendl;
511 }
512#endif
513
514 mChild.push_back(child);
515 child->setParent(getOctNode());
516
517 if (!silent)
518 {
519 oct_node* node = getOctNode();
520
521 for (U32 i = 0; i < node->getListenerCount(); i++)
522 {
523 oct_listener* listener = node->getOctListener(i);
524 listener->handleChildAddition(node, child);
525 }
526 }
527 }
528
529 virtual void removeChild(U8 index, BOOL destroy = FALSE)
530 {
531 oct_node* node = getOctNode();
532 for (U32 i = 0; i < node->getListenerCount(); i++)
533 {
534 oct_listener* listener = node->getOctListener(i);
535 listener->handleChildRemoval(node, getChild(index));
536 }
537
538 if (destroy)
539 {
540 mChild[index]->destroy();
541 delete mChild[index];
542 }
543 mChild.erase(mChild.begin() + index);
544
545 checkAlive();
546 }
547
548 virtual void checkAlive()
549 {
550 if (getChildCount() == 0 && getElementCount() == 0)
551 {
552 oct_node* node = getOctNode();
553 oct_node* parent = node->getOctParent();
554 if (parent)
555 {
556 parent->deleteChild(node);
557 }
558 }
559 }
560
561 virtual void deleteChild(oct_node* node)
562 {
563 for (U32 i = 0; i < getChildCount(); i++)
564 {
565 if (getChild(i) == node)
566 {
567 removeChild(i, TRUE);
568 return;
569 }
570 }
571
572 OCT_ERRS << "Octree failed to delete requested child." << llendl;
573 }
574
575protected:
576 child_list mChild;
577 element_list mData;
578};
579
580//just like a branch, except it might expand the node it points to
581template <class T>
582class LLOctreeRoot : public LLOctreeState<T>
583{
584public:
585 typedef LLOctreeState<T> BaseType;
586 typedef LLOctreeNode<T> oct_node;
587
588 LLOctreeRoot(oct_node* node = NULL) : BaseType(node) { }
589
590 oct_node* getOctNode() { return BaseType::getOctNode(); }
591 virtual bool isLeaf() { return false; }
592
593 virtual bool balance()
594 {
595 //the cached node might be invalid, so don't reference it
596 if (this->getChildCount() == 1 &&
597 !(this->mChild[0]->hasLeafState()) &&
598 this->mChild[0]->getElementCount() == 0)
599 { //if we have only one child and that child is an empty branch, make that child the root
600 BaseType* state = this->mChild[0]->getOctState();
601 oct_node* child = this->mChild[0];
602 oct_node* root = getOctNode();
603
604 //make the root node look like the child
605 root->setCenter(this->mChild[0]->getCenter());
606 root->setSize(this->mChild[0]->getSize());
607 root->updateMinMax();
608
609 //reset root node child list
610 this->clearChildren();
611
612 //copy the child's children into the root node silently
613 //(don't notify listeners of addition)
614 for (U32 i = 0; i < state->getChildCount(); i++)
615 {
616 addChild(state->getChild(i), TRUE);
617 }
618
619 //destroy child
620 state->clearChildren();
621 delete child;
622 }
623
624 return true;
625 }
626
627 // LLOctreeRoot::insert
628 virtual bool insert(T* data)
629 {
630 if (data == NULL)
631 {
632 OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
633 return false;
634 }
635
636 if (data->getBinRadius() > 4096.0)
637 {
638 OCT_ERRS << "!!! ELEMENT EXCEDES MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
639 }
640
641 LLOctreeNode<T>* node = getOctNode();
642 if (node->getSize().mdV[0] > data->getBinRadius() && node->isInside(data->getPositionGroup()))
643 {
644 //we got it, just act like a branch
645 LLOctreeState<T>::insert(data);
646 }
647 else if (this->getChildCount() == 0)
648 {
649 //first object being added, just wrap it up
650 while (!(node->getSize().mdV[0] > data->getBinRadius() && node->isInside(data->getPositionGroup())))
651 {
652 LLVector3d center, size;
653 center = node->getCenter();
654 size = node->getSize();
655 LLOctreeNode<T>::pushCenter(center, size, data);
656 node->setCenter(center);
657 node->setSize(size*2);
658 node->updateMinMax();
659 }
660 LLOctreeState<T>::insert(data);
661 }
662 else
663 {
664 //the data is outside the root node, we need to grow
665 LLVector3d center(node->getCenter());
666 LLVector3d size(node->getSize());
667
668 //expand this node
669 LLVector3d newcenter(center);
670 LLOctreeNode<T>::pushCenter(newcenter, size, data);
671 node->setCenter(newcenter);
672 node->setSize(size*2);
673 node->updateMinMax();
674
675 //copy our children to a new branch
676 LLOctreeState<T>* newstate = new LLOctreeState<T>();
677 LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, newstate, node);
678
679 for (U32 i = 0; i < this->getChildCount(); i++)
680 {
681 LLOctreeNode<T>* child = this->getChild(i);
682 newstate->addChild(child);
683 }
684
685 //clear our children and add the root copy
686 this->clearChildren();
687 addChild(newnode);
688
689 //insert the data
690 node->insert(data);
691 }
692
693 return false;
694 }
695};
696
697
698//========================
699// LLOctreeTraveler
700//========================
701template <class T>
702void LLOctreeTraveler<T>::traverse(const LLTreeNode<T>* node)
703{
704 const LLOctreeState<T>* state = (const LLOctreeState<T>*) node->getState();
705 state->accept(this);
706 for (U32 i = 0; i < state->getChildCount(); i++)
707 {
708 traverse(state->getChild(i));
709 }
710}
711
712#endif
diff --git a/linden/indra/llmath/llperlin.cpp b/linden/indra/llmath/llperlin.cpp
new file mode 100644
index 0000000..553b6a1
--- /dev/null
+++ b/linden/indra/llmath/llperlin.cpp
@@ -0,0 +1,295 @@
1/**
2 * @file llperlin.cpp
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28#include "llmath.h"
29
30#include "llperlin.h"
31
32#define B 0x100
33#define BM 0xff
34#define N 0x1000
35#define NF32 (4096.f)
36#define NP 12 /* 2^N */
37#define NM 0xfff
38
39static S32 p[B + B + 2];
40static F32 g3[B + B + 2][3];
41static F32 g2[B + B + 2][2];
42static F32 g1[B + B + 2];
43
44bool LLPerlinNoise::sInitialized = 0;
45
46static void normalize2(F32 v[2])
47{
48 F32 s = 1.f/(F32)sqrt(v[0] * v[0] + v[1] * v[1]);
49 v[0] = v[0] * s;
50 v[1] = v[1] * s;
51}
52
53static void normalize3(F32 v[3])
54{
55 F32 s = 1.f/(F32)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
56 v[0] = v[0] * s;
57 v[1] = v[1] * s;
58 v[2] = v[2] * s;
59}
60
61static void fast_setup(F32 vec, U8 &b0, U8 &b1, F32 &r0, F32 &r1)
62{
63 S32 t_S32;
64
65 r1 = vec + NF32;
66 t_S32 = lltrunc(r1);
67 b0 = (U8)t_S32;
68 b1 = b0 + 1;
69 r0 = r1 - t_S32;
70 r1 = r0 - 1.f;
71}
72
73
74void LLPerlinNoise::init(void)
75{
76 int i, j, k;
77
78 for (i = 0 ; i < B ; i++)
79 {
80 p[i] = i;
81
82 g1[i] = (F32)((rand() % (B + B)) - B) / B;
83
84 for (j = 0 ; j < 2 ; j++)
85 g2[i][j] = (F32)((rand() % (B + B)) - B) / B;
86 normalize2(g2[i]);
87
88 for (j = 0 ; j < 3 ; j++)
89 g3[i][j] = (F32)((rand() % (B + B)) - B) / B;
90 normalize3(g3[i]);
91 }
92
93 while (--i)
94 {
95 k = p[i];
96 p[i] = p[j = rand() % B];
97 p[j] = k;
98 }
99
100 for (i = 0 ; i < B + 2 ; i++)
101 {
102 p[B + i] = p[i];
103 g1[B + i] = g1[i];
104 for (j = 0 ; j < 2 ; j++)
105 g2[B + i][j] = g2[i][j];
106 for (j = 0 ; j < 3 ; j++)
107 g3[B + i][j] = g3[i][j];
108 }
109
110 sInitialized = true;
111}
112
113
114//============================================================================
115// Noise functions
116
117#define s_curve(t) ( t * t * (3.f - 2.f * t) )
118
119#define lerp_m(t, a, b) ( a + t * (b - a) )
120
121F32 LLPerlinNoise::noise1(F32 x)
122{
123 int bx0, bx1;
124 F32 rx0, rx1, sx, t, u, v;
125
126 if (!sInitialized)
127 init();
128
129 t = x + N;
130 bx0 = (lltrunc(t)) & BM;
131 bx1 = (bx0+1) & BM;
132 rx0 = t - lltrunc(t);
133 rx1 = rx0 - 1.f;
134
135 sx = s_curve(rx0);
136
137 u = rx0 * g1[ p[ bx0 ] ];
138 v = rx1 * g1[ p[ bx1 ] ];
139
140 return lerp_m(sx, u, v);
141}
142
143static F32 fast_at2(F32 rx, F32 ry, F32 *q)
144{
145 return rx * q[0] + ry * q[1];
146}
147
148F32 LLPerlinNoise::noise2(F32 x, F32 y)
149{
150 U8 bx0, bx1, by0, by1;
151 U32 b00, b10, b01, b11;
152 F32 rx0, rx1, ry0, ry1, *q, sx, sy, a, b, u, v;
153 S32 i, j;
154
155 if (!sInitialized)
156 init();
157
158 fast_setup(x, bx0, bx1, rx0, rx1);
159 fast_setup(y, by0, by1, ry0, ry1);
160
161 i = *(p + bx0);
162 j = *(p + bx1);
163
164 b00 = *(p + i + by0);
165 b10 = *(p + j + by0);
166 b01 = *(p + i + by1);
167 b11 = *(p + j + by1);
168
169 sx = s_curve(rx0);
170 sy = s_curve(ry0);
171
172
173 q = *(g2 + b00);
174 u = fast_at2(rx0, ry0, q);
175 q = *(g2 + b10);
176 v = fast_at2(rx1, ry0, q);
177 a = lerp_m(sx, u, v);
178
179 q = *(g2 + b01);
180 u = fast_at2(rx0,ry1,q);
181 q = *(g2 + b11);
182 v = fast_at2(rx1,ry1,q);
183 b = lerp_m(sx, u, v);
184
185 return lerp_m(sy, a, b);
186}
187
188static F32 fast_at3(F32 rx, F32 ry, F32 rz, F32 *q)
189{
190 return rx * q[0] + ry * q[1] + rz * q[2];
191}
192
193F32 LLPerlinNoise::noise3(F32 x, F32 y, F32 z)
194{
195 U8 bx0, bx1, by0, by1, bz0, bz1;
196 S32 b00, b10, b01, b11;
197 F32 rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
198 S32 i, j;
199
200 if (!sInitialized)
201 init();
202
203 fast_setup(x, bx0,bx1, rx0,rx1);
204 fast_setup(y, by0,by1, ry0,ry1);
205 fast_setup(z, bz0,bz1, rz0,rz1);
206
207 i = p[ bx0 ];
208 j = p[ bx1 ];
209
210 b00 = p[ i + by0 ];
211 b10 = p[ j + by0 ];
212 b01 = p[ i + by1 ];
213 b11 = p[ j + by1 ];
214
215 t = s_curve(rx0);
216 sy = s_curve(ry0);
217 sz = s_curve(rz0);
218
219 q = g3[ b00 + bz0 ];
220 u = fast_at3(rx0,ry0,rz0,q);
221 q = g3[ b10 + bz0 ];
222 v = fast_at3(rx1,ry0,rz0,q);
223 a = lerp_m(t, u, v);
224
225 q = g3[ b01 + bz0 ];
226 u = fast_at3(rx0,ry1,rz0,q);
227 q = g3[ b11 + bz0 ];
228 v = fast_at3(rx1,ry1,rz0,q);
229 b = lerp_m(t, u, v);
230
231 c = lerp_m(sy, a, b);
232
233 q = g3[ b00 + bz1 ];
234 u = fast_at3(rx0,ry0,rz1,q);
235 q = g3[ b10 + bz1 ];
236 v = fast_at3(rx1,ry0,rz1,q);
237 a = lerp_m(t, u, v);
238
239 q = g3[ b01 + bz1 ];
240 u = fast_at3(rx0,ry1,rz1,q);
241 q = g3[ b11 + bz1 ];
242 v = fast_at3(rx1,ry1,rz1,q);
243 b = lerp_m(t, u, v);
244
245 d = lerp_m(sy, a, b);
246
247 return lerp_m(sz, c, d);
248}
249
250F32 LLPerlinNoise::turbulence2(F32 x, F32 y, F32 freq)
251{
252 F32 t, lx, ly;
253
254 for (t = 0.f ; freq >= 1.f ; freq *= 0.5f)
255 {
256 lx = freq * x;
257 ly = freq * y;
258 t += noise2(lx, ly)/freq;
259 }
260 return t;
261}
262
263F32 LLPerlinNoise::turbulence3(F32 x, F32 y, F32 z, F32 freq)
264{
265 F32 t, lx, ly, lz;
266
267 for (t = 0.f ; freq >= 1.f ; freq *= 0.5f)
268 {
269 lx = freq * x;
270 ly = freq * y;
271 lz = freq * z;
272 t += noise3(lx,ly,lz)/freq;
273// t += fabs(noise3(lx,ly,lz)) / freq; // Like snow - bubbly at low frequencies
274// t += sqrt(fabs(noise3(lx,ly,lz))) / freq; // Better at low freq
275// t += (noise3(lx,ly,lz)*noise3(lx,ly,lz)) / freq;
276 }
277 return t;
278}
279
280F32 LLPerlinNoise::clouds3(F32 x, F32 y, F32 z, F32 freq)
281{
282 F32 t, lx, ly, lz;
283
284 for (t = 0.f ; freq >= 1.f ; freq *= 0.5f)
285 {
286 lx = freq * x;
287 ly = freq * y;
288 lz = freq * z;
289// t += noise3(lx,ly,lz)/freq;
290// t += fabs(noise3(lx,ly,lz)) / freq; // Like snow - bubbly at low frequencies
291// t += sqrt(fabs(noise3(lx,ly,lz))) / freq; // Better at low freq
292 t += (noise3(lx,ly,lz)*noise3(lx,ly,lz)) / freq;
293 }
294 return t;
295}
diff --git a/linden/indra/llmath/llperlin.h b/linden/indra/llmath/llperlin.h
new file mode 100644
index 0000000..dcd6506
--- /dev/null
+++ b/linden/indra/llmath/llperlin.h
@@ -0,0 +1,47 @@
1/**
2 * @file llperlin.h
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_PERLIN_H
28#define LL_PERLIN_H
29
30#include "stdtypes.h"
31
32// namespace wrapper
33class LLPerlinNoise
34{
35public:
36 static F32 noise1(F32 x);
37 static F32 noise2(F32 x, F32 y);
38 static F32 noise3(F32 x, F32 y, F32 z);
39 static F32 turbulence2(F32 x, F32 y, F32 freq);
40 static F32 turbulence3(F32 x, F32 y, F32 z, F32 freq);
41 static F32 clouds3(F32 x, F32 y, F32 z, F32 freq);
42private:
43 static bool sInitialized;
44 static void init(void);
45};
46
47#endif // LL_PERLIN_
diff --git a/linden/indra/llmath/llplane.h b/linden/indra/llmath/llplane.h
new file mode 100644
index 0000000..44721f3
--- /dev/null
+++ b/linden/indra/llmath/llplane.h
@@ -0,0 +1,68 @@
1/**
2 * @file llplane.h
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_LLPLANE_H
28#define LL_LLPLANE_H
29
30#include "v3math.h"
31#include "v4math.h"
32
33// A simple way to specify a plane is to give its normal,
34// and it's nearest approach to the origin.
35//
36// Given the equation for a plane : A*x + B*y + C*z + D = 0
37// The plane normal = [A, B, C]
38// The closest approach = D / sqrt(A*A + B*B + C*C)
39
40class LLPlane : public LLVector4
41{
42public:
43 LLPlane() {}; // no default constructor
44 LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
45 LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); }
46 void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); }
47 void setVec(const LLVector3 &p0, const LLVector3 &n)
48 {
49 F32 d = -(p0 * n);
50 setVec(n, d);
51 }
52 void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2)
53 {
54 LLVector3 u, v, w;
55 u = p1 - p0;
56 v = p2 - p0;
57 w = u % v;
58 w.normVec();
59 F32 d = -(w * p0);
60 setVec(w, d);
61 }
62 LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;}
63 F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; }
64};
65
66
67
68#endif // LL_LLPLANE_H
diff --git a/linden/indra/llmath/llquantize.h b/linden/indra/llmath/llquantize.h
new file mode 100644
index 0000000..6045911
--- /dev/null
+++ b/linden/indra/llmath/llquantize.h
@@ -0,0 +1,122 @@
1/**
2 * @file llquantize.h
3 * @brief useful routines for quantizing floats to various length ints
4 * and back out again
5 *
6 * Copyright (c) 2001-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LL_LLQUANTIZE_H
30#define LL_LLQUANTIZE_H
31
32const U16 U16MAX = 65535;
33const F32 OOU16MAX = 1.f/(F32)(U16MAX);
34
35const U8 U8MAX = 255;
36const F32 OOU8MAX = 1.f/(F32)(U8MAX);
37
38const U8 FIRSTVALIDCHAR = 54;
39const U8 MAXSTRINGVAL = U8MAX - FIRSTVALIDCHAR; //we don't allow newline or null
40
41
42inline U16 F32_to_U16(F32 val, F32 lower, F32 upper)
43{
44 val = llclamp(val, lower, upper);
45 // make sure that the value is positive and normalized to <0, 1>
46 val -= lower;
47 val /= (upper - lower);
48
49 // return the U16
50 return (U16)(llfloor(val*U16MAX));
51}
52
53inline F32 U16_to_F32(U16 ival, F32 lower, F32 upper)
54{
55 F32 val = ival*OOU16MAX;
56 F32 delta = (upper - lower);
57 val *= delta;
58 val += lower;
59
60 F32 max_error = delta*OOU16MAX;
61
62 // make sure that zero's come through as zero
63 if (fabsf(val) < max_error)
64 val = 0.f;
65
66 return val;
67}
68
69inline U8 F32_to_U8(F32 val, F32 lower, F32 upper)
70{
71 val = llclamp(val, lower, upper);
72 // make sure that the value is positive and normalized to <0, 1>
73 val -= lower;
74 val /= (upper - lower);
75
76 // return the U8
77 return (U8)(llfloor(val*U8MAX));
78}
79
80inline F32 U8_to_F32(U8 ival, F32 lower, F32 upper)
81{
82 F32 val = ival*OOU8MAX;
83 F32 delta = (upper - lower);
84 val *= delta;
85 val += lower;
86
87 F32 max_error = delta*OOU8MAX;
88
89 // make sure that zero's come through as zero
90 if (fabsf(val) < max_error)
91 val = 0.f;
92
93 return val;
94}
95
96inline U8 F32_TO_STRING(F32 val, F32 lower, F32 upper)
97{
98 val = llclamp(val, lower, upper); //[lower, upper]
99 // make sure that the value is positive and normalized to <0, 1>
100 val -= lower; //[0, upper-lower]
101 val /= (upper - lower); //[0,1]
102 val = val * MAXSTRINGVAL; //[0, MAXSTRINGVAL]
103 val = floor(val + 0.5f); //[0, MAXSTRINGVAL]
104
105 U8 stringVal = (U8)(val) + FIRSTVALIDCHAR; //[FIRSTVALIDCHAR, MAXSTRINGVAL + FIRSTVALIDCHAR]
106 return stringVal;
107}
108
109inline F32 STRING_TO_F32(U8 ival, F32 lower, F32 upper)
110{
111 // remove empty space left for NULL, newline, etc.
112 ival -= FIRSTVALIDCHAR; //[0, MAXSTRINGVAL]
113
114 F32 val = (F32)ival * (1.f / (F32)MAXSTRINGVAL); //[0, 1]
115 F32 delta = (upper - lower);
116 val *= delta; //[0, upper - lower]
117 val += lower; //[lower, upper]
118
119 return val;
120}
121
122#endif
diff --git a/linden/indra/llmath/llquaternion.cpp b/linden/indra/llmath/llquaternion.cpp
new file mode 100644
index 0000000..1111ca5
--- /dev/null
+++ b/linden/indra/llmath/llquaternion.cpp
@@ -0,0 +1,849 @@
1/**
2 * @file qmath.cpp
3 * @brief LLQuaternion class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llquaternion.h"
31
32#include "llmath.h" // for F_PI
33//#include "vmath.h"
34#include "v3math.h"
35#include "v3dmath.h"
36#include "v4math.h"
37#include "m4math.h"
38#include "m3math.h"
39#include "llquantize.h"
40
41// WARNING: Don't use this for global const definitions! using this
42// at the top of a *.cpp file might not give you what you think.
43const LLQuaternion LLQuaternion::DEFAULT;
44
45// Constructors
46
47LLQuaternion::LLQuaternion(const LLMatrix4 &mat)
48{
49 *this = mat.quaternion();
50 normQuat();
51}
52
53LLQuaternion::LLQuaternion(const LLMatrix3 &mat)
54{
55 *this = mat.quaternion();
56 normQuat();
57}
58
59LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
60{
61 LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
62 v.normVec();
63
64 F32 c, s;
65 c = cosf(angle*0.5f);
66 s = sinf(angle*0.5f);
67
68 mQ[VX] = v.mV[VX] * s;
69 mQ[VY] = v.mV[VY] * s;
70 mQ[VZ] = v.mV[VZ] * s;
71 mQ[VW] = c;
72 normQuat();
73}
74
75LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)
76{
77 LLVector3 v(vec);
78 v.normVec();
79
80 F32 c, s;
81 c = cosf(angle*0.5f);
82 s = sinf(angle*0.5f);
83
84 mQ[VX] = v.mV[VX] * s;
85 mQ[VY] = v.mV[VY] * s;
86 mQ[VZ] = v.mV[VZ] * s;
87 mQ[VW] = c;
88 normQuat();
89}
90
91LLQuaternion::LLQuaternion(const LLVector3 &x_axis,
92 const LLVector3 &y_axis,
93 const LLVector3 &z_axis)
94{
95 LLMatrix3 mat;
96 mat.setRows(x_axis, y_axis, z_axis);
97 *this = mat.quaternion();
98 normQuat();
99}
100
101// Quatizations
102void LLQuaternion::quantize16(F32 lower, F32 upper)
103{
104 F32 x = mQ[VX];
105 F32 y = mQ[VY];
106 F32 z = mQ[VZ];
107 F32 s = mQ[VS];
108
109 x = U16_to_F32(F32_to_U16(x, lower, upper), lower, upper);
110 y = U16_to_F32(F32_to_U16(y, lower, upper), lower, upper);
111 z = U16_to_F32(F32_to_U16(z, lower, upper), lower, upper);
112 s = U16_to_F32(F32_to_U16(s, lower, upper), lower, upper);
113
114 mQ[VX] = x;
115 mQ[VY] = y;
116 mQ[VZ] = z;
117 mQ[VS] = s;
118}
119
120void LLQuaternion::quantize8(F32 lower, F32 upper)
121{
122 mQ[VX] = U8_to_F32(F32_to_U8(mQ[VX], lower, upper), lower, upper);
123 mQ[VY] = U8_to_F32(F32_to_U8(mQ[VY], lower, upper), lower, upper);
124 mQ[VZ] = U8_to_F32(F32_to_U8(mQ[VZ], lower, upper), lower, upper);
125 mQ[VS] = U8_to_F32(F32_to_U8(mQ[VS], lower, upper), lower, upper);
126}
127
128// LLVector3 Magnitude and Normalization Functions
129
130
131// Set LLQuaternion routines
132
133const LLQuaternion& LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z)
134{
135 LLVector3 vec(x, y, z);
136 vec.normVec();
137
138 angle *= 0.5f;
139 F32 c, s;
140 c = cosf(angle);
141 s = sinf(angle);
142
143 mQ[VX] = vec.mV[VX]*s;
144 mQ[VY] = vec.mV[VY]*s;
145 mQ[VZ] = vec.mV[VZ]*s;
146 mQ[VW] = c;
147
148 normQuat();
149 return (*this);
150}
151
152const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector3 &vec)
153{
154 LLVector3 v(vec);
155 v.normVec();
156
157 angle *= 0.5f;
158 F32 c, s;
159 c = cosf(angle);
160 s = sinf(angle);
161
162 mQ[VX] = v.mV[VX]*s;
163 mQ[VY] = v.mV[VY]*s;
164 mQ[VZ] = v.mV[VZ]*s;
165 mQ[VW] = c;
166
167 normQuat();
168 return (*this);
169}
170
171const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector4 &vec)
172{
173 LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
174 v.normVec();
175
176 F32 c, s;
177 c = cosf(angle*0.5f);
178 s = sinf(angle*0.5f);
179
180 mQ[VX] = v.mV[VX]*s;
181 mQ[VY] = v.mV[VY]*s;
182 mQ[VZ] = v.mV[VZ]*s;
183 mQ[VW] = c;
184
185 normQuat();
186 return (*this);
187}
188
189const LLQuaternion& LLQuaternion::setQuat(F32 roll, F32 pitch, F32 yaw)
190{
191 LLMatrix3 rot_mat(roll, pitch, yaw);
192 rot_mat.orthogonalize();
193 *this = rot_mat.quaternion();
194
195 normQuat();
196 return (*this);
197//#if 1
198// // NOTE: LLQuaternion's are actually inverted with respect to
199// // the matrices, so this code also assumes inverted quaternions
200// // (-x, -y, -z, w). The result is that roll,pitch,yaw are applied
201// // in reverse order (yaw,pitch,roll).
202// F64 cosX = cos(roll);
203// F64 cosY = cos(pitch);
204// F64 cosZ = cos(yaw);
205//
206// F64 sinX = sin(roll);
207// F64 sinY = sin(pitch);
208// F64 sinZ = sin(yaw);
209//
210// mQ[VW] = (F32)sqrt(cosY*cosZ - sinX*sinY*sinZ + cosX*cosZ + cosX*cosY + 1.0)*.5;
211// if (fabs(mQ[VW]) < F_APPROXIMATELY_ZERO)
212// {
213// // null rotation, any axis will do
214// mQ[VX] = 0.0f;
215// mQ[VY] = 1.0f;
216// mQ[VZ] = 0.0f;
217// }
218// else
219// {
220// F32 inv_s = 1.0f / (4.0f * mQ[VW]);
221// mQ[VX] = (F32)-(-sinX*cosY - cosX*sinY*sinZ - sinX*cosZ) * inv_s;
222// mQ[VY] = (F32)-(-cosX*sinY*cosZ + sinX*sinZ - sinY) * inv_s;
223// mQ[VZ] = (F32)-(-cosY*sinZ - sinX*sinY*cosZ - cosX*sinZ) * inv_s;
224// }
225//
226//#else // This only works on a certain subset of roll/pitch/yaw
227//
228// F64 cosX = cosf(roll/2.0);
229// F64 cosY = cosf(pitch/2.0);
230// F64 cosZ = cosf(yaw/2.0);
231//
232// F64 sinX = sinf(roll/2.0);
233// F64 sinY = sinf(pitch/2.0);
234// F64 sinZ = sinf(yaw/2.0);
235//
236// mQ[VW] = (F32)(cosX*cosY*cosZ + sinX*sinY*sinZ);
237// mQ[VX] = (F32)(sinX*cosY*cosZ - cosX*sinY*sinZ);
238// mQ[VY] = (F32)(cosX*sinY*cosZ + sinX*cosY*sinZ);
239// mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ);
240//#endif
241//
242// normQuat();
243// return (*this);
244}
245
246// SJB: This code is correct for a logicly stored (non-transposed) matrix;
247// Our matrices are stored transposed, OpenGL style, so this generates the
248// INVERSE matrix, or the CORRECT matrix form an INVERSE quaternion.
249// Because we use similar logic in LLMatrix3::quaternion(),
250// we are internally consistant so everything works OK :)
251LLMatrix3 LLQuaternion::getMatrix3(void) const
252{
253 LLMatrix3 mat;
254 F32 xx, xy, xz, xw, yy, yz, yw, zz, zw;
255
256 xx = mQ[VX] * mQ[VX];
257 xy = mQ[VX] * mQ[VY];
258 xz = mQ[VX] * mQ[VZ];
259 xw = mQ[VX] * mQ[VW];
260
261 yy = mQ[VY] * mQ[VY];
262 yz = mQ[VY] * mQ[VZ];
263 yw = mQ[VY] * mQ[VW];
264
265 zz = mQ[VZ] * mQ[VZ];
266 zw = mQ[VZ] * mQ[VW];
267
268 mat.mMatrix[0][0] = 1.f - 2.f * ( yy + zz );
269 mat.mMatrix[0][1] = 2.f * ( xy + zw );
270 mat.mMatrix[0][2] = 2.f * ( xz - yw );
271
272 mat.mMatrix[1][0] = 2.f * ( xy - zw );
273 mat.mMatrix[1][1] = 1.f - 2.f * ( xx + zz );
274 mat.mMatrix[1][2] = 2.f * ( yz + xw );
275
276 mat.mMatrix[2][0] = 2.f * ( xz + yw );
277 mat.mMatrix[2][1] = 2.f * ( yz - xw );
278 mat.mMatrix[2][2] = 1.f - 2.f * ( xx + yy );
279
280 return mat;
281}
282
283LLMatrix4 LLQuaternion::getMatrix4(void) const
284{
285 LLMatrix4 mat;
286 F32 xx, xy, xz, xw, yy, yz, yw, zz, zw;
287
288 xx = mQ[VX] * mQ[VX];
289 xy = mQ[VX] * mQ[VY];
290 xz = mQ[VX] * mQ[VZ];
291 xw = mQ[VX] * mQ[VW];
292
293 yy = mQ[VY] * mQ[VY];
294 yz = mQ[VY] * mQ[VZ];
295 yw = mQ[VY] * mQ[VW];
296
297 zz = mQ[VZ] * mQ[VZ];
298 zw = mQ[VZ] * mQ[VW];
299
300 mat.mMatrix[0][0] = 1.f - 2.f * ( yy + zz );
301 mat.mMatrix[0][1] = 2.f * ( xy + zw );
302 mat.mMatrix[0][2] = 2.f * ( xz - yw );
303
304 mat.mMatrix[1][0] = 2.f * ( xy - zw );
305 mat.mMatrix[1][1] = 1.f - 2.f * ( xx + zz );
306 mat.mMatrix[1][2] = 2.f * ( yz + xw );
307
308 mat.mMatrix[2][0] = 2.f * ( xz + yw );
309 mat.mMatrix[2][1] = 2.f * ( yz - xw );
310 mat.mMatrix[2][2] = 1.f - 2.f * ( xx + yy );
311
312 // TODO -- should we set the translation portion to zero?
313
314 return mat;
315}
316
317
318
319
320// Other useful methods
321
322
323// calculate the shortest rotation from a to b
324void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)
325{
326 // Make a local copy of both vectors.
327 LLVector3 vec_a = a;
328 LLVector3 vec_b = b;
329
330 // Make sure neither vector is zero length. Also normalize
331 // the vectors while we are at it.
332 F32 vec_a_mag = vec_a.normVec();
333 F32 vec_b_mag = vec_b.normVec();
334 if (vec_a_mag < F_APPROXIMATELY_ZERO ||
335 vec_b_mag < F_APPROXIMATELY_ZERO)
336 {
337 // Can't calculate a rotation from this.
338 // Just return ZERO_ROTATION instead.
339 loadIdentity();
340 return;
341 }
342
343 // Create an axis to rotate around, and the cos of the angle to rotate.
344 LLVector3 axis = vec_a % vec_b;
345 F32 cos_theta = vec_a * vec_b;
346
347 // Check the angle between the vectors to see if they are parallel or anti-parallel.
348 if (cos_theta > 1.0 - F_APPROXIMATELY_ZERO)
349 {
350 // a and b are parallel. No rotation is necessary.
351 loadIdentity();
352 }
353 else if (cos_theta < -1.0 + F_APPROXIMATELY_ZERO)
354 {
355 // a and b are anti-parallel.
356 // Rotate 180 degrees around some orthogonal axis.
357 // Find the projection of the x-axis onto a, and try
358 // using the vector between the projection and the x-axis
359 // as the orthogonal axis.
360 LLVector3 proj = vec_a.mV[VX] / (vec_a * vec_a) * vec_a;
361 LLVector3 ortho_axis(1.f, 0.f, 0.f);
362 ortho_axis -= proj;
363
364 // Turn this into an orthonormal axis.
365 F32 ortho_length = ortho_axis.normVec();
366 // If the axis' length is 0, then our guess at an orthogonal axis
367 // was wrong (a is parallel to the x-axis).
368 if (ortho_length < F_APPROXIMATELY_ZERO)
369 {
370 // Use the z-axis instead.
371 ortho_axis.setVec(0.f, 0.f, 1.f);
372 }
373
374 // Construct a quaternion from this orthonormal axis.
375 mQ[VX] = ortho_axis.mV[VX];
376 mQ[VY] = ortho_axis.mV[VY];
377 mQ[VZ] = ortho_axis.mV[VZ];
378 mQ[VW] = 0.f;
379 }
380 else
381 {
382 // a and b are NOT parallel or anti-parallel.
383 // Return the rotation between these vectors.
384 F32 theta = (F32)acos(cos_theta);
385
386 setQuat(theta, axis);
387 }
388}
389
390// constrains rotation to a cone angle specified in radians
391const LLQuaternion &LLQuaternion::constrain(F32 radians)
392{
393 const F32 cos_angle_lim = cosf( radians/2 ); // mQ[VW] limit
394 const F32 sin_angle_lim = sinf( radians/2 ); // rotation axis length limit
395
396 if (mQ[VW] < 0.f)
397 {
398 mQ[VX] *= -1.f;
399 mQ[VY] *= -1.f;
400 mQ[VZ] *= -1.f;
401 mQ[VW] *= -1.f;
402 }
403
404 // if rotation angle is greater than limit (cos is less than limit)
405 if( mQ[VW] < cos_angle_lim )
406 {
407 mQ[VW] = cos_angle_lim;
408 F32 axis_len = sqrtf( mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] ); // sin(theta/2)
409 F32 axis_mult_fact = sin_angle_lim / axis_len;
410 mQ[VX] *= axis_mult_fact;
411 mQ[VY] *= axis_mult_fact;
412 mQ[VZ] *= axis_mult_fact;
413 }
414
415 return *this;
416}
417
418// Operators
419
420std::ostream& operator<<(std::ostream &s, const LLQuaternion &a)
421{
422 s << "{ "
423 << a.mQ[VX] << ", " << a.mQ[VY] << ", " << a.mQ[VZ] << ", " << a.mQ[VW]
424 << " }";
425 return s;
426}
427
428
429// Does NOT renormalize the result
430LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b)
431{
432// LLQuaternion::mMultCount++;
433
434 LLQuaternion q(
435 b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1],
436 b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2],
437 b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0],
438 b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2]
439 );
440 return q;
441}
442
443/*
444LLMatrix4 operator*(const LLMatrix4 &m, const LLQuaternion &q)
445{
446 LLMatrix4 qmat(q);
447 return (m*qmat);
448}
449*/
450
451
452
453LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot)
454{
455 F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ];
456 F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY];
457 F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ];
458 F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX];
459
460 F32 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY];
461 F32 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ];
462 F32 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX];
463
464 return LLVector4(nx, ny, nz, a.mV[VW]);
465}
466
467LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot)
468{
469 F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ];
470 F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY];
471 F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ];
472 F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX];
473
474 F32 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY];
475 F32 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ];
476 F32 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX];
477
478 return LLVector3(nx, ny, nz);
479}
480
481LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot)
482{
483 F64 rw = - rot.mQ[VX] * a.mdV[VX] - rot.mQ[VY] * a.mdV[VY] - rot.mQ[VZ] * a.mdV[VZ];
484 F64 rx = rot.mQ[VW] * a.mdV[VX] + rot.mQ[VY] * a.mdV[VZ] - rot.mQ[VZ] * a.mdV[VY];
485 F64 ry = rot.mQ[VW] * a.mdV[VY] + rot.mQ[VZ] * a.mdV[VX] - rot.mQ[VX] * a.mdV[VZ];
486 F64 rz = rot.mQ[VW] * a.mdV[VZ] + rot.mQ[VX] * a.mdV[VY] - rot.mQ[VY] * a.mdV[VX];
487
488 F64 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY];
489 F64 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ];
490 F64 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX];
491
492 return LLVector3d(nx, ny, nz);
493}
494
495F32 dot(const LLQuaternion &a, const LLQuaternion &b)
496{
497 return a.mQ[VX] * b.mQ[VX] +
498 a.mQ[VY] * b.mQ[VY] +
499 a.mQ[VZ] * b.mQ[VZ] +
500 a.mQ[VW] * b.mQ[VW];
501}
502
503// DEMO HACK: This lerp is probably inocrrect now due intermediate normalization
504// it should look more like the lerp below
505#if 0
506// linear interpolation
507LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)
508{
509 LLQuaternion r;
510 r = t * (q - p) + p;
511 r.normQuat();
512 return r;
513}
514#endif
515
516// lerp from identity to q
517LLQuaternion lerp(F32 t, const LLQuaternion &q)
518{
519 LLQuaternion r;
520 r.mQ[VX] = t * q.mQ[VX];
521 r.mQ[VY] = t * q.mQ[VY];
522 r.mQ[VZ] = t * q.mQ[VZ];
523 r.mQ[VW] = t * (q.mQ[VZ] - 1.f) + 1.f;
524 r.normQuat();
525 return r;
526}
527
528LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)
529{
530 LLQuaternion r;
531 F32 inv_t;
532
533 inv_t = 1.f - t;
534
535 r.mQ[VX] = t * q.mQ[VX] + (inv_t * p.mQ[VX]);
536 r.mQ[VY] = t * q.mQ[VY] + (inv_t * p.mQ[VY]);
537 r.mQ[VZ] = t * q.mQ[VZ] + (inv_t * p.mQ[VZ]);
538 r.mQ[VW] = t * q.mQ[VW] + (inv_t * p.mQ[VW]);
539 r.normQuat();
540 return r;
541}
542
543
544// spherical linear interpolation
545LLQuaternion slerp( F32 u, const LLQuaternion &a, const LLQuaternion &b )
546{
547 // cosine theta = dot product of a and b
548 F32 cos_t = a.mQ[0]*b.mQ[0] + a.mQ[1]*b.mQ[1] + a.mQ[2]*b.mQ[2] + a.mQ[3]*b.mQ[3];
549
550 // if b is on opposite hemisphere from a, use -a instead
551 int bflip;
552 if (cos_t < 0.0f)
553 {
554 cos_t = -cos_t;
555 bflip = TRUE;
556 }
557 else
558 bflip = FALSE;
559
560 // if B is (within precision limits) the same as A,
561 // just linear interpolate between A and B.
562 F32 alpha; // interpolant
563 F32 beta; // 1 - interpolant
564 if (1.0f - cos_t < 0.00001f)
565 {
566 beta = 1.0f - u;
567 alpha = u;
568 }
569 else
570 {
571 F32 theta = acosf(cos_t);
572 F32 sin_t = sinf(theta);
573 beta = sinf(theta - u*theta) / sin_t;
574 alpha = sinf(u*theta) / sin_t;
575 }
576
577 if (bflip)
578 beta = -beta;
579
580 // interpolate
581 LLQuaternion ret;
582 ret.mQ[0] = beta*a.mQ[0] + alpha*b.mQ[0];
583 ret.mQ[1] = beta*a.mQ[1] + alpha*b.mQ[1];
584 ret.mQ[2] = beta*a.mQ[2] + alpha*b.mQ[2];
585 ret.mQ[3] = beta*a.mQ[3] + alpha*b.mQ[3];
586
587 return ret;
588}
589
590// lerp whenever possible
591LLQuaternion nlerp(F32 t, const LLQuaternion &a, const LLQuaternion &b)
592{
593 if (dot(a, b) < 0.f)
594 {
595 return slerp(t, a, b);
596 }
597 else
598 {
599 return lerp(t, a, b);
600 }
601}
602
603LLQuaternion nlerp(F32 t, const LLQuaternion &q)
604{
605 if (q.mQ[VW] < 0.f)
606 {
607 return slerp(t, q);
608 }
609 else
610 {
611 return lerp(t, q);
612 }
613}
614
615// slerp from identity quaternion to another quaternion
616LLQuaternion slerp(F32 t, const LLQuaternion &q)
617{
618 F32 c = q.mQ[VW];
619 if (1.0f == t || 1.0f == c)
620 {
621 // the trivial cases
622 return q;
623 }
624
625 LLQuaternion r;
626 F32 s, angle, stq, stp;
627
628 s = (F32) sqrt(1.f - c*c);
629
630 if (c < 0.0f)
631 {
632 // when c < 0.0 then theta > PI/2
633 // since quat and -quat are the same rotation we invert one of
634 // p or q to reduce unecessary spins
635 // A equivalent way to do it is to convert acos(c) as if it had been negative,
636 // and to negate stp
637 angle = (F32) acos(-c);
638 stp = -(F32) sin(angle * (1.f - t));
639 stq = (F32) sin(angle * t);
640 }
641 else
642 {
643 angle = (F32) acos(c);
644 stp = (F32) sin(angle * (1.f - t));
645 stq = (F32) sin(angle * t);
646 }
647
648 r.mQ[VX] = (q.mQ[VX] * stq) / s;
649 r.mQ[VY] = (q.mQ[VY] * stq) / s;
650 r.mQ[VZ] = (q.mQ[VZ] * stq) / s;
651 r.mQ[VW] = (stp + q.mQ[VW] * stq) / s;
652
653 return r;
654}
655
656LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order)
657{
658 LLQuaternion xQ( xRot*DEG_TO_RAD, LLVector3(1.0f, 0.0f, 0.0f) );
659 LLQuaternion yQ( yRot*DEG_TO_RAD, LLVector3(0.0f, 1.0f, 0.0f) );
660 LLQuaternion zQ( zRot*DEG_TO_RAD, LLVector3(0.0f, 0.0f, 1.0f) );
661 LLQuaternion ret;
662 switch( order )
663 {
664 case LLQuaternion::XYZ:
665 ret = xQ * yQ * zQ;
666 break;
667 case LLQuaternion::YZX:
668 ret = yQ * zQ * xQ;
669 break;
670 case LLQuaternion::ZXY:
671 ret = zQ * xQ * yQ;
672 break;
673 case LLQuaternion::XZY:
674 ret = xQ * zQ * yQ;
675 break;
676 case LLQuaternion::YXZ:
677 ret = yQ * xQ * zQ;
678 break;
679 case LLQuaternion::ZYX:
680 ret = zQ * yQ * xQ;
681 break;
682 }
683 return ret;
684}
685
686const char *OrderToString( const LLQuaternion::Order order )
687{
688 char *p = NULL;
689 switch( order )
690 {
691 default:
692 case LLQuaternion::XYZ:
693 p = "XYZ";
694 break;
695 case LLQuaternion::YZX:
696 p = "YZX";
697 break;
698 case LLQuaternion::ZXY:
699 p = "ZXY";
700 break;
701 case LLQuaternion::XZY:
702 p = "XZY";
703 break;
704 case LLQuaternion::YXZ:
705 p = "YXZ";
706 break;
707 case LLQuaternion::ZYX:
708 p = "ZYX";
709 break;
710 }
711 return p;
712}
713
714LLQuaternion::Order StringToOrder( const char *str )
715{
716 if (strncmp(str, "XYZ", 3)==0 || strncmp(str, "xyz", 3)==0)
717 return LLQuaternion::XYZ;
718
719 if (strncmp(str, "YZX", 3)==0 || strncmp(str, "yzx", 3)==0)
720 return LLQuaternion::YZX;
721
722 if (strncmp(str, "ZXY", 3)==0 || strncmp(str, "zxy", 3)==0)
723 return LLQuaternion::ZXY;
724
725 if (strncmp(str, "XZY", 3)==0 || strncmp(str, "xzy", 3)==0)
726 return LLQuaternion::XZY;
727
728 if (strncmp(str, "YXZ", 3)==0 || strncmp(str, "yxz", 3)==0)
729 return LLQuaternion::YXZ;
730
731 if (strncmp(str, "ZYX", 3)==0 || strncmp(str, "zyx", 3)==0)
732 return LLQuaternion::ZYX;
733
734 return LLQuaternion::XYZ;
735}
736
737const LLQuaternion& LLQuaternion::setQuat(const LLMatrix3 &mat)
738{
739 *this = mat.quaternion();
740 normQuat();
741 return (*this);
742}
743
744const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat)
745{
746 *this = mat.quaternion();
747 normQuat();
748 return (*this);
749}
750
751void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const
752{
753 F32 cos_a = mQ[VW];
754 if (cos_a > 1.0f) cos_a = 1.0f;
755 if (cos_a < -1.0f) cos_a = -1.0f;
756
757 F32 sin_a = (F32) sqrt( 1.0f - cos_a * cos_a );
758
759 if ( fabs( sin_a ) < 0.0005f )
760 sin_a = 1.0f;
761 else
762 sin_a = 1.f/sin_a;
763
764 *angle = 2.0f * (F32) acos( cos_a );
765 vec.mV[VX] = mQ[VX] * sin_a;
766 vec.mV[VY] = mQ[VY] * sin_a;
767 vec.mV[VZ] = mQ[VZ] * sin_a;
768}
769
770
771// quaternion does not need to be normalized
772void LLQuaternion::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const
773{
774 LLMatrix3 rot_mat(*this);
775 rot_mat.orthogonalize();
776 rot_mat.getEulerAngles(roll, pitch, yaw);
777
778// // NOTE: LLQuaternion's are actually inverted with respect to
779// // the matrices, so this code also assumes inverted quaternions
780// // (-x, -y, -z, w). The result is that roll,pitch,yaw are applied
781// // in reverse order (yaw,pitch,roll).
782// F32 x = -mQ[VX], y = -mQ[VY], z = -mQ[VZ], w = mQ[VW];
783// F64 m20 = 2.0*(x*z-y*w);
784// if (1.0f - fabsf(m20) < F_APPROXIMATELY_ZERO)
785// {
786// *roll = 0.0f;
787// *pitch = (F32)asin(m20);
788// *yaw = (F32)atan2(2.0*(x*y-z*w), 1.0 - 2.0*(x*x+z*z));
789// }
790// else
791// {
792// *roll = (F32)atan2(-2.0*(y*z+x*w), 1.0-2.0*(x*x+y*y));
793// *pitch = (F32)asin(m20);
794// *yaw = (F32)atan2(-2.0*(x*y+z*w), 1.0-2.0*(y*y+z*z));
795// }
796}
797
798// Saves space by using the fact that our quaternions are normalized
799LLVector3 LLQuaternion::packToVector3() const
800{
801 if( mQ[VW] >= 0 )
802 {
803 return LLVector3( mQ[VX], mQ[VY], mQ[VZ] );
804 }
805 else
806 {
807 return LLVector3( -mQ[VX], -mQ[VY], -mQ[VZ] );
808 }
809}
810
811// Saves space by using the fact that our quaternions are normalized
812void LLQuaternion::unpackFromVector3( const LLVector3& vec )
813{
814 mQ[VX] = vec.mV[VX];
815 mQ[VY] = vec.mV[VY];
816 mQ[VZ] = vec.mV[VZ];
817 F32 t = 1.f - vec.magVecSquared();
818 if( t > 0 )
819 {
820 mQ[VW] = sqrt( t );
821 }
822 else
823 {
824 // Need this to avoid trying to find the square root of a negative number due
825 // to floating point error.
826 mQ[VW] = 0;
827 }
828}
829
830BOOL LLQuaternion::parseQuat(const char* buf, LLQuaternion* value)
831{
832 if( buf == NULL || buf[0] == '\0' || value == NULL)
833 {
834 return FALSE;
835 }
836
837 LLQuaternion quat;
838 S32 count = sscanf( buf, "%f %f %f %f", quat.mQ + 0, quat.mQ + 1, quat.mQ + 2, quat.mQ + 3 );
839 if( 4 == count )
840 {
841 value->setQuat( quat );
842 return TRUE;
843 }
844
845 return FALSE;
846}
847
848
849// End
diff --git a/linden/indra/llmath/llquaternion.h b/linden/indra/llmath/llquaternion.h
new file mode 100644
index 0000000..1e3f2b6
--- /dev/null
+++ b/linden/indra/llmath/llquaternion.h
@@ -0,0 +1,461 @@
1/**
2 * @file llquaternion.h
3 * @brief LLQuaternion class header file.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LLQUATERNION_H
29#define LLQUATERNION_H
30
31#include "llmath.h"
32
33class LLVector4;
34class LLVector3;
35class LLVector3d;
36class LLMatrix4;
37class LLMatrix3;
38
39// NOTA BENE: Quaternion code is written assuming Unit Quaternions!!!!
40// Moreover, it is written assuming that all vectors and matricies
41// passed as arguments are normalized and unitary respectively.
42// VERY VERY VERY VERY BAD THINGS will happen if these assumptions fail.
43
44static const U32 LENGTHOFQUAT = 4;
45
46class LLQuaternion
47{
48public:
49 F32 mQ[LENGTHOFQUAT];
50
51 static const LLQuaternion DEFAULT;
52
53 LLQuaternion(); // Initializes Quaternion to (0,0,0,1)
54 explicit LLQuaternion(const LLMatrix4 &mat); // Initializes Quaternion from Matrix4
55 explicit LLQuaternion(const LLMatrix3 &mat); // Initializes Quaternion from Matrix3
56 LLQuaternion(F32 x, F32 y, F32 z, F32 w); // Initializes Quaternion to normQuat(x, y, z, w)
57 LLQuaternion(F32 angle, const LLVector4 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec)
58 LLQuaternion(F32 angle, const LLVector3 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec)
59 LLQuaternion(const F32 *q); // Initializes Quaternion to normQuat(x, y, z, w)
60 LLQuaternion(const LLVector3 &x_axis,
61 const LLVector3 &y_axis,
62 const LLVector3 &z_axis); // Initializes Quaternion from Matrix3 = [x_axis ; y_axis ; z_axis]
63
64 BOOL isIdentity() const;
65 BOOL isNotIdentity() const;
66 BOOL isFinite() const; // checks to see if all values of LLQuaternion are finite
67 void quantize16(F32 lower, F32 upper); // changes the vector to reflect quatization
68 void quantize8(F32 lower, F32 upper); // changes the vector to reflect quatization
69 void loadIdentity(); // Loads the quaternion that represents the identity rotation
70 const LLQuaternion& setQuatInit(F32 x, F32 y, F32 z, F32 w); // Sets Quaternion to normQuat(x, y, z, w)
71 const LLQuaternion& setQuat(const LLQuaternion &quat); // Copies Quaternion
72 const LLQuaternion& setQuat(const F32 *q); // Sets Quaternion to normQuat(quat[VX], quat[VY], quat[VZ], quat[VW])
73 const LLQuaternion& setQuat(const LLMatrix3 &mat); // Sets Quaternion to mat2quat(mat)
74 const LLQuaternion& setQuat(const LLMatrix4 &mat); // Sets Quaternion to mat2quat(mat)
75 const LLQuaternion& setQuat(F32 angle, F32 x, F32 y, F32 z); // Sets Quaternion to axis_angle2quat(angle, x, y, z)
76 const LLQuaternion& setQuat(F32 angle, const LLVector3 &vec); // Sets Quaternion to axis_angle2quat(angle, vec)
77 const LLQuaternion& setQuat(F32 angle, const LLVector4 &vec); // Sets Quaternion to axis_angle2quat(angle, vec)
78 const LLQuaternion& setQuat(F32 roll, F32 pitch, F32 yaw); // Sets Quaternion to euler2quat(pitch, yaw, roll)
79
80 LLMatrix4 getMatrix4(void) const; // Returns the Matrix4 equivalent of Quaternion
81 LLMatrix3 getMatrix3(void) const; // Returns the Matrix3 equivalent of Quaternion
82 void getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const; // returns rotation in radians about axis x,y,z
83 void getAngleAxis(F32* angle, LLVector3 &vec) const;
84 void getEulerAngles(F32 *roll, F32* pitch, F32 *yaw) const;
85
86 F32 normQuat(); // Normalizes Quaternion and returns magnitude
87 const LLQuaternion& conjQuat(void); // Conjugates Quaternion and returns result
88
89 // Other useful methods
90 const LLQuaternion& transQuat(); // Transpose
91 void shortestArc(const LLVector3 &a, const LLVector3 &b); // shortest rotation from a to b
92 const LLQuaternion& constrain(F32 radians); // constrains rotation to a cone angle specified in radians
93
94 // Standard operators
95 friend std::ostream& operator<<(std::ostream &s, const LLQuaternion &a); // Prints a
96 friend LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b); // Addition
97 friend LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b); // Subtraction
98 friend LLQuaternion operator-(const LLQuaternion &a); // Negation
99 friend LLQuaternion operator*(F32 a, const LLQuaternion &q); // Scale
100 friend LLQuaternion operator*(const LLQuaternion &q, F32 b); // Scale
101 friend LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b); // Returns a * b
102 friend LLQuaternion operator~(const LLQuaternion &a); // Returns a* (Conjugate of a)
103 bool operator==(const LLQuaternion &b) const; // Returns a == b
104 bool operator!=(const LLQuaternion &b) const; // Returns a != b
105
106 friend const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b); // Returns a * b
107
108 friend LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot); // Rotates a by rot
109 friend LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot); // Rotates a by rot
110 friend LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot); // Rotates a by rot
111
112 // Non-standard operators
113 friend F32 dot(const LLQuaternion &a, const LLQuaternion &b);
114 friend LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // linear interpolation (t = 0 to 1) from p to q
115 friend LLQuaternion lerp(F32 t, const LLQuaternion &q); // linear interpolation (t = 0 to 1) from identity to q
116 friend LLQuaternion slerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // spherical linear interpolation from p to q
117 friend LLQuaternion slerp(F32 t, const LLQuaternion &q); // spherical linear interpolation from identity to q
118 friend LLQuaternion nlerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // normalized linear interpolation from p to q
119 friend LLQuaternion nlerp(F32 t, const LLQuaternion &q); // normalized linear interpolation from p to q
120
121 LLVector3 packToVector3() const; // Saves space by using the fact that our quaternions are normalized
122 void unpackFromVector3(const LLVector3& vec); // Saves space by using the fact that our quaternions are normalized
123
124 enum Order {
125 XYZ = 0,
126 YZX = 1,
127 ZXY = 2,
128 XZY = 3,
129 YXZ = 4,
130 ZYX = 5
131 };
132 // Creates a quaternions from maya's rotation representation,
133 // which is 3 rotations (in DEGREES) in the specified order
134 friend LLQuaternion mayaQ(F32 x, F32 y, F32 z, Order order);
135
136 // Conversions between Order and strings like "xyz" or "ZYX"
137 friend const char *OrderToString( const Order order );
138 friend Order StringToOrder( const char *str );
139
140 static BOOL parseQuat(const char* buf, LLQuaternion* value);
141
142 // For debugging, only
143 //static U32 mMultCount;
144};
145
146// checker
147inline BOOL LLQuaternion::isFinite() const
148{
149 return (llfinite(mQ[VX]) && llfinite(mQ[VY]) && llfinite(mQ[VZ]) && llfinite(mQ[VS]));
150}
151
152inline BOOL LLQuaternion::isIdentity() const
153{
154 return
155 ( mQ[VX] == 0.f ) &&
156 ( mQ[VY] == 0.f ) &&
157 ( mQ[VZ] == 0.f ) &&
158 ( mQ[VS] == 1.f );
159}
160
161inline BOOL LLQuaternion::isNotIdentity() const
162{
163 return
164 ( mQ[VX] != 0.f ) ||
165 ( mQ[VY] != 0.f ) ||
166 ( mQ[VZ] != 0.f ) ||
167 ( mQ[VS] != 1.f );
168}
169
170
171
172inline LLQuaternion::LLQuaternion(void)
173{
174 mQ[VX] = 0.f;
175 mQ[VY] = 0.f;
176 mQ[VZ] = 0.f;
177 mQ[VS] = 1.f;
178}
179
180inline LLQuaternion::LLQuaternion(F32 x, F32 y, F32 z, F32 w)
181{
182 mQ[VX] = x;
183 mQ[VY] = y;
184 mQ[VZ] = z;
185 mQ[VS] = w;
186
187 //RN: don't normalize this case as its used mainly for temporaries during calculations
188 //normQuat();
189 /*
190 F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
191 mag -= 1.f;
192 mag = fabs(mag);
193 llassert(mag < 10.f*FP_MAG_THRESHOLD);
194 */
195}
196
197inline LLQuaternion::LLQuaternion(const F32 *q)
198{
199 mQ[VX] = q[VX];
200 mQ[VY] = q[VY];
201 mQ[VZ] = q[VZ];
202 mQ[VS] = q[VW];
203
204 normQuat();
205 /*
206 F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
207 mag -= 1.f;
208 mag = fabs(mag);
209 llassert(mag < FP_MAG_THRESHOLD);
210 */
211}
212
213
214inline void LLQuaternion::loadIdentity()
215{
216 mQ[VX] = 0.0f;
217 mQ[VY] = 0.0f;
218 mQ[VZ] = 0.0f;
219 mQ[VW] = 1.0f;
220}
221
222
223inline const LLQuaternion& LLQuaternion::setQuatInit(F32 x, F32 y, F32 z, F32 w)
224{
225 mQ[VX] = x;
226 mQ[VY] = y;
227 mQ[VZ] = z;
228 mQ[VS] = w;
229 normQuat();
230 return (*this);
231}
232
233inline const LLQuaternion& LLQuaternion::setQuat(const LLQuaternion &quat)
234{
235 mQ[VX] = quat.mQ[VX];
236 mQ[VY] = quat.mQ[VY];
237 mQ[VZ] = quat.mQ[VZ];
238 mQ[VW] = quat.mQ[VW];
239 normQuat();
240 return (*this);
241}
242
243inline const LLQuaternion& LLQuaternion::setQuat(const F32 *q)
244{
245 mQ[VX] = q[VX];
246 mQ[VY] = q[VY];
247 mQ[VZ] = q[VZ];
248 mQ[VS] = q[VW];
249 normQuat();
250 return (*this);
251}
252
253// There may be a cheaper way that avoids the sqrt.
254// Does sin_a = VX*VX + VY*VY + VZ*VZ?
255// Copied from Matrix and Quaternion FAQ 1.12
256inline void LLQuaternion::getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const
257{
258 F32 cos_a = mQ[VW];
259 if (cos_a > 1.0f) cos_a = 1.0f;
260 if (cos_a < -1.0f) cos_a = -1.0f;
261
262 F32 sin_a = (F32) sqrt( 1.0f - cos_a * cos_a );
263
264 if ( fabs( sin_a ) < 0.0005f )
265 sin_a = 1.0f;
266 else
267 sin_a = 1.f/sin_a;
268
269 *angle = 2.0f * (F32) acos( cos_a );
270 *x = mQ[VX] * sin_a;
271 *y = mQ[VY] * sin_a;
272 *z = mQ[VZ] * sin_a;
273}
274
275inline const LLQuaternion& LLQuaternion::conjQuat()
276{
277 mQ[VX] *= -1.f;
278 mQ[VY] *= -1.f;
279 mQ[VZ] *= -1.f;
280 return (*this);
281}
282
283// Transpose
284inline const LLQuaternion& LLQuaternion::transQuat()
285{
286 mQ[VX] = -mQ[VX];
287 mQ[VY] = -mQ[VY];
288 mQ[VZ] = -mQ[VZ];
289 return *this;
290}
291
292
293inline LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b)
294{
295 return LLQuaternion(
296 a.mQ[VX] + b.mQ[VX],
297 a.mQ[VY] + b.mQ[VY],
298 a.mQ[VZ] + b.mQ[VZ],
299 a.mQ[VW] + b.mQ[VW] );
300}
301
302
303inline LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b)
304{
305 return LLQuaternion(
306 a.mQ[VX] - b.mQ[VX],
307 a.mQ[VY] - b.mQ[VY],
308 a.mQ[VZ] - b.mQ[VZ],
309 a.mQ[VW] - b.mQ[VW] );
310}
311
312
313inline LLQuaternion operator-(const LLQuaternion &a)
314{
315 return LLQuaternion(
316 -a.mQ[VX],
317 -a.mQ[VY],
318 -a.mQ[VZ],
319 -a.mQ[VW] );
320}
321
322
323inline LLQuaternion operator*(F32 a, const LLQuaternion &q)
324{
325 return LLQuaternion(
326 a * q.mQ[VX],
327 a * q.mQ[VY],
328 a * q.mQ[VZ],
329 a * q.mQ[VW] );
330}
331
332
333inline LLQuaternion operator*(const LLQuaternion &q, F32 a)
334{
335 return LLQuaternion(
336 a * q.mQ[VX],
337 a * q.mQ[VY],
338 a * q.mQ[VZ],
339 a * q.mQ[VW] );
340}
341
342inline LLQuaternion operator~(const LLQuaternion &a)
343{
344 LLQuaternion q(a);
345 q.conjQuat();
346 return q;
347}
348
349inline bool LLQuaternion::operator==(const LLQuaternion &b) const
350{
351 return ( (mQ[VX] == b.mQ[VX])
352 &&(mQ[VY] == b.mQ[VY])
353 &&(mQ[VZ] == b.mQ[VZ])
354 &&(mQ[VS] == b.mQ[VS]));
355}
356
357inline bool LLQuaternion::operator!=(const LLQuaternion &b) const
358{
359 return ( (mQ[VX] != b.mQ[VX])
360 ||(mQ[VY] != b.mQ[VY])
361 ||(mQ[VZ] != b.mQ[VZ])
362 ||(mQ[VS] != b.mQ[VS]));
363}
364
365inline const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b)
366{
367#if 1
368 LLQuaternion q(
369 b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1],
370 b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2],
371 b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0],
372 b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2]
373 );
374 a = q;
375#else
376 a = a * b;
377#endif
378 return a;
379}
380
381inline F32 LLQuaternion::normQuat()
382{
383 F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
384
385 if (mag > FP_MAG_THRESHOLD)
386 {
387 F32 oomag = 1.f/mag;
388 mQ[VX] *= oomag;
389 mQ[VY] *= oomag;
390 mQ[VZ] *= oomag;
391 mQ[VS] *= oomag;
392 }
393 else
394 {
395 mQ[VX] = 0.f;
396 mQ[VY] = 0.f;
397 mQ[VZ] = 0.f;
398 mQ[VS] = 1.f;
399 }
400
401 return mag;
402}
403
404LLQuaternion::Order StringToOrder( const char *str );
405
406// Some notes about Quaternions
407
408// What is a Quaternion?
409// ---------------------
410// A quaternion is a point in 4-dimensional complex space.
411// Q = { Qx, Qy, Qz, Qw }
412//
413//
414// Why Quaternions?
415// ----------------
416// The set of quaternions that make up the the 4-D unit sphere
417// can be mapped to the set of all rotations in 3-D space. Sometimes
418// it is easier to describe/manipulate rotations in quaternion space
419// than rotation-matrix space.
420//
421//
422// How Quaternions?
423// ----------------
424// In order to take advantage of quaternions we need to know how to
425// go from rotation-matricies to quaternions and back. We also have
426// to agree what variety of rotations we're generating.
427//
428// Consider the equation... v' = v * R
429//
430// There are two ways to think about rotations of vectors.
431// 1) v' is the same vector in a different reference frame
432// 2) v' is a new vector in the same reference frame
433//
434// bookmark -- which way are we using?
435//
436//
437// Quaternion from Angle-Axis:
438// ---------------------------
439// Suppose we wanted to represent a rotation of some angle (theta)
440// about some axis ({Ax, Ay, Az})...
441//
442// axis of rotation = {Ax, Ay, Az}
443// angle_of_rotation = theta
444//
445// s = sin(0.5 * theta)
446// c = cos(0.5 * theta)
447// Q = { s * Ax, s * Ay, s * Az, c }
448//
449//
450// 3x3 Matrix from Quaternion
451// --------------------------
452//
453// | |
454// | 1 - 2 * (y^2 + z^2) 2 * (x * y + z * w) 2 * (y * w - x * z) |
455// | |
456// M = | 2 * (x * y - z * w) 1 - 2 * (x^2 + z^2) 2 * (y * z + x * w) |
457// | |
458// | 2 * (x * z + y * w) 2 * (y * z - x * w) 1 - 2 * (x^2 + y^2) |
459// | |
460
461#endif
diff --git a/linden/indra/llmath/llrand.cpp b/linden/indra/llmath/llrand.cpp
new file mode 100644
index 0000000..38e0639
--- /dev/null
+++ b/linden/indra/llmath/llrand.cpp
@@ -0,0 +1,74 @@
1/**
2 * @file llrand.cpp
3 * @brief a few useful math functions.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llrand.h"
31#include "lluuid.h"
32
33/* Put this back if you re-enabled slamFPCW
34#if LL_WINDOWS
35#include <float.h>
36#else
37#include <stdlib.h>
38#endif
39*/
40
41void slamFPCW( void )
42{
43/*
44#if LL_WINDOWS
45 // for Intel based CPUs, slam the FP control word directly
46 WORD wTemp, wSave;
47
48 __asm fstcw wSave
49 if ( (wSave & 0x300) // Not single mode
50 ||(0x3f != (wSave & 0x3f)) // Exceptions enabled
51 ||(wSave & 0xC00)) // Not round to nearest mode
52 {
53 __asm
54 {
55 mov ax, wSave
56 and ax, not 300h ;; single mode
57 or ax, 3fh ;; disable all exceptions
58 and ax, not 0xC00 ;; round to nearest mode
59 mov wTemp, ax
60 fldcw wTemp
61 }
62 }
63#endif
64*/
65}
66
67LLRand gLindenLabRandomNumber(LLUUID::getRandomSeed());
68
69F32 frand(F32 val)
70{
71// return (val * (F32)rand()/(F32)RAND_MAX);
72 return gLindenLabRandomNumber.llfrand(val);
73}
74
diff --git a/linden/indra/llmath/llrand.h b/linden/indra/llmath/llrand.h
new file mode 100644
index 0000000..db9f353
--- /dev/null
+++ b/linden/indra/llmath/llrand.h
@@ -0,0 +1,88 @@
1/**
2 * @file llrand.h
3 * @brief Some useful math functions.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLRAND_H
29#define LL_LLRAND_H
30
31// As long as you #include "llviewerprecompiledheaders.h",
32// you can use "gLindenLabRandomNumber.llfrand( range );" which returns a
33// random number F32 ranging from 0.0f to range.
34// -Ventrella - Sept 30, 2005
35
36// Slams Intel processors into Single Precision FP mode
37// (which is not any faster on modern hardware)
38void slamFPCW( void );
39
40class LLRand
41{
42public:
43 LLRand(U32 seed) : mSeed(seed) {}
44 ~LLRand() {}
45
46 void seed(U32 seed) { mSeed = seed; }
47
48 U32 llrand()
49 {
50 mSeed = U64L(1664525) * mSeed + U64L(1013904223);
51 return (U32)mSeed;
52 }
53
54 U32 llrand(U32 val)
55 {
56 mSeed = U64L(1664525) * mSeed + U64L(1013904223);
57 return (U32)(mSeed) % val;
58 }
59
60 // val is the maximum
61 F32 llfrand(F32 val)
62 {
63 const U32 FP_ONE = 0x3f800000;
64 const U32 FP_MASK = 0x007fffff;
65 U32 ir = llrand();
66
67 ir = FP_ONE | (FP_MASK & ir);
68
69 // generate random float
70 F32 fr = (*(F32 *)&ir);
71
72 // correct to [0..1)
73 fr -= 1.f;
74
75 fr *= val;
76
77 return fr;
78 }
79
80public:
81 U64 mSeed;
82};
83
84F32 frand(F32 val);
85
86extern LLRand gLindenLabRandomNumber;
87
88#endif
diff --git a/linden/indra/llmath/llrect.cpp b/linden/indra/llmath/llrect.cpp
new file mode 100644
index 0000000..390573e
--- /dev/null
+++ b/linden/indra/llmath/llrect.cpp
@@ -0,0 +1,29 @@
1/**
2 * @file llrect.cpp
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "llrect.h"
diff --git a/linden/indra/llmath/llrect.h b/linden/indra/llmath/llrect.h
new file mode 100644
index 0000000..fd45d3c
--- /dev/null
+++ b/linden/indra/llmath/llrect.h
@@ -0,0 +1,289 @@
1/**
2 * @file llrect.h
3 * @brief A rectangle in GL coordinates, with bottom,left = 0,0
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28
29#ifndef LL_LLRECT_H
30#define LL_LLRECT_H
31
32#include <iostream>
33#include "llmath.h"
34#include "llsd.h"
35
36// Top > Bottom due to GL coords
37template <class Type> class LLRectBase
38{
39public:
40 Type mLeft;
41 Type mTop;
42 Type mRight;
43 Type mBottom;
44
45 // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
46 Type getWidth() const { return mRight - mLeft; }
47 Type getHeight() const { return mTop - mBottom; }
48 Type getCenterX() const { return (mLeft + mRight) / 2; }
49 Type getCenterY() const { return (mTop + mBottom) / 2; }
50
51 LLRectBase(): mLeft(0), mTop(0), mRight(0), mBottom(0)
52 {}
53
54 LLRectBase(const LLRectBase &r):
55 mLeft(r.mLeft), mTop(r.mTop), mRight(r.mRight), mBottom(r.mBottom)
56 {}
57
58 LLRectBase(Type left, Type top, Type right, Type bottom):
59 mLeft(left), mTop(top), mRight(right), mBottom(bottom)
60 {}
61
62 LLRectBase(const LLSD& sd)
63 {
64 setValue(sd);
65 }
66
67 const LLRectBase& operator=(const LLSD& sd)
68 {
69 setValue(sd);
70 return *this;
71 }
72
73 void setValue(const LLSD& sd)
74 {
75 mLeft = sd[0].asInteger();
76 mTop = sd[1].asInteger();
77 mRight = sd[2].asInteger();
78 mBottom = sd[3].asInteger();
79 }
80
81 LLSD getValue() const
82 {
83 LLSD ret;
84 ret[0] = mLeft;
85 ret[1] = mTop;
86 ret[2] = mRight;
87 ret[3] = mBottom;
88 return ret;
89 }
90
91 // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
92 BOOL pointInRect(const Type x, const Type y) const
93 {
94 return mLeft <= x && x < mRight &&
95 mBottom <= y && y < mTop;
96 }
97
98 //// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
99 BOOL localPointInRect(const Type x, const Type y) const
100 {
101 return 0 <= x && x < getWidth() &&
102 0 <= y && y < getHeight();
103 }
104
105 void clampPointToRect(Type& x, Type& y)
106 {
107 x = llclamp(x, mLeft, mRight);
108 y = llclamp(y, mBottom, mTop);
109 }
110
111 void clipPointToRect(const Type start_x, const Type start_y, Type& end_x, Type& end_y)
112 {
113 if (!pointInRect(start_x, start_y))
114 {
115 return;
116 }
117 Type clip_x = 0;
118 Type clip_y = 0;
119 Type delta_x = end_x - start_x;
120 Type delta_y = end_y - start_y;
121 if (end_x > mRight) clip_x = end_x - mRight;
122 if (end_x < mLeft) clip_x = end_x - mLeft;
123 if (end_y > mTop) clip_y = end_y - mTop;
124 if (end_y < mBottom) clip_y = end_y - mBottom;
125 // clip_? and delta_? should have same sign, since starting point is in rect
126 // so ratios will be positive
127 F32 ratio_x = ((F32)clip_x / (F32)delta_x);
128 F32 ratio_y = ((F32)clip_y / (F32)delta_y);
129 if (ratio_x > ratio_y)
130 {
131 // clip along x direction
132 end_x -= (Type)(clip_x);
133 end_y -= (Type)(delta_y * ratio_x);
134 }
135 else
136 {
137 // clip along y direction
138 end_x -= (Type)(delta_x * ratio_y);
139 end_y -= (Type)clip_y;
140 }
141 }
142
143 // Note: Does NOT follow GL_QUAD conventions: the top and right edges ARE considered part of the rect
144 // returns TRUE if any part of rect is is inside this LLRect
145 BOOL rectInRect(const LLRectBase* rect) const
146 {
147 return mLeft <= rect->mRight && rect->mLeft <= mRight &&
148 mBottom <= rect->mTop && rect->mBottom <= mTop ;
149 }
150
151 void set(Type left, Type top, Type right, Type bottom)
152 {
153 mLeft = left;
154 mTop = top;
155 mRight = right;
156 mBottom = bottom;
157 }
158
159 // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
160 void setOriginAndSize( Type left, Type bottom, Type width, Type height)
161 {
162 mLeft = left;
163 mTop = bottom + height;
164 mRight = left + width;
165 mBottom = bottom;
166 }
167
168 // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
169 void setLeftTopAndSize( Type left, Type top, Type width, Type height)
170 {
171 mLeft = left;
172 mTop = top;
173 mRight = left + width;
174 mBottom = top - height;
175 }
176
177 void setCenterAndSize(Type x, Type y, Type width, Type height)
178 {
179 mLeft = x - width/2;
180 mTop = y + height/2;
181 mRight = x + width/2;
182 mBottom = y - height/2;
183 }
184
185
186 void translate(Type horiz, Type vertical)
187 {
188 mLeft += horiz;
189 mRight += horiz;
190 mTop += vertical;
191 mBottom += vertical;
192 }
193
194 void stretch( Type dx, Type dy)
195 {
196 mLeft -= dx;
197 mRight += dx;
198 mTop += dy;
199 mBottom -= dy;
200 makeValid();
201 }
202
203 void stretch( Type delta )
204 {
205 stretch(delta, delta);
206
207 }
208
209 void makeValid()
210 {
211 mLeft = llmin(mLeft, mRight);
212 mBottom = llmin(mBottom, mTop);
213 }
214
215 friend const LLRectBase& operator|=(LLRectBase &a, const LLRectBase &b) // Return rect including a & b
216 {
217 a.mLeft = llmin(a.mLeft, b.mLeft);
218 a.mRight = llmax(a.mRight, b.mRight);
219 a.mBottom = llmin(a.mBottom, b.mBottom);
220 a.mTop = llmax(a.mTop, b.mTop);
221 return a;
222 }
223
224 friend LLRectBase operator|(const LLRectBase &a, const LLRectBase &b) // Return rect including a & b
225 {
226 LLRectBase<Type> result;
227 result.mLeft = llmin(a.mLeft, b.mLeft);
228 result.mRight = llmax(a.mRight, b.mRight);
229 result.mBottom = llmin(a.mBottom, b.mBottom);
230 result.mTop = llmax(a.mTop, b.mTop);
231 return result;
232 }
233
234 friend const LLRectBase& operator&=(LLRectBase &a, const LLRectBase &b) // set a to rect where a intersects b
235 {
236 a.mLeft = llmax(a.mLeft, b.mLeft);
237 a.mRight = llmin(a.mRight, b.mRight);
238 a.mBottom = llmax(a.mBottom, b.mBottom);
239 a.mTop = llmin(a.mTop, b.mTop);
240 if (a.mLeft > a.mRight)
241 {
242 a.mLeft = a.mRight;
243 }
244 if (a.mBottom > a.mTop)
245 {
246 a.mBottom = a.mTop;
247 }
248 return a;
249 }
250
251 friend LLRectBase operator&(const LLRectBase &a, const LLRectBase &b) // Return rect where a intersects b
252 {
253 LLRectBase result = a;
254 result &= b;
255 return result;
256 }
257
258 friend std::ostream &operator<<(std::ostream &s, const LLRectBase &rect)
259 {
260 s << "{ L " << rect.mLeft << " B " << rect.mBottom
261 << " W " << rect.getWidth() << " H " << rect.getHeight() << " }";
262 return s;
263 }
264
265 bool operator==(const LLRectBase &b)
266 {
267 return ((mLeft == b.mLeft) &&
268 (mTop == b.mTop) &&
269 (mRight == b.mRight) &&
270 (mBottom == b.mBottom));
271 }
272
273 bool operator!=(const LLRectBase &b)
274 {
275 return ((mLeft != b.mLeft) ||
276 (mTop != b.mTop) ||
277 (mRight != b.mRight) ||
278 (mBottom != b.mBottom));
279 }
280
281 static LLRectBase<Type> null;
282};
283
284template <class Type> LLRectBase<Type> LLRectBase<Type>::null(0,0,0,0);
285
286typedef LLRectBase<S32> LLRect;
287typedef LLRectBase<F32> LLRectf;
288
289#endif
diff --git a/linden/indra/llmath/lltreenode.h b/linden/indra/llmath/lltreenode.h
new file mode 100644
index 0000000..78ff759
--- /dev/null
+++ b/linden/indra/llmath/lltreenode.h
@@ -0,0 +1,180 @@
1/**
2 * @file lltreenode.h
3 *
4 * Copyright (c) 2005-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_LLTREENODE_H
28#define LL_LLTREENODE_H
29
30#include "stdtypes.h"
31#include "xform.h"
32#include <vector>
33
34template <class T> class LLTreeNode;
35template <class T> class LLTreeTraveler;
36template <class T> class LLTreeListener;
37
38template <class T>
39class LLTreeState
40{
41public:
42 LLTreeState(LLTreeNode<T>* node) { setNode(node); }
43 virtual ~LLTreeState() { };
44
45 virtual bool insert(T* data) = 0;
46 virtual bool remove(T* data) = 0;
47 virtual void setNode(LLTreeNode<T>* node);
48 virtual const LLTreeNode<T>* getNode() const { return mNode; }
49 virtual LLTreeNode<T>* getNode() { return mNode; }
50 virtual void accept(LLTreeTraveler<T>* traveler) const = 0;
51 virtual LLTreeListener<T>* getListener(U32 index) const;
52private:
53 LLTreeNode<T>* mNode;
54};
55
56template <class T>
57class LLTreeListener
58{
59public:
60 virtual ~LLTreeListener() { };
61 virtual void handleInsertion(const LLTreeNode<T>* node, T* data) = 0;
62 virtual void handleRemoval(const LLTreeNode<T>* node, T* data) = 0;
63 virtual void handleDestruction(const LLTreeNode<T>* node) = 0;
64 virtual void handleStateChange(const LLTreeNode<T>* node) = 0;
65};
66
67template <class T>
68class LLTreeNode
69{
70public:
71 LLTreeNode(LLTreeState<T>* state) { setState(state); }
72 virtual ~LLTreeNode();
73 virtual LLTreeState<T>* getState() { return mState; }
74 virtual const LLTreeState<T>* getState() const { return mState; }
75
76 virtual void setState(LLTreeState<T>* state);
77 virtual void insert(T* data);
78 virtual bool remove(T* data);
79 virtual void notifyRemoval(T* data);
80 virtual U32 getListenerCount() { return mListeners.size(); }
81 virtual LLTreeListener<T>* getListener(U32 index) const { return mListeners[index]; }
82 virtual void addListener(LLTreeListener<T>* listener) { mListeners.push_back(listener); }
83 virtual void removeListener(U32 index) { mListeners.erase(mListeners.begin()+index); }
84
85protected:
86 void destroyListeners()
87 {
88 for (U32 i = 0; i < mListeners.size(); i++)
89 {
90 mListeners[i]->handleDestruction(this);
91 }
92 mListeners.clear();
93 }
94
95 LLTreeState<T>* mState;
96public:
97 std::vector<LLTreeListener<T>*> mListeners;
98};
99
100template <class T>
101class LLTreeTraveler
102{
103public:
104 virtual ~LLTreeTraveler() { };
105 virtual void traverse(const LLTreeNode<T>* node) = 0;
106 virtual void visit(const LLTreeState<T>* state) = 0;
107};
108
109template <class T>
110LLTreeNode<T>::~LLTreeNode()
111{
112 destroyListeners();
113};
114
115template <class T>
116void LLTreeNode<T>::insert(T* data)
117{
118 if (mState->insert(data))
119 {
120 for (U32 i = 0; i < mListeners.size(); i++)
121 {
122 mListeners[i]->handleInsertion(this, data);
123 }
124 }
125};
126
127template <class T>
128bool LLTreeNode<T>::remove(T* data)
129{
130 if (mState->remove(data))
131 {
132 return true;
133 }
134 return false;
135};
136
137template <class T>
138void LLTreeNode<T>::notifyRemoval(T* data)
139{
140 for (U32 i = 0; i < mListeners.size(); i++)
141 {
142 mListeners[i]->handleRemoval(this, data);
143 }
144}
145
146template <class T>
147void LLTreeNode<T>::setState(LLTreeState<T>* state)
148{
149 mState = state;
150 if (state)
151 {
152 if (state->getNode() != this)
153 {
154 state->setNode(this);
155 }
156
157 for (U32 i = 0; i < mListeners.size(); i++)
158 {
159 mListeners[i]->handleStateChange(this);
160 }
161 }
162};
163
164template <class T>
165void LLTreeState<T>::setNode(LLTreeNode<T>* node)
166{
167 mNode = node;
168 if (node && node->getState() != this)
169 {
170 node->setState(this);
171 }
172};
173
174template <class T>
175LLTreeListener<T>* LLTreeState<T>::getListener(U32 index) const
176{
177 return mNode->getListener(index);
178}
179
180#endif
diff --git a/linden/indra/llmath/lluuid.cpp b/linden/indra/llmath/lluuid.cpp
new file mode 100644
index 0000000..216dac9
--- /dev/null
+++ b/linden/indra/llmath/lluuid.cpp
@@ -0,0 +1,864 @@
1/**
2 * @file lluuid.cpp
3 *
4 * Copyright (c) 2000-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
30#if LL_WINDOWS
31# undef WIN32_LEAN_AND_MEAN
32# include <winsock2.h>
33# include <windows.h>
34#endif
35
36#include "stdtypes.h"
37#include "lldefs.h"
38#include "llerror.h"
39
40#include "lluuid.h"
41#include "llerror.h"
42#include "llrand.h"
43#include "llmd5.h"
44#include "llstring.h"
45#include "lltimer.h"
46
47const LLUUID LLUUID::null;
48const LLTransactionID LLTransactionID::tnull;
49
50/*
51
52NOT DONE YET!!!
53
54static char BASE85_TABLE[] = {
55 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
56 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
57 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
58 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
59 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
60 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
61 'y', 'z', '!', '#', '$', '%', '&', '(', ')', '*',
62 '+', '-', ';', '[', '=', '>', '?', '@', '^', '_',
63 '`', '{', '|', '}', '~', '\0'
64};
65
66
67void encode( char * fiveChars, unsigned int word ) throw( )
68{
69for( int ix = 0; ix < 5; ++ix ) {
70fiveChars[4-ix] = encodeTable[ word % 85];
71word /= 85;
72}
73}
74
75To decode:
76unsigned int decode( char const * fiveChars ) throw( bad_input_data )
77{
78unsigned int ret = 0;
79for( int ix = 0; ix < 5; ++ix ) {
80char * s = strchr( encodeTable, fiveChars[ ix ] );
81if( s == 0 ) throw bad_input_data();
82ret = ret * 85 + (s-encodeTable);
83}
84return ret;
85}
86
87void LLUUID::toBase85(char* out)
88{
89 U32* me = (U32*)&(mData[0]);
90 for(S32 i = 0; i < 4; ++i)
91 {
92 char* o = &out[i*i];
93 for(S32 j = 0; j < 5; ++j)
94 {
95 o[4-j] = BASE85_TABLE[ me[i] % 85];
96 word /= 85;
97 }
98 }
99}
100
101unsigned int decode( char const * fiveChars ) throw( bad_input_data )
102{
103 unsigned int ret = 0;
104 for( S32 ix = 0; ix < 5; ++ix )
105 {
106 char * s = strchr( encodeTable, fiveChars[ ix ] );
107 ret = ret * 85 + (s-encodeTable);
108 }
109 return ret;
110}
111*/
112
113
114// Common to all UUID implementations
115void LLUUID::toString(char *out) const
116{
117 sprintf(out,
118 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
119 (U8)(mData[0]),
120 (U8)(mData[1]),
121 (U8)(mData[2]),
122 (U8)(mData[3]),
123 (U8)(mData[4]),
124 (U8)(mData[5]),
125 (U8)(mData[6]),
126 (U8)(mData[7]),
127 (U8)(mData[8]),
128 (U8)(mData[9]),
129 (U8)(mData[10]),
130 (U8)(mData[11]),
131 (U8)(mData[12]),
132 (U8)(mData[13]),
133 (U8)(mData[14]),
134 (U8)(mData[15]));
135}
136
137void LLUUID::toCompressedString(char *out) const
138{
139 memcpy(out, mData, UUID_BYTES);
140 out[UUID_BYTES] = '\0';
141}
142
143LLString LLUUID::getString() const
144{
145 char str[UUID_STR_SIZE];
146 toString(str);
147 return LLString(str);
148}
149
150BOOL LLUUID::set(const std::string& in_string, BOOL emit)
151{
152 return set(in_string.c_str(), emit);
153}
154
155BOOL LLUUID::set(const char *in_string, BOOL emit)
156{
157 BOOL broken_format = FALSE;
158 if (!in_string)
159 {
160 llerrs << "No string pointer in LLUUID::set!" << llendl;
161 setNull();
162 return FALSE;
163 }
164
165 // empty strings should make NULL uuid
166 if (!in_string[0])
167 {
168 setNull();
169 return TRUE;
170 }
171
172 if (strlen(in_string) != (UUID_STR_LENGTH - 1))
173 {
174 // I'm a moron. First implementation didn't have the right UUID format.
175 // Shouldn't see any of these any more
176 if (strlen(in_string) == (UUID_STR_LENGTH - 2))
177 {
178 if(emit)
179 {
180 llinfos << "Warning! Using broken UUID string format" << llendl;
181 }
182 broken_format = TRUE;
183 }
184 else
185 {
186 // Bad UUID string. Spam as INFO, as most cases we don't care.
187 if(emit)
188 {
189 llinfos << "Bad UUID string: " << in_string << llendl;
190 }
191 setNull();
192 return FALSE;
193 }
194 }
195
196 U8 cur_pos = 0;
197 S32 i;
198 for (i = 0; i < UUID_BYTES; i++)
199 {
200 if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
201 {
202 cur_pos++;
203 if (broken_format && (i==10))
204 {
205 // Missing - in the broken format
206 cur_pos--;
207 }
208 }
209
210 mData[i] = 0;
211
212 if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9'))
213 {
214 mData[i] += (U8)(*(in_string + cur_pos) - '0');
215 }
216 else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f'))
217 {
218 mData[i] += (U8)(10 + *(in_string + cur_pos) - 'a');
219 }
220 else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F'))
221 {
222 mData[i] += (U8)(10 + *(in_string + cur_pos) - 'A');
223 }
224 else
225 {
226 if(emit)
227 {
228 llwarns << "Invalid UUID string character" << llendl;
229 }
230 setNull();
231 return FALSE;
232 }
233
234 mData[i] = mData[i] << 4;
235 cur_pos++;
236
237 if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9'))
238 {
239 mData[i] += (U8)(*(in_string + cur_pos) - '0');
240 }
241 else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f'))
242 {
243 mData[i] += (U8)(10 + *(in_string + cur_pos) - 'a');
244 }
245 else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F'))
246 {
247 mData[i] += (U8)(10 + *(in_string + cur_pos) - 'A');
248 }
249 else
250 {
251 if(emit)
252 {
253 llwarns << "Invalid UUID string character" << llendl;
254 }
255 setNull();
256 return FALSE;
257 }
258 cur_pos++;
259 }
260
261 return TRUE;
262}
263
264BOOL LLUUID::validate(const std::string& in_string)
265{
266 return validate(in_string.c_str());
267}
268
269BOOL LLUUID::validate(const char *in_string)
270{
271 BOOL broken_format = FALSE;
272 if (!in_string)
273 {
274 return FALSE;
275 }
276 if (strlen(in_string) != (UUID_STR_LENGTH - 1))
277 {
278 // I'm a moron. First implementation didn't have the right UUID format.
279 if (strlen(in_string) == (UUID_STR_LENGTH - 2))
280 {
281 broken_format = TRUE;
282 }
283 else
284 {
285 return FALSE;
286 }
287 }
288
289 U8 cur_pos = 0;
290 U32 i;
291 for (i = 0; i < 16; i++)
292 {
293 if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
294 {
295 cur_pos++;
296 if (broken_format && (i==10))
297 {
298 // Missing - in the broken format
299 cur_pos--;
300 }
301 }
302
303 if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9'))
304 {
305 }
306 else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f'))
307 {
308 }
309 else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F'))
310 {
311 }
312 else
313 {
314 return FALSE;
315 }
316
317 cur_pos++;
318
319 if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9'))
320 {
321 }
322 else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f'))
323 {
324 }
325 else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F'))
326 {
327 }
328 else
329 {
330 return FALSE;
331 }
332 cur_pos++;
333 }
334 return TRUE;
335}
336
337const LLUUID& LLUUID::operator^=(const LLUUID& rhs)
338{
339 U32* me = (U32*)&(mData[0]);
340 const U32* other = (U32*)&(rhs.mData[0]);
341 for(S32 i = 0; i < 4; ++i)
342 {
343 me[i] = me[i] ^ other[i];
344 }
345 return *this;
346}
347
348LLUUID LLUUID::operator^(const LLUUID& rhs) const
349{
350 LLUUID id(*this);
351 id ^= rhs;
352 return id;
353}
354
355void LLUUID::combine(const LLUUID& other, LLUUID& result) const
356{
357 LLMD5 md5_uuid;
358 md5_uuid.update((unsigned char*)mData, 16);
359 md5_uuid.update((unsigned char*)other.mData, 16);
360 md5_uuid.finalize();
361 md5_uuid.raw_digest(result.mData);
362}
363
364LLUUID LLUUID::combine(const LLUUID &other) const
365{
366 LLUUID combination;
367 combine(other, combination);
368 return combination;
369}
370
371std::ostream& operator<<(std::ostream& s, const LLUUID &uuid)
372{
373 char uuid_str[UUID_STR_LENGTH];
374
375 uuid.toString(uuid_str);
376 s << uuid_str;
377 return s;
378}
379
380std::istream& operator>>(std::istream &s, LLUUID &uuid)
381{
382 U32 i;
383 char uuid_str[UUID_STR_LENGTH];
384 for (i = 0; i < UUID_STR_LENGTH-1; i++)
385 {
386 s >> uuid_str[i];
387 }
388 uuid_str[i] = '\0';
389 uuid.set(uuid_str);
390 return s;
391}
392
393static void get_random_bytes(void *buf, int nbytes)
394{
395 int i;
396 char *cp = (char *) buf;
397
398 for (i=0; i < nbytes; i++)
399 *cp++ = gLindenLabRandomNumber.llrand() & 0xFF;
400 return;
401}
402
403#if LL_WINDOWS
404typedef struct _ASTAT_
405{
406 ADAPTER_STATUS adapt;
407 NAME_BUFFER NameBuff [30];
408}ASTAT, * PASTAT;
409
410// static
411S32 LLUUID::getNodeID(unsigned char * node_id)
412{
413 ASTAT Adapter;
414 NCB Ncb;
415 UCHAR uRetCode;
416 LANA_ENUM lenum;
417 int i;
418 int retval = 0;
419
420 memset( &Ncb, 0, sizeof(Ncb) );
421 Ncb.ncb_command = NCBENUM;
422 Ncb.ncb_buffer = (UCHAR *)&lenum;
423 Ncb.ncb_length = sizeof(lenum);
424 uRetCode = Netbios( &Ncb );
425 // printf( "The NCBENUM return code is: 0x%x \n", uRetCode );
426
427 for(i=0; i < lenum.length ;i++)
428 {
429 memset( &Ncb, 0, sizeof(Ncb) );
430 Ncb.ncb_command = NCBRESET;
431 Ncb.ncb_lana_num = lenum.lana[i];
432
433 uRetCode = Netbios( &Ncb );
434 // printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
435 // lenum.lana[i], uRetCode );
436
437 memset( &Ncb, 0, sizeof (Ncb) );
438 Ncb.ncb_command = NCBASTAT;
439 Ncb.ncb_lana_num = lenum.lana[i];
440
441 strcpy( (char *)Ncb.ncb_callname, "* " );
442 Ncb.ncb_buffer = (unsigned char *)&Adapter;
443 Ncb.ncb_length = sizeof(Adapter);
444
445 uRetCode = Netbios( &Ncb );
446// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
447// lenum.lana[i], uRetCode );
448 if ( uRetCode == 0 )
449 {
450// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n",
451// lenum.lana[i],
452// Adapter.adapt.adapter_address[0],
453// Adapter.adapt.adapter_address[1],
454// Adapter.adapt.adapter_address[2],
455// Adapter.adapt.adapter_address[3],
456// Adapter.adapt.adapter_address[4],
457// Adapter.adapt.adapter_address[5] );
458 memcpy(node_id,Adapter.adapt.adapter_address,6);
459 retval = 1;
460
461 }
462 }
463 return retval;
464}
465
466#elif LL_DARWIN
467// Mac OS X version of the UUID generation code...
468/*
469 * Get an ethernet hardware address, if we can find it...
470 */
471#include <stdio.h>
472#include <stdlib.h>
473#include <unistd.h>
474#include <sys/types.h>
475#include <sys/time.h>
476#include <sys/socket.h>
477#include <sys/ioctl.h>
478#include <net/if.h>
479#include <net/if_types.h>
480#include <net/if_dl.h>
481#include <net/route.h>
482#include <ifaddrs.h>
483
484// static
485S32 LLUUID::getNodeID(unsigned char *node_id)
486{
487 int i;
488 unsigned char *a = NULL;
489 struct ifaddrs *ifap, *ifa;
490 int rv;
491 S32 result = 0;
492
493 if ((rv=getifaddrs(&ifap))==-1)
494 {
495 return -1;
496 }
497 if (ifap == NULL)
498 {
499 return -1;
500 }
501
502 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
503 {
504// printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family);
505 for(i=0; i< ifa->ifa_addr->sa_len; i++)
506 {
507// printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]);
508 }
509// printf("\n");
510
511 if(ifa->ifa_addr->sa_family == AF_LINK)
512 {
513 // This is a link-level address
514 struct sockaddr_dl *lla = (struct sockaddr_dl *)ifa->ifa_addr;
515
516// printf("\tLink level address, type %02X\n", lla->sdl_type);
517
518 if(lla->sdl_type == IFT_ETHER)
519 {
520 // Use the first ethernet MAC in the list.
521 // For some reason, the macro LLADDR() defined in net/if_dl.h doesn't expand correctly. This is what it would do.
522 a = (unsigned char *)&((lla)->sdl_data);
523 a += (lla)->sdl_nlen;
524
525 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
526 {
527 continue;
528 }
529
530 if (node_id)
531 {
532 memcpy(node_id, a, 6);
533 result = 1;
534 }
535
536 // We found one.
537 break;
538 }
539 }
540 }
541 freeifaddrs(ifap);
542
543 return result;
544}
545
546#else
547
548// Linux version of the UUID generation code...
549/*
550 * Get the ethernet hardware address, if we can find it...
551 */
552#include <unistd.h>
553#include <stdlib.h>
554#include <string.h>
555#include <fcntl.h>
556#include <errno.h>
557#include <time.h>
558#include <sys/types.h>
559#include <sys/time.h>
560#include <sys/stat.h>
561#include <sys/file.h>
562#include <sys/ioctl.h>
563#include <sys/socket.h>
564#include <net/if.h>
565#define HAVE_NETINET_IN_H
566#ifdef HAVE_NETINET_IN_H
567#include <netinet/in.h>
568#if !LL_DARWIN
569#include <linux/sockios.h>
570#endif
571#endif
572
573// static
574S32 LLUUID::getNodeID(unsigned char *node_id)
575{
576 int sd;
577 struct ifreq ifr, *ifrp;
578 struct ifconf ifc;
579 char buf[1024];
580 int n, i;
581 unsigned char *a;
582
583/*
584 * BSD 4.4 defines the size of an ifreq to be
585 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
586 * However, under earlier systems, sa_len isn't present, so the size is
587 * just sizeof(struct ifreq)
588 */
589#ifdef HAVE_SA_LEN
590#ifndef max
591#define max(a,b) ((a) > (b) ? (a) : (b))
592#endif
593#define ifreq_size(i) max(sizeof(struct ifreq),\
594 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
595#else
596#define ifreq_size(i) sizeof(struct ifreq)
597#endif /* HAVE_SA_LEN*/
598
599 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
600 if (sd < 0) {
601 return -1;
602 }
603 memset(buf, 0, sizeof(buf));
604 ifc.ifc_len = sizeof(buf);
605 ifc.ifc_buf = buf;
606 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
607 close(sd);
608 return -1;
609 }
610 n = ifc.ifc_len;
611 for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
612 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
613 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
614#ifdef SIOCGIFHWADDR
615 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
616 continue;
617 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
618#else
619#ifdef SIOCGENADDR
620 if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
621 continue;
622 a = (unsigned char *) ifr.ifr_enaddr;
623#else
624 /*
625 * XXX we don't have a way of getting the hardware
626 * address
627 */
628 close(sd);
629 return 0;
630#endif /* SIOCGENADDR */
631#endif /* SIOCGIFHWADDR */
632 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
633 continue;
634 if (node_id) {
635 memcpy(node_id, a, 6);
636 close(sd);
637 return 1;
638 }
639 }
640 close(sd);
641 return 0;
642}
643
644#endif
645
646S32 LLUUID::cmpTime(uuid_time_t *t1, uuid_time_t *t2)
647{
648 // Compare two time values.
649
650 if (t1->high < t2->high) return -1;
651 if (t1->high > t2->high) return 1;
652 if (t1->low < t2->low) return -1;
653 if (t1->low > t2->low) return 1;
654 return 0;
655}
656
657void LLUUID::getSystemTime(uuid_time_t *timestamp)
658{
659 // Get system time with 100ns precision. Time is since Oct 15, 1582.
660#if LL_WINDOWS
661 ULARGE_INTEGER time;
662 GetSystemTimeAsFileTime((FILETIME *)&time);
663 // NT keeps time in FILETIME format which is 100ns ticks since
664 // Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
665 // The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
666 // + 18 years and 5 leap days.
667 time.QuadPart +=
668 (unsigned __int64) (1000*1000*10) // seconds
669 * (unsigned __int64) (60 * 60 * 24) // days
670 * (unsigned __int64) (17+30+31+365*18+5); // # of days
671
672 timestamp->high = time.HighPart;
673 timestamp->low = time.LowPart;
674#else
675 struct timeval tp;
676 gettimeofday(&tp, 0);
677
678 // Offset between UUID formatted times and Unix formatted times.
679 // UUID UTC base time is October 15, 1582.
680 // Unix base time is January 1, 1970.
681 U64 uuid_time = ((U64)tp.tv_sec * 10000000) + (tp.tv_usec * 10) +
682 U64L(0x01B21DD213814000);
683 timestamp->high = (U32) (uuid_time >> 32);
684 timestamp->low = (U32) (uuid_time & 0xFFFFFFFF);
685#endif
686}
687
688void LLUUID::getCurrentTime(uuid_time_t *timestamp)
689{
690 // Get current time as 60 bit 100ns ticks since whenever.
691 // Compensate for the fact that real clock resolution is less
692 // than 100ns.
693
694 const U32 uuids_per_tick = 1024;
695
696 static uuid_time_t time_last;
697 static U32 uuids_this_tick;
698 static BOOL init = FALSE;
699
700 if (!init) {
701 getSystemTime(&time_last);
702 uuids_this_tick = uuids_per_tick;
703 init = TRUE;
704 }
705
706 uuid_time_t time_now = {0,0};
707
708 while (1) {
709 getSystemTime(&time_now);
710
711 // if clock reading changed since last UUID generated
712 if (cmpTime(&time_last, &time_now)) {
713 // reset count of uuid's generated with this clock reading
714 uuids_this_tick = 0;
715 break;
716 }
717 if (uuids_this_tick < uuids_per_tick) {
718 uuids_this_tick++;
719 break;
720 }
721 // going too fast for our clock; spin
722 }
723
724 time_last = time_now;
725
726 if (uuids_this_tick != 0) {
727 if (time_now.low & 0x80000000) {
728 time_now.low += uuids_this_tick;
729 if (!(time_now.low & 0x80000000))
730 time_now.high++;
731 } else
732 time_now.low += uuids_this_tick;
733 }
734
735 timestamp->high = time_now.high;
736 timestamp->low = time_now.low;
737}
738
739void LLUUID::generate()
740{
741 // Create a UUID.
742
743
744 uuid_time_t timestamp;
745
746 static unsigned char node_id[6];
747 static int has_init = 0;
748
749 // Create a UUID.
750 static uuid_time_t time_last = {0,0};
751 static U16 clock_seq = 0;
752 static LLRand random_generator(0); // dummy seed. reset it below
753 if (!has_init)
754 {
755 if (getNodeID(node_id) <= 0)
756 {
757 get_random_bytes(node_id, 6);
758 /*
759 * Set multicast bit, to prevent conflicts
760 * with IEEE 802 addresses obtained from
761 * network cards
762 */
763 node_id[0] |= 0x80;
764 }
765
766 getCurrentTime(&time_last);
767 random_generator.seed(time_last.low);
768 clock_seq = (U16) random_generator.llrand(65536);
769 has_init = 1;
770 }
771
772 // get current time
773 getCurrentTime(&timestamp);
774
775 // if clock went backward change clockseq
776 if (cmpTime(&timestamp, &time_last) == -1) {
777 clock_seq = (clock_seq + 1) & 0x3FFF;
778 if (clock_seq == 0) clock_seq++;
779 }
780
781 memcpy(mData+10, node_id, 6);
782 U32 tmp;
783 tmp = timestamp.low;
784 mData[3] = (unsigned char) tmp;
785 tmp >>= 8;
786 mData[2] = (unsigned char) tmp;
787 tmp >>= 8;
788 mData[1] = (unsigned char) tmp;
789 tmp >>= 8;
790 mData[0] = (unsigned char) tmp;
791
792 tmp = (U16) timestamp.high;
793 mData[5] = (unsigned char) tmp;
794 tmp >>= 8;
795 mData[4] = (unsigned char) tmp;
796
797 tmp = (timestamp.high >> 16) | 0x1000;
798 mData[7] = (unsigned char) tmp;
799 tmp >>= 8;
800 mData[6] = (unsigned char) tmp;
801
802 tmp = clock_seq;
803 mData[9] = (unsigned char) tmp;
804 tmp >>= 8;
805 mData[8] = (unsigned char) tmp;
806
807 LLMD5 md5_uuid;
808
809 md5_uuid.update(mData,16);
810 md5_uuid.finalize();
811 md5_uuid.raw_digest(mData);
812
813 time_last = timestamp;
814}
815
816
817U32 LLUUID::getRandomSeed()
818{
819 static unsigned char seed[16];
820
821 getNodeID(&seed[0]);
822 seed[6]='\0';
823 seed[7]='\0';
824 getSystemTime((uuid_time_t *)(&seed[8]));
825
826 LLMD5 md5_seed;
827
828 md5_seed.update(seed,16);
829 md5_seed.finalize();
830 md5_seed.raw_digest(seed);
831
832 return(*(U32 *)seed);
833}
834
835BOOL LLUUID::parseUUID(const char* buf, LLUUID* value)
836{
837 if( buf == NULL || buf[0] == '\0' || value == NULL)
838 {
839 return FALSE;
840 }
841
842 LLString temp( buf );
843 LLString::trim(temp);
844 if( LLUUID::validate( temp ) )
845 {
846 value->set( temp );
847 return TRUE;
848 }
849 return FALSE;
850}
851
852LLAssetID LLTransactionID::makeAssetID(const LLUUID& session) const
853{
854 LLAssetID result;
855 if (isNull())
856 {
857 result.setNull();
858 }
859 else
860 {
861 combine(session, result);
862 }
863 return result;
864}
diff --git a/linden/indra/llmath/lluuid.h b/linden/indra/llmath/lluuid.h
new file mode 100644
index 0000000..b8288eb
--- /dev/null
+++ b/linden/indra/llmath/lluuid.h
@@ -0,0 +1,321 @@
1/**
2 * @file lluuid.h
3 *
4 * Copyright (c) 2000-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_LLUUID_H
28#define LL_LLUUID_H
29
30#include <iostream>
31#include <set>
32
33#include "llstring.h"
34
35const S32 UUID_BYTES = 16;
36const S32 UUID_WORDS = 4;
37const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below
38const S32 UUID_STR_SIZE = 37;
39const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL.
40
41struct uuid_time_t {
42 U32 high;
43 U32 low;
44 };
45
46class LLUUID
47{
48public:
49 //
50 // CREATORS
51 //
52 LLUUID();
53 explicit LLUUID(const char *in_string); // Convert from string.
54 explicit LLUUID(const std::string& in_string); // Convert from string.
55 LLUUID(const LLUUID &in);
56 LLUUID &operator=(const LLUUID &rhs);
57
58 ~LLUUID();
59
60 //
61 // MANIPULATORS
62 //
63 void generate(); // Generate a new UUID
64 BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings
65 BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings
66 void setNull(); // Faster than setting to LLUUID::null.
67
68 S32 cmpTime(uuid_time_t *t1, uuid_time_t *t2);
69 static void getSystemTime(uuid_time_t *timestamp);
70 void getCurrentTime(uuid_time_t *timestamp);
71
72 //
73 // ACCESSORS
74 //
75 BOOL isNull() const; // Faster than comparing to LLUUID::null.
76 BOOL notNull() const; // Faster than comparing to LLUUID::null.
77 // JC: This is dangerous. It allows UUIDs to be cast automatically
78 // to integers, among other things. Use isNull() or notNull().
79 // operator bool() const;
80
81 // JC: These must return real bool's (not BOOLs) or else use of the STL
82 // will generate bool-to-int performance warnings.
83 bool operator==(const LLUUID &rhs) const;
84 bool operator!=(const LLUUID &rhs) const;
85 bool operator<(const LLUUID &rhs) const;
86 bool operator>(const LLUUID &rhs) const;
87
88 // xor functions. Useful since any two random uuids xored together
89 // will yield a determinate third random unique id that can be
90 // used as a key in a single uuid that represents 2.
91 const LLUUID& operator^=(const LLUUID& rhs);
92 LLUUID operator^(const LLUUID& rhs) const;
93
94 // similar to functions above, but not invertible
95 // yields a third random UUID that can be reproduced from the two inputs
96 // but which, given the result and one of the inputs can't be used to
97 // deduce the other input
98 LLUUID combine(const LLUUID& other) const;
99 void combine(const LLUUID& other, LLUUID& result) const;
100
101 friend std::ostream& operator<<(std::ostream& s, const LLUUID &uuid);
102 friend std::istream& operator>>(std::istream& s, LLUUID &uuid);
103
104 void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0)
105 void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0)
106 LLString getString() const;
107 U16 getCRC16() const;
108 U32 getCRC32() const;
109
110 static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal.
111 static BOOL validate(const char *in_string); // Validate that the UUID string is legal.
112
113 static const LLUUID null;
114
115 static U32 getRandomSeed();
116 static S32 getNodeID(unsigned char * node_id);
117
118 static BOOL parseUUID(const char* buf, LLUUID* value);
119
120 U8 mData[UUID_BYTES];
121};
122
123
124// Construct
125inline LLUUID::LLUUID()
126{
127 setNull();
128}
129
130
131// Faster than copying from memory
132inline void LLUUID::setNull()
133{
134 U32 *word = (U32 *)mData;
135 word[0] = 0;
136 word[1] = 0;
137 word[2] = 0;
138 word[3] = 0;
139}
140
141
142// Compare
143inline bool LLUUID::operator==(const LLUUID& rhs) const
144{
145 U32 *tmp = (U32 *)mData;
146 U32 *rhstmp = (U32 *)rhs.mData;
147 // Note: binary & to avoid branching
148 return
149 (tmp[0] == rhstmp[0]) &
150 (tmp[1] == rhstmp[1]) &
151 (tmp[2] == rhstmp[2]) &
152 (tmp[3] == rhstmp[3]);
153}
154
155
156inline bool LLUUID::operator!=(const LLUUID& rhs) const
157{
158 U32 *tmp = (U32 *)mData;
159 U32 *rhstmp = (U32 *)rhs.mData;
160 // Note: binary | to avoid branching
161 return
162 (tmp[0] != rhstmp[0]) |
163 (tmp[1] != rhstmp[1]) |
164 (tmp[2] != rhstmp[2]) |
165 (tmp[3] != rhstmp[3]);
166}
167
168/*
169// JC: This is dangerous. It allows UUIDs to be cast automatically
170// to integers, among other things. Use isNull() or notNull().
171inline LLUUID::operator bool() const
172{
173 U32 *word = (U32 *)mData;
174 return (word[0] | word[1] | word[2] | word[3]) > 0;
175}
176*/
177
178inline BOOL LLUUID::notNull() const
179{
180 U32 *word = (U32 *)mData;
181 return (word[0] | word[1] | word[2] | word[3]) > 0;
182}
183
184// Faster than == LLUUID::null because doesn't require
185// as much memory access.
186inline BOOL LLUUID::isNull() const
187{
188 U32 *word = (U32 *)mData;
189 // If all bits are zero, return !0 == TRUE
190 return !(word[0] | word[1] | word[2] | word[3]);
191}
192
193// Copy constructor
194inline LLUUID::LLUUID(const LLUUID& rhs)
195{
196 U32 *tmp = (U32 *)mData;
197 U32 *rhstmp = (U32 *)rhs.mData;
198 tmp[0] = rhstmp[0];
199 tmp[1] = rhstmp[1];
200 tmp[2] = rhstmp[2];
201 tmp[3] = rhstmp[3];
202}
203
204inline LLUUID::~LLUUID()
205{
206}
207
208// Assignment
209inline LLUUID& LLUUID::operator=(const LLUUID& rhs)
210{
211 // No need to check the case where this==&rhs. The branch is slower than the write.
212 U32 *tmp = (U32 *)mData;
213 U32 *rhstmp = (U32 *)rhs.mData;
214 tmp[0] = rhstmp[0];
215 tmp[1] = rhstmp[1];
216 tmp[2] = rhstmp[2];
217 tmp[3] = rhstmp[3];
218
219 return *this;
220}
221
222
223inline LLUUID::LLUUID(const char *in_string)
224{
225 if (!in_string || in_string[0] == 0)
226 {
227 setNull();
228 return;
229 }
230
231 set(in_string);
232}
233
234inline LLUUID::LLUUID(const std::string& in_string)
235{
236 if (in_string.empty())
237 {
238 setNull();
239 return;
240 }
241
242 set(in_string);
243}
244
245// IW: DON'T "optimize" these w/ U32s or you'll scoogie the sort order
246// IW: this will make me very sad
247inline bool LLUUID::operator<(const LLUUID &rhs) const
248{
249 U32 i;
250 for( i = 0; i < (UUID_BYTES - 1); i++ )
251 {
252 if( mData[i] != rhs.mData[i] )
253 {
254 return (mData[i] < rhs.mData[i]);
255 }
256 }
257 return (mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1]);
258}
259
260inline bool LLUUID::operator>(const LLUUID &rhs) const
261{
262 U32 i;
263 for( i = 0; i < (UUID_BYTES - 1); i++ )
264 {
265 if( mData[i] != rhs.mData[i] )
266 {
267 return (mData[i] > rhs.mData[i]);
268 }
269 }
270 return (mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1]);
271}
272
273inline U16 LLUUID::getCRC16() const
274{
275 // A UUID is 16 bytes, or 8 shorts.
276 U16 *short_data = (U16*)mData;
277 U16 out = 0;
278 out += short_data[0];
279 out += short_data[1];
280 out += short_data[2];
281 out += short_data[3];
282 out += short_data[4];
283 out += short_data[5];
284 out += short_data[6];
285 out += short_data[7];
286 return out;
287}
288
289inline U32 LLUUID::getCRC32() const
290{
291 U32 *tmp = (U32*)mData;
292 return tmp[0] + tmp[1] + tmp[2] + tmp[3];
293}
294
295
296// Helper structure for ordering lluuids in stl containers.
297// eg: std::map<LLUUID, LLWidget*, lluuid_less> widget_map;
298struct lluuid_less
299{
300 bool operator()(const LLUUID& lhs, const LLUUID& rhs) const
301 {
302 return (lhs < rhs) ? true : false;
303 }
304};
305
306typedef std::set<LLUUID, lluuid_less> uuid_list_t;
307
308/*
309 * Sub-classes for keeping transaction IDs and asset IDs
310 * straight.
311 */
312typedef LLUUID LLAssetID;
313
314class LLTransactionID : public LLUUID
315{
316public:
317 static const LLTransactionID tnull;
318 LLAssetID makeAssetID(const LLUUID& session) const;
319};
320
321#endif
diff --git a/linden/indra/llmath/llvolume.cpp b/linden/indra/llmath/llvolume.cpp
new file mode 100644
index 0000000..14d4cdf
--- /dev/null
+++ b/linden/indra/llmath/llvolume.cpp
@@ -0,0 +1,4576 @@
1/**
2 * @file llvolume.cpp
3 *
4 * Copyright (c) 2002-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28#include "llmath.h"
29
30#include <set>
31
32#include "llerror.h"
33
34#include "llvolumemgr.h"
35#include "v2math.h"
36#include "v3math.h"
37#include "v4math.h"
38#include "m4math.h"
39#include "m3math.h"
40#include "lldarray.h"
41#include "llvolume.h"
42#include "llstl.h"
43
44#define DEBUG_SILHOUETTE_BINORMALS 0
45#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
46#define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette
47
48const F32 CUT_MIN = 0.f;
49const F32 CUT_MAX = 1.f;
50const F32 MIN_CUT_DELTA = 0.02f;
51
52const F32 HOLLOW_MIN = 0.f;
53const F32 HOLLOW_MAX = 0.95f;
54const F32 HOLLOW_MAX_SQUARE = 0.7f;
55
56const F32 TWIST_MIN = -1.f;
57const F32 TWIST_MAX = 1.f;
58
59const F32 RATIO_MIN = 0.f;
60const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper
61
62const F32 HOLE_X_MIN= 0.05f;
63const F32 HOLE_X_MAX= 1.0f;
64
65const F32 HOLE_Y_MIN= 0.05f;
66const F32 HOLE_Y_MAX= 0.5f;
67
68const F32 SHEAR_MIN = -0.5f;
69const F32 SHEAR_MAX = 0.5f;
70
71const F32 REV_MIN = 1.f;
72const F32 REV_MAX = 4.f;
73
74const F32 TAPER_MIN = -1.f;
75const F32 TAPER_MAX = 1.f;
76
77const F32 SKEW_MIN = -0.95f;
78const F32 SKEW_MAX = 0.95f;
79
80BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
81{
82 LLVector3 test = (pt2-pt1)%(pt3-pt2);
83
84 //answer
85 if(test * norm < 0)
86 {
87 return FALSE;
88 }
89 else
90 {
91 return TRUE;
92 }
93}
94
95// intersect test between triangle pt1,pt2,pt3 and line from linept to linept+vect
96//returns TRUE if intersecting and moves linept to the point of intersection
97BOOL LLTriangleLineSegmentIntersect( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, LLVector3& linept, const LLVector3& vect)
98{
99 LLVector3 V1 = pt2-pt1;
100 LLVector3 V2 = pt3-pt2;
101
102 LLVector3 norm = V1 % V2;
103
104 F32 dotprod = norm * vect;
105
106 if(dotprod < 0)
107 {
108 //Find point of intersect to triangle plane.
109 //find t to intersect point
110 F32 t = -(norm * (linept-pt1))/dotprod;
111
112 // if ds is neg line started past triangle so can't hit triangle.
113 if (t > 0)
114 {
115 return FALSE;
116 }
117
118 LLVector3 pt_int = linept + (vect*t);
119
120 if(check_same_clock_dir(pt1, pt2, pt_int, norm))
121 {
122 if(check_same_clock_dir(pt2, pt3, pt_int, norm))
123 {
124 if(check_same_clock_dir(pt3, pt1, pt_int, norm))
125 {
126 // answer in pt_int is insde triangle
127 linept.setVec(pt_int);
128 return TRUE;
129 }
130 }
131 }
132 }
133
134 return FALSE;
135}
136
137
138//-------------------------------------------------------------------
139// statics
140//-------------------------------------------------------------------
141
142
143//----------------------------------------------------
144
145LLProfile::Face* LLProfile::addCap(S16 faceID)
146{
147 Face *face = vector_append(mFaces, 1);
148
149 face->mIndex = 0;
150 face->mCount = mTotal;
151 face->mScaleU= 1.0f;
152 face->mCap = TRUE;
153 face->mFaceID = faceID;
154 return face;
155}
156
157LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat)
158{
159 Face *face = vector_append(mFaces, 1);
160
161 face->mIndex = i;
162 face->mCount = count;
163 face->mScaleU= scaleU;
164
165 face->mFlat = flat;
166 face->mCap = FALSE;
167 face->mFaceID = faceID;
168 return face;
169}
170
171// What is the bevel parameter used for? - DJS 04/05/02
172// Bevel parameter is currently unused but presumedly would support
173// filleted and chamfered corners
174void LLProfile::genNGon(S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split)
175{
176 // Generate an n-sided "circular" path.
177 // 0 is (1,0), and we go counter-clockwise along a circular path from there.
178 const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
179 F32 scale = 0.5f;
180 F32 t, t_step, t_first, t_fraction, ang, ang_step;
181 LLVector3 pt1,pt2;
182
183 mMaxX = 0.f;
184 mMinX = 0.f;
185
186 F32 begin = mParams.getBegin();
187 F32 end = mParams.getEnd();
188
189 t_step = 1.0f / sides;
190 ang_step = 2.0f*F_PI*t_step*ang_scale;
191
192 // Scale to have size "match" scale. Compensates to get object to generally fill bounding box.
193
194 S32 total_sides = llround(sides / ang_scale); // Total number of sides all around
195
196 if (total_sides < 8)
197 {
198 scale = tableScale[total_sides];
199 }
200
201 t_first = floor(begin * sides) / (F32)sides;
202
203 // pt1 is the first point on the fractional face.
204 // Starting t and ang values for the first face
205 t = t_first;
206 ang = 2.0f*F_PI*(t*ang_scale + offset);
207 pt1.setVec(cos(ang)*scale,sin(ang)*scale, t);
208
209 // Increment to the next point.
210 // pt2 is the end point on the fractional face
211 t += t_step;
212 ang += ang_step;
213 pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
214
215 t_fraction = (begin - t_first)*sides;
216
217 // Only use if it's not almost exactly on an edge.
218 if (t_fraction < 0.99f)
219 {
220 LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
221 F32 pt_x = new_pt.mV[VX];
222 if (pt_x < mMinX)
223 {
224 mMinX = pt_x;
225 }
226 else if (pt_x > mMaxX)
227 {
228 mMaxX = pt_x;
229 }
230 mProfile.push_back(new_pt);
231 }
232
233 // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02
234 while (t < end)
235 {
236 // Iterate through all the integer steps of t.
237 pt1.setVec(cos(ang)*scale,sin(ang)*scale,t);
238
239 F32 pt_x = pt1.mV[VX];
240 if (pt_x < mMinX)
241 {
242 mMinX = pt_x;
243 }
244 else if (pt_x > mMaxX)
245 {
246 mMaxX = pt_x;
247 }
248
249 if (mProfile.size() > 0) {
250 LLVector3 p = mProfile[mProfile.size()-1];
251 for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
252 mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1));
253 }
254 }
255 mProfile.push_back(pt1);
256
257 t += t_step;
258 ang += ang_step;
259 }
260
261 t_fraction = (end - (t - t_step))*sides;
262
263 // pt1 is the first point on the fractional face
264 // pt2 is the end point on the fractional face
265 pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
266
267 // Find the fraction that we need to add to the end point.
268 t_fraction = (end - (t - t_step))*sides;
269 if (t_fraction > 0.01f)
270 {
271 LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
272 F32 pt_x = new_pt.mV[VX];
273 if (pt_x < mMinX)
274 {
275 mMinX = pt_x;
276 }
277 else if (pt_x > mMaxX)
278 {
279 mMaxX = pt_x;
280 }
281
282 if (mProfile.size() > 0) {
283 LLVector3 p = mProfile[mProfile.size()-1];
284 for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
285 mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1));
286 }
287 }
288 mProfile.push_back(new_pt);
289 }
290
291 // If we're sliced, the profile is open.
292 if ((end - begin)*ang_scale < 0.99f)
293 {
294 if ((end - begin)*ang_scale > 0.5f)
295 {
296 mConcave = TRUE;
297 }
298 else
299 {
300 mConcave = FALSE;
301 }
302 mOpen = TRUE;
303 if (!isHollow())
304 {
305 // put center point if not hollow.
306 mProfile.push_back(LLVector3(0,0,0));
307 }
308 }
309 else
310 {
311 // The profile isn't open.
312 mOpen = FALSE;
313 mConcave = FALSE;
314 }
315
316 mTotal = mProfile.size();
317}
318
319void LLProfile::genNormals()
320{
321 S32 count = mProfile.size();
322
323 S32 outer_count;
324 if (mTotalOut)
325 {
326 outer_count = mTotalOut;
327 }
328 else
329 {
330 outer_count = mTotal / 2;
331 }
332
333 mEdgeNormals.resize(count * 2);
334 mEdgeCenters.resize(count * 2);
335 mNormals.resize(count);
336
337 LLVector2 pt0,pt1;
338
339 BOOL hollow;
340 hollow = isHollow();
341
342 S32 i0, i1, i2, i3, i4;
343
344 // Parametrically generate normal
345 for (i2 = 0; i2 < count; i2++)
346 {
347 mNormals[i2].mV[0] = mProfile[i2].mV[0];
348 mNormals[i2].mV[1] = mProfile[i2].mV[1];
349 if (hollow && (i2 >= outer_count))
350 {
351 mNormals[i2] *= -1.f;
352 }
353 if (mNormals[i2].magVec() < 0.001)
354 {
355 // Special case for point at center, get adjacent points.
356 i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1;
357 i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1;
358 i3 = (i2 + 1) < count ? i2 + 1 : 0;
359 i4 = (i3 + 1) < count ? i3 + 1 : 0;
360
361 pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX],
362 mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]);
363 pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX],
364 mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]);
365
366 mNormals[i2] = pt0 + pt1;
367 mNormals[i2] *= 0.5f;
368 }
369 mNormals[i2].normVec();
370 }
371
372 S32 num_normal_sets = isConcave() ? 2 : 1;
373 for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++)
374 {
375 S32 point_num;
376 for (point_num = 0; point_num < mTotal; point_num++)
377 {
378 LLVector3 point_1 = mProfile[point_num];
379 point_1.mV[VZ] = 0.f;
380
381 LLVector3 point_2;
382
383 if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2)
384 {
385 point_2 = mProfile[mTotal - 1];
386 }
387 else if (isConcave() && normal_set == 1 && point_num == mTotal - 1)
388 {
389 point_2 = mProfile[(mTotal - 1) / 2];
390 }
391 else
392 {
393 LLVector3 delta_pos;
394 S32 neighbor_point = (point_num + 1) % mTotal;
395 while(delta_pos.magVecSquared() < 0.01f * 0.01f)
396 {
397 point_2 = mProfile[neighbor_point];
398 delta_pos = point_2 - point_1;
399 neighbor_point = (neighbor_point + 1) % mTotal;
400 if (neighbor_point == point_num)
401 {
402 break;
403 }
404 }
405 }
406
407 point_2.mV[VZ] = 0.f;
408 LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis;
409 face_normal.normVec();
410 mEdgeNormals[normal_set * count + point_num] = face_normal;
411 mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f);
412 }
413 }
414}
415
416
417// Hollow is percent of the original bounding box, not of this particular
418// profile's geometry. Thus, a swept triangle needs lower hollow values than
419// a swept square.
420LLProfile::Face* LLProfile::addHole(BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split)
421{
422 // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them.
423
424 // Total add has number of vertices on outside.
425 mTotalOut = mTotal;
426
427 // Why is the "bevel" parameter -1? DJS 04/05/02
428 genNGon(llfloor(sides),offset,-1, ang_scale, split);
429
430 Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat);
431
432 LLVector3 pt[128];
433
434 for (S32 i=mTotalOut;i<mTotal;i++)
435 {
436 pt[i] = mProfile[i] * box_hollow;
437 }
438
439 S32 j=mTotal-1;
440 for (S32 i=mTotalOut;i<mTotal;i++)
441 {
442 mProfile[i] = pt[j--];
443 }
444
445 for (S32 i=0;i<(S32)mFaces.size();i++)
446 {
447 if (mFaces[i].mCap)
448 {
449 mFaces[i].mCount *= 2;
450 }
451 }
452
453 return face;
454}
455
456BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split)
457{
458 if (!mDirty)
459 {
460 return FALSE;
461 }
462 mDirty = FALSE;
463
464 if (detail < MIN_LOD)
465 {
466 llinfos << "Generating profile with LOD < MIN_LOD. CLAMPING" << llendl;
467 detail = MIN_LOD;
468 }
469
470 mProfile.clear();
471 mFaces.clear();
472
473 // Generate the face data
474 S32 i;
475 F32 begin = mParams.getBegin();
476 F32 end = mParams.getEnd();
477 F32 hollow = mParams.getHollow();
478
479 // Quick validation to eliminate some server crashes.
480 if (begin > end - 0.01f)
481 {
482 llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl;
483 return FALSE;
484 }
485
486 S32 face_num = 0;
487
488 switch (mParams.getCurveType() & LL_PCODE_PROFILE_MASK)
489 {
490 case LL_PCODE_PROFILE_SQUARE:
491 {
492 genNGon(4,-0.375, 0, 1, split);
493 if (path_open)
494 {
495 addCap (LL_FACE_PATH_BEGIN);
496 }
497
498 for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++)
499 {
500 addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
501 }
502
503 for (i = 0; i <(S32) mProfile.size(); i++)
504 {
505 // Scale by 4 to generate proper tex coords.
506 mProfile[i].mV[2] *= 4.f;
507 }
508
509 if (hollow)
510 {
511 switch (mParams.getCurveType() & LL_PCODE_HOLE_MASK)
512 {
513 case LL_PCODE_HOLE_TRIANGLE:
514 // This offset is not correct, but we can't change it now... DK 11/17/04
515 addHole(TRUE, 3, -0.375f, hollow, 1.f, split);
516 break;
517 case LL_PCODE_HOLE_CIRCLE:
518 // TODO: Compute actual detail levels for cubes
519 addHole(FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f);
520 break;
521 case LL_PCODE_HOLE_SAME:
522 case LL_PCODE_HOLE_SQUARE:
523 default:
524 addHole(TRUE, 4, -0.375f, hollow, 1.f, split);
525 break;
526 }
527 }
528
529 if (path_open) {
530 mFaces[0].mCount = mTotal;
531 }
532 }
533 break;
534 case LL_PCODE_PROFILE_ISOTRI:
535 case LL_PCODE_PROFILE_RIGHTTRI:
536 case LL_PCODE_PROFILE_EQUALTRI:
537 {
538 genNGon(3,0, 0, 1, split);
539 for (i = 0; i <(S32) mProfile.size(); i++)
540 {
541 // Scale by 3 to generate proper tex coords.
542 mProfile[i].mV[2] *= 3.f;
543 }
544
545 if (path_open)
546 {
547 addCap(LL_FACE_PATH_BEGIN);
548 }
549
550 for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++)
551 {
552 addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
553 }
554 if (hollow)
555 {
556 // Swept triangles need smaller hollowness values,
557 // because the triangle doesn't fill the bounding box.
558 F32 triangle_hollow = hollow / 2.f;
559
560 switch (mParams.getCurveType() & LL_PCODE_HOLE_MASK)
561 {
562 case LL_PCODE_HOLE_CIRCLE:
563 // TODO: Actually generate level of detail for triangles
564 addHole(FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f);
565 break;
566 case LL_PCODE_HOLE_SQUARE:
567 addHole(TRUE, 4, 0, triangle_hollow, 1.f, split);
568 break;
569 case LL_PCODE_HOLE_SAME:
570 case LL_PCODE_HOLE_TRIANGLE:
571 default:
572 addHole(TRUE, 3, 0, triangle_hollow, 1.f, split);
573 break;
574 }
575 }
576 }
577 break;
578 case LL_PCODE_PROFILE_CIRCLE:
579 {
580 // If this has a square hollow, we should adjust the
581 // number of faces a bit so that the geometry lines up.
582 U8 hole_type=0;
583 F32 circle_detail = MIN_DETAIL_FACES * detail;
584 if (hollow)
585 {
586 hole_type = mParams.getCurveType() & LL_PCODE_HOLE_MASK;
587 if (hole_type == LL_PCODE_HOLE_SQUARE)
588 {
589 // Snap to the next multiple of four sides,
590 // so that corners line up.
591 circle_detail = llceil(circle_detail / 4.0f) * 4.0f;
592 }
593 }
594
595 //llinfos << "(CIRCLE) detail: " << detail << "; genNGon("
596 // << llfloor(circle_detail) << ")" << llendl;
597 genNGon(llfloor(circle_detail));
598 if (path_open)
599 {
600 addCap (LL_FACE_PATH_BEGIN);
601 }
602
603 if (mOpen && !hollow)
604 {
605 addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
606 }
607 else
608 {
609 addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
610 }
611
612 if (hollow)
613 {
614 switch (hole_type)
615 {
616 case LL_PCODE_HOLE_SQUARE:
617 addHole(TRUE, 4, 0, hollow, 1.f, split);
618 break;
619 case LL_PCODE_HOLE_TRIANGLE:
620 addHole(TRUE, 3, 0, hollow, 1.f, split);
621 break;
622 case LL_PCODE_HOLE_CIRCLE:
623 case LL_PCODE_HOLE_SAME:
624 default:
625 addHole(FALSE, circle_detail, 0, hollow, 1.f);
626 break;
627 }
628 }
629 }
630 break;
631 case LL_PCODE_PROFILE_CIRCLE_HALF:
632 {
633 // If this has a square hollow, we should adjust the
634 // number of faces a bit so that the geometry lines up.
635 U8 hole_type=0;
636 // Number of faces is cut in half because it's only a half-circle.
637 F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f;
638 if (hollow)
639 {
640 hole_type = mParams.getCurveType() & LL_PCODE_HOLE_MASK;
641 if (hole_type == LL_PCODE_HOLE_SQUARE)
642 {
643 // Snap to the next multiple of four sides (div 2),
644 // so that corners line up.
645 circle_detail = llceil(circle_detail / 2.0f) * 2.0f;
646 }
647 }
648 genNGon(llfloor(circle_detail), 0.5f, 0.f, 0.5f);
649 if (path_open)
650 {
651 addCap(LL_FACE_PATH_BEGIN);
652 }
653 if (mOpen && !mParams.getHollow())
654 {
655 addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
656 }
657 else
658 {
659 addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
660 }
661
662 if (hollow)
663 {
664 switch (hole_type)
665 {
666 case LL_PCODE_HOLE_SQUARE:
667 addHole(TRUE, 2, 0.5f, hollow, 0.5f, split);
668 break;
669 case LL_PCODE_HOLE_TRIANGLE:
670 addHole(TRUE, 3, 0.5f, hollow, 0.5f, split);
671 break;
672 case LL_PCODE_HOLE_CIRCLE:
673 case LL_PCODE_HOLE_SAME:
674 default:
675 addHole(FALSE, circle_detail, 0.5f, hollow, 0.5f);
676 break;
677 }
678 }
679
680 // Special case for openness of sphere
681 if ((mParams.getEnd() - mParams.getBegin()) < 1.f)
682 {
683 mOpen = TRUE;
684 }
685 else if (!hollow)
686 {
687 mOpen = FALSE;
688 mProfile.push_back(mProfile[0]);
689 mTotal++;
690 }
691 }
692 break;
693 default:
694 llerrs << "Unknown profile: getCurveType()=" << mParams.getCurveType() << llendl;
695 break;
696 };
697
698 if (path_open)
699 {
700 addCap(LL_FACE_PATH_END); // bottom
701 }
702
703 if ( mOpen) // interior edge caps
704 {
705 addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE);
706
707 if (hollow)
708 {
709 addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE);
710 }
711 else
712 {
713 addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE);
714 }
715 }
716
717 //genNormals();
718
719 return TRUE;
720}
721
722
723
724BOOL LLProfileParams::importFile(FILE *fp)
725{
726 const S32 BUFSIZE = 16384;
727 char buffer[BUFSIZE];
728 char keyword[256];
729 char valuestr[256];
730 keyword[0] = 0;
731 valuestr[0] = 0;
732 F32 tempF32;
733 U32 tempU32;
734
735 while (!feof(fp))
736 {
737 fgets(buffer, BUFSIZE, fp);
738 sscanf(buffer, " %s %s", keyword, valuestr);
739 if (!keyword)
740 {
741 continue;
742 }
743 if (!strcmp("{", keyword))
744 {
745 continue;
746 }
747 if (!strcmp("}",keyword))
748 {
749 break;
750 }
751 else if (!strcmp("curve", keyword))
752 {
753 sscanf(valuestr,"%d",&tempU32);
754 setCurveType((U8) tempU32);
755 }
756 else if (!strcmp("begin",keyword))
757 {
758 sscanf(valuestr,"%g",&tempF32);
759 setBegin(tempF32);
760 }
761 else if (!strcmp("end",keyword))
762 {
763 sscanf(valuestr,"%g",&tempF32);
764 setEnd(tempF32);
765 }
766 else if (!strcmp("hollow",keyword))
767 {
768 sscanf(valuestr,"%g",&tempF32);
769 setHollow(tempF32);
770 }
771 else
772 {
773 llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
774 }
775 }
776
777 return TRUE;
778}
779
780
781BOOL LLProfileParams::exportFile(FILE *fp) const
782{
783 fprintf(fp,"\t\tprofile 0\n");
784 fprintf(fp,"\t\t{\n");
785 fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType());
786 fprintf(fp,"\t\t\tbegin\t%g\n", getBegin());
787 fprintf(fp,"\t\t\tend\t%g\n", getEnd());
788 fprintf(fp,"\t\t\thollow\t%g\n", getHollow());
789 fprintf(fp, "\t\t}\n");
790 return TRUE;
791}
792
793
794BOOL LLProfileParams::importLegacyStream(std::istream& input_stream)
795{
796 const S32 BUFSIZE = 16384;
797 char buffer[BUFSIZE];
798 char keyword[256];
799 char valuestr[256];
800 keyword[0] = 0;
801 valuestr[0] = 0;
802 F32 tempF32;
803 U32 tempU32;
804
805 while (input_stream.good())
806 {
807 input_stream.getline(buffer, BUFSIZE);
808 sscanf(buffer, " %s %s", keyword, valuestr);
809 if (!keyword)
810 {
811 continue;
812 }
813 if (!strcmp("{", keyword))
814 {
815 continue;
816 }
817 if (!strcmp("}",keyword))
818 {
819 break;
820 }
821 else if (!strcmp("curve", keyword))
822 {
823 sscanf(valuestr,"%d",&tempU32);
824 setCurveType((U8) tempU32);
825 }
826 else if (!strcmp("begin",keyword))
827 {
828 sscanf(valuestr,"%g",&tempF32);
829 setBegin(tempF32);
830 }
831 else if (!strcmp("end",keyword))
832 {
833 sscanf(valuestr,"%g",&tempF32);
834 setEnd(tempF32);
835 }
836 else if (!strcmp("hollow",keyword))
837 {
838 sscanf(valuestr,"%g",&tempF32);
839 setHollow(tempF32);
840 }
841 else
842 {
843 llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
844 }
845 }
846
847 return TRUE;
848}
849
850
851BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const
852{
853 output_stream <<"\t\tprofile 0\n";
854 output_stream <<"\t\t{\n";
855 output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n";
856 output_stream <<"\t\t\tbegin\t" << getBegin() << "\n";
857 output_stream <<"\t\t\tend\t" << getEnd() << "\n";
858 output_stream <<"\t\t\thollow\t" << getHollow() << "\n";
859 output_stream << "\t\t}\n";
860 return TRUE;
861}
862
863LLSD LLProfileParams::asLLSD() const
864{
865 LLSD sd;
866
867 sd["curve"] = getCurveType();
868 sd["begin"] = getBegin();
869 sd["end"] = getEnd();
870 sd["hollow"] = getHollow();
871 return sd;
872}
873
874bool LLProfileParams::fromLLSD(LLSD& sd)
875{
876 setCurveType(sd["curve"].asInteger());
877 setBegin((F32)sd["begin"].asReal());
878 setEnd((F32)sd["end"].asReal());
879 setHollow((F32)sd["hollow"].asReal());
880 return true;
881}
882
883void LLProfileParams::copyParams(const LLProfileParams &params)
884{
885 setCurveType(params.getCurveType());
886 setBegin(params.getBegin());
887 setEnd(params.getEnd());
888 setHollow(params.getHollow());
889}
890
891
892LLPath::~LLPath()
893{
894}
895
896void LLPath::genNGon(S32 sides, F32 startOff, F32 end_scale, F32 twist_scale)
897{
898 // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
899 const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
900
901 F32 revolutions = mParams.getRevolutions();
902 F32 skew = mParams.getSkew();
903 F32 skew_mag = fabs(skew);
904 F32 hole_x = mParams.getScaleX() * (1.0f - skew_mag);
905 F32 hole_y = mParams.getScaleY();
906
907 // Calculate taper begin/end for x,y (Negative means taper the beginning)
908 F32 taper_x_begin = 1.0f;
909 F32 taper_x_end = 1.0f - mParams.getTaperX();
910 F32 taper_y_begin = 1.0f;
911 F32 taper_y_end = 1.0f - mParams.getTaperY();
912
913 if ( taper_x_end > 1.0f )
914 {
915 // Flip tapering.
916 taper_x_begin = 2.0f - taper_x_end;
917 taper_x_end = 1.0f;
918 }
919 if ( taper_y_end > 1.0f )
920 {
921 // Flip tapering.
922 taper_y_begin = 2.0f - taper_y_end;
923 taper_y_end = 1.0f;
924 }
925
926 // For spheres, the radius is usually zero.
927 F32 radius_start = 0.5f;
928 if (sides < 8)
929 {
930 radius_start = tableScale[sides];
931 }
932
933 // Scale the radius to take the hole size into account.
934 radius_start *= 1.0f - hole_y;
935
936 // Now check the radius offset to calculate the start,end radius. (Negative means
937 // decrease the start radius instead).
938 F32 radius_end = radius_start;
939 F32 radius_offset = mParams.getRadiusOffset();
940 if (radius_offset < 0.f)
941 {
942 radius_start *= 1.f + radius_offset;
943 }
944 else
945 {
946 radius_end *= 1.f - radius_offset;
947 }
948
949 // Is the path NOT a closed loop?
950 mOpen = ( (mParams.getEnd()*end_scale - mParams.getBegin() < 1.0f) ||
951 (skew_mag > 0.001f) ||
952 (fabs(taper_x_end - taper_x_begin) > 0.001f) ||
953 (fabs(taper_y_end - taper_y_begin) > 0.001f) ||
954 (fabs(radius_end - radius_start) > 0.001f) );
955
956 F32 ang, c, s;
957 LLQuaternion twist, qang;
958 PathPt *pt;
959 LLVector3 path_axis (1.f, 0.f, 0.f);
960 //LLVector3 twist_axis(0.f, 0.f, 1.f);
961 F32 twist_begin = mParams.getTwistBegin() * twist_scale;
962 F32 twist_end = mParams.getTwist() * twist_scale;
963
964 // We run through this once before the main loop, to make sure
965 // the path begins at the correct cut.
966 F32 step= 1.0f / sides;
967 F32 t = mParams.getBegin();
968 pt = vector_append(mPath, 1);
969 ang = 2.0f*F_PI*revolutions * t;
970 s = sin(ang)*lerp(radius_start, radius_end, t);
971 c = cos(ang)*lerp(radius_start, radius_end, t);
972
973
974 pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s)
975 + lerp(-skew ,skew, t) * 0.5f,
976 c + lerp(0,mParams.getShear().mV[1],s),
977 s);
978 pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
979 pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
980 pt->mTexT = t;
981
982 // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
983 twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
984 // Rotate the point around the circle's center.
985 qang.setQuat (ang,path_axis);
986 pt->mRot = twist * qang;
987
988 t+=step;
989
990 // Snap to a quantized parameter, so that cut does not
991 // affect most sample points.
992 t = ((S32)(t * sides)) / (F32)sides;
993
994 // Run through the non-cut dependent points.
995 while (t < mParams.getEnd())
996 {
997 pt = vector_append(mPath, 1);
998
999 ang = 2.0f*F_PI*revolutions * t;
1000 c = cos(ang)*lerp(radius_start, radius_end, t);
1001 s = sin(ang)*lerp(radius_start, radius_end, t);
1002
1003 pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s)
1004 + lerp(-skew ,skew, t) * 0.5f,
1005 c + lerp(0,mParams.getShear().mV[1],s),
1006 s);
1007
1008 pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
1009 pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
1010 pt->mTexT = t;
1011
1012 // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
1013 twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
1014 // Rotate the point around the circle's center.
1015 qang.setQuat (ang,path_axis);
1016 pt->mRot = twist * qang;
1017
1018 t+=step;
1019 }
1020
1021 // Make one final pass for the end cut.
1022 t = mParams.getEnd();
1023 pt = vector_append(mPath, 1);
1024 ang = 2.0f*F_PI*revolutions * t;
1025 c = cos(ang)*lerp(radius_start, radius_end, t);
1026 s = sin(ang)*lerp(radius_start, radius_end, t);
1027
1028 pt->mPos.setVec(0 + lerp(0,mParams.getShear().mV[0],s)
1029 + lerp(-skew ,skew, t) * 0.5f,
1030 c + lerp(0,mParams.getShear().mV[1],s),
1031 s);
1032 pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
1033 pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
1034 pt->mTexT = t;
1035
1036 // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
1037 twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
1038 // Rotate the point around the circle's center.
1039 qang.setQuat (ang,path_axis);
1040 pt->mRot = twist * qang;
1041
1042 mTotal = mPath.size();
1043}
1044
1045const LLVector2 LLPathParams::getBeginScale() const
1046{
1047 LLVector2 begin_scale(1.f, 1.f);
1048 if (getScaleX() > 1)
1049 {
1050 begin_scale.mV[0] = 2-getScaleX();
1051 }
1052 if (getScaleY() > 1)
1053 {
1054 begin_scale.mV[1] = 2-getScaleY();
1055 }
1056 return begin_scale;
1057}
1058
1059const LLVector2 LLPathParams::getEndScale() const
1060{
1061 LLVector2 end_scale(1.f, 1.f);
1062 if (getScaleX() < 1)
1063 {
1064 end_scale.mV[0] = getScaleX();
1065 }
1066 if (getScaleY() < 1)
1067 {
1068 end_scale.mV[1] = getScaleY();
1069 }
1070 return end_scale;
1071}
1072
1073BOOL LLPath::generate(F32 detail, S32 split)
1074{
1075 if (!mDirty)
1076 {
1077 return FALSE;
1078 }
1079
1080 if (detail < MIN_LOD)
1081 {
1082 llinfos << "Generating path with LOD < MIN! Clamping to 1" << llendl;
1083 detail = MIN_LOD;
1084 }
1085
1086 mDirty = FALSE;
1087 S32 np = 2; // hardcode for line
1088
1089 mPath.clear();
1090 mOpen = TRUE;
1091
1092 // Is this 0xf0 mask really necessary? DK 03/02/05
1093 switch (mParams.getCurveType() & 0xf0)
1094 {
1095 default:
1096 case LL_PCODE_PATH_LINE:
1097 {
1098 // Take the begin/end twist into account for detail.
1099 np = llfloor(fabs(mParams.getTwistBegin() - mParams.getTwist()) * 3.5f * (detail-0.5f)) + 2;
1100 if (np < split+2)
1101 {
1102 np = split+2;
1103 }
1104
1105 mStep = 1.0f / (np-1);
1106
1107 mPath.resize(np);
1108
1109 LLVector2 start_scale = mParams.getBeginScale();
1110 LLVector2 end_scale = mParams.getEndScale();
1111
1112 for (S32 i=0;i<np;i++)
1113 {
1114 F32 t = lerp(mParams.getBegin(),mParams.getEnd(),(F32)i * mStep);
1115 mPath[i].mPos.setVec(lerp(0,mParams.getShear().mV[0],t),
1116 lerp(0,mParams.getShear().mV[1],t),
1117 t - 0.5f);
1118 mPath[i].mRot.setQuat(lerp(F_PI * mParams.getTwistBegin(),F_PI * mParams.getTwist(),t),0,0,1);
1119 mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t);
1120 mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t);
1121 mPath[i].mTexT = t;
1122 }
1123 }
1124 break;
1125
1126 case LL_PCODE_PATH_CIRCLE:
1127 {
1128 // Increase the detail as the revolutions and twist increase.
1129 F32 twist_mag = fabs(mParams.getTwistBegin() - mParams.getTwist());
1130 genNGon(llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * mParams.getRevolutions()));
1131 }
1132 break;
1133
1134 case LL_PCODE_PATH_CIRCLE2:
1135 {
1136 if (mParams.getEnd() - mParams.getBegin() >= 0.99f &&
1137 mParams.getScaleX() >= .99f)
1138 {
1139 mOpen = FALSE;
1140 }
1141
1142 //genNGon(llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f);
1143 genNGon(llfloor(MIN_DETAIL_FACES * detail));
1144
1145 F32 t = 0.f;
1146 F32 tStep = 1.0f / mPath.size();
1147
1148 F32 toggle = 0.5f;
1149 for (S32 i=0;i<(S32)mPath.size();i++)
1150 {
1151 mPath[i].mPos.mV[0] = toggle;
1152 if (toggle == 0.5f)
1153 toggle = -0.5f;
1154 else
1155 toggle = 0.5f;
1156 t += tStep;
1157 }
1158 }
1159
1160 break;
1161
1162 case LL_PCODE_PATH_TEST:
1163
1164 np = 5;
1165 mStep = 1.0f / (np-1);
1166
1167 mPath.resize(np);
1168
1169 for (S32 i=0;i<np;i++)
1170 {
1171 F32 t = (F32)i * mStep;
1172 mPath[i].mPos.setVec(0,
1173 lerp(0, -sin(F_PI*mParams.getTwist()*t)*0.5f,t),
1174 lerp(-0.5, cos(F_PI*mParams.getTwist()*t)*0.5f,t));
1175 mPath[i].mScale.mV[0] = lerp(1,mParams.getScale().mV[0],t);
1176 mPath[i].mScale.mV[1] = lerp(1,mParams.getScale().mV[1],t);
1177 mPath[i].mTexT = t;
1178 mPath[i].mRot.setQuat(F_PI * mParams.getTwist() * t,1,0,0);
1179 }
1180
1181 break;
1182 };
1183
1184 if (mParams.getTwist() != mParams.getTwistBegin()) mOpen = TRUE;
1185
1186 //if ((int(fabsf(mParams.getTwist() - mParams.getTwistBegin())*100))%100 != 0) {
1187 // mOpen = TRUE;
1188 //}
1189
1190 return TRUE;
1191}
1192
1193BOOL LLDynamicPath::generate(F32 detail, S32 split)
1194{
1195 mOpen = TRUE; // Draw end caps
1196 if (getPathLength() == 0)
1197 {
1198 // Path hasn't been generated yet.
1199 // Some algorithms later assume at least TWO path points.
1200 resizePath(2);
1201 for (U32 i = 0; i < 2; i++)
1202 {
1203 mPath[i].mPos.setVec(0, 0, 0);
1204 mPath[i].mRot.setQuat(0, 0, 0);
1205 mPath[i].mScale.setVec(1, 1);
1206 mPath[i].mTexT = 0;
1207 }
1208 }
1209
1210 return TRUE;
1211}
1212
1213
1214BOOL LLPathParams::importFile(FILE *fp)
1215{
1216 const S32 BUFSIZE = 16384;
1217 char buffer[BUFSIZE];
1218 char keyword[256];
1219 char valuestr[256];
1220 keyword[0] = 0;
1221 valuestr[0] = 0;
1222
1223 F32 tempF32;
1224 F32 x, y;
1225 U32 tempU32;
1226
1227 while (!feof(fp))
1228 {
1229 fgets(buffer, BUFSIZE, fp);
1230 sscanf(buffer, " %s %s", keyword, valuestr);
1231 if (!keyword)
1232 {
1233 continue;
1234 }
1235 if (!strcmp("{", keyword))
1236 {
1237 continue;
1238 }
1239 if (!strcmp("}",keyword))
1240 {
1241 break;
1242 }
1243 else if (!strcmp("curve", keyword))
1244 {
1245 sscanf(valuestr,"%d",&tempU32);
1246 setCurveType((U8) tempU32);
1247 }
1248 else if (!strcmp("begin",keyword))
1249 {
1250 sscanf(valuestr,"%g",&tempF32);
1251 setBegin(tempF32);
1252 }
1253 else if (!strcmp("end",keyword))
1254 {
1255 sscanf(valuestr,"%g",&tempF32);
1256 setEnd(tempF32);
1257 }
1258 else if (!strcmp("scale",keyword))
1259 {
1260 // Legacy for one dimensional scale per path
1261 sscanf(valuestr,"%g",&tempF32);
1262 setScale(tempF32, tempF32);
1263 }
1264 else if (!strcmp("scale_x", keyword))
1265 {
1266 sscanf(valuestr, "%g", &x);
1267 setScaleX(x);
1268 }
1269 else if (!strcmp("scale_y", keyword))
1270 {
1271 sscanf(valuestr, "%g", &y);
1272 setScaleY(y);
1273 }
1274 else if (!strcmp("shear_x", keyword))
1275 {
1276 sscanf(valuestr, "%g", &x);
1277 setShearX(x);
1278 }
1279 else if (!strcmp("shear_y", keyword))
1280 {
1281 sscanf(valuestr, "%g", &y);
1282 setShearY(y);
1283 }
1284 else if (!strcmp("twist",keyword))
1285 {
1286 sscanf(valuestr,"%g",&tempF32);
1287 setTwist(tempF32);
1288 }
1289 else if (!strcmp("twist_begin", keyword))
1290 {
1291 sscanf(valuestr, "%g", &y);
1292 setTwistBegin(y);
1293 }
1294 else if (!strcmp("radius_offset", keyword))
1295 {
1296 sscanf(valuestr, "%g", &y);
1297 setRadiusOffset(y);
1298 }
1299 else if (!strcmp("taper_x", keyword))
1300 {
1301 sscanf(valuestr, "%g", &y);
1302 setTaperX(y);
1303 }
1304 else if (!strcmp("taper_y", keyword))
1305 {
1306 sscanf(valuestr, "%g", &y);
1307 setTaperY(y);
1308 }
1309 else if (!strcmp("revolutions", keyword))
1310 {
1311 sscanf(valuestr, "%g", &y);
1312 setRevolutions(y);
1313 }
1314 else if (!strcmp("skew", keyword))
1315 {
1316 sscanf(valuestr, "%g", &y);
1317 setSkew(y);
1318 }
1319 else
1320 {
1321 llwarns << "unknown keyword " << " in path import" << llendl;
1322 }
1323 }
1324 return TRUE;
1325}
1326
1327
1328BOOL LLPathParams::exportFile(FILE *fp) const
1329{
1330 fprintf(fp, "\t\tpath 0\n");
1331 fprintf(fp, "\t\t{\n");
1332 fprintf(fp, "\t\t\tcurve\t%d\n", getCurveType());
1333 fprintf(fp, "\t\t\tbegin\t%g\n", getBegin());
1334 fprintf(fp, "\t\t\tend\t%g\n", getEnd());
1335 fprintf(fp, "\t\t\tscale_x\t%g\n", getScaleX() );
1336 fprintf(fp, "\t\t\tscale_y\t%g\n", getScaleY() );
1337 fprintf(fp, "\t\t\tshear_x\t%g\n", getShearX() );
1338 fprintf(fp, "\t\t\tshear_y\t%g\n", getShearY() );
1339 fprintf(fp,"\t\t\ttwist\t%g\n", getTwist());
1340
1341 fprintf(fp,"\t\t\ttwist_begin\t%g\n", getTwistBegin());
1342 fprintf(fp,"\t\t\tradius_offset\t%g\n", getRadiusOffset());
1343 fprintf(fp,"\t\t\ttaper_x\t%g\n", getTaperX());
1344 fprintf(fp,"\t\t\ttaper_y\t%g\n", getTaperY());
1345 fprintf(fp,"\t\t\trevolutions\t%g\n", getRevolutions());
1346 fprintf(fp,"\t\t\tskew\t%g\n", getSkew());
1347
1348 fprintf(fp, "\t\t}\n");
1349 return TRUE;
1350}
1351
1352
1353BOOL LLPathParams::importLegacyStream(std::istream& input_stream)
1354{
1355 const S32 BUFSIZE = 16384;
1356 char buffer[BUFSIZE];
1357 char keyword[256];
1358 char valuestr[256];
1359 keyword[0] = 0;
1360 valuestr[0] = 0;
1361
1362 F32 tempF32;
1363 F32 x, y;
1364 U32 tempU32;
1365
1366 while (input_stream.good())
1367 {
1368 input_stream.getline(buffer, BUFSIZE);
1369 sscanf(buffer, " %s %s", keyword, valuestr);
1370 if (!keyword)
1371 {
1372 continue;
1373 }
1374 if (!strcmp("{", keyword))
1375 {
1376 continue;
1377 }
1378 if (!strcmp("}",keyword))
1379 {
1380 break;
1381 }
1382 else if (!strcmp("curve", keyword))
1383 {
1384 sscanf(valuestr,"%d",&tempU32);
1385 setCurveType((U8) tempU32);
1386 }
1387 else if (!strcmp("begin",keyword))
1388 {
1389 sscanf(valuestr,"%g",&tempF32);
1390 setBegin(tempF32);
1391 }
1392 else if (!strcmp("end",keyword))
1393 {
1394 sscanf(valuestr,"%g",&tempF32);
1395 setEnd(tempF32);
1396 }
1397 else if (!strcmp("scale",keyword))
1398 {
1399 // Legacy for one dimensional scale per path
1400 sscanf(valuestr,"%g",&tempF32);
1401 setScale(tempF32, tempF32);
1402 }
1403 else if (!strcmp("scale_x", keyword))
1404 {
1405 sscanf(valuestr, "%g", &x);
1406 setScaleX(x);
1407 }
1408 else if (!strcmp("scale_y", keyword))
1409 {
1410 sscanf(valuestr, "%g", &y);
1411 setScaleY(y);
1412 }
1413 else if (!strcmp("shear_x", keyword))
1414 {
1415 sscanf(valuestr, "%g", &x);
1416 setShearX(x);
1417 }
1418 else if (!strcmp("shear_y", keyword))
1419 {
1420 sscanf(valuestr, "%g", &y);
1421 setShearY(y);
1422 }
1423 else if (!strcmp("twist",keyword))
1424 {
1425 sscanf(valuestr,"%g",&tempF32);
1426 setTwist(tempF32);
1427 }
1428 else if (!strcmp("twist_begin", keyword))
1429 {
1430 sscanf(valuestr, "%g", &y);
1431 setTwistBegin(y);
1432 }
1433 else if (!strcmp("radius_offset", keyword))
1434 {
1435 sscanf(valuestr, "%g", &y);
1436 setRadiusOffset(y);
1437 }
1438 else if (!strcmp("taper_x", keyword))
1439 {
1440 sscanf(valuestr, "%g", &y);
1441 setTaperX(y);
1442 }
1443 else if (!strcmp("taper_y", keyword))
1444 {
1445 sscanf(valuestr, "%g", &y);
1446 setTaperY(y);
1447 }
1448 else if (!strcmp("revolutions", keyword))
1449 {
1450 sscanf(valuestr, "%g", &y);
1451 setRevolutions(y);
1452 }
1453 else if (!strcmp("skew", keyword))
1454 {
1455 sscanf(valuestr, "%g", &y);
1456 setSkew(y);
1457 }
1458 else
1459 {
1460 llwarns << "unknown keyword " << " in path import" << llendl;
1461 }
1462 }
1463 return TRUE;
1464}
1465
1466
1467BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const
1468{
1469 output_stream << "\t\tpath 0\n";
1470 output_stream << "\t\t{\n";
1471 output_stream << "\t\t\tcurve\t" << (S32) getCurveType() << "\n";
1472 output_stream << "\t\t\tbegin\t" << getBegin() << "\n";
1473 output_stream << "\t\t\tend\t" << getEnd() << "\n";
1474 output_stream << "\t\t\tscale_x\t" << getScaleX() << "\n";
1475 output_stream << "\t\t\tscale_y\t" << getScaleY() << "\n";
1476 output_stream << "\t\t\tshear_x\t" << getShearX() << "\n";
1477 output_stream << "\t\t\tshear_y\t" << getShearY() << "\n";
1478 output_stream <<"\t\t\ttwist\t" << getTwist() << "\n";
1479
1480 output_stream <<"\t\t\ttwist_begin\t" << getTwistBegin() << "\n";
1481 output_stream <<"\t\t\tradius_offset\t" << getRadiusOffset() << "\n";
1482 output_stream <<"\t\t\ttaper_x\t" << getTaperX() << "\n";
1483 output_stream <<"\t\t\ttaper_y\t" << getTaperY() << "\n";
1484 output_stream <<"\t\t\trevolutions\t" << getRevolutions() << "\n";
1485 output_stream <<"\t\t\tskew\t" << getSkew() << "\n";
1486
1487 output_stream << "\t\t}\n";
1488 return TRUE;
1489}
1490
1491LLSD LLPathParams::asLLSD() const
1492{
1493 LLSD sd = LLSD();
1494 sd["curve"] = getCurveType();
1495 sd["begin"] = getBegin();
1496 sd["end"] = getEnd();
1497 sd["scale_x"] = getScaleX();
1498 sd["scale_y"] = getScaleY();
1499 sd["shear_x"] = getShearX();
1500 sd["shear_y"] = getShearY();
1501 sd["twist"] = getTwist();
1502 sd["twist_begin"] = getTwistBegin();
1503 sd["radius_offset"] = getRadiusOffset();
1504 sd["taper_x"] = getTaperX();
1505 sd["taper_y"] = getTaperY();
1506 sd["revolutions"] = getRevolutions();
1507 sd["skew"] = getSkew();
1508
1509 return sd;
1510}
1511
1512bool LLPathParams::fromLLSD(LLSD& sd)
1513{
1514 setCurveType(sd["curve"].asInteger());
1515 setBegin((F32)sd["begin"].asReal());
1516 setEnd((F32)sd["end"].asReal());
1517 setScaleX((F32)sd["scale_x"].asReal());
1518 setScaleY((F32)sd["scale_y"].asReal());
1519 setShearX((F32)sd["shear_x"].asReal());
1520 setShearY((F32)sd["shear_y"].asReal());
1521 setTwist((F32)sd["twist"].asReal());
1522 setTwistBegin((F32)sd["twist_begin"].asReal());
1523 setRadiusOffset((F32)sd["radius_offset"].asReal());
1524 setTaperX((F32)sd["taper_x"].asReal());
1525 setTaperY((F32)sd["taper_y"].asReal());
1526 setRevolutions((F32)sd["revolutions"].asReal());
1527 setSkew((F32)sd["skew"].asReal());
1528 return true;
1529}
1530
1531void LLPathParams::copyParams(const LLPathParams &params)
1532{
1533 setCurveType(params.getCurveType());
1534 setBegin(params.getBegin());
1535 setEnd(params.getEnd());
1536 setScale(params.getScaleX(), params.getScaleY() );
1537 setShear(params.getShearX(), params.getShearY() );
1538 setTwist(params.getTwist());
1539 setTwistBegin(params.getTwistBegin());
1540 setRadiusOffset(params.getRadiusOffset());
1541 setTaper( params.getTaperX(), params.getTaperY() );
1542 setRevolutions(params.getRevolutions());
1543 setSkew(params.getSkew());
1544}
1545
1546LLProfile::~LLProfile()
1547{
1548
1549}
1550
1551
1552S32 LLVolume::mNumMeshPoints = 0;
1553
1554LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) : mParams(params)
1555{
1556 mUnique = is_unique;
1557 mFaceMask = 0x0;
1558 mDetail = detail;
1559 // set defaults
1560 if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
1561 {
1562 mPathp = new LLDynamicPath(mParams.getPathParams());
1563 }
1564 else
1565 {
1566 mPathp = new LLPath(mParams.getPathParams());
1567 }
1568 mProfilep = new LLProfile(mParams.getProfileParams());
1569
1570 mNumVolumeFaces = 0;
1571 mVolumeFaces = NULL;
1572 mGenerateSingleFace = generate_single_face;
1573
1574 generate();
1575 createVolumeFaces();
1576}
1577
1578void LLVolume::regen()
1579{
1580 generate();
1581 createVolumeFaces();
1582}
1583
1584LLVolume::~LLVolume()
1585{
1586 mNumMeshPoints -= mMesh.size();
1587 delete mPathp;
1588 delete mProfilep;
1589 delete[] mVolumeFaces;
1590
1591 mPathp = NULL;
1592 mProfilep = NULL;
1593 mVolumeFaces = NULL;
1594}
1595
1596BOOL LLVolume::generate()
1597{
1598 //Added 10.03.05 Dave Parks
1599 // Split is a parameter to LLProfile::generate that tesselates edges on the profile
1600 // to prevent lighting and texture interpolation errors on triangles that are
1601 // stretched due to twisting or scaling on the path.
1602 S32 split = (S32) ((mDetail)*0.66f);
1603
1604 if (mPathp->mParams.getCurveType() == LL_PCODE_PATH_LINE &&
1605 (mPathp->mParams.getScale().mV[0] != 1.0f ||
1606 mPathp->mParams.getScale().mV[1] != 1.0f) &&
1607 (mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_SQUARE ||
1608 mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_ISOTRI ||
1609 mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_EQUALTRI ||
1610 mProfilep->mParams.getCurveType() == LL_PCODE_PROFILE_RIGHTTRI))
1611 {
1612 split = 0;
1613 }
1614
1615 mLODScaleBias.setVec(0.5f, 0.5f, 0.5f);
1616
1617 F32 profile_detail = mDetail;
1618 F32 path_detail = mDetail;
1619
1620 U8 path_type = mPathp->mParams.getCurveType();
1621 U8 profile_type = mProfilep->mParams.getCurveType();
1622
1623 if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE)
1624 { //cylinders don't care about Z-Axis
1625 mLODScaleBias.setVec(0.6f, 0.6f, 0.0f);
1626 }
1627 else if (path_type == LL_PCODE_PATH_CIRCLE)
1628 {
1629 mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
1630 }
1631
1632 BOOL regenPath = mPathp->generate(path_detail, split);
1633 BOOL regenProf = mProfilep->generate(mPathp->isOpen(),profile_detail, split);
1634
1635 if (regenPath || regenProf )
1636 {
1637 mNumMeshPoints -= mMesh.size();
1638 mMesh.resize(mProfilep->mProfile.size() * mPathp->mPath.size());
1639 mNumMeshPoints += mMesh.size();
1640
1641 S32 s = 0, t=0;
1642 S32 sizeS = mPathp->mPath.size();
1643 S32 sizeT = mProfilep->mProfile.size();
1644 S32 line = 0;
1645
1646 //generate vertex positions
1647
1648 // Run along the path.
1649 while (s < sizeS)
1650 {
1651 LLVector2 scale = mPathp->mPath[s].mScale;
1652 LLQuaternion rot = mPathp->mPath[s].mRot;
1653
1654 t = 0;
1655 // Run along the profile.
1656 while (t < sizeT)
1657 {
1658 S32 i = t + line;
1659 Point& pt = mMesh[i];
1660
1661 pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0];
1662 pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1];
1663 pt.mPos.mV[2] = 0.0f;
1664 pt.mPos = pt.mPos * rot;
1665 pt.mPos += mPathp->mPath[s].mPos;
1666 t++;
1667 }
1668 line += sizeT;
1669 s++;
1670 }
1671
1672 for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++)
1673 {
1674 mFaceMask |= mProfilep->mFaces[i].mFaceID;
1675 }
1676 return TRUE;
1677 }
1678 return FALSE;
1679}
1680
1681
1682void LLVolume::createVolumeFaces()
1683{
1684 S32 i;
1685
1686 if (mVolumeFaces != NULL)
1687 {
1688 delete[] mVolumeFaces;
1689 mVolumeFaces = NULL;
1690 }
1691
1692 if (mGenerateSingleFace)
1693 {
1694 mNumVolumeFaces = 0;
1695 }
1696 else
1697 {
1698 S32 num_faces = getNumFaces();
1699 mNumVolumeFaces = num_faces;
1700 mVolumeFaces = new LLVolumeFace[num_faces];
1701 // Initialize volume faces with parameter data
1702 for (i = 0; i < num_faces; i++)
1703 {
1704 LLVolumeFace &vf = mVolumeFaces[i];
1705 LLProfile::Face &face = mProfilep->mFaces[i];
1706 vf.mVolumep = this;
1707 vf.mBeginS = face.mIndex;
1708 vf.mNumS = face.mCount;
1709 vf.mBeginT = 0;
1710 vf.mNumT= getPath().mPath.size();
1711 vf.mID = i;
1712
1713 // Set the type mask bits correctly
1714 if (mProfilep->isHollow())
1715 {
1716 vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
1717 }
1718 if (mProfilep->isOpen())
1719 {
1720 vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
1721 }
1722 if (face.mCap)
1723 {
1724 vf.mTypeMask |= LLVolumeFace::CAP_MASK;
1725 if (face.mFaceID == LL_FACE_PATH_BEGIN)
1726 {
1727 vf.mTypeMask |= LLVolumeFace::TOP_MASK;
1728 }
1729 else
1730 {
1731 llassert(face.mFaceID == LL_FACE_PATH_END);
1732 vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
1733 }
1734 }
1735 else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
1736 {
1737 vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
1738 }
1739 else
1740 {
1741 vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
1742 if (face.mFlat)
1743 {
1744 vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
1745 }
1746 if (face.mFaceID & LL_FACE_INNER_SIDE)
1747 {
1748 vf.mTypeMask |= LLVolumeFace::INNER_MASK;
1749 if (face.mFlat && vf.mNumS > 2)
1750 { //flat inner faces have to copy vert normals
1751 vf.mNumS = vf.mNumS*2;
1752 }
1753 }
1754 else
1755 {
1756 vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
1757 }
1758 }
1759 }
1760
1761 for (i = 0; i < mNumVolumeFaces; i++)
1762 {
1763 mVolumeFaces[i].create();
1764 }
1765 }
1766
1767 mBounds[1] = LLVector3(0,0,0);
1768 mBounds[0] = LLVector3(512,512,512);
1769}
1770
1771
1772BOOL LLVolume::isCap(S32 face)
1773{
1774 return mProfilep->mFaces[face].mCap;
1775}
1776
1777BOOL LLVolume::isFlat(S32 face)
1778{
1779 return mProfilep->mFaces[face].mFlat;
1780}
1781
1782
1783bool LLVolumeParams::operator==(const LLVolumeParams &params) const
1784{
1785 return (getPathParams() == params.getPathParams()) &&
1786 (getProfileParams() == params.getProfileParams());
1787}
1788
1789bool LLVolumeParams::operator!=(const LLVolumeParams &params) const
1790{
1791 return (getPathParams() != params.getPathParams()) ||
1792 (getProfileParams() != params.getProfileParams());
1793}
1794
1795bool LLVolumeParams::operator<(const LLVolumeParams &params) const
1796{
1797 if( getPathParams() != params.getPathParams() )
1798 {
1799 return getPathParams() < params.getPathParams();
1800 }
1801 else
1802 {
1803 return getProfileParams() < params.getProfileParams();
1804 }
1805}
1806
1807void LLVolumeParams::copyParams(const LLVolumeParams &params)
1808{
1809 mProfileParams.copyParams(params.mProfileParams);
1810 mPathParams.copyParams(params.mPathParams);
1811}
1812
1813// return true if in range (or nearly so)
1814static bool limit_range(F32& v, F32 min, F32 max)
1815{
1816 F32 min_delta = v - min;
1817 if (min_delta < 0.f)
1818 {
1819 v = min;
1820 if (!is_approx_zero(min_delta))
1821 return false;
1822 }
1823 F32 max_delta = max - v;
1824 if (max_delta < 0.f)
1825 {
1826 v = max;
1827 if (!is_approx_zero(max_delta))
1828 return false;
1829 }
1830 return true;
1831}
1832
1833bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e)
1834{
1835 bool valid = true;
1836
1837 // First, clamp to valid ranges.
1838 F32 begin = b;
1839 valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
1840
1841 F32 end = e;
1842 valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
1843
1844 valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA);
1845
1846 // Now set them.
1847 mProfileParams.setBegin(begin);
1848 mProfileParams.setEnd(end);
1849
1850 return valid;
1851}
1852
1853bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e)
1854{
1855 bool valid = true;
1856
1857 // First, clamp to valid ranges.
1858 F32 begin = b;
1859 valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
1860
1861 F32 end = e;
1862 valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
1863
1864 valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA);
1865
1866 // Now set them.
1867 mPathParams.setBegin(begin);
1868 mPathParams.setEnd(end);
1869
1870 return valid;
1871}
1872
1873bool LLVolumeParams::setHollow(const F32 h)
1874{
1875 // Validate the hollow based on path and profile.
1876 U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
1877 U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK;
1878
1879 F32 max_hollow = HOLLOW_MAX;
1880
1881 // Only square holes have trouble.
1882 if (LL_PCODE_HOLE_SQUARE == hole_type)
1883 {
1884 switch(profile)
1885 {
1886 case LL_PCODE_PROFILE_CIRCLE:
1887 case LL_PCODE_PROFILE_CIRCLE_HALF:
1888 case LL_PCODE_PROFILE_EQUALTRI:
1889 max_hollow = HOLLOW_MAX_SQUARE;
1890 }
1891 }
1892
1893 F32 hollow = h;
1894 bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow);
1895 mProfileParams.setHollow(hollow);
1896
1897 return valid;
1898}
1899
1900bool LLVolumeParams::setTwistBegin(const F32 b)
1901{
1902 F32 twist_begin = b;
1903 bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX);
1904 mPathParams.setTwistBegin(twist_begin);
1905 return valid;
1906}
1907
1908bool LLVolumeParams::setTwistEnd(const F32 e)
1909{
1910 F32 twist_end = e;
1911 bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX);
1912 mPathParams.setTwistEnd(twist_end);
1913 return valid;
1914}
1915
1916bool LLVolumeParams::setRatio(const F32 x, const F32 y)
1917{
1918 F32 min_x = RATIO_MIN;
1919 F32 max_x = RATIO_MAX;
1920 F32 min_y = RATIO_MIN;
1921 F32 max_y = RATIO_MAX;
1922 // If this is a circular path (and not a sphere) then 'ratio' is actually hole size.
1923 U8 path_type = mPathParams.getCurveType();
1924 U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
1925 if ( LL_PCODE_PATH_CIRCLE == path_type &&
1926 LL_PCODE_PROFILE_CIRCLE_HALF != profile_type)
1927 {
1928 // Holes are more restricted...
1929 min_x = HOLE_X_MIN;
1930 max_x = HOLE_X_MAX;
1931 min_y = HOLE_Y_MIN;
1932 max_y = HOLE_Y_MAX;
1933 }
1934
1935 F32 ratio_x = x;
1936 bool valid = limit_range(ratio_x, min_x, max_x);
1937 F32 ratio_y = y;
1938 valid &= limit_range(ratio_y, min_y, max_y);
1939
1940 mPathParams.setScale(ratio_x, ratio_y);
1941
1942 return valid;
1943}
1944
1945bool LLVolumeParams::setShear(const F32 x, const F32 y)
1946{
1947 F32 shear_x = x;
1948 bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX);
1949 F32 shear_y = y;
1950 valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX);
1951 mPathParams.setShear(shear_x, shear_y);
1952 return valid;
1953}
1954
1955bool LLVolumeParams::setTaperX(const F32 v)
1956{
1957 F32 taper = v;
1958 bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
1959 mPathParams.setTaperX(taper);
1960 return valid;
1961}
1962
1963bool LLVolumeParams::setTaperY(const F32 v)
1964{
1965 F32 taper = v;
1966 bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
1967 mPathParams.setTaperY(taper);
1968 return valid;
1969}
1970
1971bool LLVolumeParams::setRevolutions(const F32 r)
1972{
1973 F32 revolutions = r;
1974 bool valid = limit_range(revolutions, REV_MIN, REV_MAX);
1975 mPathParams.setRevolutions(revolutions);
1976 return valid;
1977}
1978
1979bool LLVolumeParams::setRadiusOffset(const F32 offset)
1980{
1981 bool valid = true;
1982
1983 // If this is a sphere, just set it to 0 and get out.
1984 U8 path_type = mPathParams.getCurveType();
1985 U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
1986 if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ||
1987 LL_PCODE_PATH_CIRCLE != path_type )
1988 {
1989 mPathParams.setRadiusOffset(0.f);
1990 return true;
1991 }
1992
1993 // Limit radius offset, based on taper and hole size y.
1994 F32 radius_offset = offset;
1995 F32 taper_y = getTaperY();
1996 F32 radius_mag = fabs(radius_offset);
1997 F32 hole_y_mag = fabs(getRatioY());
1998 F32 taper_y_mag = fabs(taper_y);
1999 // Check to see if the taper effects us.
2000 if ( (radius_offset > 0.f && taper_y < 0.f) ||
2001 (radius_offset < 0.f && taper_y > 0.f) )
2002 {
2003 // The taper does not help increase the radius offset range.
2004 taper_y_mag = 0.f;
2005 }
2006 F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
2007
2008 // Enforce the maximum magnitude.
2009 F32 delta = max_radius_mag - radius_mag;
2010 if (delta < 0.f)
2011 {
2012 // Check radius offset sign.
2013 if (radius_offset < 0.f)
2014 {
2015 radius_offset = -max_radius_mag;
2016 }
2017 else
2018 {
2019 radius_offset = max_radius_mag;
2020 }
2021 valid = is_approx_zero(delta);
2022 }
2023
2024 mPathParams.setRadiusOffset(radius_offset);
2025 return valid;
2026}
2027
2028bool LLVolumeParams::setSkew(const F32 skew_value)
2029{
2030 bool valid = true;
2031
2032 // Check the skew value against the revolutions.
2033 F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX);
2034 F32 skew_mag = fabs(skew);
2035 F32 revolutions = getRevolutions();
2036 F32 scale_x = getRatioX();
2037 F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
2038 // Discontinuity; A revolution of 1 allows skews below 0.5.
2039 if ( fabs(revolutions - 1.0f) < 0.001)
2040 min_skew_mag = 0.0f;
2041
2042 // Clip skew.
2043 F32 delta = skew_mag - min_skew_mag;
2044 if (delta < 0.f)
2045 {
2046 // Check skew sign.
2047 if (skew < 0.0f)
2048 {
2049 skew = -min_skew_mag;
2050 }
2051 else
2052 {
2053 skew = min_skew_mag;
2054 }
2055 valid = is_approx_zero(delta);
2056 }
2057
2058 mPathParams.setSkew(skew);
2059 return valid;
2060}
2061
2062bool LLVolumeParams::setType(U8 profile, U8 path)
2063{
2064 bool result = true;
2065 // First, check profile and path for validity.
2066 U8 profile_type = profile & LL_PCODE_PROFILE_MASK;
2067 U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4;
2068 U8 path_type = path >> 4;
2069
2070 if (profile_type > LL_PCODE_PROFILE_MAX)
2071 {
2072 // Bad profile. Make it square.
2073 profile = LL_PCODE_PROFILE_SQUARE;
2074 result = false;
2075 llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type
2076 << ") to be LL_PCODE_PROFILE_SQUARE" << llendl;
2077 }
2078 else if (hole_type > LL_PCODE_HOLE_MAX)
2079 {
2080 // Bad hole. Make it the same.
2081 profile = profile_type;
2082 result = false;
2083 llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type
2084 << ") to be LL_PCODE_HOLE_SAME" << llendl;
2085 }
2086
2087 if (path_type < LL_PCODE_PATH_MIN ||
2088 path_type > LL_PCODE_PATH_MAX)
2089 {
2090 // Bad path. Make it linear.
2091 result = false;
2092 llwarns << "LLVolumeParams::setType changing bad path (" << path
2093 << ") to be LL_PCODE_PATH_LINE" << llendl;
2094 path = LL_PCODE_PATH_LINE;
2095 }
2096
2097 mProfileParams.setCurveType(profile);
2098 mPathParams.setCurveType(path);
2099 return result;
2100}
2101
2102// static
2103bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
2104 U8 path_curve, F32 path_begin, F32 path_end,
2105 F32 scx, F32 scy, F32 shx, F32 shy,
2106 F32 twistend, F32 twistbegin, F32 radiusoffset,
2107 F32 tx, F32 ty, F32 revolutions, F32 skew)
2108{
2109 LLVolumeParams test_params;
2110 if (!test_params.setType (prof_curve, path_curve))
2111 {
2112 return false;
2113 }
2114 if (!test_params.setBeginAndEndS (prof_begin, prof_end))
2115 {
2116 return false;
2117 }
2118 if (!test_params.setBeginAndEndT (path_begin, path_end))
2119 {
2120 return false;
2121 }
2122 if (!test_params.setHollow (hollow))
2123 {
2124 return false;
2125 }
2126 if (!test_params.setTwistBegin (twistbegin))
2127 {
2128 return false;
2129 }
2130 if (!test_params.setTwistEnd (twistend))
2131 {
2132 return false;
2133 }
2134 if (!test_params.setRatio (scx, scy))
2135 {
2136 return false;
2137 }
2138 if (!test_params.setShear (shx, shy))
2139 {
2140 return false;
2141 }
2142 if (!test_params.setTaper (tx, ty))
2143 {
2144 return false;
2145 }
2146 if (!test_params.setRevolutions (revolutions))
2147 {
2148 return false;
2149 }
2150 if (!test_params.setRadiusOffset (radiusoffset))
2151 {
2152 return false;
2153 }
2154 if (!test_params.setSkew (skew))
2155 {
2156 return false;
2157 }
2158 return true;
2159}
2160
2161#define MAX_INDEX 10000
2162S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
2163{
2164 S32 index[MAX_INDEX];
2165 S32 count = 0;
2166 S32 *indices = NULL;
2167
2168 // Let's do this totally diffently, as we don't care about faces...
2169 // Counter-clockwise triangles are forward facing...
2170
2171 BOOL open = getProfile().isOpen();
2172 BOOL hollow = getProfile().isHollow();
2173 BOOL path_open = getPath().isOpen();
2174 S32 size_s, size_s_out, size_t;
2175 S32 s, t, i;
2176 size_s = getProfile().getTotal();
2177 size_s_out = getProfile().getTotalOut();
2178 size_t = getPath().mPath.size();
2179
2180 if (open)
2181 {
2182 if (hollow)
2183 {
2184 // Open hollow -- much like the closed solid, except we
2185 // we need to stitch up the gap between s=0 and s=size_s-1
2186
2187 if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX)
2188 goto noindices;
2189
2190 for (t = 0; t < size_t - 1; t++)
2191 {
2192 // The outer face, first cut, and inner face
2193 for (s = 0; s < size_s - 1; s++)
2194 {
2195 i = s + t*size_s;
2196 index[count++] = i; // x,y
2197 index[count++] = i + 1; // x+1,y
2198 index[count++] = i + size_s; // x,y+1
2199
2200 index[count++] = i + size_s; // x,y+1
2201 index[count++] = i + 1; // x+1,y
2202 index[count++] = i + size_s + 1; // x+1,y+1
2203 }
2204
2205 // The other cut face
2206 index[count++] = s + t*size_s; // x,y
2207 index[count++] = 0 + t*size_s; // x+1,y
2208 index[count++] = s + (t+1)*size_s; // x,y+1
2209
2210 index[count++] = s + (t+1)*size_s; // x,y+1
2211 index[count++] = 0 + t*size_s; // x+1,y
2212 index[count++] = 0 + (t+1)*size_s; // x+1,y+1
2213 }
2214
2215 // Do the top and bottom caps, if necessary
2216 if (path_open)
2217 {
2218 // Top cap
2219 S32 pt1 = 0;
2220 S32 pt2 = size_s-1;
2221 S32 i = (size_t - 1)*size_s;
2222
2223 while (pt2 - pt1 > 1)
2224 {
2225 // Use the profile points instead of the mesh, since you want
2226 // the un-transformed profile distances.
2227 LLVector3 p1 = getProfile().mProfile[pt1];
2228 LLVector3 p2 = getProfile().mProfile[pt2];
2229 LLVector3 pa = getProfile().mProfile[pt1+1];
2230 LLVector3 pb = getProfile().mProfile[pt2-1];
2231
2232 p1.mV[VZ] = 0.f;
2233 p2.mV[VZ] = 0.f;
2234 pa.mV[VZ] = 0.f;
2235 pb.mV[VZ] = 0.f;
2236
2237 // Use area of triangle to determine backfacing
2238 F32 area_1a2, area_1ba, area_21b, area_2ab;
2239 area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
2240 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
2241 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
2242
2243 area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2244 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
2245 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
2246
2247 area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
2248 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2249 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2250
2251 area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
2252 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
2253 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2254
2255 BOOL use_tri1a2 = TRUE;
2256 BOOL tri_1a2 = TRUE;
2257 BOOL tri_21b = TRUE;
2258
2259 if (area_1a2 < 0)
2260 {
2261 tri_1a2 = FALSE;
2262 }
2263 if (area_2ab < 0)
2264 {
2265 // Can't use, because it contains point b
2266 tri_1a2 = FALSE;
2267 }
2268 if (area_21b < 0)
2269 {
2270 tri_21b = FALSE;
2271 }
2272 if (area_1ba < 0)
2273 {
2274 // Can't use, because it contains point b
2275 tri_21b = FALSE;
2276 }
2277
2278 if (!tri_1a2)
2279 {
2280 use_tri1a2 = FALSE;
2281 }
2282 else if (!tri_21b)
2283 {
2284 use_tri1a2 = TRUE;
2285 }
2286 else
2287 {
2288 LLVector3 d1 = p1 - pa;
2289 LLVector3 d2 = p2 - pb;
2290
2291 if (d1.magVecSquared() < d2.magVecSquared())
2292 {
2293 use_tri1a2 = TRUE;
2294 }
2295 else
2296 {
2297 use_tri1a2 = FALSE;
2298 }
2299 }
2300
2301 if (use_tri1a2)
2302 {
2303 if (count + 3 >= MAX_INDEX)
2304 goto noindices;
2305 index[count++] = pt1 + i;
2306 index[count++] = pt1 + 1 + i;
2307 index[count++] = pt2 + i;
2308 pt1++;
2309 }
2310 else
2311 {
2312 if (count + 3 >= MAX_INDEX)
2313 goto noindices;
2314 index[count++] = pt1 + i;
2315 index[count++] = pt2 - 1 + i;
2316 index[count++] = pt2 + i;
2317 pt2--;
2318 }
2319 }
2320
2321 // Bottom cap
2322 pt1 = 0;
2323 pt2 = size_s-1;
2324 while (pt2 - pt1 > 1)
2325 {
2326 // Use the profile points instead of the mesh, since you want
2327 // the un-transformed profile distances.
2328 LLVector3 p1 = getProfile().mProfile[pt1];
2329 LLVector3 p2 = getProfile().mProfile[pt2];
2330 LLVector3 pa = getProfile().mProfile[pt1+1];
2331 LLVector3 pb = getProfile().mProfile[pt2-1];
2332
2333 p1.mV[VZ] = 0.f;
2334 p2.mV[VZ] = 0.f;
2335 pa.mV[VZ] = 0.f;
2336 pb.mV[VZ] = 0.f;
2337
2338 // Use area of triangle to determine backfacing
2339 F32 area_1a2, area_1ba, area_21b, area_2ab;
2340 area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
2341 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
2342 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
2343
2344 area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2345 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
2346 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
2347
2348 area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
2349 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2350 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2351
2352 area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
2353 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
2354 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2355
2356 BOOL use_tri1a2 = TRUE;
2357 BOOL tri_1a2 = TRUE;
2358 BOOL tri_21b = TRUE;
2359
2360 if (area_1a2 < 0)
2361 {
2362 tri_1a2 = FALSE;
2363 }
2364 if (area_2ab < 0)
2365 {
2366 // Can't use, because it contains point b
2367 tri_1a2 = FALSE;
2368 }
2369 if (area_21b < 0)
2370 {
2371 tri_21b = FALSE;
2372 }
2373 if (area_1ba < 0)
2374 {
2375 // Can't use, because it contains point b
2376 tri_21b = FALSE;
2377 }
2378
2379 if (!tri_1a2)
2380 {
2381 use_tri1a2 = FALSE;
2382 }
2383 else if (!tri_21b)
2384 {
2385 use_tri1a2 = TRUE;
2386 }
2387 else
2388 {
2389 LLVector3 d1 = p1 - pa;
2390 LLVector3 d2 = p2 - pb;
2391
2392 if (d1.magVecSquared() < d2.magVecSquared())
2393 {
2394 use_tri1a2 = TRUE;
2395 }
2396 else
2397 {
2398 use_tri1a2 = FALSE;
2399 }
2400 }
2401
2402 if (use_tri1a2)
2403 {
2404 if (count + 3 >= MAX_INDEX)
2405 goto noindices;
2406 index[count++] = pt1;
2407 index[count++] = pt2;
2408 index[count++] = pt1 + 1;
2409 pt1++;
2410 }
2411 else
2412 {
2413 if (count + 3 >= MAX_INDEX)
2414 goto noindices;
2415 index[count++] = pt1;
2416 index[count++] = pt2;
2417 index[count++] = pt2 - 1;
2418 pt2--;
2419 }
2420 }
2421 }
2422 }
2423 else
2424 {
2425 // Open solid
2426
2427 if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX)
2428 goto noindices;
2429
2430 for (t = 0; t < size_t - 1; t++)
2431 {
2432 // Outer face + 1 cut face
2433 for (s = 0; s < size_s - 1; s++)
2434 {
2435 i = s + t*size_s;
2436
2437 index[count++] = i; // x,y
2438 index[count++] = i + 1; // x+1,y
2439 index[count++] = i + size_s; // x,y+1
2440
2441 index[count++] = i + size_s; // x,y+1
2442 index[count++] = i + 1; // x+1,y
2443 index[count++] = i + size_s + 1; // x+1,y+1
2444 }
2445
2446 // The other cut face
2447 index[count++] = (size_s - 1) + (t*size_s); // x,y
2448 index[count++] = 0 + t*size_s; // x+1,y
2449 index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1
2450
2451 index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1
2452 index[count++] = 0 + (t*size_s); // x+1,y
2453 index[count++] = 0 + (t+1)*size_s; // x+1,y+1
2454 }
2455
2456 // Do the top and bottom caps, if necessary
2457 if (path_open)
2458 {
2459 if ( count + (size_s - 2) * 3 >= MAX_INDEX)
2460 goto noindices;
2461 for (s = 0; s < size_s - 2; s++)
2462 {
2463 index[count++] = s+1;
2464 index[count++] = s;
2465 index[count++] = size_s - 1;
2466 }
2467
2468 // We've got a top cap
2469 S32 offset = (size_t - 1)*size_s;
2470 if ( count + (size_s - 2) * 3 >= MAX_INDEX)
2471 goto noindices;
2472 for (s = 0; s < size_s - 2; s++)
2473 {
2474 // Inverted ordering from bottom cap.
2475 index[count++] = offset + size_s - 1;
2476 index[count++] = offset + s;
2477 index[count++] = offset + s + 1;
2478 }
2479 }
2480 }
2481 }
2482 else if (hollow)
2483 {
2484 // Closed hollow
2485 // Outer face
2486
2487 if ( (size_t - 1) * (size_s_out - 1) * 6 >= MAX_INDEX)
2488 goto noindices;
2489 for (t = 0; t < size_t - 1; t++)
2490 {
2491 for (s = 0; s < size_s_out - 1; s++)
2492 {
2493 i = s + t*size_s;
2494
2495 index[count++] = i; // x,y
2496 index[count++] = i + 1; // x+1,y
2497 index[count++] = i + size_s; // x,y+1
2498
2499 index[count++] = i + size_s; // x,y+1
2500 index[count++] = i + 1; // x+1,y
2501 index[count++] = i + 1 + size_s; // x+1,y+1
2502 }
2503 }
2504
2505 // Inner face
2506 // Invert facing from outer face
2507 if ( count + (size_t - 1) * ((size_s - 1) - size_s_out) * 6 >= MAX_INDEX)
2508 goto noindices;
2509 for (t = 0; t < size_t - 1; t++)
2510 {
2511 for (s = size_s_out; s < size_s - 1; s++)
2512 {
2513 i = s + t*size_s;
2514
2515 index[count++] = i; // x,y
2516 index[count++] = i + 1; // x+1,y
2517 index[count++] = i + size_s; // x,y+1
2518
2519 index[count++] = i + size_s; // x,y+1
2520 index[count++] = i + 1; // x+1,y
2521 index[count++] = i + 1 + size_s; // x+1,y+1
2522 }
2523 }
2524
2525 // Do the top and bottom caps, if necessary
2526 if (path_open)
2527 {
2528 // Top cap
2529 S32 pt1 = 0;
2530 S32 pt2 = size_s-1;
2531 S32 i = (size_t - 1)*size_s;
2532
2533 while (pt2 - pt1 > 1)
2534 {
2535 // Use the profile points instead of the mesh, since you want
2536 // the un-transformed profile distances.
2537 LLVector3 p1 = getProfile().mProfile[pt1];
2538 LLVector3 p2 = getProfile().mProfile[pt2];
2539 LLVector3 pa = getProfile().mProfile[pt1+1];
2540 LLVector3 pb = getProfile().mProfile[pt2-1];
2541
2542 p1.mV[VZ] = 0.f;
2543 p2.mV[VZ] = 0.f;
2544 pa.mV[VZ] = 0.f;
2545 pb.mV[VZ] = 0.f;
2546
2547 // Use area of triangle to determine backfacing
2548 F32 area_1a2, area_1ba, area_21b, area_2ab;
2549 area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
2550 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
2551 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
2552
2553 area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2554 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
2555 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
2556
2557 area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
2558 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2559 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2560
2561 area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
2562 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
2563 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2564
2565 BOOL use_tri1a2 = TRUE;
2566 BOOL tri_1a2 = TRUE;
2567 BOOL tri_21b = TRUE;
2568
2569 if (area_1a2 < 0)
2570 {
2571 tri_1a2 = FALSE;
2572 }
2573 if (area_2ab < 0)
2574 {
2575 // Can't use, because it contains point b
2576 tri_1a2 = FALSE;
2577 }
2578 if (area_21b < 0)
2579 {
2580 tri_21b = FALSE;
2581 }
2582 if (area_1ba < 0)
2583 {
2584 // Can't use, because it contains point b
2585 tri_21b = FALSE;
2586 }
2587
2588 if (!tri_1a2)
2589 {
2590 use_tri1a2 = FALSE;
2591 }
2592 else if (!tri_21b)
2593 {
2594 use_tri1a2 = TRUE;
2595 }
2596 else
2597 {
2598 LLVector3 d1 = p1 - pa;
2599 LLVector3 d2 = p2 - pb;
2600
2601 if (d1.magVecSquared() < d2.magVecSquared())
2602 {
2603 use_tri1a2 = TRUE;
2604 }
2605 else
2606 {
2607 use_tri1a2 = FALSE;
2608 }
2609 }
2610
2611 if (use_tri1a2)
2612 {
2613 if (count + 3 >= MAX_INDEX)
2614 goto noindices;
2615 index[count++] = pt1 + i;
2616 index[count++] = pt1 + 1 + i;
2617 index[count++] = pt2 + i;
2618 pt1++;
2619 }
2620 else
2621 {
2622 if (count + 3 >= MAX_INDEX)
2623 goto noindices;
2624 index[count++] = pt1 + i;
2625 index[count++] = pt2 - 1 + i;
2626 index[count++] = pt2 + i;
2627 pt2--;
2628 }
2629 }
2630
2631 // Bottom cap
2632 pt1 = 0;
2633 pt2 = size_s-1;
2634 while (pt2 - pt1 > 1)
2635 {
2636 // Use the profile points instead of the mesh, since you want
2637 // the un-transformed profile distances.
2638 LLVector3 p1 = getProfile().mProfile[pt1];
2639 LLVector3 p2 = getProfile().mProfile[pt2];
2640 LLVector3 pa = getProfile().mProfile[pt1+1];
2641 LLVector3 pb = getProfile().mProfile[pt2-1];
2642
2643 p1.mV[VZ] = 0.f;
2644 p2.mV[VZ] = 0.f;
2645 pa.mV[VZ] = 0.f;
2646 pb.mV[VZ] = 0.f;
2647
2648 // Use area of triangle to determine backfacing
2649 F32 area_1a2, area_1ba, area_21b, area_2ab;
2650 area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
2651 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
2652 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
2653
2654 area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2655 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
2656 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
2657
2658 area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
2659 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
2660 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2661
2662 area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
2663 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
2664 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
2665
2666 BOOL use_tri1a2 = TRUE;
2667 BOOL tri_1a2 = TRUE;
2668 BOOL tri_21b = TRUE;
2669
2670 if (area_1a2 < 0)
2671 {
2672 tri_1a2 = FALSE;
2673 }
2674 if (area_2ab < 0)
2675 {
2676 // Can't use, because it contains point b
2677 tri_1a2 = FALSE;
2678 }
2679 if (area_21b < 0)
2680 {
2681 tri_21b = FALSE;
2682 }
2683 if (area_1ba < 0)
2684 {
2685 // Can't use, because it contains point b
2686 tri_21b = FALSE;
2687 }
2688
2689 if (!tri_1a2)
2690 {
2691 use_tri1a2 = FALSE;
2692 }
2693 else if (!tri_21b)
2694 {
2695 use_tri1a2 = TRUE;
2696 }
2697 else
2698 {
2699 LLVector3 d1 = p1 - pa;
2700 LLVector3 d2 = p2 - pb;
2701
2702 if (d1.magVecSquared() < d2.magVecSquared())
2703 {
2704 use_tri1a2 = TRUE;
2705 }
2706 else
2707 {
2708 use_tri1a2 = FALSE;
2709 }
2710 }
2711
2712 if (use_tri1a2)
2713 {
2714 if (count + 3 >= MAX_INDEX)
2715 goto noindices;
2716 index[count++] = pt1;
2717 index[count++] = pt2;
2718 index[count++] = pt1 + 1;
2719 pt1++;
2720 }
2721 else
2722 {
2723 if (count + 3 >= MAX_INDEX)
2724 goto noindices;
2725 index[count++] = pt1;
2726 index[count++] = pt2;
2727 index[count++] = pt2 - 1;
2728 pt2--;
2729 }
2730 }
2731 }
2732 }
2733 else
2734 {
2735 // Closed solid. Easy case.
2736 if ( (size_t - 1) * (size_s - 1) * 6 > MAX_INDEX)
2737 goto noindices;
2738 for (t = 0; t < size_t - 1; t++)
2739 {
2740 for (s = 0; s < size_s - 1; s++)
2741 {
2742 // Should wrap properly, but for now...
2743 i = s + t*size_s;
2744
2745 index[count++] = i; // x,y
2746 index[count++] = i + 1; // x+1,y
2747 index[count++] = i + size_s; // x,y+1
2748
2749 index[count++] = i + size_s; // x,y+1
2750 index[count++] = i + 1; // x+1,y
2751 index[count++] = i + size_s + 1; // x+1,y+1
2752 }
2753 }
2754
2755 // Do the top and bottom caps, if necessary
2756 if (path_open)
2757 {
2758 // bottom cap
2759 if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX)
2760 goto noindices;
2761 for (s = 1; s < size_s - 2; s++)
2762 {
2763 index[count++] = s+1;
2764 index[count++] = s;
2765 index[count++] = 0;
2766 }
2767
2768 // top cap
2769 S32 offset = (size_t - 1)*size_s;
2770 if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX)
2771 goto noindices;
2772 for (s = 1; s < size_s - 2; s++)
2773 {
2774 // Inverted ordering from bottom cap.
2775 index[count++] = offset;
2776 index[count++] = offset + s;
2777 index[count++] = offset + s + 1;
2778 }
2779 }
2780 }
2781
2782#if 0
2783 S32 num_vertices = mMesh.size();
2784 for (i = 0; i < count; i+=3)
2785 {
2786 llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl;
2787 llassert(index[i] < num_vertices);
2788 llassert(index[i+1] < num_vertices);
2789 llassert(index[i+2] < num_vertices);
2790 }
2791#endif
2792
2793 indices = new S32[count];
2794noindices:
2795 if (!indices)
2796 {
2797 llwarns << "Couldn't allocate triangle indices" << llendl;
2798 num_indices = 0;
2799 return NULL;
2800 }
2801 num_indices = count;
2802 memcpy(indices, index, count * sizeof(S32));
2803 return indices;
2804}
2805
2806//-----------------------------------------------------------------------------
2807// generateSilhouetteVertices()
2808//-----------------------------------------------------------------------------
2809void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
2810 std::vector<LLVector3> &normals,
2811 std::vector<S32> &segments,
2812 const LLVector3& obj_cam_vec,
2813 const LLMatrix4& mat,
2814 const LLMatrix3& norm_mat)
2815{
2816 vertices.clear();
2817 normals.clear();
2818 segments.clear();
2819
2820 //for each face
2821 for (S32 i = 0; i < getNumFaces(); i++) {
2822 LLVolumeFace face = this->getVolumeFace(i);
2823
2824 if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
2825
2826 }
2827 else {
2828
2829 //==============================================
2830 //DEBUG draw edge map instead of silhouette edge
2831 //==============================================
2832
2833#if DEBUG_SILHOUETTE_EDGE_MAP
2834
2835 //for each triangle
2836 U32 count = face.mIndices.size();
2837 for (U32 j = 0; j < count/3; j++) {
2838 //get vertices
2839 S32 v1 = face.mIndices[j*3+0];
2840 S32 v2 = face.mIndices[j*3+1];
2841 S32 v3 = face.mIndices[j*3+2];
2842
2843 //get current face center
2844 LLVector3 cCenter = (face.mVertices[v1].mPosition +
2845 face.mVertices[v2].mPosition +
2846 face.mVertices[v3].mPosition) / 3.0f;
2847
2848 //for each edge
2849 for (S32 k = 0; k < 3; k++) {
2850 S32 nIndex = face.mEdge[j*3+k];
2851 if (nIndex <= -1) {
2852 continue;
2853 }
2854
2855 if (nIndex >= (S32) count/3) {
2856 continue;
2857 }
2858 //get neighbor vertices
2859 v1 = face.mIndices[nIndex*3+0];
2860 v2 = face.mIndices[nIndex*3+1];
2861 v3 = face.mIndices[nIndex*3+2];
2862
2863 //get neighbor face center
2864 LLVector3 nCenter = (face.mVertices[v1].mPosition +
2865 face.mVertices[v2].mPosition +
2866 face.mVertices[v3].mPosition) / 3.0f;
2867
2868 //draw line
2869 vertices.push_back(cCenter);
2870 vertices.push_back(nCenter);
2871 normals.push_back(LLVector3(1,1,1));
2872 normals.push_back(LLVector3(1,1,1));
2873 segments.push_back(vertices.size());
2874 }
2875 }
2876
2877 continue;
2878
2879 //==============================================
2880 //DEBUG
2881 //==============================================
2882
2883 //==============================================
2884 //DEBUG draw normals instead of silhouette edge
2885 //==============================================
2886#elif DEBUG_SILHOUETTE_NORMALS
2887
2888 //for each vertex
2889 for (U32 j = 0; j < face.mVertices.size(); j++) {
2890 vertices.push_back(face.mVertices[j].mPosition);
2891 vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f);
2892 normals.push_back(LLVector3(0,0,1));
2893 normals.push_back(LLVector3(0,0,1));
2894 segments.push_back(vertices.size());
2895#if DEBUG_SILHOUETTE_BINORMALS
2896 vertices.push_back(face.mVertices[j].mPosition);
2897 vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f);
2898 normals.push_back(LLVector3(0,0,1));
2899 normals.push_back(LLVector3(0,0,1));
2900 segments.push_back(vertices.size());
2901#endif
2902 }
2903
2904 continue;
2905#else
2906 //==============================================
2907 //DEBUG
2908 //==============================================
2909
2910 static const U8 AWAY = 0x01,
2911 TOWARDS = 0x02;
2912
2913 //for each triangle
2914 std::vector<U8> fFacing;
2915 vector_append(fFacing, face.mIndices.size()/3);
2916 for (U32 j = 0; j < face.mIndices.size()/3; j++)
2917 {
2918 //approximate normal
2919 S32 v1 = face.mIndices[j*3+0];
2920 S32 v2 = face.mIndices[j*3+1];
2921 S32 v3 = face.mIndices[j*3+2];
2922
2923 LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) %
2924 (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition);
2925
2926 if (norm.magVecSquared() < 0.00000001f)
2927 {
2928 fFacing[j] = AWAY | TOWARDS;
2929 }
2930 else
2931 {
2932 //get view vector
2933 LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition);
2934 bool away = view * norm > 0.0f;
2935 if (away)
2936 {
2937 fFacing[j] = AWAY;
2938 }
2939 else
2940 {
2941 fFacing[j] = TOWARDS;
2942 }
2943 }
2944 }
2945
2946 //for each triangle
2947 for (U32 j = 0; j < face.mIndices.size()/3; j++)
2948 {
2949 if (fFacing[j] == (AWAY | TOWARDS))
2950 { //this is a degenerate triangle
2951 //take neighbor facing (degenerate faces get facing of one of their neighbors)
2952 // *FIX IF NEEDED: this does not deal with neighboring degenerate faces
2953 for (S32 k = 0; k < 3; k++)
2954 {
2955 S32 index = face.mEdge[j*3+k];
2956 if (index != -1)
2957 {
2958 fFacing[j] = fFacing[index];
2959 break;
2960 }
2961 }
2962 continue; //skip degenerate face
2963 }
2964
2965 //for each edge
2966 for (S32 k = 0; k < 3; k++) {
2967 S32 index = face.mEdge[j*3+k];
2968 if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
2969 //our neighbor is degenerate, make him face our direction
2970 fFacing[face.mEdge[j*3+k]] = fFacing[j];
2971 continue;
2972 }
2973
2974 if (index == -1 || //edge has no neighbor, MUST be a silhouette edge
2975 (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge
2976
2977 S32 v1 = face.mIndices[j*3+k];
2978 S32 v2 = face.mIndices[j*3+((k+1)%3)];
2979
2980 vertices.push_back(face.mVertices[v1].mPosition*mat);
2981 normals.push_back(face.mVertices[v1].mNormal*norm_mat);
2982
2983 vertices.push_back(face.mVertices[v2].mPosition*mat);
2984 normals.push_back(face.mVertices[v2].mNormal*norm_mat);
2985 segments.push_back(vertices.size());
2986 }
2987 }
2988 }
2989#endif
2990 }
2991 }
2992}
2993
2994S32 LLVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const
2995{
2996 S32 ret = -1;
2997
2998 LLVector3 vec = end - start;
2999
3000 for (U32 i = 0; i < (U32)getNumFaces(); i++)
3001 {
3002 LLVolumeFace face = getVolumeFace(i);
3003
3004 for (U32 j = 0; j < face.mIndices.size()/3; j++)
3005 {
3006 //approximate normal
3007 S32 v1 = face.mIndices[j*3+0];
3008 S32 v2 = face.mIndices[j*3+1];
3009 S32 v3 = face.mIndices[j*3+2];
3010
3011 LLVector3 norm = (face.mVertices[v2].mPosition - face.mVertices[v1].mPosition) %
3012 (face.mVertices[v3].mPosition - face.mVertices[v2].mPosition);
3013
3014 if (norm.magVecSquared() >= 0.00000001f)
3015 {
3016 //get view vector
3017 //LLVector3 view = (start-face.mVertices[v1].mPosition);
3018 //if (view * norm < 0.0f)
3019 {
3020 if (LLTriangleLineSegmentIntersect( face.mVertices[v1].mPosition,
3021 face.mVertices[v2].mPosition,
3022 face.mVertices[v3].mPosition,
3023 end,
3024 vec))
3025 {
3026 vec = end-start;
3027 ret = (S32) i;
3028 }
3029 }
3030 }
3031 }
3032 }
3033
3034 return ret;
3035}
3036
3037class LLVertexIndexPair
3038{
3039public:
3040 LLVertexIndexPair(const LLVector3 &vertex, const S32 index);
3041
3042 LLVector3 mVertex;
3043 S32 mIndex;
3044};
3045
3046LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index)
3047{
3048 mVertex = vertex;
3049 mIndex = index;
3050}
3051
3052const F32 VERTEX_SLOP = 0.00001f;
3053const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP;
3054
3055struct lessVertex
3056{
3057 bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b)
3058 {
3059 const F32 slop = VERTEX_SLOP;
3060
3061 if (a->mVertex.mV[0] + slop < b->mVertex.mV[0])
3062 {
3063 return TRUE;
3064 }
3065 else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0])
3066 {
3067 return FALSE;
3068 }
3069
3070 if (a->mVertex.mV[1] + slop < b->mVertex.mV[1])
3071 {
3072 return TRUE;
3073 }
3074 else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1])
3075 {
3076 return FALSE;
3077 }
3078
3079 if (a->mVertex.mV[2] + slop < b->mVertex.mV[2])
3080 {
3081 return TRUE;
3082 }
3083 else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2])
3084 {
3085 return FALSE;
3086 }
3087
3088 return FALSE;
3089 }
3090};
3091
3092struct lessTriangle
3093{
3094 bool operator()(const S32 *a, const S32 *b)
3095 {
3096 if (*a < *b)
3097 {
3098 return TRUE;
3099 }
3100 else if (*a > *b)
3101 {
3102 return FALSE;
3103 }
3104
3105 if (*(a+1) < *(b+1))
3106 {
3107 return TRUE;
3108 }
3109 else if (*(a+1) > *(b+1))
3110 {
3111 return FALSE;
3112 }
3113
3114 if (*(a+2) < *(b+2))
3115 {
3116 return TRUE;
3117 }
3118 else if (*(a+2) > *(b+2))
3119 {
3120 return FALSE;
3121 }
3122
3123 return FALSE;
3124 }
3125};
3126
3127BOOL equalTriangle(const S32 *a, const S32 *b)
3128{
3129 if ((*a == *b) && (*(a+1) == *(b+1)) && ((*a+2) == (*b+2)))
3130 {
3131 return TRUE;
3132 }
3133 return FALSE;
3134}
3135
3136BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
3137 const std::vector<Point>& input_vertices,
3138 const S32 num_input_triangles,
3139 S32 *input_triangles,
3140 S32 &num_output_vertices,
3141 LLVector3 **output_vertices,
3142 S32 &num_output_triangles,
3143 S32 **output_triangles)
3144{
3145 // Here's how we do this:
3146 // Create a structure which contains the original vertex index and the
3147 // LLVector3 data.
3148 // "Sort" the data by the vectors
3149 // Create an array the size of the old vertex list, with a mapping of
3150 // old indices to new indices.
3151 // Go through triangles, shift so the lowest index is first
3152 // Sort triangles by first index
3153 // Remove duplicate triangles
3154 // Allocate and pack new triangle data.
3155
3156 //LLTimer cleanupTimer;
3157 //llinfos << "In vertices: " << num_input_vertices << llendl;
3158 //llinfos << "In triangles: " << num_input_triangles << llendl;
3159
3160 S32 i;
3161 typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t;
3162 vertex_set_t vertex_list;
3163
3164 LLVertexIndexPair *pairp = NULL;
3165 for (i = 0; i < num_input_vertices; i++)
3166 {
3167 LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i);
3168 vertex_list.insert(new_pairp);
3169 }
3170
3171 // Generate the vertex mapping and the list of vertices without
3172 // duplicates. This will crash if there are no vertices.
3173 S32 *vertex_mapping = new S32[num_input_vertices];
3174 LLVector3 *new_vertices = new LLVector3[num_input_vertices];
3175 LLVertexIndexPair *prev_pairp = NULL;
3176
3177 S32 new_num_vertices;
3178
3179 new_num_vertices = 0;
3180 for (vertex_set_t::iterator iter = vertex_list.begin(),
3181 end = vertex_list.end();
3182 iter != end; iter++)
3183 {
3184 pairp = *iter;
3185 if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD))
3186 {
3187 new_vertices[new_num_vertices] = pairp->mVertex;
3188 //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl;
3189 new_num_vertices++;
3190 // Update the previous
3191 prev_pairp = pairp;
3192 }
3193 else
3194 {
3195 //llinfos << "Removed duplicate vertex " << pairp->mVertex << llendl;
3196 }
3197 vertex_mapping[pairp->mIndex] = new_num_vertices - 1;
3198 }
3199
3200 // Iterate through triangles and remove degenerates, re-ordering vertices
3201 // along the way.
3202 S32 *new_triangles = new S32[num_input_triangles * 3];
3203 S32 new_num_triangles = 0;
3204
3205 for (i = 0; i < num_input_triangles; i++)
3206 {
3207 //llinfos << "Checking triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl;
3208 input_triangles[i*3] = vertex_mapping[input_triangles[i*3]];
3209 input_triangles[i*3+1] = vertex_mapping[input_triangles[i*3+1]];
3210 input_triangles[i*3+2] = vertex_mapping[input_triangles[i*3+2]];
3211
3212 if ((input_triangles[i*3] == input_triangles[i*3+1])
3213 || (input_triangles[i*3] == input_triangles[i*3+2])
3214 || (input_triangles[i*3+1] == input_triangles[i*3+2]))
3215 {
3216 //llinfos << "Removing degenerate triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl;
3217 // Degenerate triangle, skip
3218 continue;
3219 }
3220
3221 if (input_triangles[i*3] < input_triangles[i*3+1])
3222 {
3223 if (input_triangles[i*3] < input_triangles[i*3+2])
3224 {
3225 // (0 < 1) && (0 < 2)
3226 new_triangles[new_num_triangles*3] = input_triangles[i*3];
3227 new_triangles[new_num_triangles*3+1] = input_triangles[i*3+1];
3228 new_triangles[new_num_triangles*3+2] = input_triangles[i*3+2];
3229 }
3230 else
3231 {
3232 // (0 < 1) && (2 < 0)
3233 new_triangles[new_num_triangles*3] = input_triangles[i*3+2];
3234 new_triangles[new_num_triangles*3+1] = input_triangles[i*3];
3235 new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1];
3236 }
3237 }
3238 else if (input_triangles[i*3+1] < input_triangles[i*3+2])
3239 {
3240 // (1 < 0) && (1 < 2)
3241 new_triangles[new_num_triangles*3] = input_triangles[i*3+1];
3242 new_triangles[new_num_triangles*3+1] = input_triangles[i*3+2];
3243 new_triangles[new_num_triangles*3+2] = input_triangles[i*3];
3244 }
3245 else
3246 {
3247 // (1 < 0) && (2 < 1)
3248 new_triangles[new_num_triangles*3] = input_triangles[i*3+2];
3249 new_triangles[new_num_triangles*3+1] = input_triangles[i*3];
3250 new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1];
3251 }
3252 new_num_triangles++;
3253 }
3254
3255 if (new_num_triangles == 0)
3256 {
3257 llwarns << "Created volume object with 0 faces." << llendl;
3258 return FALSE;
3259 }
3260
3261 typedef std::set<S32*, lessTriangle> triangle_set_t;
3262 triangle_set_t triangle_list;
3263
3264 for (i = 0; i < new_num_triangles; i++)
3265 {
3266 triangle_list.insert(&new_triangles[i*3]);
3267 }
3268
3269 // Sort through the triangle list, and delete duplicates
3270
3271 S32 *prevp = NULL;
3272 S32 *curp = NULL;
3273
3274 S32 *sorted_tris = new S32[new_num_triangles*3];
3275 S32 cur_tri = 0;
3276 for (triangle_set_t::iterator iter = triangle_list.begin(),
3277 end = triangle_list.end();
3278 iter != end; iter++)
3279 {
3280 curp = *iter;
3281 if (!prevp || !equalTriangle(prevp, curp))
3282 {
3283 //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
3284 sorted_tris[cur_tri*3] = *curp;
3285 sorted_tris[cur_tri*3+1] = *(curp+1);
3286 sorted_tris[cur_tri*3+2] = *(curp+2);
3287 cur_tri++;
3288 prevp = curp;
3289 }
3290 else
3291 {
3292 //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
3293 }
3294 }
3295
3296 *output_vertices = new LLVector3[new_num_vertices];
3297 num_output_vertices = new_num_vertices;
3298 for (i = 0; i < new_num_vertices; i++)
3299 {
3300 (*output_vertices)[i] = new_vertices[i];
3301 }
3302
3303 *output_triangles = new S32[cur_tri*3];
3304 num_output_triangles = cur_tri;
3305 memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32));
3306
3307 /*
3308 llinfos << "Out vertices: " << num_output_vertices << llendl;
3309 llinfos << "Out triangles: " << num_output_triangles << llendl;
3310 for (i = 0; i < num_output_vertices; i++)
3311 {
3312 llinfos << i << ":" << (*output_vertices)[i] << llendl;
3313 }
3314 for (i = 0; i < num_output_triangles; i++)
3315 {
3316 llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl;
3317 }
3318 */
3319
3320 //llinfos << "Out vertices: " << num_output_vertices << llendl;
3321 //llinfos << "Out triangles: " << num_output_triangles << llendl;
3322 delete[] vertex_mapping;
3323 vertex_mapping = NULL;
3324 delete[] new_vertices;
3325 new_vertices = NULL;
3326 delete[] new_triangles;
3327 new_triangles = NULL;
3328 delete[] sorted_tris;
3329 sorted_tris = NULL;
3330 triangle_list.clear();
3331 std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer());
3332 vertex_list.clear();
3333
3334 return TRUE;
3335}
3336
3337
3338BOOL LLVolumeParams::importFile(FILE *fp)
3339{
3340 //llinfos << "importing volume" << llendl;
3341 const S32 BUFSIZE = 16384;
3342 char buffer[BUFSIZE];
3343 char keyword[256];
3344 keyword[0] = 0;
3345
3346 while (!feof(fp))
3347 {
3348 fgets(buffer, BUFSIZE, fp);
3349 sscanf(buffer, " %s", keyword);
3350 if (!keyword)
3351 {
3352 continue;
3353 }
3354 if (!strcmp("{", keyword))
3355 {
3356 continue;
3357 }
3358 if (!strcmp("}",keyword))
3359 {
3360 break;
3361 }
3362 else if (!strcmp("profile", keyword))
3363 {
3364 mProfileParams.importFile(fp);
3365 }
3366 else if (!strcmp("path",keyword))
3367 {
3368 mPathParams.importFile(fp);
3369 }
3370 else
3371 {
3372 llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
3373 }
3374 }
3375
3376 return TRUE;
3377}
3378
3379BOOL LLVolumeParams::exportFile(FILE *fp) const
3380{
3381 fprintf(fp,"\tshape 0\n");
3382 fprintf(fp,"\t{\n");
3383 mPathParams.exportFile(fp);
3384 mProfileParams.exportFile(fp);
3385 fprintf(fp, "\t}\n");
3386 return TRUE;
3387}
3388
3389
3390BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream)
3391{
3392 //llinfos << "importing volume" << llendl;
3393 const S32 BUFSIZE = 16384;
3394 char buffer[BUFSIZE];
3395 char keyword[256];
3396 keyword[0] = 0;
3397
3398 while (input_stream.good())
3399 {
3400 input_stream.getline(buffer, BUFSIZE);
3401 sscanf(buffer, " %s", keyword);
3402 if (!keyword)
3403 {
3404 continue;
3405 }
3406 if (!strcmp("{", keyword))
3407 {
3408 continue;
3409 }
3410 if (!strcmp("}",keyword))
3411 {
3412 break;
3413 }
3414 else if (!strcmp("profile", keyword))
3415 {
3416 mProfileParams.importLegacyStream(input_stream);
3417 }
3418 else if (!strcmp("path",keyword))
3419 {
3420 mPathParams.importLegacyStream(input_stream);
3421 }
3422 else
3423 {
3424 llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
3425 }
3426 }
3427
3428 return TRUE;
3429}
3430
3431BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
3432{
3433 output_stream <<"\tshape 0\n";
3434 output_stream <<"\t{\n";
3435 mPathParams.exportLegacyStream(output_stream);
3436 mProfileParams.exportLegacyStream(output_stream);
3437 output_stream << "\t}\n";
3438 return TRUE;
3439}
3440
3441LLSD LLVolumeParams::asLLSD() const
3442{
3443 LLSD sd = LLSD();
3444 sd["path"] = mPathParams;
3445 sd["profile"] = mProfileParams;
3446 return sd;
3447}
3448
3449bool LLVolumeParams::fromLLSD(LLSD& sd)
3450{
3451 mPathParams.fromLLSD(sd["path"]);
3452 mProfileParams.fromLLSD(sd["profile"]);
3453 return true;
3454}
3455
3456void LLVolumeParams::reduceS(F32 begin, F32 end)
3457{
3458 begin = llclampf(begin);
3459 end = llclampf(end);
3460 if (begin > end)
3461 {
3462 F32 temp = begin;
3463 begin = end;
3464 end = temp;
3465 }
3466 F32 a = mProfileParams.getBegin();
3467 F32 b = mProfileParams.getEnd();
3468 mProfileParams.setBegin(a + begin * (b - a));
3469 mProfileParams.setEnd(a + end * (b - a));
3470}
3471
3472void LLVolumeParams::reduceT(F32 begin, F32 end)
3473{
3474 begin = llclampf(begin);
3475 end = llclampf(end);
3476 if (begin > end)
3477 {
3478 F32 temp = begin;
3479 begin = end;
3480 end = temp;
3481 }
3482 F32 a = mPathParams.getBegin();
3483 F32 b = mPathParams.getEnd();
3484 mPathParams.setBegin(a + begin * (b - a));
3485 mPathParams.setEnd(a + end * (b - a));
3486}
3487
3488BOOL LLVolumeParams::isConvex() const
3489{
3490 // The logic for determining convexity is a little convoluted.
3491
3492 // Do we need to take getTwistBegin into account? DK 08/12/04
3493 if ( mProfileParams.getHollow() != 0.0f
3494 || mPathParams.getTwist() != mPathParams.getTwistBegin() )
3495 {
3496 // hollow or twist gaurantees concavity
3497 return FALSE;
3498 }
3499
3500 F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin();
3501 BOOL concave_profile = (profile_length < 1.0f) && (profile_length > 0.5f);
3502 if (concave_profile)
3503 {
3504 // concave profile
3505 return FALSE;
3506 }
3507
3508 U8 path_type = mPathParams.getCurveType();
3509 if ( LL_PCODE_PATH_LINE == path_type )
3510 {
3511 // straight paths with convex profile
3512 return TRUE;
3513 }
3514
3515 F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
3516 BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f);
3517 if (concave_path)
3518 {
3519 return FALSE;
3520 }
3521
3522 // we're left with spheres, toroids and tubes
3523 // only the spheres can be convex
3524 U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
3525 if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
3526 {
3527 return TRUE;
3528 }
3529
3530 // it's a toroid or tube
3531 return FALSE;
3532}
3533
3534LLFaceID LLVolume::generateFaceMask()
3535{
3536 LLFaceID new_mask = 0x0000;
3537
3538 switch(mProfilep->mParams.getCurveType() & LL_PCODE_PROFILE_MASK)
3539 {
3540 case LL_PCODE_PROFILE_CIRCLE:
3541 case LL_PCODE_PROFILE_CIRCLE_HALF:
3542 new_mask |= LL_FACE_OUTER_SIDE_0;
3543 break;
3544 case LL_PCODE_PROFILE_SQUARE:
3545 {
3546 for(S32 side = (S32)(mProfilep->mParams.getBegin() * 4.f); side < llceil(mProfilep->mParams.getEnd() * 4.f); side++)
3547 {
3548 new_mask |= LL_FACE_OUTER_SIDE_0 << side;
3549 }
3550 }
3551 break;
3552 case LL_PCODE_PROFILE_ISOTRI:
3553 case LL_PCODE_PROFILE_EQUALTRI:
3554 case LL_PCODE_PROFILE_RIGHTTRI:
3555 {
3556 for(S32 side = (S32)(mProfilep->mParams.getBegin() * 3.f); side < llceil(mProfilep->mParams.getEnd() * 3.f); side++)
3557 {
3558 new_mask |= LL_FACE_OUTER_SIDE_0 << side;
3559 }
3560 }
3561 break;
3562 default:
3563 llerrs << "Unknown profile!" << llendl
3564 break;
3565 }
3566
3567 // handle hollow objects
3568 if (mProfilep->isHollow())
3569 {
3570 new_mask |= LL_FACE_INNER_SIDE;
3571 }
3572
3573 // handle open profile curves
3574 if (mProfilep->isOpen())
3575 {
3576 new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END;
3577 }
3578
3579 // handle open path curves
3580 if (mPathp->isOpen())
3581 {
3582 new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END;
3583 }
3584
3585 return new_mask;
3586}
3587
3588BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask)
3589{
3590 LLFaceID test_mask = 0;
3591 for(S32 i = 0; i < getNumFaces(); i++)
3592 {
3593 test_mask |= mProfilep->mFaces[i].mFaceID;
3594 }
3595
3596 return test_mask == face_mask;
3597}
3598
3599BOOL LLVolume::isConvex() const
3600{
3601 // mParams.isConvex() may return FALSE even though the final
3602 // geometry is actually convex due to LOD approximations.
3603 // TODO -- provide LLPath and LLProfile with isConvex() methods
3604 // that correctly determine convexity. -- Leviathan
3605 return mParams.isConvex();
3606}
3607
3608
3609std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params)
3610{
3611 s << "{type=" << (U32) profile_params.mCurveType;
3612 s << ", begin=" << profile_params.mBegin;
3613 s << ", end=" << profile_params.mEnd;
3614 s << ", hollow=" << profile_params.mHollow;
3615 s << "}";
3616 return s;
3617}
3618
3619
3620std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params)
3621{
3622 s << "{type=" << (U32) path_params.mCurveType;
3623 s << ", begin=" << path_params.mBegin;
3624 s << ", end=" << path_params.mEnd;
3625 s << ", twist=" << path_params.mTwistEnd;
3626 s << ", scale=" << path_params.mScale;
3627 s << ", shear=" << path_params.mShear;
3628 s << ", twist_begin=" << path_params.mTwistBegin;
3629 s << ", radius_offset=" << path_params.mRadiusOffset;
3630 s << ", taper=" << path_params.mTaper;
3631 s << ", revolutions=" << path_params.mRevolutions;
3632 s << ", skew=" << path_params.mSkew;
3633 s << "}";
3634 return s;
3635}
3636
3637
3638std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params)
3639{
3640 s << "{profileparams = " << volume_params.mProfileParams;
3641 s << ", pathparams = " << volume_params.mPathParams;
3642 s << "}";
3643 return s;
3644}
3645
3646
3647std::ostream& operator<<(std::ostream &s, const LLProfile &profile)
3648{
3649 s << " {open=" << (U32) profile.mOpen;
3650 s << ", dirty=" << profile.mDirty;
3651 s << ", totalout=" << profile.mTotalOut;
3652 s << ", total=" << profile.mTotal;
3653 s << "}";
3654 return s;
3655}
3656
3657
3658std::ostream& operator<<(std::ostream &s, const LLPath &path)
3659{
3660 s << "{open=" << (U32) path.mOpen;
3661 s << ", dirty=" << path.mDirty;
3662 s << ", step=" << path.mStep;
3663 s << ", total=" << path.mTotal;
3664 s << "}";
3665 return s;
3666}
3667
3668std::ostream& operator<<(std::ostream &s, const LLVolume &volume)
3669{
3670 s << "{params = " << volume.mParams;
3671 s << ", path = " << *volume.mPathp;
3672 s << ", profile = " << *volume.mProfilep;
3673 s << "}";
3674 return s;
3675}
3676
3677
3678std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
3679{
3680 s << "{params = " << volumep->mParams;
3681 s << ", path = " << *(volumep->mPathp);
3682 s << ", profile = " << *(volumep->mProfilep);
3683 s << "}";
3684 return s;
3685}
3686
3687
3688LLVolumeFace::LLVolumeFace()
3689{
3690 mTypeMask = 0;
3691 mID = 0;
3692 mBeginS = 0;
3693 mBeginT = 0;
3694 mNumS = 0;
3695 mNumT = 0;
3696}
3697
3698
3699BOOL LLVolumeFace::create()
3700{
3701 if (mTypeMask & CAP_MASK)
3702 {
3703 return createCap();
3704 }
3705 else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
3706 {
3707 return createSide();
3708 }
3709 else
3710 {
3711 llerrs << "Unknown/uninitialized face type!" << llendl;
3712 return FALSE;
3713 }
3714}
3715
3716void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
3717 LLVolumeFace::VertexData& v1,
3718 LLVolumeFace::VertexData& v2,
3719 LLVolumeFace::VertexData& vout,
3720 F32 coef01,
3721 F32 coef02)
3722{
3723 vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02);
3724 vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02);
3725 vout.mNormal = v0.mNormal;
3726 vout.mBinormal = v0.mBinormal;
3727}
3728
3729BOOL LLVolumeFace::createUnCutCubeCap()
3730{
3731 const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh();
3732 const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile;
3733 S32 max_s = mVolumep->getProfile().getTotal();
3734 S32 max_t = mVolumep->getPath().mPath.size();
3735
3736 // S32 i;
3737 S32 num_vertices = 0, num_indices = 0;
3738 S32 grid_size = (profile.size()-1)/4;
3739 S32 quad_count = (grid_size * grid_size);
3740
3741 num_vertices = (grid_size+1)*(grid_size+1);
3742 num_indices = quad_count * 4;
3743
3744 S32 offset = 0;
3745 if (mTypeMask & TOP_MASK)
3746 offset = (max_t-1) * max_s;
3747 else
3748 offset = mBeginS;
3749
3750 VertexData corners[4];
3751 VertexData baseVert;
3752 for(int t = 0; t < 4; t++){
3753 corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
3754 corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
3755 corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
3756 }
3757 baseVert.mNormal =
3758 ((corners[1].mPosition-corners[0].mPosition) %
3759 (corners[2].mPosition-corners[1].mPosition));
3760 baseVert.mNormal.normVec();
3761 if(!(mTypeMask & TOP_MASK)){
3762 baseVert.mNormal *= -1.0f;
3763 }else{
3764 //Swap the UVs on the U(X) axis for top face
3765 LLVector2 swap;
3766 swap = corners[0].mTexCoord;
3767 corners[0].mTexCoord=corners[3].mTexCoord;
3768 corners[3].mTexCoord=swap;
3769 swap = corners[1].mTexCoord;
3770 corners[1].mTexCoord=corners[2].mTexCoord;
3771 corners[2].mTexCoord=swap;
3772 }
3773 baseVert.mBinormal = calc_binormal_from_triangle(
3774 corners[0].mPosition, corners[0].mTexCoord,
3775 corners[1].mPosition, corners[1].mTexCoord,
3776 corners[2].mPosition, corners[2].mTexCoord);
3777 for(int t = 0; t < 4; t++){
3778 corners[t].mBinormal = baseVert.mBinormal;
3779 corners[t].mNormal = baseVert.mNormal;
3780 }
3781
3782 S32 vtop = mVertices.size();
3783// S32 itop = mIndices.size();
3784/// vector_append(mVertices,4);
3785// vector_append(mIndices,4);
3786// LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
3787#if 0
3788 for(int t=0;t<4;t++){
3789 VertexData vd;
3790 vd.mPosition = corners[t].mPosition;
3791 vd.mNormal =
3792 ((corners[(t+1)%4].mPosition-corners[t].mPosition)%
3793 (corners[(t+2)%4].mPosition-corners[(t+1)%4].mPosition));
3794 vd.mNormal.normVec();
3795
3796 if (mTypeMask & TOP_MASK)
3797 vd.mNormal *= -1.0f;
3798 vd.mBinormal = vd.mNormal;
3799 vd.mTexCoord = corners[t].mTexCoord;
3800 mVertices.push_back(vd);
3801 }
3802 int idxs[] = {0,1,2,2,3,0};
3803 if (mTypeMask & TOP_MASK){
3804 for(int i=0;i<6;i++)mIndices.push_back(vtop+idxs[i]);
3805 }else{
3806 for(int i=5;i>=0;i--)mIndices.push_back(vtop+idxs[i]);
3807 }
3808#else
3809 for(int gx = 0;gx<grid_size+1;gx++){
3810 for(int gy = 0;gy<grid_size+1;gy++){
3811 VertexData newVert;
3812 LerpPlanarVertex(
3813 corners[0],
3814 corners[1],
3815 corners[3],
3816 newVert,
3817 (F32)gx/(F32)grid_size,
3818 (F32)gy/(F32)grid_size);
3819 mVertices.push_back(newVert);
3820 }
3821 }
3822 int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
3823 for(int gx = 0;gx<grid_size;gx++){
3824 for(int gy = 0;gy<grid_size;gy++){
3825 if (mTypeMask & TOP_MASK){
3826 for(int i=5;i>=0;i--)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
3827 }else{
3828 for(int i=0;i<6;i++)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
3829 }
3830 }
3831 }
3832#endif
3833 return TRUE;
3834}
3835
3836
3837BOOL LLVolumeFace::createCap()
3838{
3839 if (!(mTypeMask & HOLLOW_MASK) &&
3840 !(mTypeMask & OPEN_MASK) &&
3841 ((this->mVolumep->getParams().getPathParams().getBegin()==0.0f)&&
3842 (this->mVolumep->getParams().getPathParams().getEnd()==1.0f))&&
3843 (mVolumep->getProfile().mParams.getCurveType()==LL_PCODE_PROFILE_SQUARE &&
3844 mVolumep->getPath().mParams.getCurveType()==LL_PCODE_PATH_LINE)
3845 ){
3846 return createUnCutCubeCap();
3847 }
3848
3849 S32 i;
3850 S32 num_vertices = 0, num_indices = 0;
3851
3852 const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh();
3853 const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile;
3854
3855 // All types of caps have the same number of vertices and indices
3856 num_vertices = profile.size();
3857 num_indices = (profile.size() - 2)*3;
3858 vector_append(mVertices,num_vertices);
3859 vector_append(mIndices,num_indices);
3860
3861 S32 max_s = mVolumep->getProfile().getTotal();
3862 S32 max_t = mVolumep->getPath().mPath.size();
3863
3864 mCenter.clearVec();
3865
3866 S32 offset = 0;
3867 if (mTypeMask & TOP_MASK)
3868 {
3869 offset = (max_t-1) * max_s;
3870 }
3871 else
3872 {
3873 offset = mBeginS;
3874 }
3875
3876 // Figure out the normal, assume all caps are flat faces.
3877 // Cross product to get normals.
3878
3879 LLVector2 cuv = LLVector2(0,0);
3880
3881 // Copy the vertices into the array
3882 for (i = 0; i < num_vertices; i++)
3883 {
3884
3885 if (mTypeMask & TOP_MASK)
3886 {
3887 mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
3888 mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f;
3889 }
3890 else
3891 {
3892 // Mirror for underside.
3893 mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
3894 mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1];
3895 }
3896
3897 if(i){
3898 //Dont include the first point of the profile in the average
3899 cuv += mVertices[i].mTexCoord;
3900 mCenter += mVertices[i].mPosition = mesh[i + offset].mPos;
3901 }
3902 else mVertices[i].mPosition = mesh[i + offset].mPos;
3903 //mVertices[i].mNormal = normal;
3904 }
3905
3906 mCenter /= (F32)(num_vertices-1);
3907 cuv /= (F32)(num_vertices-1);
3908
3909 LLVector3 binormal = calc_binormal_from_triangle(
3910 mCenter, cuv,
3911 mVertices[0].mPosition, mVertices[0].mTexCoord,
3912 mVertices[1].mPosition, mVertices[1].mTexCoord);
3913 binormal.normVec();
3914
3915 LLVector3 d0;
3916 LLVector3 d1;
3917 LLVector3 normal;
3918
3919 d0 = mCenter-mVertices[0].mPosition;
3920 d1 = mCenter-mVertices[1].mPosition;
3921
3922 normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0);
3923 normal.normVec();
3924
3925 VertexData vd;
3926 vd.mPosition = mCenter;
3927 vd.mNormal = normal;
3928 vd.mBinormal = binormal;
3929 vd.mTexCoord = cuv;
3930
3931 if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
3932 {
3933 mVertices.push_back(vd);
3934 num_vertices++;
3935 vector_append(mIndices, 3);
3936 }
3937
3938
3939 for (i = 0; i < num_vertices; i++)
3940 {
3941 mVertices[i].mBinormal = binormal;
3942 mVertices[i].mNormal = normal;
3943 }
3944
3945 if (mTypeMask & HOLLOW_MASK)
3946 {
3947 if (mTypeMask & TOP_MASK)
3948 {
3949 // HOLLOW TOP
3950 // Does it matter if it's open or closed? - djs
3951
3952 S32 pt1 = 0, pt2 = num_vertices - 1;
3953 i = 0;
3954 while (pt2 - pt1 > 1)
3955 {
3956 // Use the profile points instead of the mesh, since you want
3957 // the un-transformed profile distances.
3958 LLVector3 p1 = profile[pt1];
3959 LLVector3 p2 = profile[pt2];
3960 LLVector3 pa = profile[pt1+1];
3961 LLVector3 pb = profile[pt2-1];
3962
3963 p1.mV[VZ] = 0.f;
3964 p2.mV[VZ] = 0.f;
3965 pa.mV[VZ] = 0.f;
3966 pb.mV[VZ] = 0.f;
3967
3968 // Use area of triangle to determine backfacing
3969 F32 area_1a2, area_1ba, area_21b, area_2ab;
3970 area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
3971 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
3972 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
3973
3974 area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
3975 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
3976 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
3977
3978 area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
3979 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
3980 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
3981
3982 area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
3983 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
3984 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
3985
3986 BOOL use_tri1a2 = TRUE;
3987 BOOL tri_1a2 = TRUE;
3988 BOOL tri_21b = TRUE;
3989
3990 if (area_1a2 < 0)
3991 {
3992 tri_1a2 = FALSE;
3993 }
3994 if (area_2ab < 0)
3995 {
3996 // Can't use, because it contains point b
3997 tri_1a2 = FALSE;
3998 }
3999 if (area_21b < 0)
4000 {
4001 tri_21b = FALSE;
4002 }
4003 if (area_1ba < 0)
4004 {
4005 // Can't use, because it contains point b
4006 tri_21b = FALSE;
4007 }
4008
4009 if (!tri_1a2)
4010 {
4011 use_tri1a2 = FALSE;
4012 }
4013 else if (!tri_21b)
4014 {
4015 use_tri1a2 = TRUE;
4016 }
4017 else
4018 {
4019 LLVector3 d1 = p1 - pa;
4020 LLVector3 d2 = p2 - pb;
4021
4022 if (d1.magVecSquared() < d2.magVecSquared())
4023 {
4024 use_tri1a2 = TRUE;
4025 }
4026 else
4027 {
4028 use_tri1a2 = FALSE;
4029 }
4030 }
4031
4032 if (use_tri1a2)
4033 {
4034 mIndices[i++] = pt1;
4035 mIndices[i++] = pt1 + 1;
4036 mIndices[i++] = pt2;
4037 pt1++;
4038 }
4039 else
4040 {
4041 mIndices[i++] = pt1;
4042 mIndices[i++] = pt2 - 1;
4043 mIndices[i++] = pt2;
4044 pt2--;
4045 }
4046 }
4047 }
4048 else
4049 {
4050 // HOLLOW BOTTOM
4051 // Does it matter if it's open or closed? - djs
4052
4053 llassert(mTypeMask & BOTTOM_MASK);
4054 S32 pt1 = 0, pt2 = num_vertices - 1;
4055
4056 i = 0;
4057 while (pt2 - pt1 > 1)
4058 {
4059 // Use the profile points instead of the mesh, since you want
4060 // the un-transformed profile distances.
4061 LLVector3 p1 = profile[pt1];
4062 LLVector3 p2 = profile[pt2];
4063 LLVector3 pa = profile[pt1+1];
4064 LLVector3 pb = profile[pt2-1];
4065
4066 p1.mV[VZ] = 0.f;
4067 p2.mV[VZ] = 0.f;
4068 pa.mV[VZ] = 0.f;
4069 pb.mV[VZ] = 0.f;
4070
4071 // Use area of triangle to determine backfacing
4072 F32 area_1a2, area_1ba, area_21b, area_2ab;
4073 area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
4074 (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
4075 (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
4076
4077 area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
4078 (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
4079 (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
4080
4081 area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
4082 (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
4083 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
4084
4085 area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
4086 (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
4087 (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
4088
4089 BOOL use_tri1a2 = TRUE;
4090 BOOL tri_1a2 = TRUE;
4091 BOOL tri_21b = TRUE;
4092
4093 if (area_1a2 < 0)
4094 {
4095 tri_1a2 = FALSE;
4096 }
4097 if (area_2ab < 0)
4098 {
4099 // Can't use, because it contains point b
4100 tri_1a2 = FALSE;
4101 }
4102 if (area_21b < 0)
4103 {
4104 tri_21b = FALSE;
4105 }
4106 if (area_1ba < 0)
4107 {
4108 // Can't use, because it contains point b
4109 tri_21b = FALSE;
4110 }
4111
4112 if (!tri_1a2)
4113 {
4114 use_tri1a2 = FALSE;
4115 }
4116 else if (!tri_21b)
4117 {
4118 use_tri1a2 = TRUE;
4119 }
4120 else
4121 {
4122 LLVector3 d1 = p1 - pa;
4123 LLVector3 d2 = p2 - pb;
4124
4125 if (d1.magVecSquared() < d2.magVecSquared())
4126 {
4127 use_tri1a2 = TRUE;
4128 }
4129 else
4130 {
4131 use_tri1a2 = FALSE;
4132 }
4133 }
4134
4135 // Flipped backfacing from top
4136 if (use_tri1a2)
4137 {
4138 mIndices[i++] = pt1;
4139 mIndices[i++] = pt2;
4140 mIndices[i++] = pt1 + 1;
4141 pt1++;
4142 }
4143 else
4144 {
4145 mIndices[i++] = pt1;
4146 mIndices[i++] = pt2;
4147 mIndices[i++] = pt2 - 1;
4148 pt2--;
4149 }
4150 }
4151 }
4152 }
4153 else
4154 {
4155 // Not hollow, generate the triangle fan.
4156 if (mTypeMask & TOP_MASK)
4157 {
4158 if (mTypeMask & OPEN_MASK)
4159 {
4160 // SOLID OPEN TOP
4161 // Generate indices
4162 // This is a tri-fan, so we reuse the same first point for all triangles.
4163 for (i = 0; i < (num_vertices - 2); i++)
4164 {
4165 mIndices[3*i] = num_vertices - 1;
4166 mIndices[3*i+1] = i;
4167 mIndices[3*i+2] = i + 1;
4168 }
4169 }
4170 else
4171 {
4172 // SOLID CLOSED TOP
4173 for (i = 0; i < (num_vertices - 2); i++)
4174 {
4175 //MSMSM fix these caps but only for the un-cut case
4176 mIndices[3*i] = num_vertices - 1;
4177 mIndices[3*i+1] = i;
4178 mIndices[3*i+2] = i + 1;
4179 }
4180 }
4181 }
4182 else
4183 {
4184 if (mTypeMask & OPEN_MASK)
4185 {
4186 // SOLID OPEN BOTTOM
4187 // Generate indices
4188 // This is a tri-fan, so we reuse the same first point for all triangles.
4189 for (i = 0; i < (num_vertices - 2); i++)
4190 {
4191 mIndices[3*i] = num_vertices - 1;
4192 mIndices[3*i+1] = i + 1;
4193 mIndices[3*i+2] = i;
4194 }
4195 }
4196 else
4197 {
4198 // SOLID CLOSED BOTTOM
4199 for (i = 0; i < (num_vertices - 2); i++)
4200 {
4201 //MSMSM fix these caps but only for the un-cut case
4202 mIndices[3*i] = num_vertices - 1;
4203 mIndices[3*i+1] = i + 1;
4204 mIndices[3*i+2] = i;
4205 }
4206 }
4207 }
4208 }
4209 return TRUE;
4210}
4211
4212
4213BOOL LLVolumeFace::createSide()
4214{
4215 BOOL flat = mTypeMask & FLAT_MASK;
4216 S32 num_vertices, num_indices;
4217
4218
4219 const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh();
4220 const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile;
4221 const std::vector<LLPath::PathPt>& path_data = mVolumep->getPath().mPath;
4222
4223 S32 max_s = mVolumep->getProfile().getTotal();
4224
4225 S32 s, t, i;
4226 F32 ss, tt;
4227
4228 num_vertices = mNumS*mNumT;
4229 num_indices = (mNumS-1)*(mNumT-1)*6;
4230 vector_append(mVertices,num_vertices);
4231 vector_append(mIndices,num_indices);
4232 vector_append(mEdge, num_indices);
4233
4234 mCenter.clearVec();
4235
4236 S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
4237 S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
4238
4239 S32 cur_vertex = 0;
4240 // Copy the vertices into the array
4241 for (t = mBeginT; t < mBeginT + mNumT; t++)
4242 {
4243 tt = path_data[t].mTexT;
4244 for (s = 0; s < num_s; s++)
4245 {
4246 if (mTypeMask & END_MASK)
4247 {
4248 if (s)
4249 {
4250 ss = 1.f;
4251 }
4252 else
4253 {
4254 ss = 0.f;
4255 }
4256 }
4257 else
4258 {
4259 // Get s value for tex-coord.
4260 if (!flat)
4261 {
4262 ss = profile[mBeginS + s].mV[2];
4263 }
4264 else
4265 {
4266 ss = profile[mBeginS + s].mV[2] - begin_stex;
4267 }
4268 }
4269
4270 // Check to see if this triangle wraps around the array.
4271 if (mBeginS + s >= max_s)
4272 {
4273 // We're wrapping
4274 i = mBeginS + s + max_s*(t-1);
4275 }
4276 else
4277 {
4278 i = mBeginS + s + max_s*t;
4279 }
4280
4281 mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos;
4282 mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
4283
4284 mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
4285 mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
4286
4287 cur_vertex++;
4288
4289 if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
4290 {
4291 mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos;
4292 mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
4293
4294 mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
4295 mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
4296 cur_vertex++;
4297 }
4298 }
4299
4300 if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2)
4301 {
4302 if (mTypeMask & OPEN_MASK)
4303 {
4304 s = num_s-1;
4305 }
4306 else
4307 {
4308 s = 0;
4309 }
4310
4311 i = mBeginS + s + max_s*t;
4312 ss = profile[mBeginS + s].mV[2] - begin_stex;
4313 mCenter += mVertices[cur_vertex].mPosition = mesh[i].mPos;
4314 mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
4315
4316 mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
4317 mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
4318 cur_vertex++;
4319 }
4320 }
4321 mCenter /= (F32)num_vertices;
4322
4323 S32 cur_index = 0;
4324 S32 cur_edge = 0;
4325 BOOL flat_face = mTypeMask & FLAT_MASK;
4326
4327 // Now we generate the indices.
4328 for (t = 0; t < (mNumT-1); t++)
4329 {
4330 for (s = 0; s < (mNumS-1); s++)
4331 {
4332 mIndices[cur_index++] = s + mNumS*t; //bottom left
4333 mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
4334 mIndices[cur_index++] = s + mNumS*(t+1); //top left
4335 mIndices[cur_index++] = s + mNumS*t; //bottom left
4336 mIndices[cur_index++] = s+1 + mNumS*t; //bottom right
4337 mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
4338
4339 mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face
4340 if (t < mNumT-2) { //top right/top left neighbor face
4341 mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
4342 }
4343 else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor
4344 mEdge[cur_edge++] = -1;
4345 }
4346 else { //wrap on T
4347 mEdge[cur_edge++] = s*2+1;
4348 }
4349 if (s > 0) { //top left/bottom left neighbor face
4350 mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
4351 }
4352 else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor
4353 mEdge[cur_edge++] = -1;
4354 }
4355 else { //wrap on S
4356 mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
4357 }
4358
4359 if (t > 0) { //bottom left/bottom right neighbor face
4360 mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
4361 }
4362 else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor
4363 mEdge[cur_edge++] = -1;
4364 }
4365 else { //wrap on T
4366 mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
4367 }
4368 if (s < mNumS-2) { //bottom right/top right neighbor face
4369 mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
4370 }
4371 else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor
4372 mEdge[cur_edge++] = -1;
4373 }
4374 else { //wrap on S
4375 mEdge[cur_edge++] = (mNumS-1)*2*t;
4376 }
4377 mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face
4378 }
4379 }
4380
4381
4382 //generate normals
4383 for (U32 i = 0; i < mIndices.size()/3; i++) { //for each triangle
4384 const VertexData& v0 = mVertices[mIndices[i*3+0]];
4385 const VertexData& v1 = mVertices[mIndices[i*3+1]];
4386 const VertexData& v2 = mVertices[mIndices[i*3+2]];
4387
4388 //calculate triangle normal
4389 LLVector3 norm = (v0.mPosition-v1.mPosition)%
4390 (v0.mPosition-v2.mPosition);
4391
4392 //calculate binormal
4393 LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
4394 v1.mPosition, v1.mTexCoord,
4395 v2.mPosition, v2.mTexCoord);
4396
4397 for (U32 j = 0; j < 3; j++) { //add triangle normal to vertices
4398 mVertices[mIndices[i*3+j]].mNormal += norm; // * (weight_sum - d[j])/weight_sum;
4399 mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
4400 }
4401
4402 //even out quad contributions
4403 if (i % 2 == 0) {
4404 mVertices[mIndices[i*3+2]].mNormal += norm;
4405 mVertices[mIndices[i*3+2]].mBinormal += binorm;
4406 }
4407 else {
4408 mVertices[mIndices[i*3+1]].mNormal += norm;
4409 mVertices[mIndices[i*3+1]].mBinormal += binorm;
4410 }
4411 }
4412
4413 if (mVolumep->getPath().isOpen() == FALSE) { //wrap normals on T
4414 for (S32 i = 0; i < mNumS; i++) {
4415 LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
4416 mVertices[i].mNormal = norm;
4417 mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
4418 }
4419 }
4420
4421 if (mVolumep->getProfile().isOpen() == FALSE) { //wrap normals on S
4422 for (S32 i = 0; i < mNumT; i++) {
4423 LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
4424 mVertices[mNumS * i].mNormal = norm;
4425 mVertices[mNumS * i+mNumS-1].mNormal = norm;
4426 }
4427 }
4428
4429 if (mVolumep->getPathType() == LL_PCODE_PATH_CIRCLE && ((mVolumep->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) {
4430 if ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f)
4431 { //all lower S have same normal
4432 for (S32 i = 0; i < mNumT; i++) {
4433 mVertices[mNumS*i].mNormal = LLVector3(1,0,0);
4434 }
4435 }
4436
4437 if ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f)
4438 { //all upper T have same normal
4439 for (S32 i = 0; i < mNumT; i++) {
4440 mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0);
4441 }
4442 }
4443 }
4444
4445 //this loop would LOVE OpenMP
4446 LLVector3 min = mVolumep->mBounds[0] - mVolumep->mBounds[1];
4447 LLVector3 max = mVolumep->mBounds[0] + mVolumep->mBounds[1];
4448
4449 if (min == max && min == LLVector3(512,512,512))
4450 {
4451 min = max = mVertices[0].mPosition;
4452 }
4453
4454 for (U32 i = 0; i < mVertices.size(); i++) {
4455 mVertices[i].mNormal.normVec();
4456 mVertices[i].mBinormal.normVec();
4457
4458 for (U32 j = 0; j < 3; j++) {
4459 if (mVertices[i].mPosition.mV[j] > max.mV[j]) {
4460 max.mV[j] = mVertices[i].mPosition.mV[j];
4461 }
4462 if (mVertices[i].mPosition.mV[j] < min.mV[j]) {
4463 min.mV[j] = mVertices[i].mPosition.mV[j];
4464 }
4465 }
4466 }
4467
4468 mVolumep->mBounds[0] = (min + max) * 0.5f; //center
4469 mVolumep->mBounds[1] = (max - min) * 0.5f; //half-height
4470
4471 return TRUE;
4472}
4473
4474// Static
4475BOOL LLVolumeFace::updateColors(LLColor4U *old_colors, const S32 num_old, const LLVolumeFace &old_vf,
4476 LLStrider<LLColor4U> &new_colors, const S32 num_new, const LLVolumeFace &new_vf)
4477{
4478 if (new_vf.mTypeMask & CAP_MASK)
4479 {
4480 // These aren't interpolated correctly. Need to fix when shadows go in...
4481 F32 ratio = (F32)num_old / (F32)num_new;
4482 S32 v = 0;
4483 for (v = 0; v < num_new; v++)
4484 {
4485 new_colors[v] = old_colors[(S32)(v*ratio)];
4486 }
4487 return FALSE;
4488 }
4489 else if (new_vf.mTypeMask & END_MASK)
4490 {
4491 // These aren't interpolated correctly. Need to fix when shadows go in...
4492 F32 ratio = (F32)num_old / (F32)num_new;
4493 S32 v = 0;
4494 for (v = 0; v < num_new; v++)
4495 {
4496 new_colors[v] = old_colors[(S32)(v*ratio)];
4497 }
4498 return FALSE;
4499 }
4500 else if (new_vf.mTypeMask & SIDE_MASK)
4501 {
4502 S32 s, t;
4503 F32 s_ratio = (F32)old_vf.mNumS / (F32)new_vf.mNumS;
4504 F32 t_ratio = (F32)old_vf.mNumT / (F32)new_vf.mNumT;
4505
4506 S32 v = 0;
4507 for (t = 0; t < new_vf.mNumT; t++)
4508 {
4509 F32 t_frac = t * t_ratio;
4510 S32 old_t = (S32)t_frac;
4511 S32 t_target = llmin(old_t + 1, (old_vf.mNumT - 1));
4512 t_frac -= old_t;
4513 for (s = 0; s < new_vf.mNumS; s++)
4514 {
4515 F32 s_frac = s * s_ratio;
4516 S32 old_s = (S32)s_frac;
4517 S32 s_target = llmin(old_s + 1, (old_vf.mNumS - 1));
4518 s_frac -= old_s;
4519
4520 // Interpolate along s, then along t.
4521 LLColor4U s_interp0 = old_colors[old_t * old_vf.mNumS + old_s].multAll(1.f - s_frac).addClampMax(old_colors[old_t * old_vf.mNumS + s_target].multAll(s_frac));
4522 LLColor4U s_interp1 = old_colors[t_target * old_vf.mNumS + old_s].multAll(1.f - s_frac).addClampMax(old_colors[t_target * old_vf.mNumS + s_target].multAll(s_frac));
4523 new_colors[v] = s_interp0.multAll(1.f - t_frac).addClampMax(s_interp1.multAll(t_frac));
4524 v++;
4525 }
4526 }
4527 }
4528 else
4529 {
4530 llerrs << "Unknown/uninitialized face type!" << llendl;
4531 return FALSE;
4532 }
4533 return TRUE;
4534}
4535
4536
4537// Finds binormal based on three vertices with texture coordinates.
4538// Fills in dummy values if the triangle has degenerate texture coordinates.
4539LLVector3 calc_binormal_from_triangle(
4540 const LLVector3& pos0,
4541 const LLVector2& tex0,
4542 const LLVector3& pos1,
4543 const LLVector2& tex1,
4544 const LLVector3& pos2,
4545 const LLVector2& tex2)
4546{
4547 LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] );
4548 LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] );
4549 LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] );
4550
4551 LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] );
4552 LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] );
4553 LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] );
4554
4555 LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] );
4556 LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] );
4557 LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] );
4558
4559 LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2);
4560 LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2);
4561 LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2);
4562
4563 if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] )
4564 {
4565 LLVector3 binormal(
4566 -r0.mV[VZ] / r0.mV[VX],
4567 -r1.mV[VZ] / r1.mV[VX],
4568 -r2.mV[VZ] / r2.mV[VX]);
4569 //binormal.normVec();
4570 return binormal;
4571 }
4572 else
4573 {
4574 return LLVector3( 0, 1 , 0 );
4575 }
4576}
diff --git a/linden/indra/llmath/llvolume.h b/linden/indra/llmath/llvolume.h
new file mode 100644
index 0000000..63981da
--- /dev/null
+++ b/linden/indra/llmath/llvolume.h
@@ -0,0 +1,901 @@
1/**
2 * @file llvolume.h
3 * @brief LLVolume base class.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLVOLUME_H
29#define LL_LLVOLUME_H
30
31#include <iostream>
32
33class LLProfileParams;
34class LLPathParams;
35class LLVolumeParams;
36class LLProfile;
37class LLPath;
38class LLVolumeFace;
39class LLVolume;
40
41#include "lldarray.h"
42#include "lluuid.h"
43#include "v4color.h"
44//#include "vmath.h"
45#include "v2math.h"
46#include "v3math.h"
47#include "llquaternion.h"
48#include "llstrider.h"
49#include "v4coloru.h"
50#include "llmemory.h"
51
52//============================================================================
53
54const S32 MIN_DETAIL_FACES = 6;
55const S32 MIN_LOD = 0;
56const S32 MAX_LOD = 3;
57
58// These are defined here but are not enforced at this level,
59// rather they are here for the convenience of code that uses
60// the LLVolume class.
61const F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f;
62const F32 MIN_VOLUME_PATH_WIDTH = 0.05f;
63
64const F32 CUT_QUANTA = 0.005f;
65const F32 SCALE_QUANTA = 0.01f;
66const F32 SHEAR_QUANTA = 0.01f;
67const F32 TAPER_QUANTA = 0.01f;
68const F32 REV_QUANTA = 0.015f;
69
70
71//============================================================================
72
73// useful masks
74const LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness
75const LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle)
76const LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles)
77const LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum
78const LLPCode LL_PCODE_BASE_MASK = 0x0F;
79
80 // primitive shapes
81const LLPCode LL_PCODE_CUBE = 1;
82const LLPCode LL_PCODE_PRISM = 2;
83const LLPCode LL_PCODE_TETRAHEDRON = 3;
84const LLPCode LL_PCODE_PYRAMID = 4;
85const LLPCode LL_PCODE_CYLINDER = 5;
86const LLPCode LL_PCODE_CONE = 6;
87const LLPCode LL_PCODE_SPHERE = 7;
88const LLPCode LL_PCODE_TORUS = 8;
89const LLPCode LL_PCODE_VOLUME = 9;
90
91 // surfaces
92//const LLPCode LL_PCODE_SURFACE_TRIANGLE = 10;
93//const LLPCode LL_PCODE_SURFACE_SQUARE = 11;
94//const LLPCode LL_PCODE_SURFACE_DISC = 12;
95
96const LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects)
97const LLPCode LL_PCODE_LEGACY = 15;
98
99// Pcodes for legacy objects
100//const LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR
101const LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER
102//const LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD
103//const LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON
104const LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS
105const LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees
106//const LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE
107const LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS
108const LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK
109//const LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT
110//const LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY;
111//const LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE
112//const LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK
113const LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE
114const LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE
115
116 // hemis
117const LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK;
118const LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK;
119const LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK;
120const LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK;
121
122
123// Volumes consist of a profile at the base that is swept around
124// a path to make a volume.
125// The profile code
126const U8 LL_PCODE_PROFILE_MASK = 0x0f;
127const U8 LL_PCODE_PROFILE_MIN = 0x00;
128const U8 LL_PCODE_PROFILE_CIRCLE = 0x00;
129const U8 LL_PCODE_PROFILE_SQUARE = 0x01;
130const U8 LL_PCODE_PROFILE_ISOTRI = 0x02;
131const U8 LL_PCODE_PROFILE_EQUALTRI = 0x03;
132const U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04;
133const U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05;
134const U8 LL_PCODE_PROFILE_MAX = 0x05;
135
136// Stored in the profile byte
137const U8 LL_PCODE_HOLE_MASK = 0xf0;
138const U8 LL_PCODE_HOLE_MIN = 0x00;
139const U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile
140const U8 LL_PCODE_HOLE_CIRCLE = 0x10;
141const U8 LL_PCODE_HOLE_SQUARE = 0x20;
142const U8 LL_PCODE_HOLE_TRIANGLE = 0x30;
143const U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max
144
145const U8 LL_PCODE_PATH_IGNORE = 0x00;
146const U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max
147const U8 LL_PCODE_PATH_LINE = 0x10;
148const U8 LL_PCODE_PATH_CIRCLE = 0x20;
149const U8 LL_PCODE_PATH_CIRCLE2 = 0x30;
150const U8 LL_PCODE_PATH_TEST = 0x40;
151const U8 LL_PCODE_PATH_FLEXIBLE = 0x80;
152const U8 LL_PCODE_PATH_MAX = 0x08;
153
154//============================================================================
155
156// face identifiers
157typedef U16 LLFaceID;
158
159const LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0;
160const LLFaceID LL_FACE_PATH_END = 0x1 << 1;
161const LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2;
162const LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3;
163const LLFaceID LL_FACE_PROFILE_END = 0x1 << 4;
164const LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5;
165const LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6;
166const LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7;
167const LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8;
168
169//============================================================================
170
171class LLProfileParams
172{
173public:
174 LLProfileParams()
175 {
176 mBegin = 0;
177 mEnd = 1;
178 mHollow = 0;
179 mCurveType = LL_PCODE_PROFILE_SQUARE;
180 }
181
182 LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow)
183 : mCurveType(curve), mBegin(begin), mEnd(end), mHollow(hollow)
184 {
185 }
186
187 LLProfileParams(U8 curve, U8 begin, U8 end, U8 hollow)
188 {
189 mCurveType = curve;
190 F32 temp_f32 = begin * CUT_QUANTA;
191 if (temp_f32 > 1.f)
192 {
193 temp_f32 = 1.f;
194 }
195 mBegin = temp_f32;
196 temp_f32 = end * CUT_QUANTA;
197 if (temp_f32 > 1.f)
198 {
199 temp_f32 = 1.f;
200 }
201 mEnd = 1.f - temp_f32;
202 temp_f32 = hollow * SCALE_QUANTA;
203 if (temp_f32 > 1.f)
204 {
205 temp_f32 = 1.f;
206 }
207 mHollow = temp_f32;
208 }
209
210 bool operator==(const LLProfileParams &params) const;
211 bool operator!=(const LLProfileParams &params) const;
212 bool operator<(const LLProfileParams &params) const;
213
214 void copyParams(const LLProfileParams &params);
215
216 BOOL importFile(FILE *fp);
217 BOOL exportFile(FILE *fp) const;
218
219 BOOL importLegacyStream(std::istream& input_stream);
220 BOOL exportLegacyStream(std::ostream& output_stream) const;
221
222 LLSD asLLSD() const;
223 operator LLSD() const { return asLLSD(); }
224 bool fromLLSD(LLSD& sd);
225
226 const F32& getBegin () const { return mBegin; }
227 const F32& getEnd () const { return mEnd; }
228 const F32& getHollow() const { return mHollow; }
229 const U8& getCurveType () const { return mCurveType; }
230
231 void setCurveType(const U32 type) { mCurveType = type;}
232 void setBegin(const F32 begin) { mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 1000))/1000.0f;}
233 void setEnd(const F32 end) { mEnd = (end <= 0.0f) ? 1.0f : ((int) (end * 1000))/1000.0f;}
234 void setHollow(const F32 hollow) { mHollow = ((int) (hollow * 1000))/1000.0f;}
235
236 friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params);
237
238protected:
239 // Profile params
240 U8 mCurveType;
241 F32 mBegin;
242 F32 mEnd;
243 F32 mHollow;
244
245 U32 mCRC;
246};
247
248inline bool LLProfileParams::operator==(const LLProfileParams &params) const
249{
250 return
251 (getCurveType() == params.getCurveType()) &&
252 (getBegin() == params.getBegin()) &&
253 (getEnd() == params.getEnd()) &&
254 (getHollow() == params.getHollow());
255}
256
257inline bool LLProfileParams::operator!=(const LLProfileParams &params) const
258{
259 return
260 (getCurveType() != params.getCurveType()) ||
261 (getBegin() != params.getBegin()) ||
262 (getEnd() != params.getEnd()) ||
263 (getHollow() != params.getHollow());
264}
265
266
267inline bool LLProfileParams::operator<(const LLProfileParams &params) const
268{
269 if (getCurveType() != params.getCurveType())
270 {
271 return getCurveType() < params.getCurveType();
272 }
273 else
274 if (getBegin() != params.getBegin())
275 {
276 return getBegin() < params.getBegin();
277 }
278 else
279 if (getEnd() != params.getEnd())
280 {
281 return getEnd() < params.getEnd();
282 }
283 else
284 {
285 return getHollow() < params.getHollow();
286 }
287}
288
289#define U8_TO_F32(x) (F32)(*((S8 *)&x))
290
291class LLPathParams
292{
293public:
294 LLPathParams()
295 {
296 mBegin = 0;
297 mEnd = 1;
298 mScale.setVec(1,1);
299 mShear.setVec(0,0);
300 mCurveType = LL_PCODE_PATH_LINE;
301 mTwistBegin = 0;
302 mTwistEnd = 0;
303 mRadiusOffset = 0;
304 mTaper.setVec(0,0);
305 mRevolutions = 1;
306 mSkew = 0;
307 }
308
309 LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew)
310 : mCurveType(curve), mBegin(begin), mEnd(end), mTwistBegin(twistbegin), mTwistEnd(twistend),
311 mRadiusOffset(radiusoffset), mRevolutions(revolutions), mSkew(skew)
312 {
313 mScale.setVec(scx,scy);
314 mShear.setVec(shx,shy);
315 mTaper.setVec(tx,ty);
316 }
317
318 LLPathParams(U8 curve, U8 begin, U8 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew)
319 {
320 mCurveType = curve;
321 mBegin = (F32)(begin * SCALE_QUANTA);
322 mEnd = (F32)(100.f - end) * SCALE_QUANTA;
323 if (mEnd > 1.f)
324 mEnd = 1.f;
325 mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA);
326 mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA);
327 mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA;
328 mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA;
329 mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA;
330 mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA);
331 mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f;
332 mSkew = U8_TO_F32(skew) * SCALE_QUANTA;
333 }
334
335 bool operator==(const LLPathParams &params) const;
336 bool operator!=(const LLPathParams &params) const;
337 bool operator<(const LLPathParams &params) const;
338
339 void copyParams(const LLPathParams &params);
340
341 BOOL importFile(FILE *fp);
342 BOOL exportFile(FILE *fp) const;
343
344 BOOL importLegacyStream(std::istream& input_stream);
345 BOOL exportLegacyStream(std::ostream& output_stream) const;
346
347 LLSD asLLSD() const;
348 operator LLSD() const { return asLLSD(); }
349 bool fromLLSD(LLSD& sd);
350
351 const F32& getBegin() const { return mBegin; }
352 const F32& getEnd() const { return mEnd; }
353 const LLVector2 &getScale() const { return mScale; }
354 const F32& getScaleX() const { return mScale.mV[0]; }
355 const F32& getScaleY() const { return mScale.mV[1]; }
356 const LLVector2 getBeginScale() const;
357 const LLVector2 getEndScale() const;
358 const LLVector2 &getShear() const { return mShear; }
359 const F32& getShearX() const { return mShear.mV[0]; }
360 const F32& getShearY() const { return mShear.mV[1]; }
361 const U8& getCurveType () const { return mCurveType; }
362
363 const F32& getTwistBegin() const { return mTwistBegin; }
364 const F32& getTwistEnd() const { return mTwistEnd; }
365 const F32& getTwist() const { return mTwistEnd; } // deprecated
366 const F32& getRadiusOffset() const { return mRadiusOffset; }
367 const LLVector2 &getTaper() const { return mTaper; }
368 const F32& getTaperX() const { return mTaper.mV[0]; }
369 const F32& getTaperY() const { return mTaper.mV[1]; }
370 const F32& getRevolutions() const { return mRevolutions; }
371 const F32& getSkew() const { return mSkew; }
372
373 void setCurveType(const U8 type) { mCurveType = type; }
374 void setBegin(const F32 begin) { mBegin = begin; }
375 void setEnd(const F32 end) { mEnd = end; }
376
377 void setScale(const F32 x, const F32 y) { mScale.setVec(x,y); }
378 void setScaleX(const F32 v) { mScale.mV[VX] = v; }
379 void setScaleY(const F32 v) { mScale.mV[VY] = v; }
380 void setShear(const F32 x, const F32 y) { mShear.setVec(x,y); }
381 void setShearX(const F32 v) { mShear.mV[VX] = v; }
382 void setShearY(const F32 v) { mShear.mV[VY] = v; }
383
384 void setTwistBegin(const F32 twist_begin) { mTwistBegin = twist_begin; }
385 void setTwistEnd(const F32 twist_end) { mTwistEnd = twist_end; }
386 void setTwist(const F32 twist) { setTwistEnd(twist); } // deprecated
387 void setRadiusOffset(const F32 radius_offset){ mRadiusOffset = radius_offset; }
388 void setTaper(const F32 x, const F32 y) { mTaper.setVec(x,y); }
389 void setTaperX(const F32 v) { mTaper.mV[VX] = v; }
390 void setTaperY(const F32 v) { mTaper.mV[VY] = v; }
391 void setRevolutions(const F32 revolutions) { mRevolutions = revolutions; }
392 void setSkew(const F32 skew) { mSkew = skew; }
393
394 friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params);
395
396protected:
397 // Path params
398 U8 mCurveType;
399 F32 mBegin;
400 F32 mEnd;
401 LLVector2 mScale;
402 LLVector2 mShear;
403
404 F32 mTwistBegin;
405 F32 mTwistEnd;
406 F32 mRadiusOffset;
407 LLVector2 mTaper;
408 F32 mRevolutions;
409 F32 mSkew;
410
411 U32 mCRC;
412};
413
414inline bool LLPathParams::operator==(const LLPathParams &params) const
415{
416 return
417 (getCurveType() == params.getCurveType()) &&
418 (getScale() == params.getScale()) &&
419 (getBegin() == params.getBegin()) &&
420 (getEnd() == params.getEnd()) &&
421 (getShear() == params.getShear()) &&
422 (getTwist() == params.getTwist()) &&
423 (getTwistBegin() == params.getTwistBegin()) &&
424 (getRadiusOffset() == params.getRadiusOffset()) &&
425 (getTaper() == params.getTaper()) &&
426 (getRevolutions() == params.getRevolutions()) &&
427 (getSkew() == params.getSkew());
428}
429
430inline bool LLPathParams::operator!=(const LLPathParams &params) const
431{
432 return
433 (getCurveType() != params.getCurveType()) ||
434 (getScale() != params.getScale()) ||
435 (getBegin() != params.getBegin()) ||
436 (getEnd() != params.getEnd()) ||
437 (getShear() != params.getShear()) ||
438 (getTwist() != params.getTwist()) ||
439 (getTwistBegin() !=params.getTwistBegin()) ||
440 (getRadiusOffset() != params.getRadiusOffset()) ||
441 (getTaper() != params.getTaper()) ||
442 (getRevolutions() != params.getRevolutions()) ||
443 (getSkew() != params.getSkew());
444}
445
446
447inline bool LLPathParams::operator<(const LLPathParams &params) const
448{
449 if( getCurveType() != params.getCurveType())
450 {
451 return getCurveType() < params.getCurveType();
452 }
453 else
454 if( getScale() != params.getScale())
455 {
456 return getScale() < params.getScale();
457 }
458 else
459 if( getBegin() != params.getBegin())
460 {
461 return getBegin() < params.getBegin();
462 }
463 else
464 if( getEnd() != params.getEnd())
465 {
466 return getEnd() < params.getEnd();
467 }
468 else
469 if( getShear() != params.getShear())
470 {
471 return getShear() < params.getShear();
472 }
473 else
474 if( getTwist() != params.getTwist())
475 {
476 return getTwist() < params.getTwist();
477 }
478 else
479 if( getTwistBegin() != params.getTwistBegin())
480 {
481 return getTwistBegin() < params.getTwistBegin();
482 }
483 else
484 if( getRadiusOffset() != params.getRadiusOffset())
485 {
486 return getRadiusOffset() < params.getRadiusOffset();
487 }
488 else
489 if( getTaper() != params.getTaper())
490 {
491 return getTaper() < params.getTaper();
492 }
493 else
494 if( getRevolutions() != params.getRevolutions())
495 {
496 return getRevolutions() < params.getRevolutions();
497 }
498 else
499 {
500 return getSkew() < params.getSkew();
501 }
502}
503
504typedef LLVolumeParams* LLVolumeParamsPtr;
505typedef const LLVolumeParams* const_LLVolumeParamsPtr;
506
507class LLVolumeParams
508{
509public:
510 LLVolumeParams()
511 {
512 }
513
514 LLVolumeParams(LLProfileParams &profile, LLPathParams &path)
515 : mProfileParams(profile), mPathParams(path)
516 {
517 }
518
519 bool operator==(const LLVolumeParams &params) const;
520 bool operator!=(const LLVolumeParams &params) const;
521 bool operator<(const LLVolumeParams &params) const;
522
523
524 void copyParams(const LLVolumeParams &params);
525
526 const LLProfileParams &getProfileParams() const {return mProfileParams;}
527 LLProfileParams &getProfileParams() {return mProfileParams;}
528 const LLPathParams &getPathParams() const {return mPathParams;}
529 LLPathParams &getPathParams() {return mPathParams;}
530
531 BOOL importFile(FILE *fp);
532 BOOL exportFile(FILE *fp) const;
533
534 BOOL importLegacyStream(std::istream& input_stream);
535 BOOL exportLegacyStream(std::ostream& output_stream) const;
536
537 LLSD asLLSD() const;
538 operator LLSD() const { return asLLSD(); }
539 bool fromLLSD(LLSD& sd);
540
541 bool setType(U8 profile, U8 path);
542
543 //void setBeginS(const F32 beginS) { mProfileParams.setBegin(beginS); } // range 0 to 1
544 //void setBeginT(const F32 beginT) { mPathParams.setBegin(beginT); } // range 0 to 1
545 //void setEndS(const F32 endS) { mProfileParams.setEnd(endS); } // range 0 to 1, must be greater than begin
546 //void setEndT(const F32 endT) { mPathParams.setEnd(endT); } // range 0 to 1, must be greater than begin
547
548 bool setBeginAndEndS(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end
549 bool setBeginAndEndT(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end
550
551 bool setHollow(const F32 hollow); // range 0 to 1
552 bool setRatio(const F32 x) { return setRatio(x,x); } // 0 = point, 1 = same as base
553 bool setShear(const F32 x) { return setShear(x,x); } // 0 = no movement,
554 bool setRatio(const F32 x, const F32 y); // 0 = point, 1 = same as base
555 bool setShear(const F32 x, const F32 y); // 0 = no movement
556
557 bool setTwistBegin(const F32 twist_begin); // range -1 to 1
558 bool setTwistEnd(const F32 twist_end); // range -1 to 1
559 bool setTwist(const F32 twist) { return setTwistEnd(twist); } // deprecated
560 bool setTaper(const F32 x, const F32 y) { bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; }
561 bool setTaperX(const F32 v); // -1 to 1
562 bool setTaperY(const F32 v); // -1 to 1
563 bool setRevolutions(const F32 revolutions); // 1 to 4
564 bool setRadiusOffset(const F32 radius_offset);
565 bool setSkew(const F32 skew);
566
567 static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
568 U8 path_curve, F32 path_begin, F32 path_end,
569 F32 scx, F32 scy, F32 shx, F32 shy,
570 F32 twistend, F32 twistbegin, F32 radiusoffset,
571 F32 tx, F32 ty, F32 revolutions, F32 skew);
572
573 const F32& getBeginS() const { return mProfileParams.getBegin(); }
574 const F32& getBeginT() const { return mPathParams.getBegin(); }
575 const F32& getEndS() const { return mProfileParams.getEnd(); }
576 const F32& getEndT() const { return mPathParams.getEnd(); }
577
578 const F32& getHollow() const { return mProfileParams.getHollow(); }
579 const F32& getTwist() const { return mPathParams.getTwist(); }
580 const F32& getRatio() const { return mPathParams.getScaleX(); }
581 const F32& getRatioX() const { return mPathParams.getScaleX(); }
582 const F32& getRatioY() const { return mPathParams.getScaleY(); }
583 const F32& getShearX() const { return mPathParams.getShearX(); }
584 const F32& getShearY() const { return mPathParams.getShearY(); }
585
586 const F32& getTwistBegin()const { return mPathParams.getTwistBegin(); }
587 const F32& getRadiusOffset() const { return mPathParams.getRadiusOffset(); }
588 const F32& getTaper() const { return mPathParams.getTaperX(); }
589 const F32& getTaperX() const { return mPathParams.getTaperX(); }
590 const F32& getTaperY() const { return mPathParams.getTaperY(); }
591 const F32& getRevolutions() const { return mPathParams.getRevolutions(); }
592 const F32& getSkew() const { return mPathParams.getSkew(); }
593
594 BOOL isConvex() const;
595
596 // 'begin' and 'end' should be in range [0, 1] (they will be clamped)
597 // (begin, end) = (0, 1) will not change the volume
598 // (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T)
599 void reduceS(F32 begin, F32 end);
600 void reduceT(F32 begin, F32 end);
601
602 struct compare
603 {
604 bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const
605 {
606 return (*first < *second);
607 }
608 };
609
610 friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
611
612protected:
613 LLProfileParams mProfileParams;
614 LLPathParams mPathParams;
615};
616
617
618class LLProfile
619{
620public:
621 LLProfile(const LLProfileParams &params) : mParams(params)
622 {
623 mTotal = 2;
624 mTotalOut = 0;
625 mDirty = TRUE;
626 mConcave = FALSE;
627 }
628
629 ~LLProfile();
630
631 S32 getTotal() const { return mTotal; }
632 S32 getTotalOut() const { return mTotalOut; } // Total number of outside points
633 BOOL isHollow() const { return (mParams.getHollow() > 0); }
634 BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); }
635 BOOL isOpen() const { return mOpen; }
636 void setDirty() { mDirty = TRUE; }
637 BOOL generate(BOOL path_open, F32 detail = 1.0f, S32 split = 0);
638 BOOL isConcave() const { return mConcave; }
639public:
640 const LLProfileParams &mParams;
641
642 struct Face
643 {
644 S32 mIndex;
645 S32 mCount;
646 F32 mScaleU;
647 BOOL mCap;
648 BOOL mFlat;
649 LLFaceID mFaceID;
650 };
651
652 std::vector<LLVector3> mProfile;
653 std::vector<LLVector2> mNormals;
654 std::vector<Face> mFaces;
655 std::vector<LLVector3> mEdgeNormals;
656 std::vector<LLVector3> mEdgeCenters;
657 F32 mMaxX;
658 F32 mMinX;
659
660 friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile);
661
662protected:
663 void genNormals();
664 void genNGon(S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0);
665
666 Face* addHole(BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0);
667 Face* addCap (S16 faceID);
668 Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat);
669
670protected:
671 BOOL mOpen;
672 BOOL mConcave;
673 BOOL mDirty;
674
675 S32 mTotalOut;
676 S32 mTotal;
677};
678
679//-------------------------------------------------------------------
680// SWEEP/EXTRUDE PATHS
681//-------------------------------------------------------------------
682
683class LLPath
684{
685public:
686 struct PathPt
687 {
688 LLVector3 mPos;
689 LLVector2 mScale;
690 LLQuaternion mRot;
691 F32 mTexT;
692 PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); }
693 };
694
695public:
696 LLPath(const LLPathParams &params) : mParams(params)
697 {
698 mOpen = FALSE;
699 mDirty = TRUE;
700 mStep = 1;
701 }
702
703 virtual ~LLPath();
704
705 void genNGon(S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f);
706 virtual BOOL generate(F32 detail=1.0f, S32 split = 0);
707
708 BOOL isOpen() const { return mOpen; }
709 F32 getStep() const { return mStep; }
710 void setDirty() { mDirty = TRUE; }
711
712 S32 getPathLength() const { return (S32)mPath.size(); }
713
714 void resizePath(S32 length) { mPath.resize(length); }
715
716 friend std::ostream& operator<<(std::ostream &s, const LLPath &path);
717
718public:
719 const LLPathParams &mParams;
720 std::vector<PathPt> mPath;
721
722protected:
723 BOOL mOpen;
724 S32 mTotal;
725 BOOL mDirty;
726 F32 mStep;
727};
728
729class LLDynamicPath : public LLPath
730{
731public:
732 LLDynamicPath(const LLPathParams &params) : LLPath(params) { }
733 BOOL generate(F32 detail=1.0f, S32 split = 0);
734};
735
736// Yet another "face" class - caches volume-specific, but not instance-specific data for faces)
737class LLVolumeFace
738{
739public:
740 LLVolumeFace();
741 BOOL create();
742
743 class VertexData
744 {
745 public:
746 LLVector3 mPosition;
747 LLVector3 mNormal;
748 LLVector3 mBinormal;
749 LLVector2 mTexCoord;
750 };
751
752 enum
753 {
754 SINGLE_MASK = 0x0001,
755 CAP_MASK = 0x0002,
756 END_MASK = 0x0004,
757 SIDE_MASK = 0x0008,
758 INNER_MASK = 0x0010,
759 OUTER_MASK = 0x0020,
760 HOLLOW_MASK = 0x0040,
761 OPEN_MASK = 0x0080,
762 FLAT_MASK = 0x0100,
763 TOP_MASK = 0x0200,
764 BOTTOM_MASK = 0x0400
765 } TypeMask;
766
767public:
768 S32 mID;
769 U32 mTypeMask;
770 LLVector3 mCenter;
771
772 // Only used for INNER/OUTER faces
773 S32 mBeginS;
774 S32 mBeginT;
775 S32 mNumS;
776 S32 mNumT;
777
778 std::vector<VertexData> mVertices;
779 std::vector<S32> mIndices;
780 std::vector<S32> mEdge;
781 LLVolume *mVolumep; // Deliberately NOT reference counted - djs 11/20/03 - otherwise would make an annoying circular reference
782
783 // Shouldn't need num_old and num_new, really - djs
784 static BOOL updateColors(LLColor4U *old_colors, const S32 num_old, const LLVolumeFace &old_face,
785 LLStrider<LLColor4U> &new_colors, const S32 num_new, const LLVolumeFace &new_face);
786
787protected:
788 BOOL createUnCutCubeCap();
789 BOOL createCap();
790 BOOL createSide();
791};
792
793class LLVolume : public LLRefCount
794{
795 friend class LLVolumeLODGroup;
796
797private:
798 LLVolume(const LLVolume&); // Don't implement
799 ~LLVolume(); // use unref
800
801public:
802 struct Point
803 {
804 LLVector3 mPos;
805 };
806
807 struct FaceParams
808 {
809 LLFaceID mFaceID;
810 S32 mBeginS;
811 S32 mCountS;
812 S32 mBeginT;
813 S32 mCountT;
814 };
815
816 LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE);
817
818 U8 getProfileType() const { return mProfilep->mParams.getCurveType(); }
819 U8 getPathType() const { return mPathp->mParams.getCurveType(); }
820 S32 getNumFaces() const { return (S32)mProfilep->mFaces.size(); }
821
822 const F32 getDetail() const { return mDetail; }
823 const LLVolumeParams & getParams() const { return mParams; }
824 LLVolumeParams getCopyOfParams() const { return mParams; }
825 const LLProfile& getProfile() const { return *mProfilep; }
826 LLPath& getPath() const { return *mPathp; }
827 const std::vector<Point>& getMesh() const { return mMesh; }
828 const LLVector3& getMeshPt(const U32 i) const { return mMesh[i].mPos; }
829
830 void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); }
831
832 void regen();
833
834 BOOL isConvex() const;
835 BOOL isCap(S32 face);
836 BOOL isFlat(S32 face);
837 BOOL isUnique() const { return mUnique; }
838
839 S32 *getTriangleIndices(U32 &num_indices) const;
840 void generateSilhouetteVertices(std::vector<LLVector3> &vertices, std::vector<LLVector3> &normals, std::vector<S32> &segments, const LLVector3& view_vec,
841 const LLMatrix4& mat,
842 const LLMatrix3& norm_mat);
843
844 //get the face index of the face that intersects with the given line segment at the point
845 //closest to start. Moves end to the point of intersection. Returns -1 if no intersection.
846 //Line segment must be in volume space.
847 S32 lineSegmentIntersect(const LLVector3& start, LLVector3& end) const;
848
849 // The following cleans up vertices and triangles,
850 // getting rid of degenerate triangles and duplicate vertices,
851 // and allocates new arrays with the clean data.
852 static BOOL cleanupTriangleData( const S32 num_input_vertices,
853 const std::vector<Point> &input_vertices,
854 const S32 num_input_triangles,
855 S32 *input_triangles,
856 S32 &num_output_vertices,
857 LLVector3 **output_vertices,
858 S32 &num_output_triangles,
859 S32 **output_triangles);
860 LLFaceID generateFaceMask();
861
862 BOOL isFaceMaskValid(LLFaceID face_mask);
863 static S32 mNumMeshPoints;
864
865 friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume);
866 friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over
867 // conversion if *(LLVolume*) to LLVolume&
868 const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
869
870 U32 mFaceMask; // bit array of which faces exist in this volume
871 LLVector3 mBounds[2]; // bounding box (center, half-height)
872 LLVector3 mLODScaleBias; // vector for biasing LOD based on scale
873
874protected:
875 BOOL generate();
876 void createVolumeFaces();
877
878protected:
879 BOOL mUnique;
880 F32 mDetail;
881 LLVolumeParams mParams;
882 LLPath *mPathp;
883 LLProfile *mProfilep;
884 std::vector<Point> mMesh;
885
886 BOOL mGenerateSingleFace;
887 S32 mNumVolumeFaces;
888 LLVolumeFace *mVolumeFaces;
889};
890
891std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
892
893LLVector3 calc_binormal_from_triangle(
894 const LLVector3& pos0,
895 const LLVector2& tex0,
896 const LLVector3& pos1,
897 const LLVector2& tex1,
898 const LLVector3& pos2,
899 const LLVector2& tex2);
900
901#endif
diff --git a/linden/indra/llmath/llvolumemgr.cpp b/linden/indra/llmath/llvolumemgr.cpp
new file mode 100644
index 0000000..6b6182a
--- /dev/null
+++ b/linden/indra/llmath/llvolumemgr.cpp
@@ -0,0 +1,314 @@
1/**
2 * @file llvolumemgr.cpp
3 *
4 * Copyright (c) 2002-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "llvolumemgr.h"
30#include "llvolume.h"
31
32
33//#define DEBUG_VOLUME
34
35LLVolumeMgr* gVolumeMgr = 0;
36
37const F32 BASE_THRESHOLD = 0.03f;
38
39//static
40F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,
41 2*BASE_THRESHOLD,
42 8*BASE_THRESHOLD,
43 100*BASE_THRESHOLD};
44
45//static
46F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f};
47
48//============================================================================
49//static
50void LLVolumeMgr::initClass()
51{
52 gVolumeMgr = new LLVolumeMgr();
53}
54
55//static
56BOOL LLVolumeMgr::cleanupClass()
57{
58 BOOL res = FALSE;
59 if (gVolumeMgr) {
60 res = gVolumeMgr->cleanup();
61 delete gVolumeMgr;
62 gVolumeMgr = 0;
63 }
64 return res;
65}
66
67//============================================================================
68
69LLVolumeMgr::LLVolumeMgr()
70{
71 mDataMutex = new LLMutex(gAPRPoolp);
72// mNumVolumes = 0;
73}
74
75LLVolumeMgr::~LLVolumeMgr()
76{
77 cleanup();
78 delete mDataMutex;
79}
80
81BOOL LLVolumeMgr::cleanup()
82{
83 #ifdef DEBUG_VOLUME
84 {
85 lldebugs << "LLVolumeMgr::cleanup()" << llendl;
86 }
87 #endif
88 BOOL no_refs = TRUE;
89 mDataMutex->lock();
90 for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
91 end = mVolumeLODGroups.end();
92 iter != end; iter++)
93 {
94 LLVolumeLODGroup *volgroupp = iter->second;
95 if (volgroupp->getNumRefs() != 1)
96 {
97 llwarns << "Volume group " << volgroupp << " has "
98 << volgroupp->getNumRefs() << " remaining refs" << llendl;
99 llwarns << volgroupp->getParams() << llendl;
100 no_refs = FALSE;
101 }
102 volgroupp->unref();// this );
103 }
104 mVolumeLODGroups.clear();
105 mDataMutex->unlock();
106 return no_refs;
107}
108
109LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32 detail)
110{
111 LLVolumeLODGroup* volgroupp;
112 mDataMutex->lock();
113 volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
114 if( iter == mVolumeLODGroups.end() )
115 {
116 volgroupp = new LLVolumeLODGroup(volume_params);
117 const LLVolumeParams* params = &(volgroupp->getParams());
118 mVolumeLODGroups[params] = volgroupp;
119 volgroupp->ref(); // initial reference
120 }
121 else
122 {
123 volgroupp = iter->second;
124 }
125 volgroupp->ref();// this );
126 mDataMutex->unlock();
127 // mNumVolumes++;
128 #ifdef DEBUG_VOLUME
129 {
130 lldebugs << "LLVolumeMgr::getVolume() " << (*this) << llendl;
131 }
132 #endif
133 return volgroupp->getLOD(detail);
134}
135
136void LLVolumeMgr::cleanupVolume(LLVolume *volumep)
137{
138 if (volumep->isUnique())
139 {
140 // TomY: Don't need to manage this volume. It is a unique instance.
141 return;
142 }
143 LLVolumeParams* params = (LLVolumeParams*) &(volumep->getParams());
144 mDataMutex->lock();
145 volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
146 if( iter == mVolumeLODGroups.end() )
147 {
148 llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
149 mDataMutex->unlock();
150 return;
151 }
152 else
153 {
154 LLVolumeLODGroup* volgroupp = iter->second;
155
156 volgroupp->derefLOD(volumep);
157 volgroupp->unref();// this );
158 if (volgroupp->getNumRefs() == 1)
159 {
160 mVolumeLODGroups.erase(params);
161 volgroupp->unref();// this );
162 }
163 // mNumVolumes--;
164 }
165 mDataMutex->unlock();
166
167 #ifdef DEBUG_VOLUME
168 {
169 lldebugs << "LLVolumeMgr::cleanupVolume() " << (*this) << llendl;
170 }
171 #endif
172}
173
174void LLVolumeMgr::dump()
175{
176 F32 avg = 0.f;
177 mDataMutex->lock();
178 for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
179 end = mVolumeLODGroups.end();
180 iter != end; iter++)
181 {
182 LLVolumeLODGroup *volgroupp = iter->second;
183 avg += volgroupp->dump();
184 }
185 int count = (int)mVolumeLODGroups.size();
186 avg = count ? avg / (F32)count : 0.0f;
187 mDataMutex->unlock();
188 llinfos << "Average usage of LODs " << avg << llendl;
189}
190
191std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
192{
193 s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
194
195 S32 total_refs = 0;
196 volume_mgr.mDataMutex->lock();
197
198 LLVolumeMgr::volume_lod_group_map_iter iter = volume_mgr.mVolumeLODGroups.begin();
199 LLVolumeMgr::volume_lod_group_map_iter end = volume_mgr.mVolumeLODGroups.end();
200 for ( ; iter != end; ++iter)
201 {
202 LLVolumeLODGroup *volgroupp = iter->second;
203 total_refs += volgroupp->getNumRefs();
204 s << ", " << (*volgroupp);
205 }
206
207 volume_mgr.mDataMutex->unlock();
208
209 s << ", total_refs=" << total_refs << " }";
210 return s;
211}
212
213LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams &params)
214{
215 S32 i;
216 mParams = params;
217
218 for (i = 0; i < NUM_LODS; i++)
219 {
220 mLODRefs[i] = 0;
221 mVolumeLODs[i] = NULL;
222 mAccessCount[i] = 0;
223 }
224}
225
226LLVolumeLODGroup::~LLVolumeLODGroup()
227{
228 S32 i;
229 for (i = 0; i < NUM_LODS; i++)
230 {
231 delete mVolumeLODs[i];
232 mVolumeLODs[i] = NULL;
233 }
234}
235
236
237LLVolume * LLVolumeLODGroup::getLOD(const S32 detail)
238{
239 llassert(detail >=0 && detail < NUM_LODS);
240 mAccessCount[detail]++;
241 mLODRefs[detail]++;
242 if (!mVolumeLODs[detail])
243 {
244 mVolumeLODs[detail] = new LLVolume(mParams, mDetailScales[detail]);
245 }
246 return mVolumeLODs[detail];
247}
248
249BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
250{
251 S32 i;
252 for (i = 0; i < NUM_LODS; i++)
253 {
254 if (mVolumeLODs[i] == volumep)
255 {
256 mLODRefs[i]--;
257 if (!mLODRefs[i])
258 {
259 mVolumeLODs[i] = NULL;
260 }
261 return TRUE;
262 }
263 }
264 llerrs << "Deref of non-matching LOD in volume LOD group" << llendl;
265 return FALSE;
266}
267
268S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle)
269{
270 S32 i = 0;
271 while (i < (NUM_LODS - 1))
272 {
273 if (tan_angle <= mDetailThresholds[i])
274 {
275 return i;
276 }
277 i++;
278 }
279 return NUM_LODS - 1;
280}
281
282F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
283{
284 return mDetailScales[detail];
285}
286
287F32 LLVolumeLODGroup::dump()
288{
289 char dump_str[255];
290 F32 usage = 0.f;
291 for (S32 i = 0; i < NUM_LODS; i++)
292 {
293 if (mAccessCount[i] > 0)
294 {
295 usage += 1.f;
296 }
297 }
298 usage = usage / (F32)NUM_LODS;
299
300 sprintf(dump_str, "%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]);
301
302 llinfos << dump_str << llendl;
303 return usage;
304}
305
306std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
307{
308 s << "{ numRefs=" << volgroup.getNumRefs();
309 s << ", mParams=" << volgroup.mParams;
310 s << " }";
311
312 return s;
313}
314
diff --git a/linden/indra/llmath/llvolumemgr.h b/linden/indra/llmath/llvolumemgr.h
new file mode 100644
index 0000000..9cb1f63
--- /dev/null
+++ b/linden/indra/llmath/llvolumemgr.h
@@ -0,0 +1,101 @@
1/**
2 * @file llvolumemgr.h
3 * @brief LLVolumeMgr class.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLVOLUMEMGR_H
29#define LL_LLVOLUMEMGR_H
30
31#include <map>
32
33#include "llvolume.h"
34#include "llmemory.h"
35#include "llthread.h"
36
37class LLVolumeParams;
38class LLVolumeLODGroup;
39
40class LLVolumeLODGroup : public LLThreadSafeRefCount
41{
42protected:
43 ~LLVolumeLODGroup();
44
45public:
46 enum
47 {
48 NUM_LODS = 4
49 };
50
51 LLVolumeLODGroup(const LLVolumeParams &params);
52
53 BOOL derefLOD(LLVolume *volumep);
54 static S32 getDetailFromTan(const F32 tan_angle);
55 static F32 getVolumeScaleFromDetail(const S32 detail);
56
57 LLVolume *getLOD(const S32 detail);
58 const LLVolumeParams &getParams() const { return mParams; };
59
60 F32 dump();
61 friend std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup);
62
63protected:
64 LLVolumeParams mParams;
65
66 S32 mLODRefs[NUM_LODS];
67 LLVolume *mVolumeLODs[NUM_LODS];
68 static F32 mDetailThresholds[NUM_LODS];
69 static F32 mDetailScales[NUM_LODS];
70 S32 mAccessCount[NUM_LODS];
71};
72
73class LLVolumeMgr
74{
75public:
76 static void initClass();
77 static BOOL cleanupClass();
78
79public:
80 LLVolumeMgr();
81 ~LLVolumeMgr();
82 BOOL cleanup(); // Cleanup all volumes being managed, returns TRUE if no dangling references
83 LLVolume *getVolume(const LLVolumeParams &volume_params, const S32 detail);
84 void cleanupVolume(LLVolume *volumep);
85
86 void dump();
87 friend std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr);
88
89protected:
90 typedef std::map<const LLVolumeParams*, LLVolumeLODGroup*, LLVolumeParams::compare> volume_lod_group_map_t;
91 typedef volume_lod_group_map_t::const_iterator volume_lod_group_map_iter;
92 volume_lod_group_map_t mVolumeLODGroups;
93
94 LLMutex* mDataMutex;
95
96// S32 mNumVolumes;
97};
98
99extern LLVolumeMgr* gVolumeMgr;
100
101#endif // LL_LLVOLUMEMGR_H
diff --git a/linden/indra/llmath/m3math.cpp b/linden/indra/llmath/m3math.cpp
new file mode 100644
index 0000000..c5d2c2d
--- /dev/null
+++ b/linden/indra/llmath/m3math.cpp
@@ -0,0 +1,549 @@
1/**
2 * @file m3math.cpp
3 * @brief LLMatrix3 class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30//#include "vmath.h"
31#include "v3math.h"
32#include "v3dmath.h"
33#include "v4math.h"
34#include "m4math.h"
35#include "m3math.h"
36#include "llquaternion.h"
37
38// LLMatrix3
39
40// ji
41// LLMatrix3 = |00 01 02 |
42// |10 11 12 |
43// |20 21 22 |
44
45// LLMatrix3 = |fx fy fz | forward-axis
46// |lx ly lz | left-axis
47// |ux uy uz | up-axis
48
49
50// Constructors
51
52
53LLMatrix3::LLMatrix3(const LLQuaternion &q)
54{
55 *this = q.getMatrix3();
56}
57
58
59LLMatrix3::LLMatrix3(const F32 angle, const LLVector3 &vec)
60{
61 LLQuaternion quat(angle, vec);
62 *this = setRot(quat);
63}
64
65LLMatrix3::LLMatrix3(const F32 angle, const LLVector3d &vec)
66{
67 LLVector3 vec_f;
68 vec_f.setVec(vec);
69 LLQuaternion quat(angle, vec_f);
70 *this = setRot(quat);
71}
72
73LLMatrix3::LLMatrix3(const F32 angle, const LLVector4 &vec)
74{
75 LLQuaternion quat(angle, vec);
76 *this = setRot(quat);
77}
78
79LLMatrix3::LLMatrix3(const F32 angle, const F32 x, const F32 y, const F32 z)
80{
81 LLVector3 vec(x, y, z);
82 LLQuaternion quat(angle, vec);
83 *this = setRot(quat);
84}
85
86LLMatrix3::LLMatrix3(const F32 roll, const F32 pitch, const F32 yaw)
87{
88 // Rotates RH about x-axis by 'roll' then
89 // rotates RH about the old y-axis by 'pitch' then
90 // rotates RH about the original z-axis by 'yaw'.
91 // .
92 // /|\ yaw axis
93 // | __.
94 // ._ ___| /| pitch axis
95 // _||\ \\ |-. /
96 // \|| \_______\_|__\_/_______
97 // | _ _ o o o_o_o_o o /_\_ ________\ roll axis
98 // // /_______/ /__________> /
99 // /_,-' // /
100 // /__,-'
101
102 F32 cx, sx, cy, sy, cz, sz;
103 F32 cxsy, sxsy;
104
105 cx = (F32)cos(roll); //A
106 sx = (F32)sin(roll); //B
107 cy = (F32)cos(pitch); //C
108 sy = (F32)sin(pitch); //D
109 cz = (F32)cos(yaw); //E
110 sz = (F32)sin(yaw); //F
111
112 cxsy = cx * sy; //AD
113 sxsy = sx * sy; //BD
114
115 mMatrix[0][0] = cy * cz;
116 mMatrix[1][0] = -cy * sz;
117 mMatrix[2][0] = sy;
118 mMatrix[0][1] = sxsy * cz + cx * sz;
119 mMatrix[1][1] = -sxsy * sz + cx * cz;
120 mMatrix[2][1] = -sx * cy;
121 mMatrix[0][2] = -cxsy * cz + sx * sz;
122 mMatrix[1][2] = cxsy * sz + sx * cz;
123 mMatrix[2][2] = cx * cy;
124}
125
126// From Matrix and Quaternion FAQ
127void LLMatrix3::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const
128{
129 F64 angle_x, angle_y, angle_z;
130 F64 cx, cy, cz; // cosine of angle_x, angle_y, angle_z
131 F64 sx, sz; // sine of angle_x, angle_y, angle_z
132
133 angle_y = asin(llclamp(mMatrix[2][0], -1.f, 1.f));
134 cy = cos(angle_y);
135
136 if (fabs(cy) > 0.005) // non-zero
137 {
138 // no gimbal lock
139 cx = mMatrix[2][2] / cy;
140 sx = - mMatrix[2][1] / cy;
141
142 angle_x = (F32) atan2(sx, cx);
143
144 cz = mMatrix[0][0] / cy;
145 sz = - mMatrix[1][0] / cy;
146
147 angle_z = (F32) atan2(sz, cz);
148 }
149 else
150 {
151 // yup, gimbal lock
152 angle_x = 0;
153
154 // some tricky math thereby avoided, see article
155
156 cz = mMatrix[1][1];
157 sz = mMatrix[0][1];
158
159 angle_z = atan2(sz, cz);
160 }
161
162 *roll = (F32)angle_x;
163 *pitch = (F32)angle_y;
164 *yaw = (F32)angle_z;
165}
166
167
168// Clear and Assignment Functions
169
170const LLMatrix3& LLMatrix3::identity()
171{
172 mMatrix[0][0] = 1.f;
173 mMatrix[0][1] = 0.f;
174 mMatrix[0][2] = 0.f;
175
176 mMatrix[1][0] = 0.f;
177 mMatrix[1][1] = 1.f;
178 mMatrix[1][2] = 0.f;
179
180 mMatrix[2][0] = 0.f;
181 mMatrix[2][1] = 0.f;
182 mMatrix[2][2] = 1.f;
183 return (*this);
184}
185
186const LLMatrix3& LLMatrix3::zero()
187{
188 mMatrix[0][0] = 0.f;
189 mMatrix[0][1] = 0.f;
190 mMatrix[0][2] = 0.f;
191
192 mMatrix[1][0] = 0.f;
193 mMatrix[1][1] = 0.f;
194 mMatrix[1][2] = 0.f;
195
196 mMatrix[2][0] = 0.f;
197 mMatrix[2][1] = 0.f;
198 mMatrix[2][2] = 0.f;
199 return (*this);
200}
201
202// various useful mMatrix functions
203
204const LLMatrix3& LLMatrix3::transpose()
205{
206 // transpose the matrix
207 F32 temp;
208 temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
209 temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
210 temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
211 return *this;
212}
213
214
215F32 LLMatrix3::determinant() const
216{
217 // Is this a useful method when we assume the matrices are valid rotation
218 // matrices throughout this implementation?
219 return mMatrix[0][0] * (mMatrix[1][1] * mMatrix[2][2] - mMatrix[1][2] * mMatrix[2][1]) +
220 mMatrix[0][1] * (mMatrix[1][2] * mMatrix[2][0] - mMatrix[1][0] * mMatrix[2][2]) +
221 mMatrix[0][2] * (mMatrix[1][0] * mMatrix[2][1] - mMatrix[1][1] * mMatrix[2][0]);
222}
223
224// This is identical to the transMat3() method because we assume a rotation matrix
225const LLMatrix3& LLMatrix3::invert()
226{
227 // transpose the matrix
228 F32 temp;
229 temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
230 temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
231 temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
232 return *this;
233}
234
235// does not assume a rotation matrix, and does not divide by determinant, assuming results will be renormalized
236const LLMatrix3& LLMatrix3::adjointTranspose()
237{
238 LLMatrix3 adjoint_transpose;
239 adjoint_transpose.mMatrix[VX][VX] = mMatrix[VY][VY] * mMatrix[VZ][VZ] - mMatrix[VY][VZ] * mMatrix[VZ][VY] ;
240 adjoint_transpose.mMatrix[VY][VX] = mMatrix[VY][VZ] * mMatrix[VZ][VX] - mMatrix[VY][VX] * mMatrix[VZ][VZ] ;
241 adjoint_transpose.mMatrix[VZ][VX] = mMatrix[VY][VX] * mMatrix[VZ][VY] - mMatrix[VY][VY] * mMatrix[VZ][VX] ;
242 adjoint_transpose.mMatrix[VX][VY] = mMatrix[VZ][VY] * mMatrix[VX][VZ] - mMatrix[VZ][VZ] * mMatrix[VX][VY] ;
243 adjoint_transpose.mMatrix[VY][VY] = mMatrix[VZ][VZ] * mMatrix[VX][VX] - mMatrix[VZ][VX] * mMatrix[VX][VZ] ;
244 adjoint_transpose.mMatrix[VZ][VY] = mMatrix[VZ][VX] * mMatrix[VX][VY] - mMatrix[VZ][VY] * mMatrix[VX][VX] ;
245 adjoint_transpose.mMatrix[VX][VZ] = mMatrix[VX][VY] * mMatrix[VY][VZ] - mMatrix[VX][VZ] * mMatrix[VY][VY] ;
246 adjoint_transpose.mMatrix[VY][VZ] = mMatrix[VX][VZ] * mMatrix[VY][VX] - mMatrix[VX][VX] * mMatrix[VY][VZ] ;
247 adjoint_transpose.mMatrix[VZ][VZ] = mMatrix[VX][VX] * mMatrix[VY][VY] - mMatrix[VX][VY] * mMatrix[VY][VX] ;
248
249 *this = adjoint_transpose;
250 return *this;
251}
252
253// SJB: This code is correct for a logicly stored (non-transposed) matrix;
254// Our matrices are stored transposed, OpenGL style, so this generates the
255// INVERSE quaternion (-x, -y, -z, w)!
256// Because we use similar logic in LLQuaternion::getMatrix3,
257// we are internally consistant so everything works OK :)
258LLQuaternion LLMatrix3::quaternion() const
259{
260 LLQuaternion quat;
261 F32 tr, s, q[4];
262 U32 i, j, k;
263 U32 nxt[3] = {1, 2, 0};
264
265 tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2];
266
267 // check the diagonal
268 if (tr > 0.f)
269 {
270 s = (F32)sqrt (tr + 1.f);
271 quat.mQ[VS] = s / 2.f;
272 s = 0.5f / s;
273 quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s;
274 quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s;
275 quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s;
276 }
277 else
278 {
279 // diagonal is negative
280 i = 0;
281 if (mMatrix[1][1] > mMatrix[0][0])
282 i = 1;
283 if (mMatrix[2][2] > mMatrix[i][i])
284 i = 2;
285
286 j = nxt[i];
287 k = nxt[j];
288
289
290 s = (F32)sqrt ((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f);
291
292 q[i] = s * 0.5f;
293
294 if (s != 0.f)
295 s = 0.5f / s;
296
297 q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s;
298 q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s;
299 q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s;
300
301 quat.setQuat(q);
302 }
303 return quat;
304}
305
306
307// These functions take Rotation arguments
308const LLMatrix3& LLMatrix3::setRot(const F32 angle, const F32 x, const F32 y, const F32 z)
309{
310 LLMatrix3 mat(angle, x, y, z);
311 *this = mat;
312 return *this;
313}
314
315const LLMatrix3& LLMatrix3::setRot(const F32 angle, const LLVector3 &vec)
316{
317 LLMatrix3 mat(angle, vec);
318 *this = mat;
319 return *this;
320}
321
322const LLMatrix3& LLMatrix3::setRot(const F32 roll, const F32 pitch, const F32 yaw)
323{
324 LLMatrix3 mat(roll, pitch, yaw);
325 *this = mat;
326 return *this;
327}
328
329
330const LLMatrix3& LLMatrix3::setRot(const LLQuaternion &q)
331{
332 LLMatrix3 mat(q);
333 *this = mat;
334 return *this;
335}
336
337
338const LLMatrix3& LLMatrix3::setRows(const LLVector3 &fwd, const LLVector3 &left, const LLVector3 &up)
339{
340 mMatrix[0][0] = fwd.mV[0];
341 mMatrix[0][1] = fwd.mV[1];
342 mMatrix[0][2] = fwd.mV[2];
343
344 mMatrix[1][0] = left.mV[0];
345 mMatrix[1][1] = left.mV[1];
346 mMatrix[1][2] = left.mV[2];
347
348 mMatrix[2][0] = up.mV[0];
349 mMatrix[2][1] = up.mV[1];
350 mMatrix[2][2] = up.mV[2];
351
352 return *this;
353}
354
355
356// Rotate exisitng mMatrix
357const LLMatrix3& LLMatrix3::rotate(const F32 angle, const F32 x, const F32 y, const F32 z)
358{
359 LLMatrix3 mat(angle, x, y, z);
360 *this *= mat;
361 return *this;
362}
363
364
365const LLMatrix3& LLMatrix3::rotate(const F32 angle, const LLVector3 &vec)
366{
367 LLMatrix3 mat(angle, vec);
368 *this *= mat;
369 return *this;
370}
371
372
373const LLMatrix3& LLMatrix3::rotate(const F32 roll, const F32 pitch, const F32 yaw)
374{
375 LLMatrix3 mat(roll, pitch, yaw);
376 *this *= mat;
377 return *this;
378}
379
380
381const LLMatrix3& LLMatrix3::rotate(const LLQuaternion &q)
382{
383 LLMatrix3 mat(q);
384 *this *= mat;
385 return *this;
386}
387
388
389LLVector3 LLMatrix3::getFwdRow() const
390{
391 return LLVector3(mMatrix[VX]);
392}
393
394LLVector3 LLMatrix3::getLeftRow() const
395{
396 return LLVector3(mMatrix[VY]);
397}
398
399LLVector3 LLMatrix3::getUpRow() const
400{
401 return LLVector3(mMatrix[VZ]);
402}
403
404
405
406const LLMatrix3& LLMatrix3::orthogonalize()
407{
408 LLVector3 x_axis(mMatrix[VX]);
409 LLVector3 y_axis(mMatrix[VY]);
410 LLVector3 z_axis(mMatrix[VZ]);
411
412 x_axis.normVec();
413 y_axis -= x_axis * (x_axis * y_axis);
414 y_axis.normVec();
415 z_axis = x_axis % y_axis;
416 setRows(x_axis, y_axis, z_axis);
417 return (*this);
418}
419
420
421// LLMatrix3 Operators
422
423LLMatrix3 operator*(const LLMatrix3 &a, const LLMatrix3 &b)
424{
425 U32 i, j;
426 LLMatrix3 mat;
427 for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
428 {
429 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
430 {
431 mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] +
432 a.mMatrix[j][1] * b.mMatrix[1][i] +
433 a.mMatrix[j][2] * b.mMatrix[2][i];
434 }
435 }
436 return mat;
437}
438
439/* Not implemented to help enforce code consistency with the syntax of
440 row-major notation. This is a Good Thing.
441LLVector3 operator*(const LLMatrix3 &a, const LLVector3 &b)
442{
443 LLVector3 vec;
444 // matrix operates "from the left" on column vector
445 vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] +
446 a.mMatrix[VX][VY] * b.mV[VY] +
447 a.mMatrix[VX][VZ] * b.mV[VZ];
448
449 vec.mV[VY] = a.mMatrix[VY][VX] * b.mV[VX] +
450 a.mMatrix[VY][VY] * b.mV[VY] +
451 a.mMatrix[VY][VZ] * b.mV[VZ];
452
453 vec.mV[VZ] = a.mMatrix[VZ][VX] * b.mV[VX] +
454 a.mMatrix[VZ][VY] * b.mV[VY] +
455 a.mMatrix[VZ][VZ] * b.mV[VZ];
456 return vec;
457}
458*/
459
460
461LLVector3 operator*(const LLVector3 &a, const LLMatrix3 &b)
462{
463 // matrix operates "from the right" on row vector
464 return LLVector3(
465 a.mV[VX] * b.mMatrix[VX][VX] +
466 a.mV[VY] * b.mMatrix[VY][VX] +
467 a.mV[VZ] * b.mMatrix[VZ][VX],
468
469 a.mV[VX] * b.mMatrix[VX][VY] +
470 a.mV[VY] * b.mMatrix[VY][VY] +
471 a.mV[VZ] * b.mMatrix[VZ][VY],
472
473 a.mV[VX] * b.mMatrix[VX][VZ] +
474 a.mV[VY] * b.mMatrix[VY][VZ] +
475 a.mV[VZ] * b.mMatrix[VZ][VZ] );
476}
477
478LLVector3d operator*(const LLVector3d &a, const LLMatrix3 &b)
479{
480 // matrix operates "from the right" on row vector
481 return LLVector3d(
482 a.mdV[VX] * b.mMatrix[VX][VX] +
483 a.mdV[VY] * b.mMatrix[VY][VX] +
484 a.mdV[VZ] * b.mMatrix[VZ][VX],
485
486 a.mdV[VX] * b.mMatrix[VX][VY] +
487 a.mdV[VY] * b.mMatrix[VY][VY] +
488 a.mdV[VZ] * b.mMatrix[VZ][VY],
489
490 a.mdV[VX] * b.mMatrix[VX][VZ] +
491 a.mdV[VY] * b.mMatrix[VY][VZ] +
492 a.mdV[VZ] * b.mMatrix[VZ][VZ] );
493}
494
495bool operator==(const LLMatrix3 &a, const LLMatrix3 &b)
496{
497 U32 i, j;
498 for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
499 {
500 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
501 {
502 if (a.mMatrix[j][i] != b.mMatrix[j][i])
503 return FALSE;
504 }
505 }
506 return TRUE;
507}
508
509bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b)
510{
511 U32 i, j;
512 for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
513 {
514 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
515 {
516 if (a.mMatrix[j][i] != b.mMatrix[j][i])
517 return TRUE;
518 }
519 }
520 return FALSE;
521}
522
523const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b)
524{
525 U32 i, j;
526 LLMatrix3 mat;
527 for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
528 {
529 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
530 {
531 mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] +
532 a.mMatrix[j][1] * b.mMatrix[1][i] +
533 a.mMatrix[j][2] * b.mMatrix[2][i];
534 }
535 }
536 a = mat;
537 return a;
538}
539
540std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a)
541{
542 s << "{ "
543 << a.mMatrix[VX][VX] << ", " << a.mMatrix[VX][VY] << ", " << a.mMatrix[VX][VZ] << "; "
544 << a.mMatrix[VY][VX] << ", " << a.mMatrix[VY][VY] << ", " << a.mMatrix[VY][VZ] << "; "
545 << a.mMatrix[VZ][VX] << ", " << a.mMatrix[VZ][VY] << ", " << a.mMatrix[VZ][VZ]
546 << " }";
547 return s;
548}
549
diff --git a/linden/indra/llmath/m3math.h b/linden/indra/llmath/m3math.h
new file mode 100644
index 0000000..74c5203
--- /dev/null
+++ b/linden/indra/llmath/m3math.h
@@ -0,0 +1,217 @@
1/**
2 * @file m3math.h
3 * @brief LLMatrix3 class header file.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_M3MATH_H
29#define LL_M3MATH_H
30
31#include "llerror.h"
32
33class LLVector4;
34class LLVector3;
35class LLVector3d;
36class LLQuaternion;
37
38// NOTA BENE: Currently assuming a right-handed, z-up universe
39
40// ji
41// LLMatrix3 = | 00 01 02 |
42// | 10 11 12 |
43// | 20 21 22 |
44
45// LLMatrix3 = | fx fy fz | forward-axis
46// | lx ly lz | left-axis
47// | ux uy uz | up-axis
48
49// NOTE: The world of computer graphics uses column-vectors and matricies that
50// "operate to the left".
51
52
53static const U32 NUM_VALUES_IN_MAT3 = 3;
54#if LL_WINDOWS
55__declspec( align(16) )
56#endif
57class LLMatrix3
58{
59 public:
60 F32 mMatrix[NUM_VALUES_IN_MAT3][NUM_VALUES_IN_MAT3];
61
62 LLMatrix3(void); // Initializes Matrix to identity matrix
63 explicit LLMatrix3(const F32 *mat); // Initializes Matrix to values in mat
64 explicit LLMatrix3(const LLQuaternion &q); // Initializes Matrix with rotation q
65
66 LLMatrix3(const F32 angle, const F32 x, const F32 y, const F32 z); // Initializes Matrix with axis angle
67 LLMatrix3(const F32 angle, const LLVector3 &vec); // Initializes Matrix with axis angle
68 LLMatrix3(const F32 angle, const LLVector3d &vec); // Initializes Matrix with axis angle
69 LLMatrix3(const F32 angle, const LLVector4 &vec); // Initializes Matrix with axis angle
70 LLMatrix3(const F32 roll, const F32 pitch, const F32 yaw); // Initializes Matrix with Euler angles
71
72 //////////////////////////////
73 //
74 // Matrix initializers - these replace any existing values in the matrix
75 //
76
77 // various useful matrix functions
78 const LLMatrix3& identity(); // Load identity matrix
79 const LLMatrix3& zero(); // Clears Matrix to zero
80
81 ///////////////////////////
82 //
83 // Matrix setters - set some properties without modifying others
84 //
85
86 // These functions take Rotation arguments
87 const LLMatrix3& setRot(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix for rotating angle radians about (x, y, z)
88 const LLMatrix3& setRot(const F32 angle, const LLVector3 &vec); // Calculate rotation matrix for rotating angle radians about vec
89 const LLMatrix3& setRot(const F32 roll, const F32 pitch, const F32 yaw); // Calculate rotation matrix from Euler angles
90 const LLMatrix3& setRot(const LLQuaternion &q); // Transform matrix by Euler angles and translating by pos
91
92 const LLMatrix3& setRows(const LLVector3 &x_axis, const LLVector3 &y_axis, const LLVector3 &z_axis);
93
94 ///////////////////////////
95 //
96 // Get properties of a matrix
97 //
98 LLQuaternion quaternion() const; // Returns quaternion from mat
99 void getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const; // Returns Euler angles, in radians
100
101 // Axis extraction routines
102 LLVector3 getFwdRow() const;
103 LLVector3 getLeftRow() const;
104 LLVector3 getUpRow() const;
105 F32 determinant() const; // Return determinant
106
107
108 ///////////////////////////
109 //
110 // Operations on an existing matrix
111 //
112 const LLMatrix3& transpose(); // Transpose MAT4
113 const LLMatrix3& invert(); // Invert MAT4
114 const LLMatrix3& orthogonalize(); // Orthogonalizes X, then Y, then Z
115 const LLMatrix3& adjointTranspose(); // returns transpose of matrix adjoint, for multiplying normals
116
117
118 // Rotate existing matrix
119 // Note: the two lines below are equivalent:
120 // foo.rotate(bar)
121 // foo = foo * bar
122 // That is, foo.rotMat3(bar) multiplies foo by bar FROM THE RIGHT
123 const LLMatrix3& rotate(const F32 angle, const F32 x, const F32 y, const F32 z); // Rotate matrix by rotating angle radians about (x, y, z)
124 const LLMatrix3& rotate(const F32 angle, const LLVector3 &vec); // Rotate matrix by rotating angle radians about vec
125 const LLMatrix3& rotate(const F32 roll, const F32 pitch, const F32 yaw); // Rotate matrix by roll (about x), pitch (about y), and yaw (about z)
126 const LLMatrix3& rotate(const LLQuaternion &q); // Transform matrix by Euler angles and translating by pos
127
128// This operator is misleading as to operation direction
129// friend LLVector3 operator*(const LLMatrix3 &a, const LLVector3 &b); // Apply rotation a to vector b
130
131 friend LLVector3 operator*(const LLVector3 &a, const LLMatrix3 &b); // Apply rotation b to vector a
132 friend LLVector3d operator*(const LLVector3d &a, const LLMatrix3 &b); // Apply rotation b to vector a
133 friend LLMatrix3 operator*(const LLMatrix3 &a, const LLMatrix3 &b); // Return a * b
134
135 friend bool operator==(const LLMatrix3 &a, const LLMatrix3 &b); // Return a == b
136 friend bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b); // Return a != b
137
138 friend const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b); // Return a * b
139
140 friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a
141}
142#if LL_DARWIN
143__attribute__ ((aligned (16)))
144#endif
145;
146
147inline LLMatrix3::LLMatrix3(void)
148{
149 mMatrix[0][0] = 1.f;
150 mMatrix[0][1] = 0.f;
151 mMatrix[0][2] = 0.f;
152
153 mMatrix[1][0] = 0.f;
154 mMatrix[1][1] = 1.f;
155 mMatrix[1][2] = 0.f;
156
157 mMatrix[2][0] = 0.f;
158 mMatrix[2][1] = 0.f;
159 mMatrix[2][2] = 1.f;
160}
161
162inline LLMatrix3::LLMatrix3(const F32 *mat)
163{
164 mMatrix[0][0] = mat[0];
165 mMatrix[0][1] = mat[1];
166 mMatrix[0][2] = mat[2];
167
168 mMatrix[1][0] = mat[3];
169 mMatrix[1][1] = mat[4];
170 mMatrix[1][2] = mat[5];
171
172 mMatrix[2][0] = mat[6];
173 mMatrix[2][1] = mat[7];
174 mMatrix[2][2] = mat[8];
175}
176
177
178#endif
179
180
181// Rotation matrix hints...
182
183// Inverse of Rotation Matrices
184// ----------------------------
185// If R is a rotation matrix that rotate vectors from Frame-A to Frame-B,
186// then the transpose of R will rotate vectors from Frame-B to Frame-A.
187
188
189// Creating Rotation Matricies From Object Axes
190// --------------------------------------------
191// Suppose you know the three axes of some object in some "absolute-frame".
192// If you take those three vectors and throw them into the rows of
193// a rotation matrix what do you get?
194//
195// R = | X0 X1 X2 |
196// | Y0 Y1 Y2 |
197// | Z0 Z1 Z2 |
198//
199// Yeah, but what does it mean?
200//
201// Transpose the matrix and have it operate on a vector...
202//
203// V * R_transpose = [ V0 V1 V2 ] * | X0 Y0 Z0 |
204// | X1 Y1 Z1 |
205// | X2 Y2 Z2 |
206//
207// = [ V*X V*Y V*Z ]
208//
209// = components of V that are parallel to the three object axes
210//
211// = transformation of V into object frame
212//
213// Since the transformation of a rotation matrix is its inverse, then
214// R must rotate vectors from the object-frame into the absolute-frame.
215
216
217
diff --git a/linden/indra/llmath/m4math.cpp b/linden/indra/llmath/m4math.cpp
new file mode 100644
index 0000000..ee7e6f3
--- /dev/null
+++ b/linden/indra/llmath/m4math.cpp
@@ -0,0 +1,813 @@
1/**
2 * @file m4math.cpp
3 * @brief LLMatrix4 class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30//#include "vmath.h"
31#include "v3math.h"
32#include "v4math.h"
33#include "m4math.h"
34#include "m3math.h"
35#include "llquaternion.h"
36
37
38
39
40// LLMatrix4
41
42// Constructors
43
44
45LLMatrix4::LLMatrix4(const F32 *mat)
46{
47 mMatrix[0][0] = mat[0];
48 mMatrix[0][1] = mat[1];
49 mMatrix[0][2] = mat[2];
50 mMatrix[0][3] = mat[3];
51
52 mMatrix[1][0] = mat[4];
53 mMatrix[1][1] = mat[5];
54 mMatrix[1][2] = mat[6];
55 mMatrix[1][3] = mat[7];
56
57 mMatrix[2][0] = mat[8];
58 mMatrix[2][1] = mat[9];
59 mMatrix[2][2] = mat[10];
60 mMatrix[2][3] = mat[11];
61
62 mMatrix[3][0] = mat[12];
63 mMatrix[3][1] = mat[13];
64 mMatrix[3][2] = mat[14];
65 mMatrix[3][3] = mat[15];
66}
67
68LLMatrix4::LLMatrix4(const LLMatrix3 &mat, const LLVector4 &vec)
69{
70 mMatrix[0][0] = mat.mMatrix[0][0];
71 mMatrix[0][1] = mat.mMatrix[0][1];
72 mMatrix[0][2] = mat.mMatrix[0][2];
73 mMatrix[0][3] = 0.f;
74
75 mMatrix[1][0] = mat.mMatrix[1][0];
76 mMatrix[1][1] = mat.mMatrix[1][1];
77 mMatrix[1][2] = mat.mMatrix[1][2];
78 mMatrix[1][3] = 0.f;
79
80 mMatrix[2][0] = mat.mMatrix[2][0];
81 mMatrix[2][1] = mat.mMatrix[2][1];
82 mMatrix[2][2] = mat.mMatrix[2][2];
83 mMatrix[2][3] = 0.f;
84
85 mMatrix[3][0] = vec.mV[0];
86 mMatrix[3][1] = vec.mV[1];
87 mMatrix[3][2] = vec.mV[2];
88 mMatrix[3][3] = 1.f;
89}
90
91LLMatrix4::LLMatrix4(const LLMatrix3 &mat)
92{
93 mMatrix[0][0] = mat.mMatrix[0][0];
94 mMatrix[0][1] = mat.mMatrix[0][1];
95 mMatrix[0][2] = mat.mMatrix[0][2];
96 mMatrix[0][3] = 0.f;
97
98 mMatrix[1][0] = mat.mMatrix[1][0];
99 mMatrix[1][1] = mat.mMatrix[1][1];
100 mMatrix[1][2] = mat.mMatrix[1][2];
101 mMatrix[1][3] = 0.f;
102
103 mMatrix[2][0] = mat.mMatrix[2][0];
104 mMatrix[2][1] = mat.mMatrix[2][1];
105 mMatrix[2][2] = mat.mMatrix[2][2];
106 mMatrix[2][3] = 0.f;
107
108 mMatrix[3][0] = 0.f;
109 mMatrix[3][1] = 0.f;
110 mMatrix[3][2] = 0.f;
111 mMatrix[3][3] = 1.f;
112}
113
114LLMatrix4::LLMatrix4(const LLQuaternion &q)
115{
116 *this = initRotation(q);
117}
118
119LLMatrix4::LLMatrix4(const LLQuaternion &q, const LLVector4 &pos)
120{
121 *this = initRotTrans(q, pos);
122}
123
124LLMatrix4::LLMatrix4(const F32 angle, const LLVector4 &vec, const LLVector4 &pos)
125{
126 initRotTrans(LLQuaternion(angle, vec), pos);
127}
128
129LLMatrix4::LLMatrix4(const F32 angle, const LLVector4 &vec)
130{
131 initRotation(LLQuaternion(angle, vec));
132
133 mMatrix[3][0] = 0.f;
134 mMatrix[3][1] = 0.f;
135 mMatrix[3][2] = 0.f;
136 mMatrix[3][3] = 1.f;
137}
138
139LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos)
140{
141 LLMatrix3 mat(roll, pitch, yaw);
142 initRotTrans(LLQuaternion(mat), pos);
143}
144
145LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw)
146{
147 LLMatrix3 mat(roll, pitch, yaw);
148 initRotation(LLQuaternion(mat));
149
150 mMatrix[3][0] = 0.f;
151 mMatrix[3][1] = 0.f;
152 mMatrix[3][2] = 0.f;
153 mMatrix[3][3] = 1.f;
154}
155
156LLMatrix4::~LLMatrix4(void)
157{
158}
159
160// Clear and Assignment Functions
161
162const LLMatrix4& LLMatrix4::zero()
163{
164 mMatrix[0][0] = 0.f;
165 mMatrix[0][1] = 0.f;
166 mMatrix[0][2] = 0.f;
167 mMatrix[0][3] = 0.f;
168
169 mMatrix[1][0] = 0.f;
170 mMatrix[1][1] = 0.f;
171 mMatrix[1][2] = 0.f;
172 mMatrix[1][3] = 0.f;
173
174 mMatrix[2][0] = 0.f;
175 mMatrix[2][1] = 0.f;
176 mMatrix[2][2] = 0.f;
177 mMatrix[2][3] = 0.f;
178
179 mMatrix[3][0] = 0.f;
180 mMatrix[3][1] = 0.f;
181 mMatrix[3][2] = 0.f;
182 mMatrix[3][3] = 0.f;
183 return *this;
184}
185
186
187// various useful mMatrix functions
188
189const LLMatrix4& LLMatrix4::transpose()
190{
191 LLMatrix4 mat;
192 mat.mMatrix[0][0] = mMatrix[0][0];
193 mat.mMatrix[1][0] = mMatrix[0][1];
194 mat.mMatrix[2][0] = mMatrix[0][2];
195 mat.mMatrix[3][0] = mMatrix[0][3];
196
197 mat.mMatrix[0][1] = mMatrix[1][0];
198 mat.mMatrix[1][1] = mMatrix[1][1];
199 mat.mMatrix[2][1] = mMatrix[1][2];
200 mat.mMatrix[3][1] = mMatrix[1][3];
201
202 mat.mMatrix[0][2] = mMatrix[2][0];
203 mat.mMatrix[1][2] = mMatrix[2][1];
204 mat.mMatrix[2][2] = mMatrix[2][2];
205 mat.mMatrix[3][2] = mMatrix[2][3];
206
207 mat.mMatrix[0][3] = mMatrix[3][0];
208 mat.mMatrix[1][3] = mMatrix[3][1];
209 mat.mMatrix[2][3] = mMatrix[3][2];
210 mat.mMatrix[3][3] = mMatrix[3][3];
211
212 *this = mat;
213 return *this;
214}
215
216
217F32 LLMatrix4::determinant() const
218{
219 llerrs << "Not implemented!" << llendl;
220 return 0.f;
221}
222
223// Only works for pure orthonormal, homogeneous transform matrices.
224const LLMatrix4& LLMatrix4::invert(void)
225{
226 // transpose the rotation part
227 F32 temp;
228 temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
229 temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
230 temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
231
232 // rotate the translation part by the new rotation
233 // (temporarily store in empty column of matrix)
234 U32 j;
235 for (j=0; j<3; j++)
236 {
237 mMatrix[j][VW] = mMatrix[VW][VX] * mMatrix[VX][j] +
238 mMatrix[VW][VY] * mMatrix[VY][j] +
239 mMatrix[VW][VZ] * mMatrix[VZ][j];
240 }
241
242 // negate and copy the temporary vector back to the tranlation row
243 mMatrix[VW][VX] = -mMatrix[VX][VW];
244 mMatrix[VW][VY] = -mMatrix[VY][VW];
245 mMatrix[VW][VZ] = -mMatrix[VZ][VW];
246
247 // zero the empty column again
248 mMatrix[VX][VW] = mMatrix[VY][VW] = mMatrix[VZ][VW] = 0.0f;
249
250 return *this;
251}
252
253LLVector4 LLMatrix4::getFwdRow4() const
254{
255 return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]);
256}
257
258LLVector4 LLMatrix4::getLeftRow4() const
259{
260 return LLVector4(mMatrix[VY][VX], mMatrix[VY][VY], mMatrix[VY][VZ], mMatrix[VY][VW]);
261}
262
263LLVector4 LLMatrix4::getUpRow4() const
264{
265 return LLVector4(mMatrix[VZ][VX], mMatrix[VZ][VY], mMatrix[VZ][VZ], mMatrix[VZ][VW]);
266}
267
268// SJB: This code is correct for a logicly stored (non-transposed) matrix;
269// Our matrices are stored transposed, OpenGL style, so this generates the
270// INVERSE quaternion (-x, -y, -z, w)!
271// Because we use similar logic in LLQuaternion::getMatrix3,
272// we are internally consistant so everything works OK :)
273LLQuaternion LLMatrix4::quaternion() const
274{
275 LLQuaternion quat;
276 F32 tr, s, q[4];
277 U32 i, j, k;
278 U32 nxt[3] = {1, 2, 0};
279
280 tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2];
281
282 // check the diagonal
283 if (tr > 0.f)
284 {
285 s = (F32)sqrt (tr + 1.f);
286 quat.mQ[VS] = s / 2.f;
287 s = 0.5f / s;
288 quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s;
289 quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s;
290 quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s;
291 }
292 else
293 {
294 // diagonal is negative
295 i = 0;
296 if (mMatrix[1][1] > mMatrix[0][0])
297 i = 1;
298 if (mMatrix[2][2] > mMatrix[i][i])
299 i = 2;
300
301 j = nxt[i];
302 k = nxt[j];
303
304
305 s = (F32)sqrt ((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f);
306
307 q[i] = s * 0.5f;
308
309 if (s != 0.f)
310 s = 0.5f / s;
311
312 q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s;
313 q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s;
314 q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s;
315
316 quat.setQuat(q);
317 }
318 return quat;
319}
320
321
322
323void LLMatrix4::initRows(const LLVector4 &row0,
324 const LLVector4 &row1,
325 const LLVector4 &row2,
326 const LLVector4 &row3)
327{
328 mMatrix[0][0] = row0.mV[0];
329 mMatrix[0][1] = row0.mV[1];
330 mMatrix[0][2] = row0.mV[2];
331 mMatrix[0][3] = row0.mV[3];
332
333 mMatrix[1][0] = row1.mV[0];
334 mMatrix[1][1] = row1.mV[1];
335 mMatrix[1][2] = row1.mV[2];
336 mMatrix[1][3] = row1.mV[3];
337
338 mMatrix[2][0] = row2.mV[0];
339 mMatrix[2][1] = row2.mV[1];
340 mMatrix[2][2] = row2.mV[2];
341 mMatrix[2][3] = row2.mV[3];
342
343 mMatrix[3][0] = row3.mV[0];
344 mMatrix[3][1] = row3.mV[1];
345 mMatrix[3][2] = row3.mV[2];
346 mMatrix[3][3] = row3.mV[3];
347}
348
349
350const LLMatrix4& LLMatrix4::initRotation(const F32 angle, const F32 x, const F32 y, const F32 z)
351{
352 LLMatrix3 mat(angle, x, y, z);
353 return initMatrix(mat);
354}
355
356
357const LLMatrix4& LLMatrix4::initRotation(F32 angle, const LLVector4 &vec)
358{
359 LLMatrix3 mat(angle, vec);
360 return initMatrix(mat);
361}
362
363
364const LLMatrix4& LLMatrix4::initRotation(const F32 roll, const F32 pitch, const F32 yaw)
365{
366 LLMatrix3 mat(roll, pitch, yaw);
367 return initMatrix(mat);
368}
369
370
371const LLMatrix4& LLMatrix4::initRotation(const LLQuaternion &q)
372{
373 LLMatrix3 mat(q);
374 return initMatrix(mat);
375}
376
377
378// Position and Rotation
379const LLMatrix4& LLMatrix4::initRotTrans(const F32 angle, const F32 rx, const F32 ry, const F32 rz,
380 const F32 tx, const F32 ty, const F32 tz)
381{
382 LLMatrix3 mat(angle, rx, ry, rz);
383 LLVector3 translation(tx, ty, tz);
384 initMatrix(mat);
385 setTranslation(translation);
386 return (*this);
387}
388
389const LLMatrix4& LLMatrix4::initRotTrans(const F32 angle, const LLVector3 &axis, const LLVector3&translation)
390{
391 LLMatrix3 mat(angle, axis);
392 initMatrix(mat);
393 setTranslation(translation);
394 return (*this);
395}
396
397const LLMatrix4& LLMatrix4::initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &translation)
398{
399 LLMatrix3 mat(roll, pitch, yaw);
400 initMatrix(mat);
401 setTranslation(translation);
402 return (*this);
403}
404
405/*
406const LLMatrix4& LLMatrix4::initRotTrans(const LLVector4 &fwd,
407 const LLVector4 &left,
408 const LLVector4 &up,
409 const LLVector4 &translation)
410{
411 LLMatrix3 mat(fwd, left, up);
412 initMatrix(mat);
413 setTranslation(translation);
414 return (*this);
415}
416*/
417
418const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector4 &translation)
419{
420 LLMatrix3 mat(q);
421 initMatrix(mat);
422 setTranslation(translation);
423 return (*this);
424}
425
426const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos)
427{
428 F32 sx, sy, sz;
429 F32 xx, xy, xz, xw, yy, yz, yw, zz, zw;
430
431 sx = scale.mV[0];
432 sy = scale.mV[1];
433 sz = scale.mV[2];
434
435 xx = q.mQ[VX] * q.mQ[VX];
436 xy = q.mQ[VX] * q.mQ[VY];
437 xz = q.mQ[VX] * q.mQ[VZ];
438 xw = q.mQ[VX] * q.mQ[VW];
439
440 yy = q.mQ[VY] * q.mQ[VY];
441 yz = q.mQ[VY] * q.mQ[VZ];
442 yw = q.mQ[VY] * q.mQ[VW];
443
444 zz = q.mQ[VZ] * q.mQ[VZ];
445 zw = q.mQ[VZ] * q.mQ[VW];
446
447 mMatrix[0][0] = (1.f - 2.f * ( yy + zz )) *sx;
448 mMatrix[0][1] = ( 2.f * ( xy + zw )) *sx;
449 mMatrix[0][2] = ( 2.f * ( xz - yw )) *sx;
450
451 mMatrix[1][0] = ( 2.f * ( xy - zw )) *sy;
452 mMatrix[1][1] = (1.f - 2.f * ( xx + zz )) *sy;
453 mMatrix[1][2] = ( 2.f * ( yz + xw )) *sy;
454
455 mMatrix[2][0] = ( 2.f * ( xz + yw )) *sz;
456 mMatrix[2][1] = ( 2.f * ( yz - xw )) *sz;
457 mMatrix[2][2] = (1.f - 2.f * ( xx + yy )) *sz;
458
459 mMatrix[3][0] = pos.mV[0];
460 mMatrix[3][1] = pos.mV[1];
461 mMatrix[3][2] = pos.mV[2];
462 mMatrix[3][3] = 1.0;
463
464 // TODO -- should we set the translation portion to zero?
465 return (*this);
466}
467
468// Rotate exisitng mMatrix
469const LLMatrix4& LLMatrix4::rotate(const F32 angle, const F32 x, const F32 y, const F32 z)
470{
471 LLVector4 vec4(x, y, z);
472 LLMatrix4 mat(angle, vec4);
473 *this *= mat;
474 return *this;
475}
476
477const LLMatrix4& LLMatrix4::rotate(const F32 angle, const LLVector4 &vec)
478{
479 LLMatrix4 mat(angle, vec);
480 *this *= mat;
481 return *this;
482}
483
484const LLMatrix4& LLMatrix4::rotate(const F32 roll, const F32 pitch, const F32 yaw)
485{
486 LLMatrix4 mat(roll, pitch, yaw);
487 *this *= mat;
488 return *this;
489}
490
491const LLMatrix4& LLMatrix4::rotate(const LLQuaternion &q)
492{
493 LLMatrix4 mat(q);
494 *this *= mat;
495 return *this;
496}
497
498
499const LLMatrix4& LLMatrix4::translate(const LLVector3 &vec)
500{
501 mMatrix[3][0] += vec.mV[0];
502 mMatrix[3][1] += vec.mV[1];
503 mMatrix[3][2] += vec.mV[2];
504 return (*this);
505}
506
507
508void LLMatrix4::setFwdRow(const LLVector3 &row)
509{
510 mMatrix[VX][VX] = row.mV[VX];
511 mMatrix[VX][VY] = row.mV[VY];
512 mMatrix[VX][VZ] = row.mV[VZ];
513}
514
515void LLMatrix4::setLeftRow(const LLVector3 &row)
516{
517 mMatrix[VY][VX] = row.mV[VX];
518 mMatrix[VY][VY] = row.mV[VY];
519 mMatrix[VY][VZ] = row.mV[VZ];
520}
521
522void LLMatrix4::setUpRow(const LLVector3 &row)
523{
524 mMatrix[VZ][VX] = row.mV[VX];
525 mMatrix[VZ][VY] = row.mV[VY];
526 mMatrix[VZ][VZ] = row.mV[VZ];
527}
528
529
530void LLMatrix4::setFwdCol(const LLVector3 &col)
531{
532 mMatrix[VX][VX] = col.mV[VX];
533 mMatrix[VY][VX] = col.mV[VY];
534 mMatrix[VZ][VX] = col.mV[VZ];
535}
536
537void LLMatrix4::setLeftCol(const LLVector3 &col)
538{
539 mMatrix[VX][VY] = col.mV[VX];
540 mMatrix[VY][VY] = col.mV[VY];
541 mMatrix[VZ][VY] = col.mV[VZ];
542}
543
544void LLMatrix4::setUpCol(const LLVector3 &col)
545{
546 mMatrix[VX][VZ] = col.mV[VX];
547 mMatrix[VY][VZ] = col.mV[VY];
548 mMatrix[VZ][VZ] = col.mV[VZ];
549}
550
551
552const LLMatrix4& LLMatrix4::setTranslation(const F32 tx, const F32 ty, const F32 tz)
553{
554 mMatrix[VW][VX] = tx;
555 mMatrix[VW][VY] = ty;
556 mMatrix[VW][VZ] = tz;
557 return (*this);
558}
559
560const LLMatrix4& LLMatrix4::setTranslation(const LLVector3 &translation)
561{
562 mMatrix[VW][VX] = translation.mV[VX];
563 mMatrix[VW][VY] = translation.mV[VY];
564 mMatrix[VW][VZ] = translation.mV[VZ];
565 return (*this);
566}
567
568const LLMatrix4& LLMatrix4::setTranslation(const LLVector4 &translation)
569{
570 mMatrix[VW][VX] = translation.mV[VX];
571 mMatrix[VW][VY] = translation.mV[VY];
572 mMatrix[VW][VZ] = translation.mV[VZ];
573 return (*this);
574}
575
576// LLMatrix3 Extraction and Setting
577LLMatrix3 LLMatrix4::getMat3() const
578{
579 LLMatrix3 retmat;
580
581 retmat.mMatrix[0][0] = mMatrix[0][0];
582 retmat.mMatrix[0][1] = mMatrix[0][1];
583 retmat.mMatrix[0][2] = mMatrix[0][2];
584
585 retmat.mMatrix[1][0] = mMatrix[1][0];
586 retmat.mMatrix[1][1] = mMatrix[1][1];
587 retmat.mMatrix[1][2] = mMatrix[1][2];
588
589 retmat.mMatrix[2][0] = mMatrix[2][0];
590 retmat.mMatrix[2][1] = mMatrix[2][1];
591 retmat.mMatrix[2][2] = mMatrix[2][2];
592
593 return retmat;
594}
595
596const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat)
597{
598 mMatrix[0][0] = mat.mMatrix[0][0];
599 mMatrix[0][1] = mat.mMatrix[0][1];
600 mMatrix[0][2] = mat.mMatrix[0][2];
601 mMatrix[0][3] = 0.f;
602
603 mMatrix[1][0] = mat.mMatrix[1][0];
604 mMatrix[1][1] = mat.mMatrix[1][1];
605 mMatrix[1][2] = mat.mMatrix[1][2];
606 mMatrix[1][3] = 0.f;
607
608 mMatrix[2][0] = mat.mMatrix[2][0];
609 mMatrix[2][1] = mat.mMatrix[2][1];
610 mMatrix[2][2] = mat.mMatrix[2][2];
611 mMatrix[2][3] = 0.f;
612
613 mMatrix[3][0] = 0.f;
614 mMatrix[3][1] = 0.f;
615 mMatrix[3][2] = 0.f;
616 mMatrix[3][3] = 1.f;
617 return (*this);
618}
619
620const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 &translation)
621{
622 mMatrix[0][0] = mat.mMatrix[0][0];
623 mMatrix[0][1] = mat.mMatrix[0][1];
624 mMatrix[0][2] = mat.mMatrix[0][2];
625 mMatrix[0][3] = 0.f;
626
627 mMatrix[1][0] = mat.mMatrix[1][0];
628 mMatrix[1][1] = mat.mMatrix[1][1];
629 mMatrix[1][2] = mat.mMatrix[1][2];
630 mMatrix[1][3] = 0.f;
631
632 mMatrix[2][0] = mat.mMatrix[2][0];
633 mMatrix[2][1] = mat.mMatrix[2][1];
634 mMatrix[2][2] = mat.mMatrix[2][2];
635 mMatrix[2][3] = 0.f;
636
637 mMatrix[3][0] = translation.mV[0];
638 mMatrix[3][1] = translation.mV[1];
639 mMatrix[3][2] = translation.mV[2];
640 mMatrix[3][3] = 1.f;
641 return (*this);
642}
643
644// LLMatrix4 Operators
645
646
647/* Not implemented to help enforce code consistency with the syntax of
648 row-major notation. This is a Good Thing.
649LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b)
650{
651 // Operate "to the right" on column-vector b
652 LLVector4 vec;
653 vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] +
654 a.mMatrix[VY][VX] * b.mV[VY] +
655 a.mMatrix[VZ][VX] * b.mV[VZ] +
656 a.mMatrix[VW][VX] * b.mV[VW];
657
658 vec.mV[VY] = a.mMatrix[VX][VY] * b.mV[VX] +
659 a.mMatrix[VY][VY] * b.mV[VY] +
660 a.mMatrix[VZ][VY] * b.mV[VZ] +
661 a.mMatrix[VW][VY] * b.mV[VW];
662
663 vec.mV[VZ] = a.mMatrix[VX][VZ] * b.mV[VX] +
664 a.mMatrix[VY][VZ] * b.mV[VY] +
665 a.mMatrix[VZ][VZ] * b.mV[VZ] +
666 a.mMatrix[VW][VZ] * b.mV[VW];
667
668 vec.mV[VW] = a.mMatrix[VX][VW] * b.mV[VX] +
669 a.mMatrix[VY][VW] * b.mV[VY] +
670 a.mMatrix[VZ][VW] * b.mV[VZ] +
671 a.mMatrix[VW][VW] * b.mV[VW];
672 return vec;
673}
674*/
675
676
677LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b)
678{
679 // Operate "to the left" on row-vector a
680 LLVector4 vec;
681 vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] +
682 a.mV[VY] * b.mMatrix[VY][VX] +
683 a.mV[VZ] * b.mMatrix[VZ][VX] +
684 a.mV[VW] * b.mMatrix[VW][VX];
685
686 vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] +
687 a.mV[VY] * b.mMatrix[VY][VY] +
688 a.mV[VZ] * b.mMatrix[VZ][VY] +
689 a.mV[VW] * b.mMatrix[VW][VY];
690
691 vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] +
692 a.mV[VY] * b.mMatrix[VY][VZ] +
693 a.mV[VZ] * b.mMatrix[VZ][VZ] +
694 a.mV[VW] * b.mMatrix[VW][VZ];
695
696 vec.mV[VW] = a.mV[VX] * b.mMatrix[VX][VW] +
697 a.mV[VY] * b.mMatrix[VY][VW] +
698 a.mV[VZ] * b.mMatrix[VZ][VW] +
699 a.mV[VW] * b.mMatrix[VW][VW];
700 return vec;
701}
702
703LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b)
704{
705 // Rotates but does not translate
706 // Operate "to the left" on row-vector a
707 LLVector4 vec;
708 vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] +
709 a.mV[VY] * b.mMatrix[VY][VX] +
710 a.mV[VZ] * b.mMatrix[VZ][VX];
711
712 vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] +
713 a.mV[VY] * b.mMatrix[VY][VY] +
714 a.mV[VZ] * b.mMatrix[VZ][VY];
715
716 vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] +
717 a.mV[VY] * b.mMatrix[VY][VZ] +
718 a.mV[VZ] * b.mMatrix[VZ][VZ];
719
720// vec.mV[VW] = a.mV[VX] * b.mMatrix[VX][VW] +
721// a.mV[VY] * b.mMatrix[VY][VW] +
722// a.mV[VZ] * b.mMatrix[VZ][VW] +
723 vec.mV[VW] = a.mV[VW];
724 return vec;
725}
726
727LLVector3 rotate_vector(const LLVector3 &a, const LLMatrix4 &b)
728{
729 // Rotates but does not translate
730 // Operate "to the left" on row-vector a
731 LLVector3 vec;
732 vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] +
733 a.mV[VY] * b.mMatrix[VY][VX] +
734 a.mV[VZ] * b.mMatrix[VZ][VX];
735
736 vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] +
737 a.mV[VY] * b.mMatrix[VY][VY] +
738 a.mV[VZ] * b.mMatrix[VZ][VY];
739
740 vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] +
741 a.mV[VY] * b.mMatrix[VY][VZ] +
742 a.mV[VZ] * b.mMatrix[VZ][VZ];
743 return vec;
744}
745
746bool operator==(const LLMatrix4 &a, const LLMatrix4 &b)
747{
748 U32 i, j;
749 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
750 {
751 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
752 {
753 if (a.mMatrix[j][i] != b.mMatrix[j][i])
754 return FALSE;
755 }
756 }
757 return TRUE;
758}
759
760bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b)
761{
762 U32 i, j;
763 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
764 {
765 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
766 {
767 if (a.mMatrix[j][i] != b.mMatrix[j][i])
768 return TRUE;
769 }
770 }
771 return FALSE;
772}
773
774const LLMatrix4& operator*=(LLMatrix4 &a, F32 k)
775{
776 U32 i, j;
777 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
778 {
779 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
780 {
781 a.mMatrix[j][i] *= k;
782 }
783 }
784 return a;
785}
786
787std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a)
788{
789 s << "{ "
790 << a.mMatrix[VX][VX] << ", "
791 << a.mMatrix[VX][VY] << ", "
792 << a.mMatrix[VX][VZ] << ", "
793 << a.mMatrix[VX][VW]
794 << "; "
795 << a.mMatrix[VY][VX] << ", "
796 << a.mMatrix[VY][VY] << ", "
797 << a.mMatrix[VY][VZ] << ", "
798 << a.mMatrix[VY][VW]
799 << "; "
800 << a.mMatrix[VZ][VX] << ", "
801 << a.mMatrix[VZ][VY] << ", "
802 << a.mMatrix[VZ][VZ] << ", "
803 << a.mMatrix[VZ][VW]
804 << "; "
805 << a.mMatrix[VW][VX] << ", "
806 << a.mMatrix[VW][VY] << ", "
807 << a.mMatrix[VW][VZ] << ", "
808 << a.mMatrix[VW][VW]
809 << " }";
810 return s;
811}
812
813
diff --git a/linden/indra/llmath/m4math.h b/linden/indra/llmath/m4math.h
new file mode 100644
index 0000000..fe9b26a
--- /dev/null
+++ b/linden/indra/llmath/m4math.h
@@ -0,0 +1,384 @@
1/**
2 * @file m4math.h
3 * @brief LLMatrix3 class header file.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_M4MATH_H
29#define LL_M4MATH_H
30
31#include "v3math.h"
32
33class LLVector4;
34class LLMatrix3;
35class LLQuaternion;
36
37// NOTA BENE: Currently assuming a right-handed, x-forward, y-left, z-up universe
38
39// Us versus OpenGL:
40
41// Even though OpenGL uses column vectors and we use row vectors, we can plug our matrices
42// directly into OpenGL. This is because OpenGL numbers its matrices going columnwise:
43//
44// OpenGL indexing: Our indexing:
45// 0 4 8 12 [0][0] [0][1] [0][2] [0][3]
46// 1 5 9 13 [1][0] [1][1] [1][2] [1][3]
47// 2 6 10 14 [2][0] [2][1] [2][2] [2][3]
48// 3 7 11 15 [3][0] [3][1] [3][2] [3][3]
49//
50// So when you're looking at OpenGL related matrices online, our matrices will be
51// "transposed". But our matrices can be plugged directly into OpenGL and work fine!
52//
53
54// We're using row vectors - [vx, vy, vz, vw]
55//
56// There are several different ways of thinking of matrices, if you mix them up, you'll get very confused.
57//
58// One way to think about it is a matrix that takes the origin frame A
59// and rotates it into B': i.e. A*M = B
60//
61// Vectors:
62// f - forward axis of B expressed in A
63// l - left axis of B expressed in A
64// u - up axis of B expressed in A
65//
66// | 0: fx 1: fy 2: fz 3:0 |
67// M = | 4: lx 5: ly 6: lz 7:0 |
68// | 8: ux 9: uy 10: uz 11:0 |
69// | 12: 0 13: 0 14: 0 15:1 |
70//
71//
72//
73//
74// Another way to think of matrices is matrix that takes a point p in frame A, and puts it into frame B:
75// This is used most commonly for the modelview matrix.
76//
77// so p*M = p'
78//
79// Vectors:
80// f - forward of frame B in frame A
81// l - left of frame B in frame A
82// u - up of frame B in frame A
83// o - origin of frame frame B in frame A
84//
85// | 0: fx 1: lx 2: ux 3:0 |
86// M = | 4: fy 5: ly 6: uy 7:0 |
87// | 8: fz 9: lz 10: uz 11:0 |
88// | 12:-of 13:-ol 14:-ou 15:1 |
89//
90// of, ol, and ou mean the component of the "global" origin o in the f axis, l axis, and u axis.
91//
92
93static const U32 NUM_VALUES_IN_MAT4 = 4;
94
95#if LL_WINDOWS
96__declspec(align(16))
97#endif
98class LLMatrix4
99{
100public:
101 F32 mMatrix[NUM_VALUES_IN_MAT4][NUM_VALUES_IN_MAT4];
102
103 LLMatrix4(); // Initializes Matrix to identity matrix
104 explicit LLMatrix4(const F32 *mat); // Initializes Matrix to values in mat
105 explicit LLMatrix4(const LLMatrix3 &mat); // Initializes Matrix to valuee in mat and sets position to (0,0,0)
106 explicit LLMatrix4(const LLQuaternion &q); // Initializes Matrix with rotation q and sets position to (0,0,0)
107
108 LLMatrix4(const LLMatrix3 &mat, const LLVector4 &pos); // Initializes Matrix to values in mat and pos
109
110 // These are really, really, inefficient as implemented! - djs
111 LLMatrix4(const LLQuaternion &q, const LLVector4 &pos); // Initializes Matrix with rotation q and position pos
112 LLMatrix4(F32 angle,
113 const LLVector4 &vec,
114 const LLVector4 &pos); // Initializes Matrix with axis-angle and position
115 LLMatrix4(F32 angle, const LLVector4 &vec); // Initializes Matrix with axis-angle and sets position to (0,0,0)
116 LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw,
117 const LLVector4 &pos); // Initializes Matrix with Euler angles
118 LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw); // Initializes Matrix with Euler angles
119
120 ~LLMatrix4(void); // Destructor
121
122
123 //////////////////////////////
124 //
125 // Matrix initializers - these replace any existing values in the matrix
126 //
127
128 void initRows(const LLVector4 &row0,
129 const LLVector4 &row1,
130 const LLVector4 &row2,
131 const LLVector4 &row3);
132
133 // various useful matrix functions
134 const LLMatrix4& identity(); // Load identity matrix
135 const LLMatrix4& zero(); // Clears matrix to all zeros.
136
137 const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z)
138 const LLMatrix4& initRotation(const F32 angle, const LLVector4 &axis); // Calculate rotation matrix for rotating angle radians about vec
139 const LLMatrix4& initRotation(const F32 roll, const F32 pitch, const F32 yaw); // Calculate rotation matrix from Euler angles
140 const LLMatrix4& initRotation(const LLQuaternion &q); // Set with Quaternion and position
141
142 // Position Only
143 const LLMatrix4& initMatrix(const LLMatrix3 &mat); //
144 const LLMatrix4& initMatrix(const LLMatrix3 &mat, const LLVector4 &translation);
145
146 // These operation create a matrix that will rotate and translate by the
147 // specified amounts.
148 const LLMatrix4& initRotTrans(const F32 angle,
149 const F32 rx, const F32 ry, const F32 rz,
150 const F32 px, const F32 py, const F32 pz);
151
152 const LLMatrix4& initRotTrans(const F32 angle, const LLVector3 &axis, const LLVector3 &translation); // Rotation from axis angle + translation
153 const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation
154 const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position
155
156
157 // Set all
158 const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos);
159
160
161 ///////////////////////////
162 //
163 // Matrix setters - set some properties without modifying others
164 //
165
166 const LLMatrix4& setTranslation(const F32 x, const F32 y, const F32 z); // Sets matrix to translate by (x,y,z)
167
168 void setFwdRow(const LLVector3 &row);
169 void setLeftRow(const LLVector3 &row);
170 void setUpRow(const LLVector3 &row);
171
172 void setFwdCol(const LLVector3 &col);
173 void setLeftCol(const LLVector3 &col);
174 void setUpCol(const LLVector3 &col);
175
176 const LLMatrix4& setTranslation(const LLVector4 &translation);
177 const LLMatrix4& setTranslation(const LLVector3 &translation);
178
179 ///////////////////////////
180 //
181 // Get properties of a matrix
182 //
183
184 F32 determinant(void) const; // Return determinant
185 LLQuaternion quaternion(void) const; // Returns quaternion
186
187 LLVector4 getFwdRow4() const;
188 LLVector4 getLeftRow4() const;
189 LLVector4 getUpRow4() const;
190
191 LLMatrix3 getMat3() const;
192
193 const LLVector3& getTranslation() const { return *(LLVector3*)&mMatrix[3][0]; }
194
195 ///////////////////////////
196 //
197 // Operations on an existing matrix
198 //
199
200 const LLMatrix4& transpose(); // Transpose LLMatrix4
201 const LLMatrix4& invert(); // Invert LLMatrix4
202
203 // Rotate existing matrix
204 // These are really, really, inefficient as implemented! - djs
205 const LLMatrix4& rotate(const F32 angle, const F32 x, const F32 y, const F32 z); // Rotate matrix by rotating angle radians about (x, y, z)
206 const LLMatrix4& rotate(const F32 angle, const LLVector4 &vec); // Rotate matrix by rotating angle radians about vec
207 const LLMatrix4& rotate(const F32 roll, const F32 pitch, const F32 yaw); // Rotate matrix by Euler angles
208 const LLMatrix4& rotate(const LLQuaternion &q); // Rotate matrix by Quaternion
209
210
211 // Translate existing matrix
212 const LLMatrix4& translate(const LLVector3 &vec); // Translate matrix by (vec[VX], vec[VY], vec[VZ])
213
214
215
216
217 ///////////////////////
218 //
219 // Operators
220 //
221
222// Not implemented to enforce code that agrees with symbolic syntax
223// friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b); // Apply rotation a to vector b
224
225// friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b
226 friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b); // Return transform of vector a by matrix b
227 friend LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b
228 friend LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b); // Rotates a but does not translate
229 friend LLVector3 rotate_vector(const LLVector3 &a, const LLMatrix4 &b); // Rotates a but does not translate
230
231 friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b); // Return a == b
232 friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b); // Return a != b
233
234 friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b); // Return a + b
235 friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b); // Return a - b
236 friend const LLMatrix4& operator*=(LLMatrix4 &a, const LLMatrix4 &b); // Return a * b
237 friend const LLMatrix4& operator*=(LLMatrix4 &a, const F32 &b); // Return a * b
238
239 friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a
240}
241#if LL_DARWIN
242__attribute__ ((aligned (16)))
243#endif
244;
245
246
247inline LLMatrix4::LLMatrix4()
248{
249 identity();
250}
251
252inline const LLMatrix4& LLMatrix4::identity()
253{
254 mMatrix[0][0] = 1.f;
255 mMatrix[0][1] = 0.f;
256 mMatrix[0][2] = 0.f;
257 mMatrix[0][3] = 0.f;
258
259 mMatrix[1][0] = 0.f;
260 mMatrix[1][1] = 1.f;
261 mMatrix[1][2] = 0.f;
262 mMatrix[1][3] = 0.f;
263
264 mMatrix[2][0] = 0.f;
265 mMatrix[2][1] = 0.f;
266 mMatrix[2][2] = 1.f;
267 mMatrix[2][3] = 0.f;
268
269 mMatrix[3][0] = 0.f;
270 mMatrix[3][1] = 0.f;
271 mMatrix[3][2] = 0.f;
272 mMatrix[3][3] = 1.f;
273 return (*this);
274}
275
276inline LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b)
277{
278 // Converts a to LLVector4 and applies full transformation
279 // Operates "to the left" on row-vector a
280 LLVector3 vec;
281 vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] +
282 a.mV[VY] * b.mMatrix[VY][VX] +
283 a.mV[VZ] * b.mMatrix[VZ][VX] +
284 b.mMatrix[VW][VX];
285
286 vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] +
287 a.mV[VY] * b.mMatrix[VY][VY] +
288 a.mV[VZ] * b.mMatrix[VZ][VY] +
289 b.mMatrix[VW][VY];
290
291 vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] +
292 a.mV[VY] * b.mMatrix[VY][VZ] +
293 a.mV[VZ] * b.mMatrix[VZ][VZ] +
294 b.mMatrix[VW][VZ];
295 return vec;
296}
297
298/*
299inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b)
300{
301 U32 i, j;
302 LLMatrix4 mat;
303 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
304 {
305 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
306 {
307 mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] +
308 a.mMatrix[j][1] * b.mMatrix[1][i] +
309 a.mMatrix[j][2] * b.mMatrix[2][i] +
310 a.mMatrix[j][3] * b.mMatrix[3][i];
311 }
312 }
313 return mat;
314}
315*/
316
317
318inline const LLMatrix4& operator*=(LLMatrix4 &a, const LLMatrix4 &b)
319{
320 U32 i, j;
321 LLMatrix4 mat;
322 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
323 {
324 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
325 {
326 mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] +
327 a.mMatrix[j][1] * b.mMatrix[1][i] +
328 a.mMatrix[j][2] * b.mMatrix[2][i] +
329 a.mMatrix[j][3] * b.mMatrix[3][i];
330 }
331 }
332 a = mat;
333 return a;
334}
335
336inline const LLMatrix4& operator*=(LLMatrix4 &a, const F32 &b)
337{
338 U32 i, j;
339 LLMatrix4 mat;
340 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
341 {
342 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
343 {
344 mat.mMatrix[j][i] = a.mMatrix[j][i] * b;
345 }
346 }
347 a = mat;
348 return a;
349}
350
351inline const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b)
352{
353 LLMatrix4 mat;
354 U32 i, j;
355 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
356 {
357 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
358 {
359 mat.mMatrix[j][i] = a.mMatrix[j][i] + b.mMatrix[j][i];
360 }
361 }
362 a = mat;
363 return a;
364}
365
366inline const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b)
367{
368 LLMatrix4 mat;
369 U32 i, j;
370 for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
371 {
372 for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
373 {
374 mat.mMatrix[j][i] = a.mMatrix[j][i] - b.mMatrix[j][i];
375 }
376 }
377 a = mat;
378 return a;
379}
380
381#endif
382
383
384
diff --git a/linden/indra/llmath/raytrace.cpp b/linden/indra/llmath/raytrace.cpp
new file mode 100644
index 0000000..64bf616
--- /dev/null
+++ b/linden/indra/llmath/raytrace.cpp
@@ -0,0 +1,1275 @@
1/**
2 * @file raytrace.cpp
3 * @brief Functions called by box object scripts.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "math.h"
31//#include "vmath.h"
32#include "v3math.h"
33#include "llquaternion.h"
34#include "m3math.h"
35#include "raytrace.h"
36
37
38BOOL line_plane(const LLVector3 &line_point, const LLVector3 &line_direction,
39 const LLVector3 &plane_point, const LLVector3 plane_normal,
40 LLVector3 &intersection)
41{
42 F32 N = line_direction * plane_normal;
43 if (0.0f == N)
44 {
45 // line is perpendicular to plane normal
46 // so it is either entirely on plane, or not on plane at all
47 return FALSE;
48 }
49 // Ax + By, + Cz + D = 0
50 // D = - (plane_point * plane_normal)
51 // N = line_direction * plane_normal
52 // intersection = line_point - ((D + plane_normal * line_point) / N) * line_direction
53 intersection = line_point - ((plane_normal * line_point - plane_point * plane_normal) / N) * line_direction;
54 return TRUE;
55}
56
57
58BOOL ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction,
59 const LLVector3 &plane_point, const LLVector3 plane_normal,
60 LLVector3 &intersection)
61{
62 F32 N = ray_direction * plane_normal;
63 if (0.0f == N)
64 {
65 // ray is perpendicular to plane normal
66 // so it is either entirely on plane, or not on plane at all
67 return FALSE;
68 }
69 // Ax + By, + Cz + D = 0
70 // D = - (plane_point * plane_normal)
71 // N = ray_direction * plane_normal
72 // intersection = ray_point - ((D + plane_normal * ray_point) / N) * ray_direction
73 F32 alpha = -(plane_normal * ray_point - plane_point * plane_normal) / N;
74 if (alpha < 0.0f)
75 {
76 // ray points away from plane
77 return FALSE;
78 }
79 intersection = ray_point + alpha * ray_direction;
80 return TRUE;
81}
82
83
84BOOL ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction,
85 const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius,
86 LLVector3 &intersection)
87{
88 if (ray_plane(ray_point, ray_direction, circle_center, plane_normal, intersection))
89 {
90 if (circle_radius >= (intersection - circle_center).magVec())
91 {
92 return TRUE;
93 }
94 }
95 return FALSE;
96}
97
98
99BOOL ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction,
100 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
101 LLVector3 &intersection, LLVector3 &intersection_normal)
102{
103 LLVector3 side_01 = point_1 - point_0;
104 LLVector3 side_12 = point_2 - point_1;
105
106 intersection_normal = side_01 % side_12;
107 intersection_normal.normVec();
108
109 if (ray_plane(ray_point, ray_direction, point_0, intersection_normal, intersection))
110 {
111 LLVector3 side_20 = point_0 - point_2;
112 if (intersection_normal * (side_01 % (intersection - point_0)) >= 0.0f &&
113 intersection_normal * (side_12 % (intersection - point_1)) >= 0.0f &&
114 intersection_normal * (side_20 % (intersection - point_2)) >= 0.0f)
115 {
116 return TRUE;
117 }
118 }
119 return FALSE;
120}
121
122
123// assumes a parallelogram
124BOOL ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction,
125 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
126 LLVector3 &intersection, LLVector3 &intersection_normal)
127{
128 LLVector3 side_01 = point_1 - point_0;
129 LLVector3 side_12 = point_2 - point_1;
130
131 intersection_normal = side_01 % side_12;
132 intersection_normal.normVec();
133
134 if (ray_plane(ray_point, ray_direction, point_0, intersection_normal, intersection))
135 {
136 LLVector3 point_3 = point_0 + (side_12);
137 LLVector3 side_23 = point_3 - point_2;
138 LLVector3 side_30 = point_0 - point_3;
139 if (intersection_normal * (side_01 % (intersection - point_0)) >= 0.0f &&
140 intersection_normal * (side_12 % (intersection - point_1)) >= 0.0f &&
141 intersection_normal * (side_23 % (intersection - point_2)) >= 0.0f &&
142 intersection_normal * (side_30 % (intersection - point_3)) >= 0.0f)
143 {
144 return TRUE;
145 }
146 }
147 return FALSE;
148}
149
150
151BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction,
152 const LLVector3 &sphere_center, F32 sphere_radius,
153 LLVector3 &intersection, LLVector3 &intersection_normal)
154{
155 LLVector3 ray_to_sphere = sphere_center - ray_point;
156 F32 dot = ray_to_sphere * ray_direction;
157
158 LLVector3 closest_approach = dot * ray_direction - ray_to_sphere;
159
160 F32 shortest_distance = closest_approach.magVecSquared();
161 F32 radius_squared = sphere_radius * sphere_radius;
162 if (shortest_distance > radius_squared)
163 {
164 return FALSE;
165 }
166
167 F32 half_chord = (F32) sqrt(radius_squared - shortest_distance);
168 closest_approach = sphere_center + closest_approach; // closest_approach now in absolute coordinates
169 intersection = closest_approach + half_chord * ray_direction;
170 dot = ray_direction * (intersection - ray_point);
171 if (dot < 0.0f)
172 {
173 // ray shoots away from sphere and is not inside it
174 return FALSE;
175 }
176
177 shortest_distance = ray_direction * ((closest_approach - half_chord * ray_direction) - ray_point);
178 if (shortest_distance > 0.0f)
179 {
180 // ray enters sphere
181 intersection = intersection - (2.0f * half_chord) * ray_direction;
182 }
183 else
184 {
185 // do nothing
186 // ray starts inside sphere and intersects as it leaves the sphere
187 }
188
189 intersection_normal = intersection - sphere_center;
190 if (sphere_radius > 0.0f)
191 {
192 intersection_normal *= 1.0f / sphere_radius;
193 }
194 else
195 {
196 intersection_normal.setVec(0.0f, 0.0f, 0.0f);
197 }
198
199 return TRUE;
200}
201
202
203BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction,
204 const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation,
205 LLVector3 &intersection, LLVector3 &intersection_normal)
206{
207 // calculate the centers of the cylinder caps in the absolute frame
208 LLVector3 cyl_top(0.0f, 0.0f, 0.5f * cyl_scale.mV[VZ]);
209 LLVector3 cyl_bottom(0.0f, 0.0f, -cyl_top.mV[VZ]);
210 cyl_top = (cyl_top * cyl_rotation) + cyl_center;
211 cyl_bottom = (cyl_bottom * cyl_rotation) + cyl_center;
212
213 // we only handle cylinders with circular cross-sections at the moment
214 F32 cyl_radius = 0.5f * llmax(cyl_scale.mV[VX], cyl_scale.mV[VY]); // HACK until scaled cylinders are supported
215
216 // This implementation is based on the intcyl() function from Graphics_Gems_IV, page 361
217 LLVector3 cyl_axis; // axis direction (bottom toward top)
218 LLVector3 ray_to_cyl; // ray_point to cyl_top
219 F32 shortest_distance; // shortest distance from ray to axis
220 F32 cyl_length;
221 LLVector3 shortest_direction;
222 LLVector3 temp_vector;
223
224 cyl_axis = cyl_bottom - cyl_top;
225 cyl_length = cyl_axis.normVec();
226 ray_to_cyl = ray_point - cyl_bottom;
227 shortest_direction = ray_direction % cyl_axis;
228 shortest_distance = shortest_direction.normVec(); // recycle shortest_distance
229
230 // check for ray parallel to cylinder axis
231 if (0.0f == shortest_distance)
232 {
233 // ray is parallel to cylinder axis
234 temp_vector = ray_to_cyl - (ray_to_cyl * cyl_axis) * cyl_axis;
235 shortest_distance = temp_vector.magVec();
236 if (shortest_distance <= cyl_radius)
237 {
238 shortest_distance = ray_to_cyl * cyl_axis;
239 F32 dot = ray_direction * cyl_axis;
240
241 if (shortest_distance > 0.0)
242 {
243 if (dot > 0.0f)
244 {
245 // ray points away from cylinder bottom
246 return FALSE;
247 }
248 // ray hit bottom of cylinder from outside
249 intersection = ray_point - shortest_distance * cyl_axis;
250 intersection_normal = cyl_axis;
251
252 }
253 else if (shortest_distance > -cyl_length)
254 {
255 // ray starts inside cylinder
256 if (dot < 0.0f)
257 {
258 // ray hit top from inside
259 intersection = ray_point - (cyl_length + shortest_distance) * cyl_axis;
260 intersection_normal = -cyl_axis;
261 }
262 else
263 {
264 // ray hit bottom from inside
265 intersection = ray_point - shortest_distance * cyl_axis;
266 intersection_normal = cyl_axis;
267 }
268 }
269 else
270 {
271 if (dot < 0.0f)
272 {
273 // ray points away from cylinder bottom
274 return FALSE;
275 }
276 // ray hit top from outside
277 intersection = ray_point - (shortest_distance + cyl_length) * cyl_axis;
278 intersection_normal = -cyl_axis;
279 }
280 return TRUE;
281 }
282 return FALSE;
283 }
284
285 // check for intersection with infinite cylinder
286 shortest_distance = (F32) fabs(ray_to_cyl * shortest_direction);
287 if (shortest_distance <= cyl_radius)
288 {
289 F32 dist_to_closest_point; // dist from ray_point to closest_point
290 F32 half_chord_length; // half length of intersection chord
291 F32 in, out; // distances to entering/exiting points
292 temp_vector = ray_to_cyl % cyl_axis;
293 dist_to_closest_point = - (temp_vector * shortest_direction);
294 temp_vector = shortest_direction % cyl_axis;
295 temp_vector.normVec();
296 half_chord_length = (F32) fabs( sqrt(cyl_radius*cyl_radius - shortest_distance * shortest_distance) /
297 (ray_direction * temp_vector) );
298
299 out = dist_to_closest_point + half_chord_length; // dist to exiting point
300 if (out < 0.0f)
301 {
302 // cylinder is behind the ray, so we return FALSE
303 return FALSE;
304 }
305
306 in = dist_to_closest_point - half_chord_length; // dist to entering point
307 if (in < 0.0f)
308 {
309 // ray_point is inside the cylinder
310 // so we store the exiting intersection
311 intersection = ray_point + out * ray_direction;
312 shortest_distance = out;
313 }
314 else
315 {
316 // ray hit cylinder from outside
317 // so we store the entering intersection
318 intersection = ray_point + in * ray_direction;
319 shortest_distance = in;
320 }
321
322 // calculate the normal at intersection
323 if (0.0f == cyl_radius)
324 {
325 intersection_normal.setVec(0.0f, 0.0f, 0.0f);
326 }
327 else
328 {
329 temp_vector = intersection - cyl_bottom;
330 intersection_normal = temp_vector - (temp_vector * cyl_axis) * cyl_axis;
331 intersection_normal.normVec();
332 }
333
334 // check for intersection with end caps
335 // calculate intersection of ray and top plane
336 if (line_plane(ray_point, ray_direction, cyl_top, -cyl_axis, temp_vector)) // NOTE side-effect: changing temp_vector
337 {
338 shortest_distance = (temp_vector - ray_point).magVec();
339 if ( (ray_direction * cyl_axis) > 0.0f)
340 {
341 // ray potentially enters the cylinder at top
342 if (shortest_distance > out)
343 {
344 // ray missed the finite cylinder
345 return FALSE;
346 }
347 if (shortest_distance > in)
348 {
349 // ray intersects cylinder at top plane
350 intersection = temp_vector;
351 intersection_normal = -cyl_axis;
352 return TRUE;
353 }
354 }
355 else
356 {
357 // ray potentially exits the cylinder at top
358 if (shortest_distance < in)
359 {
360 // missed the finite cylinder
361 return FALSE;
362 }
363 }
364
365 // calculate intersection of ray and bottom plane
366 line_plane(ray_point, ray_direction, cyl_bottom, cyl_axis, temp_vector); // NOTE side-effect: changing temp_vector
367 shortest_distance = (temp_vector - ray_point).magVec();
368 if ( (ray_direction * cyl_axis) < 0.0)
369 {
370 // ray potentially enters the cylinder at bottom
371 if (shortest_distance > out)
372 {
373 // ray missed the finite cylinder
374 return FALSE;
375 }
376 if (shortest_distance > in)
377 {
378 // ray intersects cylinder at bottom plane
379 intersection = temp_vector;
380 intersection_normal = cyl_axis;
381 return TRUE;
382 }
383 }
384 else
385 {
386 // ray potentially exits the cylinder at bottom
387 if (shortest_distance < in)
388 {
389 // ray missed the finite cylinder
390 return FALSE;
391 }
392 }
393
394 }
395 else
396 {
397 // ray is parallel to end cap planes
398 temp_vector = cyl_bottom - ray_point;
399 shortest_distance = temp_vector * cyl_axis;
400 if (shortest_distance < 0.0f || shortest_distance > cyl_length)
401 {
402 // ray missed finite cylinder
403 return FALSE;
404 }
405 }
406
407 return TRUE;
408 }
409
410 return FALSE;
411}
412
413
414U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction,
415 const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation,
416 LLVector3 &intersection, LLVector3 &intersection_normal)
417{
418
419 // Need to rotate into box frame
420 LLQuaternion into_box_frame(box_rotation); // rotates things from box frame to absolute
421 into_box_frame.conjQuat(); // now rotates things into box frame
422 LLVector3 line_point = (ray_point - box_center) * into_box_frame;
423 LLVector3 line_direction = ray_direction * into_box_frame;
424
425 // Suppose we have a plane: Ax + By + Cz + D = 0
426 // then, assuming [A, B, C] is a unit vector:
427 //
428 // plane_normal = [A, B, C]
429 // D = - (plane_normal * plane_point)
430 //
431 // Suppose we have a line: X = line_point + alpha * line_direction
432 //
433 // the intersection of the plane and line determines alpha
434 //
435 // alpha = - (D + plane_normal * line_point) / (plane_normal * line_direction)
436
437 LLVector3 line_plane_intersection;
438
439 F32 pointX = line_point.mV[VX];
440 F32 pointY = line_point.mV[VY];
441 F32 pointZ = line_point.mV[VZ];
442
443 F32 dirX = line_direction.mV[VX];
444 F32 dirY = line_direction.mV[VY];
445 F32 dirZ = line_direction.mV[VZ];
446
447 // we'll be using the half-scales of the box
448 F32 boxX = 0.5f * box_scale.mV[VX];
449 F32 boxY = 0.5f * box_scale.mV[VY];
450 F32 boxZ = 0.5f * box_scale.mV[VZ];
451
452 // check to see if line_point is OUTSIDE the box
453 if (pointX < -boxX ||
454 pointX > boxX ||
455 pointY < -boxY ||
456 pointY > boxY ||
457 pointZ < -boxZ ||
458 pointZ > boxZ)
459 {
460 // -------------- point is OUTSIDE the box ----------------
461
462 // front
463 if (pointX > 0.0f && dirX < 0.0f)
464 {
465 // plane_normal = [ 1, 0, 0]
466 // plane_normal*line_point = pointX
467 // plane_normal*line_direction = dirX
468 // D = -boxX
469 // alpha = - (-boxX + pointX) / dirX
470 line_plane_intersection = line_point - ((pointX - boxX) / dirX) * line_direction;
471 if (line_plane_intersection.mV[VY] < boxY &&
472 line_plane_intersection.mV[VY] > -boxY &&
473 line_plane_intersection.mV[VZ] < boxZ &&
474 line_plane_intersection.mV[VZ] > -boxZ )
475 {
476 intersection = (line_plane_intersection * box_rotation) + box_center;
477 intersection_normal = LLVector3(1.0f, 0.0f, 0.0f) * box_rotation;
478 return FRONT_SIDE;
479 }
480 }
481
482 // back
483 if (pointX < 0.0f && dirX > 0.0f)
484 {
485 // plane_normal = [ -1, 0, 0]
486 // plane_normal*line_point = -pX
487 // plane_normal*line_direction = -direction.mV[VX]
488 // D = -bX
489 // alpha = - (-bX - pX) / (-dirX)
490 line_plane_intersection = line_point - ((boxX + pointX)/ dirX) * line_direction;
491 if (line_plane_intersection.mV[VY] < boxY &&
492 line_plane_intersection.mV[VY] > -boxY &&
493 line_plane_intersection.mV[VZ] < boxZ &&
494 line_plane_intersection.mV[VZ] > -boxZ )
495 {
496 intersection = (line_plane_intersection * box_rotation) + box_center;
497 intersection_normal = LLVector3(-1.0f, 0.0f, 0.0f) * box_rotation;
498 return BACK_SIDE;
499 }
500 }
501
502 // left
503 if (pointY > 0.0f && dirY < 0.0f)
504 {
505 // plane_normal = [0, 1, 0]
506 // plane_normal*line_point = pointY
507 // plane_normal*line_direction = dirY
508 // D = -boxY
509 // alpha = - (-boxY + pointY) / dirY
510 line_plane_intersection = line_point + ((boxY - pointY)/dirY) * line_direction;
511
512 if (line_plane_intersection.mV[VX] < boxX &&
513 line_plane_intersection.mV[VX] > -boxX &&
514 line_plane_intersection.mV[VZ] < boxZ &&
515 line_plane_intersection.mV[VZ] > -boxZ )
516 {
517 intersection = (line_plane_intersection * box_rotation) + box_center;
518 intersection_normal = LLVector3(0.0f, 1.0f, 0.0f) * box_rotation;
519 return LEFT_SIDE;
520 }
521 }
522
523 // right
524 if (pointY < 0.0f && dirY > 0.0f)
525 {
526 // plane_normal = [0, -1, 0]
527 // plane_normal*line_point = -pointY
528 // plane_normal*line_direction = -dirY
529 // D = -boxY
530 // alpha = - (-boxY - pointY) / (-dirY)
531 line_plane_intersection = line_point - ((boxY + pointY)/dirY) * line_direction;
532 if (line_plane_intersection.mV[VX] < boxX &&
533 line_plane_intersection.mV[VX] > -boxX &&
534 line_plane_intersection.mV[VZ] < boxZ &&
535 line_plane_intersection.mV[VZ] > -boxZ )
536 {
537 intersection = (line_plane_intersection * box_rotation) + box_center;
538 intersection_normal = LLVector3(0.0f, -1.0f, 0.0f) * box_rotation;
539 return RIGHT_SIDE;
540 }
541 }
542
543 // top
544 if (pointZ > 0.0f && dirZ < 0.0f)
545 {
546 // plane_normal = [0, 0, 1]
547 // plane_normal*line_point = pointZ
548 // plane_normal*line_direction = dirZ
549 // D = -boxZ
550 // alpha = - (-boxZ + pointZ) / dirZ
551 line_plane_intersection = line_point - ((pointZ - boxZ)/dirZ) * line_direction;
552 if (line_plane_intersection.mV[VX] < boxX &&
553 line_plane_intersection.mV[VX] > -boxX &&
554 line_plane_intersection.mV[VY] < boxY &&
555 line_plane_intersection.mV[VY] > -boxY )
556 {
557 intersection = (line_plane_intersection * box_rotation) + box_center;
558 intersection_normal = LLVector3(0.0f, 0.0f, 1.0f) * box_rotation;
559 return TOP_SIDE;
560 }
561 }
562
563 // bottom
564 if (pointZ < 0.0f && dirZ > 0.0f)
565 {
566 // plane_normal = [0, 0, -1]
567 // plane_normal*line_point = -pointZ
568 // plane_normal*line_direction = -dirZ
569 // D = -boxZ
570 // alpha = - (-boxZ - pointZ) / (-dirZ)
571 line_plane_intersection = line_point - ((boxZ + pointZ)/dirZ) * line_direction;
572 if (line_plane_intersection.mV[VX] < boxX &&
573 line_plane_intersection.mV[VX] > -boxX &&
574 line_plane_intersection.mV[VY] < boxY &&
575 line_plane_intersection.mV[VY] > -boxY )
576 {
577 intersection = (line_plane_intersection * box_rotation) + box_center;
578 intersection_normal = LLVector3(0.0f, 0.0f, -1.0f) * box_rotation;
579 return BOTTOM_SIDE;
580 }
581 }
582 return NO_SIDE;
583 }
584
585 // -------------- point is INSIDE the box ----------------
586
587 // front
588 if (dirX > 0.0f)
589 {
590 // plane_normal = [ 1, 0, 0]
591 // plane_normal*line_point = pointX
592 // plane_normal*line_direction = dirX
593 // D = -boxX
594 // alpha = - (-boxX + pointX) / dirX
595 line_plane_intersection = line_point - ((pointX - boxX) / dirX) * line_direction;
596 if (line_plane_intersection.mV[VY] < boxY &&
597 line_plane_intersection.mV[VY] > -boxY &&
598 line_plane_intersection.mV[VZ] < boxZ &&
599 line_plane_intersection.mV[VZ] > -boxZ )
600 {
601 intersection = (line_plane_intersection * box_rotation) + box_center;
602 intersection_normal = LLVector3(1.0f, 0.0f, 0.0f) * box_rotation;
603 return FRONT_SIDE;
604 }
605 }
606
607 // back
608 if (dirX < 0.0f)
609 {
610 // plane_normal = [ -1, 0, 0]
611 // plane_normal*line_point = -pX
612 // plane_normal*line_direction = -direction.mV[VX]
613 // D = -bX
614 // alpha = - (-bX - pX) / (-dirX)
615 line_plane_intersection = line_point - ((boxX + pointX)/ dirX) * line_direction;
616 if (line_plane_intersection.mV[VY] < boxY &&
617 line_plane_intersection.mV[VY] > -boxY &&
618 line_plane_intersection.mV[VZ] < boxZ &&
619 line_plane_intersection.mV[VZ] > -boxZ )
620 {
621 intersection = (line_plane_intersection * box_rotation) + box_center;
622 intersection_normal = LLVector3(-1.0f, 0.0f, 0.0f) * box_rotation;
623 return BACK_SIDE;
624 }
625 }
626
627 // left
628 if (dirY > 0.0f)
629 {
630 // plane_normal = [0, 1, 0]
631 // plane_normal*line_point = pointY
632 // plane_normal*line_direction = dirY
633 // D = -boxY
634 // alpha = - (-boxY + pointY) / dirY
635 line_plane_intersection = line_point + ((boxY - pointY)/dirY) * line_direction;
636
637 if (line_plane_intersection.mV[VX] < boxX &&
638 line_plane_intersection.mV[VX] > -boxX &&
639 line_plane_intersection.mV[VZ] < boxZ &&
640 line_plane_intersection.mV[VZ] > -boxZ )
641 {
642 intersection = (line_plane_intersection * box_rotation) + box_center;
643 intersection_normal = LLVector3(0.0f, 1.0f, 0.0f) * box_rotation;
644 return LEFT_SIDE;
645 }
646 }
647
648 // right
649 if (dirY < 0.0f)
650 {
651 // plane_normal = [0, -1, 0]
652 // plane_normal*line_point = -pointY
653 // plane_normal*line_direction = -dirY
654 // D = -boxY
655 // alpha = - (-boxY - pointY) / (-dirY)
656 line_plane_intersection = line_point - ((boxY + pointY)/dirY) * line_direction;
657 if (line_plane_intersection.mV[VX] < boxX &&
658 line_plane_intersection.mV[VX] > -boxX &&
659 line_plane_intersection.mV[VZ] < boxZ &&
660 line_plane_intersection.mV[VZ] > -boxZ )
661 {
662 intersection = (line_plane_intersection * box_rotation) + box_center;
663 intersection_normal = LLVector3(0.0f, -1.0f, 0.0f) * box_rotation;
664 return RIGHT_SIDE;
665 }
666 }
667
668 // top
669 if (dirZ > 0.0f)
670 {
671 // plane_normal = [0, 0, 1]
672 // plane_normal*line_point = pointZ
673 // plane_normal*line_direction = dirZ
674 // D = -boxZ
675 // alpha = - (-boxZ + pointZ) / dirZ
676 line_plane_intersection = line_point - ((pointZ - boxZ)/dirZ) * line_direction;
677 if (line_plane_intersection.mV[VX] < boxX &&
678 line_plane_intersection.mV[VX] > -boxX &&
679 line_plane_intersection.mV[VY] < boxY &&
680 line_plane_intersection.mV[VY] > -boxY )
681 {
682 intersection = (line_plane_intersection * box_rotation) + box_center;
683 intersection_normal = LLVector3(0.0f, 0.0f, 1.0f) * box_rotation;
684 return TOP_SIDE;
685 }
686 }
687
688 // bottom
689 if (dirZ < 0.0f)
690 {
691 // plane_normal = [0, 0, -1]
692 // plane_normal*line_point = -pointZ
693 // plane_normal*line_direction = -dirZ
694 // D = -boxZ
695 // alpha = - (-boxZ - pointZ) / (-dirZ)
696 line_plane_intersection = line_point - ((boxZ + pointZ)/dirZ) * line_direction;
697 if (line_plane_intersection.mV[VX] < boxX &&
698 line_plane_intersection.mV[VX] > -boxX &&
699 line_plane_intersection.mV[VY] < boxY &&
700 line_plane_intersection.mV[VY] > -boxY )
701 {
702 intersection = (line_plane_intersection * box_rotation) + box_center;
703 intersection_normal = LLVector3(0.0f, 0.0f, -1.0f) * box_rotation;
704 return BOTTOM_SIDE;
705 }
706 }
707
708 // should never get here unless line instersects at tangent point on edge or corner
709 // however such cases will be EXTREMELY rare
710 return NO_SIDE;
711}
712
713
714BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction,
715 const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation,
716 LLVector3 &intersection, LLVector3 &intersection_normal)
717{
718 // (0) Z
719 // /| \ .
720 // (1)| \ /|\ _.Y
721 // | \ \ | /|
722 // | |\ \ | /
723 // | | \(0)\ | /
724 // | | \ \ |/
725 // | | \ \ (*)----> X
726 // |(3)---\---(2)
727 // |/ \ /
728 // (4)-------(5)
729
730 // need to calculate the points of the prism so we can run ray tests with each face
731 F32 x = prism_scale.mV[VX];
732 F32 y = prism_scale.mV[VY];
733 F32 z = prism_scale.mV[VZ];
734
735 F32 tx = x * 2.0f / 3.0f;
736 F32 ty = y * 0.5f;
737 F32 tz = z * 2.0f / 3.0f;
738
739 LLVector3 point0(tx-x, ty, tz);
740 LLVector3 point1(tx-x, -ty, tz);
741 LLVector3 point2(tx, ty, tz-z);
742 LLVector3 point3(tx-x, ty, tz-z);
743 LLVector3 point4(tx-x, -ty, tz-z);
744 LLVector3 point5(tx, -ty, tz-z);
745
746 // transform these points into absolute frame
747 point0 = (point0 * prism_rotation) + prism_center;
748 point1 = (point1 * prism_rotation) + prism_center;
749 point2 = (point2 * prism_rotation) + prism_center;
750 point3 = (point3 * prism_rotation) + prism_center;
751 point4 = (point4 * prism_rotation) + prism_center;
752 point5 = (point5 * prism_rotation) + prism_center;
753
754 // test ray intersection for each face
755 BOOL b_hit = FALSE;
756 LLVector3 face_intersection, face_normal;
757 F32 distance_squared = 0.0f;
758 F32 temp;
759
760 // face 0
761 if (ray_direction * ( (point0 - point2) % (point5 - point2)) < 0.0f &&
762 ray_quadrangle(ray_point, ray_direction, point5, point2, point0, intersection, intersection_normal))
763 {
764 distance_squared = (ray_point - intersection).magVecSquared();
765 b_hit = TRUE;
766 }
767
768 // face 1
769 if (ray_direction * ( (point0 - point3) % (point2 - point3)) < 0.0f &&
770 ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal))
771 {
772 if (TRUE == b_hit)
773 {
774 temp = (ray_point - face_intersection).magVecSquared();
775 if (temp < distance_squared)
776 {
777 distance_squared = temp;
778 intersection = face_intersection;
779 intersection_normal = face_normal;
780 }
781 }
782 else
783 {
784 distance_squared = (ray_point - face_intersection).magVecSquared();
785 intersection = face_intersection;
786 intersection_normal = face_normal;
787 b_hit = TRUE;
788 }
789 }
790
791 // face 2
792 if (ray_direction * ( (point1 - point4) % (point3 - point4)) < 0.0f &&
793 ray_quadrangle(ray_point, ray_direction, point3, point4, point1, face_intersection, face_normal))
794 {
795 if (TRUE == b_hit)
796 {
797 temp = (ray_point - face_intersection).magVecSquared();
798 if (temp < distance_squared)
799 {
800 distance_squared = temp;
801 intersection = face_intersection;
802 intersection_normal = face_normal;
803 }
804 }
805 else
806 {
807 distance_squared = (ray_point - face_intersection).magVecSquared();
808 intersection = face_intersection;
809 intersection_normal = face_normal;
810 b_hit = TRUE;
811 }
812 }
813
814 // face 3
815 if (ray_direction * ( (point5 - point4) % (point1 - point4)) < 0.0f &&
816 ray_triangle(ray_point, ray_direction, point1, point4, point5, face_intersection, face_normal))
817 {
818 if (TRUE == b_hit)
819 {
820 temp = (ray_point - face_intersection).magVecSquared();
821 if (temp < distance_squared)
822 {
823 distance_squared = temp;
824 intersection = face_intersection;
825 intersection_normal = face_normal;
826 }
827 }
828 else
829 {
830 distance_squared = (ray_point - face_intersection).magVecSquared();
831 intersection = face_intersection;
832 intersection_normal = face_normal;
833 b_hit = TRUE;
834 }
835 }
836
837 // face 4
838 if (ray_direction * ( (point4 - point5) % (point2 - point5)) < 0.0f &&
839 ray_quadrangle(ray_point, ray_direction, point2, point5, point4, face_intersection, face_normal))
840 {
841 if (TRUE == b_hit)
842 {
843 temp = (ray_point - face_intersection).magVecSquared();
844 if (temp < distance_squared)
845 {
846 distance_squared = temp;
847 intersection = face_intersection;
848 intersection_normal = face_normal;
849 }
850 }
851 else
852 {
853 distance_squared = (ray_point - face_intersection).magVecSquared();
854 intersection = face_intersection;
855 intersection_normal = face_normal;
856 b_hit = TRUE;
857 }
858 }
859
860 return b_hit;
861}
862
863
864BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction,
865 const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation,
866 LLVector3 &intersection, LLVector3 &intersection_normal)
867{
868 F32 a = 0.5f * F_SQRT3; // height of unit triangle
869 F32 b = 1.0f / F_SQRT3; // distance of center of unit triangle to each point
870 F32 c = F_SQRT2 / F_SQRT3; // height of unit tetrahedron
871 F32 d = 0.5f * F_SQRT3 / F_SQRT2; // distance of center of tetrahedron to each point
872
873 // if we want the tetrahedron to have unit height (c = 1.0) then we need to divide
874 // each constant by hieght of a unit tetrahedron
875 F32 oo_c = 1.0f / c;
876 a = a * oo_c;
877 b = b * oo_c;
878 c = 1.0f;
879 d = d * oo_c;
880 F32 e = 0.5f * oo_c;
881
882 LLVector3 point0( 0.0f, 0.0f, t_scale.mV[VZ] * d);
883 LLVector3 point1(t_scale.mV[VX] * b, 0.0f, t_scale.mV[VZ] * (d-c));
884 LLVector3 point2(t_scale.mV[VX] * (b-a), e * t_scale.mV[VY], t_scale.mV[VZ] * (d-c));
885 LLVector3 point3(t_scale.mV[VX] * (b-a), -e * t_scale.mV[VY], t_scale.mV[VZ] * (d-c));
886
887 // transform these points into absolute frame
888 point0 = (point0 * t_rotation) + t_center;
889 point1 = (point1 * t_rotation) + t_center;
890 point2 = (point2 * t_rotation) + t_center;
891 point3 = (point3 * t_rotation) + t_center;
892
893 // test ray intersection for each face
894 BOOL b_hit = FALSE;
895 LLVector3 face_intersection, face_normal;
896 F32 distance_squared = 1.0e12f;
897 F32 temp;
898
899 // face 0
900 if (ray_direction * ( (point2 - point1) % (point0 - point1)) < 0.0f &&
901 ray_triangle(ray_point, ray_direction, point1, point2, point0, intersection, intersection_normal))
902 {
903 distance_squared = (ray_point - intersection).magVecSquared();
904 b_hit = TRUE;
905 }
906
907 // face 1
908 if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f &&
909 ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal))
910 {
911 if (TRUE == b_hit)
912 {
913 temp = (ray_point - face_intersection).magVecSquared();
914 if (temp < distance_squared)
915 {
916 distance_squared = temp;
917 intersection = face_intersection;
918 intersection_normal = face_normal;
919 }
920 }
921 else
922 {
923 distance_squared = (ray_point - face_intersection).magVecSquared();
924 intersection = face_intersection;
925 intersection_normal = face_normal;
926 b_hit = TRUE;
927 }
928 }
929
930 // face 2
931 if (ray_direction * ( (point1 - point3) % (point0 - point3)) < 0.0f &&
932 ray_triangle(ray_point, ray_direction, point3, point1, point0, face_intersection, face_normal))
933 {
934 if (TRUE == b_hit)
935 {
936 temp = (ray_point - face_intersection).magVecSquared();
937 if (temp < distance_squared)
938 {
939 distance_squared = temp;
940 intersection = face_intersection;
941 intersection_normal = face_normal;
942 }
943 }
944 else
945 {
946 distance_squared = (ray_point - face_intersection).magVecSquared();
947 intersection = face_intersection;
948 intersection_normal = face_normal;
949 b_hit = TRUE;
950 }
951 }
952
953 // face 3
954 if (ray_direction * ( (point2 - point3) % (point1 - point3)) < 0.0f &&
955 ray_triangle(ray_point, ray_direction, point3, point2, point1, face_intersection, face_normal))
956 {
957 if (TRUE == b_hit)
958 {
959 temp = (ray_point - face_intersection).magVecSquared();
960 if (temp < distance_squared)
961 {
962 intersection = face_intersection;
963 intersection_normal = face_normal;
964 }
965 }
966 else
967 {
968 intersection = face_intersection;
969 intersection_normal = face_normal;
970 b_hit = TRUE;
971 }
972 }
973
974 return b_hit;
975}
976
977
978BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction,
979 const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation,
980 LLVector3 &intersection, LLVector3 &intersection_normal)
981{
982 // center of mass of pyramid is located 1/4 its height from the base
983 F32 x = 0.5f * p_scale.mV[VX];
984 F32 y = 0.5f * p_scale.mV[VY];
985 F32 z = 0.25f * p_scale.mV[VZ];
986
987 LLVector3 point0(0.0f, 0.0f, p_scale.mV[VZ] - z);
988 LLVector3 point1( x, y, -z);
989 LLVector3 point2(-x, y, -z);
990 LLVector3 point3(-x, -y, -z);
991 LLVector3 point4( x, -y, -z);
992
993 // transform these points into absolute frame
994 point0 = (point0 * p_rotation) + p_center;
995 point1 = (point1 * p_rotation) + p_center;
996 point2 = (point2 * p_rotation) + p_center;
997 point3 = (point3 * p_rotation) + p_center;
998 point4 = (point4 * p_rotation) + p_center;
999
1000 // test ray intersection for each face
1001 BOOL b_hit = FALSE;
1002 LLVector3 face_intersection, face_normal;
1003 F32 distance_squared = 1.0e12f;
1004 F32 temp;
1005
1006 // face 0
1007 if (ray_direction * ( (point1 - point4) % (point0 - point4)) < 0.0f &&
1008 ray_triangle(ray_point, ray_direction, point4, point1, point0, intersection, intersection_normal))
1009 {
1010 distance_squared = (ray_point - intersection).magVecSquared();
1011 b_hit = TRUE;
1012 }
1013
1014 // face 1
1015 if (ray_direction * ( (point2 - point1) % (point0 - point1)) < 0.0f &&
1016 ray_triangle(ray_point, ray_direction, point1, point2, point0, face_intersection, face_normal))
1017 {
1018 if (TRUE == b_hit)
1019 {
1020 temp = (ray_point - face_intersection).magVecSquared();
1021 if (temp < distance_squared)
1022 {
1023 distance_squared = temp;
1024 intersection = face_intersection;
1025 intersection_normal = face_normal;
1026 }
1027 }
1028 else
1029 {
1030 distance_squared = (ray_point - face_intersection).magVecSquared();
1031 intersection = face_intersection;
1032 intersection_normal = face_normal;
1033 b_hit = TRUE;
1034 }
1035 }
1036
1037 // face 2
1038 if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f &&
1039 ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal))
1040 {
1041 if (TRUE == b_hit)
1042 {
1043 temp = (ray_point - face_intersection).magVecSquared();
1044 if (temp < distance_squared)
1045 {
1046 distance_squared = temp;
1047 intersection = face_intersection;
1048 intersection_normal = face_normal;
1049 }
1050 }
1051 else
1052 {
1053 distance_squared = (ray_point - face_intersection).magVecSquared();
1054 intersection = face_intersection;
1055 intersection_normal = face_normal;
1056 b_hit = TRUE;
1057 }
1058 }
1059
1060 // face 3
1061 if (ray_direction * ( (point4 - point3) % (point0 - point3)) < 0.0f &&
1062 ray_triangle(ray_point, ray_direction, point3, point4, point0, face_intersection, face_normal))
1063 {
1064 if (TRUE == b_hit)
1065 {
1066 temp = (ray_point - face_intersection).magVecSquared();
1067 if (temp < distance_squared)
1068 {
1069 distance_squared = temp;
1070 intersection = face_intersection;
1071 intersection_normal = face_normal;
1072 }
1073 }
1074 else
1075 {
1076 distance_squared = (ray_point - face_intersection).magVecSquared();
1077 intersection = face_intersection;
1078 intersection_normal = face_normal;
1079 b_hit = TRUE;
1080 }
1081 }
1082
1083 // face 4
1084 if (ray_direction * ( (point3 - point4) % (point2 - point4)) < 0.0f &&
1085 ray_quadrangle(ray_point, ray_direction, point4, point3, point2, face_intersection, face_normal))
1086 {
1087 if (TRUE == b_hit)
1088 {
1089 temp = (ray_point - face_intersection).magVecSquared();
1090 if (temp < distance_squared)
1091 {
1092 intersection = face_intersection;
1093 intersection_normal = face_normal;
1094 }
1095 }
1096 else
1097 {
1098 intersection = face_intersection;
1099 intersection_normal = face_normal;
1100 b_hit = TRUE;
1101 }
1102 }
1103
1104 return b_hit;
1105}
1106
1107
1108BOOL linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b,
1109 const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius,
1110 LLVector3 &intersection)
1111{
1112 LLVector3 ray_direction = point_b - point_a;
1113 F32 segment_length = ray_direction.normVec();
1114
1115 if (ray_circle(point_a, ray_direction, circle_center, plane_normal, circle_radius, intersection))
1116 {
1117 if (segment_length >= (point_a - intersection).magVec())
1118 {
1119 return TRUE;
1120 }
1121 }
1122 return FALSE;
1123}
1124
1125
1126BOOL linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b,
1127 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
1128 LLVector3 &intersection, LLVector3 &intersection_normal)
1129{
1130 LLVector3 ray_direction = point_b - point_a;
1131 F32 segment_length = ray_direction.normVec();
1132
1133 if (ray_triangle(point_a, ray_direction, point_0, point_1, point_2, intersection, intersection_normal))
1134 {
1135 if (segment_length >= (point_a - intersection).magVec())
1136 {
1137 return TRUE;
1138 }
1139 }
1140 return FALSE;
1141}
1142
1143
1144BOOL linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b,
1145 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
1146 LLVector3 &intersection, LLVector3 &intersection_normal)
1147{
1148 LLVector3 ray_direction = point_b - point_a;
1149 F32 segment_length = ray_direction.normVec();
1150
1151 if (ray_quadrangle(point_a, ray_direction, point_0, point_1, point_2, intersection, intersection_normal))
1152 {
1153 if (segment_length >= (point_a - intersection).magVec())
1154 {
1155 return TRUE;
1156 }
1157 }
1158 return FALSE;
1159}
1160
1161
1162BOOL linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b,
1163 const LLVector3 &sphere_center, F32 sphere_radius,
1164 LLVector3 &intersection, LLVector3 &intersection_normal)
1165{
1166 LLVector3 ray_direction = point_b - point_a;
1167 F32 segment_length = ray_direction.normVec();
1168
1169 if (ray_sphere(point_a, ray_direction, sphere_center, sphere_radius, intersection, intersection_normal))
1170 {
1171 if (segment_length >= (point_a - intersection).magVec())
1172 {
1173 return TRUE;
1174 }
1175 }
1176 return FALSE;
1177}
1178
1179
1180BOOL linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b,
1181 const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation,
1182 LLVector3 &intersection, LLVector3 &intersection_normal)
1183{
1184 LLVector3 ray_direction = point_b - point_a;
1185 F32 segment_length = ray_direction.normVec();
1186
1187 if (ray_cylinder(point_a, ray_direction, cyl_center, cyl_scale, cyl_rotation, intersection, intersection_normal))
1188 {
1189 if (segment_length >= (point_a - intersection).magVec())
1190 {
1191 return TRUE;
1192 }
1193 }
1194 return FALSE;
1195}
1196
1197
1198U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b,
1199 const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation,
1200 LLVector3 &intersection, LLVector3 &intersection_normal)
1201{
1202 LLVector3 direction = point_b - point_a;
1203 if (direction.isNull())
1204 {
1205 return NO_SIDE;
1206 }
1207
1208 F32 segment_length = direction.normVec();
1209 U32 box_side = ray_box(point_a, direction, box_center, box_scale, box_rotation, intersection, intersection_normal);
1210 if (NO_SIDE == box_side || segment_length < (intersection - point_a).magVec())
1211 {
1212 return NO_SIDE;
1213 }
1214
1215 return box_side;
1216}
1217
1218
1219BOOL linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b,
1220 const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation,
1221 LLVector3 &intersection, LLVector3 &intersection_normal)
1222{
1223 LLVector3 ray_direction = point_b - point_a;
1224 F32 segment_length = ray_direction.normVec();
1225
1226 if (ray_prism(point_a, ray_direction, prism_center, prism_scale, prism_rotation, intersection, intersection_normal))
1227 {
1228 if (segment_length >= (point_a - intersection).magVec())
1229 {
1230 return TRUE;
1231 }
1232 }
1233 return FALSE;
1234}
1235
1236
1237BOOL linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b,
1238 const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation,
1239 LLVector3 &intersection, LLVector3 &intersection_normal)
1240{
1241 LLVector3 ray_direction = point_b - point_a;
1242 F32 segment_length = ray_direction.normVec();
1243
1244 if (ray_tetrahedron(point_a, ray_direction, t_center, t_scale, t_rotation, intersection, intersection_normal))
1245 {
1246 if (segment_length >= (point_a - intersection).magVec())
1247 {
1248 return TRUE;
1249 }
1250 }
1251 return FALSE;
1252}
1253
1254
1255BOOL linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b,
1256 const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation,
1257 LLVector3 &intersection, LLVector3 &intersection_normal)
1258{
1259 LLVector3 ray_direction = point_b - point_a;
1260 F32 segment_length = ray_direction.normVec();
1261
1262 if (ray_pyramid(point_a, ray_direction, p_center, p_scale, p_rotation, intersection, intersection_normal))
1263 {
1264 if (segment_length >= (point_a - intersection).magVec())
1265 {
1266 return TRUE;
1267 }
1268 }
1269 return FALSE;
1270}
1271
1272
1273
1274
1275
diff --git a/linden/indra/llmath/raytrace.h b/linden/indra/llmath/raytrace.h
new file mode 100644
index 0000000..58cca69
--- /dev/null
+++ b/linden/indra/llmath/raytrace.h
@@ -0,0 +1,233 @@
1/**
2 * @file raytrace.h
3 * @brief Ray intersection tests for primitives.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_RAYTRACE_H
29#define LL_RAYTRACE_H
30
31class LLVector3;
32class LLQuaternion;
33
34// All functions produce results in the same reference frame as the arguments.
35//
36// Any arguments of the form "foo_direction" or "foo_normal" are assumed to
37// be normalized, or normalized vectors are stored in them.
38//
39// Vector arguments of the form "shape_scale" represent the scale of the
40// object along the three axes.
41//
42// All functions return the expected TRUE or FALSE, unless otherwise noted.
43// When FALSE is returned, any resulting values that might have been stored
44// are undefined.
45//
46// Rays are defined by a "ray_point" and a "ray_direction" (unit).
47//
48// Lines are defined by a "line_point" and a "line_direction" (unit).
49//
50// Line segements are defined by "point_a" and "point_b", and for intersection
51// purposes are assumed to point from "point_a" to "point_b".
52//
53// A ray is different from a line in that it starts at a point and extends
54// in only one direction.
55//
56// Intersection normals always point outside the object, normal to the object's
57// surface at the point of intersection.
58//
59// Object rotations passed as quaternions are expected to rotate from the
60// object's local frame to the absolute frame. So, if "foo" is a vector in
61// the object's local frame, then "foo * object_rotation" is in the absolute
62// frame.
63
64
65// returns TRUE iff line is not parallel to plane.
66BOOL line_plane(const LLVector3 &line_point, const LLVector3 &line_direction,
67 const LLVector3 &plane_point, const LLVector3 plane_normal,
68 LLVector3 &intersection);
69
70
71// returns TRUE iff line is not parallel to plane.
72BOOL ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction,
73 const LLVector3 &plane_point, const LLVector3 plane_normal,
74 LLVector3 &intersection);
75
76
77BOOL ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction,
78 const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius,
79 LLVector3 &intersection);
80
81// point_0 through point_2 define the plane_normal via the right-hand rule:
82// circle from point_0 to point_2 with fingers ==> thumb points in direction of normal
83BOOL ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction,
84 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
85 LLVector3 &intersection, LLVector3 &intersection_normal);
86
87
88// point_0 is the lower-left corner, point_1 is the lower-right, point_2 is the upper-right
89// right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right
90// ==> thumb points in direction of normal
91// assumes a parallelogram, so point_3 is determined by the other points
92BOOL ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction,
93 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
94 LLVector3 &intersection, LLVector3 &intersection_normal);
95
96
97BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction,
98 const LLVector3 &sphere_center, F32 sphere_radius,
99 LLVector3 &intersection, LLVector3 &intersection_normal);
100
101
102// finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom",
103// and by the cylinder radius "cyl_radius"
104BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction,
105 const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation,
106 LLVector3 &intersection, LLVector3 &intersection_normal);
107
108
109// this function doesn't just return a BOOL because the return is currently
110// used to decide how to break up boxes that have been hit by shots...
111// a hack that will probably be changed later
112//
113// returns a number representing the side of the box that was hit by the ray,
114// or NO_SIDE if intersection test failed.
115U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction,
116 const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation,
117 LLVector3 &intersection, LLVector3 &intersection_normal);
118
119
120/* TODO
121BOOL ray_ellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction,
122 const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation,
123 LLVector3 &intersection, LLVector3 &intersection_normal);
124
125
126BOOL ray_cone(const LLVector3 &ray_point, const LLVector3 &ray_direction,
127 const LLVector3 &cone_tip, const LLVector3 &cone_bottom,
128 const LLVector3 &cone_scale, const LLQuaternion &cone_rotation,
129 LLVector3 &intersection, LLVector3 &intersection_normal);
130*/
131
132
133BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction,
134 const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation,
135 LLVector3 &intersection, LLVector3 &intersection_normal);
136
137
138BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction,
139 const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation,
140 LLVector3 &intersection, LLVector3 &intersection_normal);
141
142
143BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction,
144 const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation,
145 LLVector3 &intersection, LLVector3 &intersection_normal);
146
147
148
149/* TODO
150BOOL ray_hemiellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction,
151 const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation,
152 const LLVector3 &e_cut_normal,
153 LLVector3 &intersection, LLVector3 &intersection_normal);
154
155
156BOOL ray_hemisphere(const LLVector3 &ray_point, const LLVector3 &ray_direction,
157 const LLVector3 &sphere_center, F32 sphere_radius, const LLVector3 &sphere_cut_normal,
158 LLVector3 &intersection, LLVector3 &intersection_normal);
159
160
161BOOL ray_hemicylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction,
162 const LLVector3 &cyl_top, const LLVector3 &cyl_bottom, F32 cyl_radius,
163 const LLVector3 &cyl_cut_normal,
164 LLVector3 &intersection, LLVector3 &intersection_normal);
165
166
167BOOL ray_hemicone(const LLVector3 &ray_point, const LLVector3 &ray_direction,
168 const LLVector3 &cone_tip, const LLVector3 &cone_bottom,
169 const LLVector3 &cone_scale, const LLVector3 &cyl_cut_normal,
170 LLVector3 &intersection, LLVector3 &intersection_normal);
171*/
172
173
174BOOL linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b,
175 const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius,
176 LLVector3 &intersection);
177
178// point_0 through point_2 define the plane_normal via the right-hand rule:
179// circle from point_0 to point_2 with fingers ==> thumb points in direction of normal
180BOOL linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b,
181 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
182 LLVector3 &intersection, LLVector3 &intersection_normal);
183
184
185// point_0 is the lower-left corner, point_1 is the lower-right, point_2 is the upper-right
186// right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right
187// ==> thumb points in direction of normal
188// assumes a parallelogram, so point_3 is determined by the other points
189BOOL linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b,
190 const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2,
191 LLVector3 &intersection, LLVector3 &intersection_normal);
192
193
194BOOL linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b,
195 const LLVector3 &sphere_center, F32 sphere_radius,
196 LLVector3 &intersection, LLVector3 &intersection_normal);
197
198
199// finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom",
200// and by the cylinder radius "cyl_radius"
201BOOL linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b,
202 const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation,
203 LLVector3 &intersection, LLVector3 &intersection_normal);
204
205
206// this function doesn't just return a BOOL because the return is currently
207// used to decide how to break up boxes that have been hit by shots...
208// a hack that will probably be changed later
209//
210// returns a number representing the side of the box that was hit by the ray,
211// or NO_SIDE if intersection test failed.
212U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b,
213 const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation,
214 LLVector3 &intersection, LLVector3 &intersection_normal);
215
216
217BOOL linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b,
218 const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation,
219 LLVector3 &intersection, LLVector3 &intersection_normal);
220
221
222BOOL linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b,
223 const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation,
224 LLVector3 &intersection, LLVector3 &intersection_normal);
225
226
227BOOL linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b,
228 const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation,
229 LLVector3 &intersection, LLVector3 &intersection_normal);
230
231
232#endif
233
diff --git a/linden/indra/llmath/v2math.cpp b/linden/indra/llmath/v2math.cpp
new file mode 100644
index 0000000..cee0f73
--- /dev/null
+++ b/linden/indra/llmath/v2math.cpp
@@ -0,0 +1,111 @@
1/**
2 * @file v2math.cpp
3 * @brief LLVector2 class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30//#include "vmath.h"
31#include "v2math.h"
32#include "v4math.h"
33#include "m4math.h"
34#include "m3math.h"
35#include "llquaternion.h"
36
37// LLVector2
38
39LLVector2 LLVector2::zero(0,0);
40
41
42// Non-member functions
43
44// Sets all values to absolute value of their original values
45// Returns TRUE if data changed
46BOOL LLVector2::abs()
47{
48 BOOL ret = FALSE;
49
50 if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = TRUE; }
51 if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = TRUE; }
52
53 return ret;
54}
55
56
57F32 angle_between(const LLVector2& a, const LLVector2& b)
58{
59 LLVector2 an = a;
60 LLVector2 bn = b;
61 an.normVec();
62 bn.normVec();
63 F32 cosine = an * bn;
64 F32 angle = (cosine >= 1.0f) ? 0.0f :
65 (cosine <= -1.0f) ? F_PI :
66 acos(cosine);
67 return angle;
68}
69
70BOOL are_parallel(const LLVector2 &a, const LLVector2 &b, float epsilon)
71{
72 LLVector2 an = a;
73 LLVector2 bn = b;
74 an.normVec();
75 bn.normVec();
76 F32 dot = an * bn;
77 if ( (1.0f - fabs(dot)) < epsilon)
78 {
79 return TRUE;
80 }
81 return FALSE;
82}
83
84
85F32 dist_vec(const LLVector2 &a, const LLVector2 &b)
86{
87 F32 x = a.mV[0] - b.mV[0];
88 F32 y = a.mV[1] - b.mV[1];
89 return fsqrtf( x*x + y*y );
90}
91
92F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b)
93{
94 F32 x = a.mV[0] - b.mV[0];
95 F32 y = a.mV[1] - b.mV[1];
96 return x*x + y*y;
97}
98
99F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b)
100{
101 F32 x = a.mV[0] - b.mV[0];
102 F32 y = a.mV[1] - b.mV[1];
103 return x*x + y*y;
104}
105
106LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u)
107{
108 return LLVector2(
109 a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
110 a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u );
111}
diff --git a/linden/indra/llmath/v2math.h b/linden/indra/llmath/v2math.h
new file mode 100644
index 0000000..1832403
--- /dev/null
+++ b/linden/indra/llmath/v2math.h
@@ -0,0 +1,326 @@
1/**
2 * @file v2math.h
3 * @brief LLVector2 class header file.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_V2MATH_H
29#define LL_V2MATH_H
30
31#include <math.h>
32
33#include "llmath.h"
34
35class LLVector4;
36class LLMatrix3;
37class LLQuaternion;
38
39// Llvector2 = |x y z w|
40
41static const U32 LENGTHOFVECTOR2 = 2;
42
43class LLVector2
44{
45 public:
46 F32 mV[LENGTHOFVECTOR2];
47
48 static LLVector2 zero;
49
50 LLVector2(); // Initializes LLVector2 to (0, 0)
51 LLVector2(F32 x, F32 y); // Initializes LLVector2 to (x. y)
52 LLVector2(const F32 *vec); // Initializes LLVector2 to (vec[0]. vec[1])
53
54 // Clears LLVector2 to (0, 0). DEPRECATED - prefer zeroVec.
55 void clearVec();
56
57 // Zero LLVector2 to (0, 0)
58 void zeroVec();
59
60 void setVec(F32 x, F32 y); // Sets LLVector2 to (x, y)
61 void setVec(const LLVector2 &vec); // Sets LLVector2 to vec
62 void setVec(const F32 *vec); // Sets LLVector2 to vec
63
64 F32 magVec() const; // Returns magnitude of LLVector2
65 F32 magVecSquared() const; // Returns magnitude squared of LLVector2
66 F32 normVec(); // Normalizes and returns the magnitude of LLVector2
67
68 BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed
69
70 const LLVector2& scaleVec(const LLVector2& vec); // scales per component by vec
71
72 BOOL isNull(); // Returns TRUE if vector has a _very_small_ length
73 BOOL isExactlyZero() const { return !mV[VX] && !mV[VY]; }
74
75 F32 operator[](int idx) const { return mV[idx]; }
76 F32 &operator[](int idx) { return mV[idx]; }
77
78 friend bool operator<(const LLVector2 &a, const LLVector2 &b); // For sorting. x is "more significant" than y
79 friend LLVector2 operator+(const LLVector2 &a, const LLVector2 &b); // Return vector a + b
80 friend LLVector2 operator-(const LLVector2 &a, const LLVector2 &b); // Return vector a minus b
81 friend F32 operator*(const LLVector2 &a, const LLVector2 &b); // Return a dot b
82 friend LLVector2 operator%(const LLVector2 &a, const LLVector2 &b); // Return a cross b
83 friend LLVector2 operator/(const LLVector2 &a, F32 k); // Return a divided by scaler k
84 friend LLVector2 operator*(const LLVector2 &a, F32 k); // Return a times scaler k
85 friend LLVector2 operator*(F32 k, const LLVector2 &a); // Return a times scaler k
86 friend bool operator==(const LLVector2 &a, const LLVector2 &b); // Return a == b
87 friend bool operator!=(const LLVector2 &a, const LLVector2 &b); // Return a != b
88
89 friend const LLVector2& operator+=(LLVector2 &a, const LLVector2 &b); // Return vector a + b
90 friend const LLVector2& operator-=(LLVector2 &a, const LLVector2 &b); // Return vector a minus b
91 friend const LLVector2& operator%=(LLVector2 &a, const LLVector2 &b); // Return a cross b
92 friend const LLVector2& operator*=(LLVector2 &a, F32 k); // Return a times scaler k
93 friend const LLVector2& operator/=(LLVector2 &a, F32 k); // Return a divided by scaler k
94
95 friend LLVector2 operator-(const LLVector2 &a); // Return vector -a
96
97 friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a
98};
99
100
101// Non-member functions
102
103F32 angle_between(const LLVector2 &a, const LLVector2 &b); // Returns angle (radians) between a and b
104BOOL are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel
105F32 dist_vec(const LLVector2 &a, const LLVector2 &b); // Returns distance between a and b
106F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b);// Returns distance sqaured between a and b
107F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b);// Returns distance sqaured between a and b ignoring Z component
108LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u); // Returns a vector that is a linear interpolation between a and b
109
110// Constructors
111
112inline LLVector2::LLVector2(void)
113{
114 mV[VX] = 0.f;
115 mV[VY] = 0.f;
116}
117
118inline LLVector2::LLVector2(F32 x, F32 y)
119{
120 mV[VX] = x;
121 mV[VY] = y;
122}
123
124inline LLVector2::LLVector2(const F32 *vec)
125{
126 mV[VX] = vec[VX];
127 mV[VY] = vec[VY];
128}
129
130
131// Clear and Assignment Functions
132
133inline void LLVector2::clearVec(void)
134{
135 mV[VX] = 0.f;
136 mV[VY] = 0.f;
137}
138
139inline void LLVector2::zeroVec(void)
140{
141 mV[VX] = 0.f;
142 mV[VY] = 0.f;
143}
144
145inline void LLVector2::setVec(F32 x, F32 y)
146{
147 mV[VX] = x;
148 mV[VY] = y;
149}
150
151inline void LLVector2::setVec(const LLVector2 &vec)
152{
153 mV[VX] = vec.mV[VX];
154 mV[VY] = vec.mV[VY];
155}
156
157inline void LLVector2::setVec(const F32 *vec)
158{
159 mV[VX] = vec[VX];
160 mV[VY] = vec[VY];
161}
162
163// LLVector2 Magnitude and Normalization Functions
164
165inline F32 LLVector2::magVec(void) const
166{
167 return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
168}
169
170inline F32 LLVector2::magVecSquared(void) const
171{
172 return mV[0]*mV[0] + mV[1]*mV[1];
173}
174
175inline F32 LLVector2::normVec(void)
176{
177 F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
178 F32 oomag;
179
180 if (mag > FP_MAG_THRESHOLD)
181 {
182 oomag = 1.f/mag;
183 mV[0] *= oomag;
184 mV[1] *= oomag;
185 }
186 else
187 {
188 mV[0] = 0.f;
189 mV[1] = 0.f;
190 mag = 0;
191 }
192 return (mag);
193}
194
195inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec)
196{
197 mV[VX] *= vec.mV[VX];
198 mV[VY] *= vec.mV[VY];
199
200 return *this;
201}
202
203inline BOOL LLVector2::isNull()
204{
205 if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] )
206 {
207 return TRUE;
208 }
209 return FALSE;
210}
211
212
213// LLVector2 Operators
214
215// For sorting. By convention, x is "more significant" than y.
216inline bool operator<(const LLVector2 &a, const LLVector2 &b)
217{
218 if( a.mV[VX] == b.mV[VX] )
219 {
220 return a.mV[VY] < b.mV[VY];
221 }
222 else
223 {
224 return a.mV[VX] < b.mV[VX];
225 }
226}
227
228
229inline LLVector2 operator+(const LLVector2 &a, const LLVector2 &b)
230{
231 LLVector2 c(a);
232 return c += b;
233}
234
235inline LLVector2 operator-(const LLVector2 &a, const LLVector2 &b)
236{
237 LLVector2 c(a);
238 return c -= b;
239}
240
241inline F32 operator*(const LLVector2 &a, const LLVector2 &b)
242{
243 return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1]);
244}
245
246inline LLVector2 operator%(const LLVector2 &a, const LLVector2 &b)
247{
248 return LLVector2(a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1], a.mV[1]*b.mV[0] - b.mV[1]*a.mV[0]);
249}
250
251inline LLVector2 operator/(const LLVector2 &a, F32 k)
252{
253 F32 t = 1.f / k;
254 return LLVector2( a.mV[0] * t, a.mV[1] * t );
255}
256
257inline LLVector2 operator*(const LLVector2 &a, F32 k)
258{
259 return LLVector2( a.mV[0] * k, a.mV[1] * k );
260}
261
262inline LLVector2 operator*(F32 k, const LLVector2 &a)
263{
264 return LLVector2( a.mV[0] * k, a.mV[1] * k );
265}
266
267inline bool operator==(const LLVector2 &a, const LLVector2 &b)
268{
269 return ( (a.mV[0] == b.mV[0])
270 &&(a.mV[1] == b.mV[1]));
271}
272
273inline bool operator!=(const LLVector2 &a, const LLVector2 &b)
274{
275 return ( (a.mV[0] != b.mV[0])
276 ||(a.mV[1] != b.mV[1]));
277}
278
279inline const LLVector2& operator+=(LLVector2 &a, const LLVector2 &b)
280{
281 a.mV[0] += b.mV[0];
282 a.mV[1] += b.mV[1];
283 return a;
284}
285
286inline const LLVector2& operator-=(LLVector2 &a, const LLVector2 &b)
287{
288 a.mV[0] -= b.mV[0];
289 a.mV[1] -= b.mV[1];
290 return a;
291}
292
293inline const LLVector2& operator%=(LLVector2 &a, const LLVector2 &b)
294{
295 LLVector2 ret(a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1], a.mV[1]*b.mV[0] - b.mV[1]*a.mV[0]);
296 a = ret;
297 return a;
298}
299
300inline const LLVector2& operator*=(LLVector2 &a, F32 k)
301{
302 a.mV[0] *= k;
303 a.mV[1] *= k;
304 return a;
305}
306
307inline const LLVector2& operator/=(LLVector2 &a, F32 k)
308{
309 F32 t = 1.f / k;
310 a.mV[0] *= t;
311 a.mV[1] *= t;
312 return a;
313}
314
315inline LLVector2 operator-(const LLVector2 &a)
316{
317 return LLVector2( -a.mV[0], -a.mV[1] );
318}
319
320inline std::ostream& operator<<(std::ostream& s, const LLVector2 &a)
321{
322 s << "{ " << a.mV[VX] << ", " << a.mV[VY] << " }";
323 return s;
324}
325
326#endif
diff --git a/linden/indra/llmath/v3color.cpp b/linden/indra/llmath/v3color.cpp
new file mode 100644
index 0000000..9428093
--- /dev/null
+++ b/linden/indra/llmath/v3color.cpp
@@ -0,0 +1,63 @@
1/**
2 * @file v3color.cpp
3 * @brief LLColor3 class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "v3color.h"
31#include "v4color.h"
32
33LLColor3 LLColor3::white(1.0f, 1.0f, 1.0f);
34LLColor3 LLColor3::black(0.0f, 0.0f, 0.0f);
35LLColor3 LLColor3::grey (0.5f, 0.5f, 0.5f);
36
37LLColor3::LLColor3(const LLColor4 &a)
38{
39 mV[0] = a.mV[0];
40 mV[1] = a.mV[1];
41 mV[2] = a.mV[2];
42}
43
44LLColor3::LLColor3(const LLSD &sd)
45{
46 mV[0] = (F32) sd[0].asReal();
47 mV[1] = (F32) sd[1].asReal();
48 mV[2] = (F32) sd[2].asReal();
49}
50
51const LLColor3& LLColor3::operator=(const LLColor4 &a)
52{
53 mV[0] = a.mV[0];
54 mV[1] = a.mV[1];
55 mV[2] = a.mV[2];
56 return (*this);
57}
58
59std::ostream& operator<<(std::ostream& s, const LLColor3 &a)
60{
61 s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << " }";
62 return s;
63}
diff --git a/linden/indra/llmath/v3color.h b/linden/indra/llmath/v3color.h
new file mode 100644
index 0000000..606a810
--- /dev/null
+++ b/linden/indra/llmath/v3color.h
@@ -0,0 +1,381 @@
1/**
2 * @file v3color.h
3 * @brief LLColor3 class header file.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_V3COLOR_H
29#define LL_V3COLOR_H
30
31class LLColor4;
32
33#include "llerror.h"
34#include "llmath.h"
35#include "llsd.h"
36
37// LLColor3 = |r g b|
38
39static const U32 LENGTHOFCOLOR3 = 3;
40
41class LLColor3
42{
43public:
44 F32 mV[LENGTHOFCOLOR3];
45
46 static LLColor3 white;
47 static LLColor3 black;
48 static LLColor3 grey;
49
50public:
51 LLColor3(); // Initializes LLColor3 to (0, 0, 0)
52 LLColor3(F32 r, F32 g, F32 b); // Initializes LLColor3 to (r, g, b)
53 LLColor3(const F32 *vec); // Initializes LLColor3 to (vec[0]. vec[1], vec[2])
54 LLColor3(char *color_string); // html format color ie "#FFDDEE"
55 explicit LLColor3(const LLColor4& color4); // "explicit" to avoid automatic conversion
56 LLColor3(const LLSD& sd);
57
58
59 LLSD getValue() const
60 {
61 LLSD ret;
62 ret[0] = mV[0];
63 ret[1] = mV[1];
64 ret[2] = mV[2];
65 return ret;
66 }
67
68 void setValue(const LLSD& sd)
69 {
70 mV[0] = (F32) sd[0].asReal();;
71 mV[1] = (F32) sd[1].asReal();;
72 mV[2] = (F32) sd[2].asReal();;
73 }
74
75 const LLColor3& setToBlack(); // Clears LLColor3 to (0, 0, 0)
76 const LLColor3& setToWhite(); // Zero LLColor3 to (0, 0, 0)
77 const LLColor3& setVec(F32 x, F32 y, F32 z); // Sets LLColor3 to (x, y, z)
78 const LLColor3& setVec(const LLColor3 &vec); // Sets LLColor3 to vec
79 const LLColor3& setVec(const F32 *vec); // Sets LLColor3 to vec
80
81 F32 magVec() const; // Returns magnitude of LLColor3
82 F32 magVecSquared() const; // Returns magnitude squared of LLColor3
83 F32 normVec(); // Normalizes and returns the magnitude of LLColor3
84
85 const LLColor3& operator=(const LLColor4 &a);
86
87 friend std::ostream& operator<<(std::ostream& s, const LLColor3 &a); // Print a
88 friend LLColor3 operator+(const LLColor3 &a, const LLColor3 &b); // Return vector a + b
89 friend LLColor3 operator-(const LLColor3 &a, const LLColor3 &b); // Return vector a minus b
90
91 friend const LLColor3& operator+=(LLColor3 &a, const LLColor3 &b); // Return vector a + b
92 friend const LLColor3& operator-=(LLColor3 &a, const LLColor3 &b); // Return vector a minus b
93 friend const LLColor3& operator*=(LLColor3 &a, const LLColor3 &b);
94
95 friend LLColor3 operator*(const LLColor3 &a, const LLColor3 &b); // Return a dot b
96 friend LLColor3 operator*(const LLColor3 &a, F32 k); // Return a times scaler k
97 friend LLColor3 operator*(F32 k, const LLColor3 &a); // Return a times scaler k
98
99 friend bool operator==(const LLColor3 &a, const LLColor3 &b); // Return a == b
100 friend bool operator!=(const LLColor3 &a, const LLColor3 &b); // Return a != b
101
102 friend const LLColor3& operator*=(LLColor3 &a, F32 k); // Return a times scaler k
103
104 friend LLColor3 operator-(const LLColor3 &a); // Return vector 1-rgb (inverse)
105
106 inline void clamp();
107 inline void exp(); // Do an exponential on the color
108};
109
110LLColor3 lerp(const LLColor3 &a, const LLColor3 &b, F32 u);
111
112
113void LLColor3::clamp()
114{
115 // Clamp the color...
116 if (mV[0] < 0.f)
117 {
118 mV[0] = 0.f;
119 }
120 else if (mV[0] > 1.f)
121 {
122 mV[0] = 1.f;
123 }
124 if (mV[1] < 0.f)
125 {
126 mV[1] = 0.f;
127 }
128 else if (mV[1] > 1.f)
129 {
130 mV[1] = 1.f;
131 }
132 if (mV[2] < 0.f)
133 {
134 mV[2] = 0.f;
135 }
136 else if (mV[2] > 1.f)
137 {
138 mV[2] = 1.f;
139 }
140}
141
142// Non-member functions
143F32 distVec(const LLColor3 &a, const LLColor3 &b); // Returns distance between a and b
144F32 distVec_squared(const LLColor3 &a, const LLColor3 &b);// Returns distance sqaured between a and b
145
146inline LLColor3::LLColor3(void)
147{
148 mV[0] = 0.f;
149 mV[1] = 0.f;
150 mV[2] = 0.f;
151}
152
153inline LLColor3::LLColor3(F32 r, F32 g, F32 b)
154{
155 mV[VX] = r;
156 mV[VY] = g;
157 mV[VZ] = b;
158}
159
160inline LLColor3::LLColor3(const F32 *vec)
161{
162 mV[VX] = vec[VX];
163 mV[VY] = vec[VY];
164 mV[VZ] = vec[VZ];
165}
166
167inline LLColor3::LLColor3(char* color_string) // takes a string of format "RRGGBB" where RR is hex 00..FF
168{
169 if (strlen(color_string) < 6)
170 {
171 mV[0] = 0.f;
172 mV[1] = 0.f;
173 mV[2] = 0.f;
174 return;
175 }
176
177 static char tempstr[7];
178 strncpy(tempstr,color_string,6);
179 tempstr[6] = '\0';
180 mV[VZ] = (F32)strtol(&tempstr[4],NULL,16)/255.f;
181 tempstr[4] = '\0';
182 mV[VY] = (F32)strtol(&tempstr[2],NULL,16)/255.f;
183 tempstr[2] = '\0';
184 mV[VX] = (F32)strtol(&tempstr[0],NULL,16)/255.f;
185}
186
187inline const LLColor3& LLColor3::setToBlack(void)
188{
189 mV[0] = 0.f;
190 mV[1] = 0.f;
191 mV[2] = 0.f;
192 return (*this);
193}
194
195inline const LLColor3& LLColor3::setToWhite(void)
196{
197 mV[0] = 1.f;
198 mV[1] = 1.f;
199 mV[2] = 1.f;
200 return (*this);
201}
202
203inline const LLColor3& LLColor3::setVec(F32 r, F32 g, F32 b)
204{
205 mV[0] = r;
206 mV[1] = g;
207 mV[2] = b;
208 return (*this);
209}
210
211inline const LLColor3& LLColor3::setVec(const LLColor3 &vec)
212{
213 mV[0] = vec.mV[0];
214 mV[1] = vec.mV[1];
215 mV[2] = vec.mV[2];
216 return (*this);
217}
218
219inline const LLColor3& LLColor3::setVec(const F32 *vec)
220{
221 mV[0] = vec[0];
222 mV[1] = vec[1];
223 mV[2] = vec[2];
224 return (*this);
225}
226
227inline F32 LLColor3::magVec(void) const
228{
229 return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
230}
231
232inline F32 LLColor3::magVecSquared(void) const
233{
234 return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2];
235}
236
237inline F32 LLColor3::normVec(void)
238{
239 F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
240 F32 oomag;
241
242 if (mag)
243 {
244 oomag = 1.f/mag;
245 mV[0] *= oomag;
246 mV[1] *= oomag;
247 mV[2] *= oomag;
248 }
249 return (mag);
250}
251
252inline void LLColor3::exp()
253{
254#if 0
255 mV[0] = ::exp(mV[0]);
256 mV[1] = ::exp(mV[1]);
257 mV[2] = ::exp(mV[2]);
258#else
259 mV[0] = (F32)LL_FAST_EXP(mV[0]);
260 mV[1] = (F32)LL_FAST_EXP(mV[1]);
261 mV[2] = (F32)LL_FAST_EXP(mV[2]);
262#endif
263}
264
265
266inline LLColor3 operator+(const LLColor3 &a, const LLColor3 &b)
267{
268 return LLColor3(
269 a.mV[0] + b.mV[0],
270 a.mV[1] + b.mV[1],
271 a.mV[2] + b.mV[2]);
272}
273
274inline LLColor3 operator-(const LLColor3 &a, const LLColor3 &b)
275{
276 return LLColor3(
277 a.mV[0] - b.mV[0],
278 a.mV[1] - b.mV[1],
279 a.mV[2] - b.mV[2]);
280}
281
282inline LLColor3 operator*(const LLColor3 &a, const LLColor3 &b)
283{
284 return LLColor3(
285 a.mV[0] * b.mV[0],
286 a.mV[1] * b.mV[1],
287 a.mV[2] * b.mV[2]);
288}
289
290inline LLColor3 operator*(const LLColor3 &a, F32 k)
291{
292 return LLColor3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k );
293}
294
295inline LLColor3 operator*(F32 k, const LLColor3 &a)
296{
297 return LLColor3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k );
298}
299
300inline bool operator==(const LLColor3 &a, const LLColor3 &b)
301{
302 return ( (a.mV[0] == b.mV[0])
303 &&(a.mV[1] == b.mV[1])
304 &&(a.mV[2] == b.mV[2]));
305}
306
307inline bool operator!=(const LLColor3 &a, const LLColor3 &b)
308{
309 return ( (a.mV[0] != b.mV[0])
310 ||(a.mV[1] != b.mV[1])
311 ||(a.mV[2] != b.mV[2]));
312}
313
314inline const LLColor3 &operator*=(LLColor3 &a, const LLColor3 &b)
315{
316 a.mV[0] *= b.mV[0];
317 a.mV[1] *= b.mV[1];
318 a.mV[2] *= b.mV[2];
319 return a;
320}
321
322inline const LLColor3& operator+=(LLColor3 &a, const LLColor3 &b)
323{
324 a.mV[0] += b.mV[0];
325 a.mV[1] += b.mV[1];
326 a.mV[2] += b.mV[2];
327 return a;
328}
329
330inline const LLColor3& operator-=(LLColor3 &a, const LLColor3 &b)
331{
332 a.mV[0] -= b.mV[0];
333 a.mV[1] -= b.mV[1];
334 a.mV[2] -= b.mV[2];
335 return a;
336}
337
338inline const LLColor3& operator*=(LLColor3 &a, F32 k)
339{
340 a.mV[0] *= k;
341 a.mV[1] *= k;
342 a.mV[2] *= k;
343 return a;
344}
345
346inline LLColor3 operator-(const LLColor3 &a)
347{
348 return LLColor3(
349 1.f - a.mV[0],
350 1.f - a.mV[1],
351 1.f - a.mV[2] );
352}
353
354// Non-member functions
355
356inline F32 distVec(const LLColor3 &a, const LLColor3 &b)
357{
358 F32 x = a.mV[0] - b.mV[0];
359 F32 y = a.mV[1] - b.mV[1];
360 F32 z = a.mV[2] - b.mV[2];
361 return fsqrtf( x*x + y*y + z*z );
362}
363
364inline F32 distVec_squared(const LLColor3 &a, const LLColor3 &b)
365{
366 F32 x = a.mV[0] - b.mV[0];
367 F32 y = a.mV[1] - b.mV[1];
368 F32 z = a.mV[2] - b.mV[2];
369 return x*x + y*y + z*z;
370}
371
372inline LLColor3 lerp(const LLColor3 &a, const LLColor3 &b, F32 u)
373{
374 return LLColor3(
375 a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
376 a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u,
377 a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u);
378}
379
380
381#endif
diff --git a/linden/indra/llmath/v3dmath.cpp b/linden/indra/llmath/v3dmath.cpp
new file mode 100644
index 0000000..5d3aad0
--- /dev/null
+++ b/linden/indra/llmath/v3dmath.cpp
@@ -0,0 +1,148 @@
1/**
2 * @file v3dmath.cpp
3 * @brief LLVector3d class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30//#include <sstream> // gcc 2.95.2 doesn't support sstream
31
32#include "v3dmath.h"
33
34//#include "vmath.h"
35#include "v4math.h"
36#include "m4math.h"
37#include "m3math.h"
38#include "llquaternion.h"
39#include "llquantize.h"
40
41// LLVector3d
42// WARNING: Don't use these for global const definitions!
43// For example:
44// const LLQuaternion(0.5f * F_PI, LLVector3d::zero);
45// at the top of a *.cpp file might not give you what you think.
46const LLVector3d LLVector3d::zero(0,0,0);
47const LLVector3d LLVector3d::x_axis(1, 0, 0);
48const LLVector3d LLVector3d::y_axis(0, 1, 0);
49const LLVector3d LLVector3d::z_axis(0, 0, 1);
50const LLVector3d LLVector3d::x_axis_neg(-1, 0, 0);
51const LLVector3d LLVector3d::y_axis_neg(0, -1, 0);
52const LLVector3d LLVector3d::z_axis_neg(0, 0, -1);
53
54
55// Clamps each values to range (min,max).
56// Returns TRUE if data changed.
57BOOL LLVector3d::clamp(F64 min, F64 max)
58{
59 BOOL ret = FALSE;
60
61 if (mdV[0] < min) { mdV[0] = min; ret = TRUE; }
62 if (mdV[1] < min) { mdV[1] = min; ret = TRUE; }
63 if (mdV[2] < min) { mdV[2] = min; ret = TRUE; }
64
65 if (mdV[0] > max) { mdV[0] = max; ret = TRUE; }
66 if (mdV[1] > max) { mdV[1] = max; ret = TRUE; }
67 if (mdV[2] > max) { mdV[2] = max; ret = TRUE; }
68
69 return ret;
70}
71
72// Sets all values to absolute value of their original values
73// Returns TRUE if data changed
74BOOL LLVector3d::abs()
75{
76 BOOL ret = FALSE;
77
78 if (mdV[0] < 0.0) { mdV[0] = -mdV[0]; ret = TRUE; }
79 if (mdV[1] < 0.0) { mdV[1] = -mdV[1]; ret = TRUE; }
80 if (mdV[2] < 0.0) { mdV[2] = -mdV[2]; ret = TRUE; }
81
82 return ret;
83}
84
85std::ostream& operator<<(std::ostream& s, const LLVector3d &a)
86{
87 s << "{ " << a.mdV[VX] << ", " << a.mdV[VY] << ", " << a.mdV[VZ] << " }";
88 return s;
89}
90
91const LLVector3d& LLVector3d::operator=(const LLVector4 &a)
92{
93 mdV[0] = a.mV[0];
94 mdV[1] = a.mV[1];
95 mdV[2] = a.mV[2];
96 return *this;
97}
98
99const LLVector3d& LLVector3d::rotVec(const LLMatrix3 &mat)
100{
101 *this = *this * mat;
102 return *this;
103}
104
105const LLVector3d& LLVector3d::rotVec(const LLQuaternion &q)
106{
107 *this = *this * q;
108 return *this;
109}
110
111const LLVector3d& LLVector3d::rotVec(F64 angle, const LLVector3d &vec)
112{
113 if ( !vec.isExactlyZero() && angle )
114 {
115 *this = *this * LLMatrix3((F32)angle, vec);
116 }
117 return *this;
118}
119
120const LLVector3d& LLVector3d::rotVec(F64 angle, F64 x, F64 y, F64 z)
121{
122 LLVector3d vec(x, y, z);
123 if ( !vec.isExactlyZero() && angle )
124 {
125 *this = *this * LLMatrix3((F32)angle, vec);
126 }
127 return *this;
128}
129
130
131BOOL LLVector3d::parseVector3d(const char* buf, LLVector3d* value)
132{
133 if( buf == NULL || buf[0] == '\0' || value == NULL)
134 {
135 return FALSE;
136 }
137
138 LLVector3d v;
139 S32 count = sscanf( buf, "%lf %lf %lf", v.mdV + 0, v.mdV + 1, v.mdV + 2 );
140 if( 3 == count )
141 {
142 value->setVec( v );
143 return TRUE;
144 }
145
146 return FALSE;
147}
148
diff --git a/linden/indra/llmath/v3dmath.h b/linden/indra/llmath/v3dmath.h
new file mode 100644
index 0000000..da13cc3
--- /dev/null
+++ b/linden/indra/llmath/v3dmath.h
@@ -0,0 +1,437 @@
1/**
2 * @file v3dmath.h
3 * @brief High precision 3 dimensional vector.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_V3DMATH_H
29#define LL_V3DMATH_H
30
31#include "llerror.h"
32#include "v3math.h"
33
34class LLVector3d
35{
36 public:
37 F64 mdV[3];
38
39 const static LLVector3d zero;
40 const static LLVector3d x_axis;
41 const static LLVector3d y_axis;
42 const static LLVector3d z_axis;
43 const static LLVector3d x_axis_neg;
44 const static LLVector3d y_axis_neg;
45 const static LLVector3d z_axis_neg;
46
47 inline LLVector3d(); // Initializes LLVector3d to (0, 0, 0)
48 inline LLVector3d(const F64 x, const F64 y, const F64 z); // Initializes LLVector3d to (x. y, z)
49 inline explicit LLVector3d(const F64 *vec); // Initializes LLVector3d to (vec[0]. vec[1], vec[2])
50 inline explicit LLVector3d(const LLVector3 &vec);
51 LLVector3d(const LLSD& sd)
52 {
53 setValue(sd);
54 }
55
56 void setValue(const LLSD& sd)
57 {
58 mdV[0] = sd[0].asReal();
59 mdV[1] = sd[1].asReal();
60 mdV[2] = sd[2].asReal();
61 }
62
63 const LLVector3d& operator=(const LLSD& sd)
64 {
65 setValue(sd);
66 return *this;
67 }
68
69 LLSD getValue() const
70 {
71 LLSD ret;
72 ret[0] = mdV[0];
73 ret[1] = mdV[1];
74 ret[2] = mdV[2];
75 return ret;
76 }
77
78 inline BOOL isFinite() const; // checks to see if all values of LLVector3d are finite
79 BOOL clamp(const F64 min, const F64 max); // Clamps all values to (min,max), returns TRUE if data changed
80 BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed
81
82 inline const LLVector3d& clearVec(); // Clears LLVector3d to (0, 0, 0, 1)
83 inline const LLVector3d& zeroVec(); // Zero LLVector3d to (0, 0, 0, 0)
84 inline const LLVector3d& setVec(const F64 x, const F64 y, const F64 z); // Sets LLVector3d to (x, y, z, 1)
85 inline const LLVector3d& setVec(const LLVector3d &vec); // Sets LLVector3d to vec
86 inline const LLVector3d& setVec(const F64 *vec); // Sets LLVector3d to vec
87 inline const LLVector3d& setVec(const LLVector3 &vec);
88
89 F64 magVec() const; // Returns magnitude of LLVector3d
90 F64 magVecSquared() const; // Returns magnitude squared of LLVector3d
91 inline F64 normVec(); // Normalizes and returns the magnitude of LLVector3d
92
93 const LLVector3d& rotVec(const F64 angle, const LLVector3d &vec); // Rotates about vec by angle radians
94 const LLVector3d& rotVec(const F64 angle, const F64 x, const F64 y, const F64 z); // Rotates about x,y,z by angle radians
95 const LLVector3d& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
96 const LLVector3d& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
97
98 BOOL isNull() const; // Returns TRUE if vector has a _very_small_ length
99 BOOL isExactlyZero() const { return !mdV[VX] && !mdV[VY] && !mdV[VZ]; }
100
101 const LLVector3d& operator=(const LLVector4 &a);
102
103 F64 operator[](int idx) const { return mdV[idx]; }
104 F64 &operator[](int idx) { return mdV[idx]; }
105
106 friend LLVector3d operator+(const LLVector3d &a, const LLVector3d &b); // Return vector a + b
107 friend LLVector3d operator-(const LLVector3d &a, const LLVector3d &b); // Return vector a minus b
108 friend F64 operator*(const LLVector3d &a, const LLVector3d &b); // Return a dot b
109 friend LLVector3d operator%(const LLVector3d &a, const LLVector3d &b); // Return a cross b
110 friend LLVector3d operator*(const LLVector3d &a, const F64 k); // Return a times scaler k
111 friend LLVector3d operator/(const LLVector3d &a, const F64 k); // Return a divided by scaler k
112 friend LLVector3d operator*(const F64 k, const LLVector3d &a); // Return a times scaler k
113 friend bool operator==(const LLVector3d &a, const LLVector3d &b); // Return a == b
114 friend bool operator!=(const LLVector3d &a, const LLVector3d &b); // Return a != b
115
116 friend const LLVector3d& operator+=(LLVector3d &a, const LLVector3d &b); // Return vector a + b
117 friend const LLVector3d& operator-=(LLVector3d &a, const LLVector3d &b); // Return vector a minus b
118 friend const LLVector3d& operator%=(LLVector3d &a, const LLVector3d &b); // Return a cross b
119 friend const LLVector3d& operator*=(LLVector3d &a, const F64 k); // Return a times scaler k
120 friend const LLVector3d& operator/=(LLVector3d &a, const F64 k); // Return a divided by scaler k
121
122 friend LLVector3d operator-(const LLVector3d &a); // Return vector -a
123
124 friend std::ostream& operator<<(std::ostream& s, const LLVector3d &a); // Stream a
125
126 static BOOL parseVector3d(const char* buf, LLVector3d* value);
127
128};
129
130typedef LLVector3d LLGlobalVec;
131
132const LLVector3d &LLVector3d::setVec(const LLVector3 &vec)
133{
134 mdV[0] = vec.mV[0];
135 mdV[1] = vec.mV[1];
136 mdV[2] = vec.mV[2];
137 return *this;
138}
139
140
141inline LLVector3d::LLVector3d(void)
142{
143 mdV[0] = 0.f;
144 mdV[1] = 0.f;
145 mdV[2] = 0.f;
146}
147
148inline LLVector3d::LLVector3d(const F64 x, const F64 y, const F64 z)
149{
150 mdV[VX] = x;
151 mdV[VY] = y;
152 mdV[VZ] = z;
153}
154
155inline LLVector3d::LLVector3d(const F64 *vec)
156{
157 mdV[VX] = vec[VX];
158 mdV[VY] = vec[VY];
159 mdV[VZ] = vec[VZ];
160}
161
162inline LLVector3d::LLVector3d(const LLVector3 &vec)
163{
164 mdV[VX] = vec.mV[VX];
165 mdV[VY] = vec.mV[VY];
166 mdV[VZ] = vec.mV[VZ];
167}
168
169/*
170inline LLVector3d::LLVector3d(const LLVector3d &copy)
171{
172 mdV[VX] = copy.mdV[VX];
173 mdV[VY] = copy.mdV[VY];
174 mdV[VZ] = copy.mdV[VZ];
175}
176*/
177
178// Destructors
179
180// checker
181inline BOOL LLVector3d::isFinite() const
182{
183 return (llfinite(mdV[VX]) && llfinite(mdV[VY]) && llfinite(mdV[VZ]));
184}
185
186
187// Clear and Assignment Functions
188
189inline const LLVector3d& LLVector3d::clearVec(void)
190{
191 mdV[0] = 0.f;
192 mdV[1] = 0.f;
193 mdV[2]= 0.f;
194 return (*this);
195}
196
197inline const LLVector3d& LLVector3d::zeroVec(void)
198{
199 mdV[0] = 0.f;
200 mdV[1] = 0.f;
201 mdV[2] = 0.f;
202 return (*this);
203}
204
205inline const LLVector3d& LLVector3d::setVec(const F64 x, const F64 y, const F64 z)
206{
207 mdV[VX] = x;
208 mdV[VY] = y;
209 mdV[VZ] = z;
210 return (*this);
211}
212
213inline const LLVector3d& LLVector3d::setVec(const LLVector3d &vec)
214{
215 mdV[0] = vec.mdV[0];
216 mdV[1] = vec.mdV[1];
217 mdV[2] = vec.mdV[2];
218 return (*this);
219}
220
221inline const LLVector3d& LLVector3d::setVec(const F64 *vec)
222{
223 mdV[0] = vec[0];
224 mdV[1] = vec[1];
225 mdV[2] = vec[2];
226 return (*this);
227}
228
229inline F64 LLVector3d::normVec(void)
230{
231 F64 mag = fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
232 F64 oomag;
233
234 if (mag > FP_MAG_THRESHOLD)
235 {
236 oomag = 1.f/mag;
237 mdV[0] *= oomag;
238 mdV[1] *= oomag;
239 mdV[2] *= oomag;
240 }
241 else
242 {
243 mdV[0] = 0.f;
244 mdV[1] = 0.f;
245 mdV[2] = 0.f;
246 mag = 0;
247 }
248 return (mag);
249}
250
251// LLVector3d Magnitude and Normalization Functions
252
253inline F64 LLVector3d::magVec(void) const
254{
255 return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
256}
257
258inline F64 LLVector3d::magVecSquared(void) const
259{
260 return mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2];
261}
262
263inline LLVector3d operator+(const LLVector3d &a, const LLVector3d &b)
264{
265 LLVector3d c(a);
266 return c += b;
267}
268
269inline LLVector3d operator-(const LLVector3d &a, const LLVector3d &b)
270{
271 LLVector3d c(a);
272 return c -= b;
273}
274
275inline F64 operator*(const LLVector3d &a, const LLVector3d &b)
276{
277 return (a.mdV[0]*b.mdV[0] + a.mdV[1]*b.mdV[1] + a.mdV[2]*b.mdV[2]);
278}
279
280inline LLVector3d operator%(const LLVector3d &a, const LLVector3d &b)
281{
282 return LLVector3d( a.mdV[1]*b.mdV[2] - b.mdV[1]*a.mdV[2], a.mdV[2]*b.mdV[0] - b.mdV[2]*a.mdV[0], a.mdV[0]*b.mdV[1] - b.mdV[0]*a.mdV[1] );
283}
284
285inline LLVector3d operator/(const LLVector3d &a, const F64 k)
286{
287 F64 t = 1.f / k;
288 return LLVector3d( a.mdV[0] * t, a.mdV[1] * t, a.mdV[2] * t );
289}
290
291inline LLVector3d operator*(const LLVector3d &a, const F64 k)
292{
293 return LLVector3d( a.mdV[0] * k, a.mdV[1] * k, a.mdV[2] * k );
294}
295
296inline LLVector3d operator*(F64 k, const LLVector3d &a)
297{
298 return LLVector3d( a.mdV[0] * k, a.mdV[1] * k, a.mdV[2] * k );
299}
300
301inline bool operator==(const LLVector3d &a, const LLVector3d &b)
302{
303 return ( (a.mdV[0] == b.mdV[0])
304 &&(a.mdV[1] == b.mdV[1])
305 &&(a.mdV[2] == b.mdV[2]));
306}
307
308inline bool operator!=(const LLVector3d &a, const LLVector3d &b)
309{
310 return ( (a.mdV[0] != b.mdV[0])
311 ||(a.mdV[1] != b.mdV[1])
312 ||(a.mdV[2] != b.mdV[2]));
313}
314
315inline const LLVector3d& operator+=(LLVector3d &a, const LLVector3d &b)
316{
317 a.mdV[0] += b.mdV[0];
318 a.mdV[1] += b.mdV[1];
319 a.mdV[2] += b.mdV[2];
320 return a;
321}
322
323inline const LLVector3d& operator-=(LLVector3d &a, const LLVector3d &b)
324{
325 a.mdV[0] -= b.mdV[0];
326 a.mdV[1] -= b.mdV[1];
327 a.mdV[2] -= b.mdV[2];
328 return a;
329}
330
331inline const LLVector3d& operator%=(LLVector3d &a, const LLVector3d &b)
332{
333 LLVector3d ret( a.mdV[1]*b.mdV[2] - b.mdV[1]*a.mdV[2], a.mdV[2]*b.mdV[0] - b.mdV[2]*a.mdV[0], a.mdV[0]*b.mdV[1] - b.mdV[0]*a.mdV[1]);
334 a = ret;
335 return a;
336}
337
338inline const LLVector3d& operator*=(LLVector3d &a, const F64 k)
339{
340 a.mdV[0] *= k;
341 a.mdV[1] *= k;
342 a.mdV[2] *= k;
343 return a;
344}
345
346inline const LLVector3d& operator/=(LLVector3d &a, const F64 k)
347{
348 F64 t = 1.f / k;
349 a.mdV[0] *= t;
350 a.mdV[1] *= t;
351 a.mdV[2] *= t;
352 return a;
353}
354
355inline LLVector3d operator-(const LLVector3d &a)
356{
357 return LLVector3d( -a.mdV[0], -a.mdV[1], -a.mdV[2] );
358}
359
360inline F64 dist_vec(const LLVector3d &a, const LLVector3d &b)
361{
362 F64 x = a.mdV[0] - b.mdV[0];
363 F64 y = a.mdV[1] - b.mdV[1];
364 F64 z = a.mdV[2] - b.mdV[2];
365 return fsqrtf( x*x + y*y + z*z );
366}
367
368inline F64 dist_vec_squared(const LLVector3d &a, const LLVector3d &b)
369{
370 F64 x = a.mdV[0] - b.mdV[0];
371 F64 y = a.mdV[1] - b.mdV[1];
372 F64 z = a.mdV[2] - b.mdV[2];
373 return x*x + y*y + z*z;
374}
375
376inline F64 dist_vec_squared2D(const LLVector3d &a, const LLVector3d &b)
377{
378 F64 x = a.mdV[0] - b.mdV[0];
379 F64 y = a.mdV[1] - b.mdV[1];
380 return x*x + y*y;
381}
382
383inline LLVector3d lerp(const LLVector3d &a, const LLVector3d &b, const F64 u)
384{
385 return LLVector3d(
386 a.mdV[VX] + (b.mdV[VX] - a.mdV[VX]) * u,
387 a.mdV[VY] + (b.mdV[VY] - a.mdV[VY]) * u,
388 a.mdV[VZ] + (b.mdV[VZ] - a.mdV[VZ]) * u);
389}
390
391
392inline BOOL LLVector3d::isNull() const
393{
394 if ( F_APPROXIMATELY_ZERO > mdV[VX]*mdV[VX] + mdV[VY]*mdV[VY] + mdV[VZ]*mdV[VZ] )
395 {
396 return TRUE;
397 }
398 return FALSE;
399}
400
401
402inline F64 angle_between(const LLVector3d& a, const LLVector3d& b)
403{
404 LLVector3d an = a;
405 LLVector3d bn = b;
406 an.normVec();
407 bn.normVec();
408 F64 cosine = an * bn;
409 F64 angle = (cosine >= 1.0f) ? 0.0f :
410 (cosine <= -1.0f) ? F_PI :
411 acos(cosine);
412 return angle;
413}
414
415inline BOOL are_parallel(const LLVector3d &a, const LLVector3d &b, const F64 epsilon)
416{
417 LLVector3d an = a;
418 LLVector3d bn = b;
419 an.normVec();
420 bn.normVec();
421 F64 dot = an * bn;
422 if ( (1.0f - fabs(dot)) < epsilon)
423 {
424 return TRUE;
425 }
426 return FALSE;
427
428}
429
430inline LLVector3d projected_vec(const LLVector3d &a, const LLVector3d &b)
431{
432 LLVector3d project_axis = b;
433 project_axis.normVec();
434 return project_axis * (a * project_axis);
435}
436
437#endif // LL_V3DMATH_H
diff --git a/linden/indra/llmath/v3math.cpp b/linden/indra/llmath/v3math.cpp
new file mode 100644
index 0000000..39d3b70
--- /dev/null
+++ b/linden/indra/llmath/v3math.cpp
@@ -0,0 +1,232 @@
1/**
2 * @file v3math.cpp
3 * @brief LLVector3 class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "v3math.h"
31
32//#include "vmath.h"
33#include "v4math.h"
34#include "m4math.h"
35#include "m3math.h"
36#include "llquaternion.h"
37#include "llquantize.h"
38#include "v3dmath.h"
39
40// LLVector3
41// WARNING: Don't use these for global const definitions!
42// For example:
43// const LLQuaternion(0.5f * F_PI, LLVector3::zero);
44// at the top of a *.cpp file might not give you what you think.
45const LLVector3 LLVector3::zero(0,0,0);
46const LLVector3 LLVector3::x_axis(1.f, 0, 0);
47const LLVector3 LLVector3::y_axis(0, 1.f, 0);
48const LLVector3 LLVector3::z_axis(0, 0, 1.f);
49const LLVector3 LLVector3::x_axis_neg(-1.f, 0, 0);
50const LLVector3 LLVector3::y_axis_neg(0, -1.f, 0);
51const LLVector3 LLVector3::z_axis_neg(0, 0, -1.f);
52const LLVector3 LLVector3::all_one(1.f,1.f,1.f);
53
54
55// Clamps each values to range (min,max).
56// Returns TRUE if data changed.
57BOOL LLVector3::clamp(F32 min, F32 max)
58{
59 BOOL ret = FALSE;
60
61 if (mV[0] < min) { mV[0] = min; ret = TRUE; }
62 if (mV[1] < min) { mV[1] = min; ret = TRUE; }
63 if (mV[2] < min) { mV[2] = min; ret = TRUE; }
64
65 if (mV[0] > max) { mV[0] = max; ret = TRUE; }
66 if (mV[1] > max) { mV[1] = max; ret = TRUE; }
67 if (mV[2] > max) { mV[2] = max; ret = TRUE; }
68
69 return ret;
70}
71
72// Sets all values to absolute value of their original values
73// Returns TRUE if data changed
74BOOL LLVector3::abs()
75{
76 BOOL ret = FALSE;
77
78 if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = TRUE; }
79 if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = TRUE; }
80 if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = TRUE; }
81
82 return ret;
83}
84
85// Quatizations
86void LLVector3::quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz)
87{
88 F32 x = mV[VX];
89 F32 y = mV[VY];
90 F32 z = mV[VZ];
91
92 x = U16_to_F32(F32_to_U16(x, lowerxy, upperxy), lowerxy, upperxy);
93 y = U16_to_F32(F32_to_U16(y, lowerxy, upperxy), lowerxy, upperxy);
94 z = U16_to_F32(F32_to_U16(z, lowerz, upperz), lowerz, upperz);
95
96 mV[VX] = x;
97 mV[VY] = y;
98 mV[VZ] = z;
99}
100
101void LLVector3::quantize8(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz)
102{
103 mV[VX] = U8_to_F32(F32_to_U8(mV[VX], lowerxy, upperxy), lowerxy, upperxy);;
104 mV[VY] = U8_to_F32(F32_to_U8(mV[VY], lowerxy, upperxy), lowerxy, upperxy);
105 mV[VZ] = U8_to_F32(F32_to_U8(mV[VZ], lowerz, upperz), lowerz, upperz);
106}
107
108
109void LLVector3::snap(S32 sig_digits)
110{
111 mV[VX] = snap_to_sig_figs(mV[VX], sig_digits);
112 mV[VY] = snap_to_sig_figs(mV[VY], sig_digits);
113 mV[VZ] = snap_to_sig_figs(mV[VZ], sig_digits);
114}
115
116
117std::ostream& operator<<(std::ostream& s, const LLVector3 &a)
118{
119 s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << " }";
120 return s;
121}
122
123
124const LLVector3& LLVector3::rotVec(const LLMatrix3 &mat)
125{
126 *this = *this * mat;
127 return *this;
128}
129
130const LLVector3& LLVector3::rotVec(const LLQuaternion &q)
131{
132 *this = *this * q;
133 return *this;
134}
135
136const LLVector3& LLVector3::rotVec(F32 angle, const LLVector3 &vec)
137{
138 if ( !vec.isExactlyZero() && angle )
139 {
140 *this = *this * LLMatrix3(angle, vec);
141 }
142 return *this;
143}
144
145const LLVector3& LLVector3::rotVec(F32 angle, F32 x, F32 y, F32 z)
146{
147 LLVector3 vec(x, y, z);
148 if ( !vec.isExactlyZero() && angle )
149 {
150 *this = *this * LLMatrix3(angle, vec);
151 }
152 return *this;
153}
154
155const LLVector3& LLVector3::scaleVec(const LLVector3& vec)
156{
157 mV[VX] *= vec.mV[VX];
158 mV[VY] *= vec.mV[VY];
159 mV[VZ] *= vec.mV[VZ];
160
161 return *this;
162}
163
164LLVector3 LLVector3::scaledVec(const LLVector3& vec) const
165{
166 LLVector3 ret = LLVector3(*this);
167 ret.scaleVec(vec);
168 return ret;
169}
170
171const LLVector3& LLVector3::setVec(const LLVector3d &vec)
172{
173 mV[0] = (F32)vec.mdV[0];
174 mV[1] = (F32)vec.mdV[1];
175 mV[2] = (F32)vec.mdV[2];
176 return (*this);
177}
178
179const LLVector3& LLVector3::setVec(const LLVector4 &vec)
180{
181 mV[0] = vec.mV[0];
182 mV[1] = vec.mV[1];
183 mV[2] = vec.mV[2];
184 return (*this);
185}
186
187LLVector3::LLVector3(const LLVector3d &vec)
188{
189 mV[VX] = (F32)vec.mdV[VX];
190 mV[VY] = (F32)vec.mdV[VY];
191 mV[VZ] = (F32)vec.mdV[VZ];
192}
193
194LLVector3::LLVector3(const LLVector4 &vec)
195{
196 mV[VX] = (F32)vec.mV[VX];
197 mV[VY] = (F32)vec.mV[VY];
198 mV[VZ] = (F32)vec.mV[VZ];
199}
200
201const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &rot)
202{
203 const F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ];
204 const F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY];
205 const F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ];
206 const F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX];
207
208 a.mV[VX] = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY];
209 a.mV[VY] = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ];
210 a.mV[VZ] = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX];
211
212 return a;
213}
214
215// static
216BOOL LLVector3::parseVector3(const char* buf, LLVector3* value)
217{
218 if( buf == NULL || buf[0] == '\0' || value == NULL)
219 {
220 return FALSE;
221 }
222
223 LLVector3 v;
224 S32 count = sscanf( buf, "%f %f %f", v.mV + 0, v.mV + 1, v.mV + 2 );
225 if( 3 == count )
226 {
227 value->setVec( v );
228 return TRUE;
229 }
230
231 return FALSE;
232}
diff --git a/linden/indra/llmath/v3math.h b/linden/indra/llmath/v3math.h
new file mode 100644
index 0000000..68e60de
--- /dev/null
+++ b/linden/indra/llmath/v3math.h
@@ -0,0 +1,465 @@
1/**
2 * @file v3math.h
3 * @brief LLVector3 class header file.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_V3MATH_H
29#define LL_V3MATH_H
30
31#include "llerror.h"
32#include "llmath.h"
33
34#include "llsd.h"
35class LLVector4;
36class LLMatrix3;
37class LLVector3d;
38class LLQuaternion;
39
40// Llvector3 = |x y z w|
41
42static const U32 LENGTHOFVECTOR3 = 3;
43
44class LLVector3
45{
46 public:
47 F32 mV[LENGTHOFVECTOR3];
48
49 static const LLVector3 zero;
50 static const LLVector3 x_axis;
51 static const LLVector3 y_axis;
52 static const LLVector3 z_axis;
53 static const LLVector3 x_axis_neg;
54 static const LLVector3 y_axis_neg;
55 static const LLVector3 z_axis_neg;
56 static const LLVector3 all_one;
57
58 inline LLVector3(); // Initializes LLVector3 to (0, 0, 0)
59 inline LLVector3(const F32 x, const F32 y, const F32 z); // Initializes LLVector3 to (x. y, z)
60 inline explicit LLVector3(const F32 *vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2])
61 explicit LLVector3(const LLVector3d &vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2])
62 explicit LLVector3(const LLVector4 &vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2])
63 LLVector3(const LLSD& sd)
64 {
65 setValue(sd);
66 }
67
68 LLSD getValue() const
69 {
70 LLSD ret;
71 ret[0] = mV[0];
72 ret[1] = mV[1];
73 ret[2] = mV[2];
74 return ret;
75 }
76
77 void setValue(const LLSD& sd)
78 {
79 mV[0] = (F32) sd[0].asReal();
80 mV[1] = (F32) sd[1].asReal();
81 mV[2] = (F32) sd[2].asReal();
82 }
83
84 const LLVector3& operator=(const LLSD& sd)
85 {
86 setValue(sd);
87 return *this;
88 }
89
90 inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite
91 BOOL clamp(F32 min, F32 max); // Clamps all values to (min,max), returns TRUE if data changed
92
93 void quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization
94 void quantize8(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization
95 void snap(S32 sig_digits); // snaps x,y,z to sig_digits decimal places
96
97 BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed
98
99 inline void clearVec(); // Clears LLVector3 to (0, 0, 0, 1)
100 inline void zeroVec(); // Zero LLVector3 to (0, 0, 0, 0)
101 inline void setVec(F32 x, F32 y, F32 z); // Sets LLVector3 to (x, y, z, 1)
102 inline void setVec(const LLVector3 &vec); // Sets LLVector3 to vec
103 inline void setVec(const F32 *vec); // Sets LLVector3 to vec
104
105 const LLVector3& setVec(const LLVector4 &vec);
106 const LLVector3& setVec(const LLVector3d &vec); // Sets LLVector3 to vec
107
108 F32 magVec() const; // Returns magnitude of LLVector3
109 F32 magVecSquared() const; // Returns magnitude squared of LLVector3
110 inline F32 normVec(); // Normalizes and returns the magnitude of LLVector3
111
112 const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians
113 const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
114 const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
115 const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
116
117 const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
118 LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
119
120 BOOL isNull() const; // Returns TRUE if vector has a _very_small_ length
121 BOOL isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; }
122
123 F32 operator[](int idx) const { return mV[idx]; }
124 F32 &operator[](int idx) { return mV[idx]; }
125
126 friend LLVector3 operator+(const LLVector3 &a, const LLVector3 &b); // Return vector a + b
127 friend LLVector3 operator-(const LLVector3 &a, const LLVector3 &b); // Return vector a minus b
128 friend F32 operator*(const LLVector3 &a, const LLVector3 &b); // Return a dot b
129 friend LLVector3 operator%(const LLVector3 &a, const LLVector3 &b); // Return a cross b
130 friend LLVector3 operator*(const LLVector3 &a, F32 k); // Return a times scaler k
131 friend LLVector3 operator/(const LLVector3 &a, F32 k); // Return a divided by scaler k
132 friend LLVector3 operator*(F32 k, const LLVector3 &a); // Return a times scaler k
133 friend bool operator==(const LLVector3 &a, const LLVector3 &b); // Return a == b
134 friend bool operator!=(const LLVector3 &a, const LLVector3 &b); // Return a != b
135 // less than operator useful for using vectors as std::map keys
136 friend bool operator<(const LLVector3 &a, const LLVector3 &b); // Return a < b
137
138 friend const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b); // Return vector a + b
139 friend const LLVector3& operator-=(LLVector3 &a, const LLVector3 &b); // Return vector a minus b
140 friend const LLVector3& operator%=(LLVector3 &a, const LLVector3 &b); // Return a cross b
141 friend const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b); // Returns a * b;
142 friend const LLVector3& operator*=(LLVector3 &a, F32 k); // Return a times scaler k
143 friend const LLVector3& operator/=(LLVector3 &a, F32 k); // Return a divided by scaler k
144 friend const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &b); // Returns a * b;
145
146 friend LLVector3 operator-(const LLVector3 &a); // Return vector -a
147
148 friend std::ostream& operator<<(std::ostream& s, const LLVector3 &a); // Stream a
149
150 static BOOL parseVector3(const char* buf, LLVector3* value);
151};
152
153typedef LLVector3 LLSimLocalVec;
154
155// Non-member functions
156
157F32 angle_between(const LLVector3 &a, const LLVector3 &b); // Returns angle (radians) between a and b
158BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel
159F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance between a and b
160F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance sqaured between a and b
161F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance sqaured between a and b ignoring Z component
162LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b
163LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b
164
165inline LLVector3::LLVector3(void)
166{
167 mV[0] = 0.f;
168 mV[1] = 0.f;
169 mV[2] = 0.f;
170}
171
172inline LLVector3::LLVector3(const F32 x, const F32 y, const F32 z)
173{
174 mV[VX] = x;
175 mV[VY] = y;
176 mV[VZ] = z;
177}
178
179inline LLVector3::LLVector3(const F32 *vec)
180{
181 mV[VX] = vec[VX];
182 mV[VY] = vec[VY];
183 mV[VZ] = vec[VZ];
184}
185
186/*
187inline LLVector3::LLVector3(const LLVector3 &copy)
188{
189 mV[VX] = copy.mV[VX];
190 mV[VY] = copy.mV[VY];
191 mV[VZ] = copy.mV[VZ];
192}
193*/
194
195// Destructors
196
197// checker
198inline BOOL LLVector3::isFinite() const
199{
200 return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]));
201}
202
203
204// Clear and Assignment Functions
205
206inline void LLVector3::clearVec(void)
207{
208 mV[0] = 0.f;
209 mV[1] = 0.f;
210 mV[2] = 0.f;
211}
212
213inline void LLVector3::zeroVec(void)
214{
215 mV[0] = 0.f;
216 mV[1] = 0.f;
217 mV[2] = 0.f;
218}
219
220inline void LLVector3::setVec(F32 x, F32 y, F32 z)
221{
222 mV[VX] = x;
223 mV[VY] = y;
224 mV[VZ] = z;
225}
226
227inline void LLVector3::setVec(const LLVector3 &vec)
228{
229 mV[0] = vec.mV[0];
230 mV[1] = vec.mV[1];
231 mV[2] = vec.mV[2];
232}
233
234inline void LLVector3::setVec(const F32 *vec)
235{
236 mV[0] = vec[0];
237 mV[1] = vec[1];
238 mV[2] = vec[2];
239}
240
241inline F32 LLVector3::normVec(void)
242{
243 F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
244 F32 oomag;
245
246 if (mag > FP_MAG_THRESHOLD)
247 {
248 oomag = 1.f/mag;
249 mV[0] *= oomag;
250 mV[1] *= oomag;
251 mV[2] *= oomag;
252 }
253 else
254 {
255 mV[0] = 0.f;
256 mV[1] = 0.f;
257 mV[2] = 0.f;
258 mag = 0;
259 }
260 return (mag);
261}
262
263// LLVector3 Magnitude and Normalization Functions
264
265inline F32 LLVector3::magVec(void) const
266{
267 return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
268}
269
270inline F32 LLVector3::magVecSquared(void) const
271{
272 return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2];
273}
274
275inline LLVector3 operator+(const LLVector3 &a, const LLVector3 &b)
276{
277 LLVector3 c(a);
278 return c += b;
279}
280
281inline LLVector3 operator-(const LLVector3 &a, const LLVector3 &b)
282{
283 LLVector3 c(a);
284 return c -= b;
285}
286
287inline F32 operator*(const LLVector3 &a, const LLVector3 &b)
288{
289 return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]);
290}
291
292inline LLVector3 operator%(const LLVector3 &a, const LLVector3 &b)
293{
294 return LLVector3( a.mV[1]*b.mV[2] - b.mV[1]*a.mV[2], a.mV[2]*b.mV[0] - b.mV[2]*a.mV[0], a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1] );
295}
296
297inline LLVector3 operator/(const LLVector3 &a, F32 k)
298{
299 F32 t = 1.f / k;
300 return LLVector3( a.mV[0] * t, a.mV[1] * t, a.mV[2] * t );
301}
302
303inline LLVector3 operator*(const LLVector3 &a, F32 k)
304{
305 return LLVector3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k );
306}
307
308inline LLVector3 operator*(F32 k, const LLVector3 &a)
309{
310 return LLVector3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k );
311}
312
313inline bool operator==(const LLVector3 &a, const LLVector3 &b)
314{
315 return ( (a.mV[0] == b.mV[0])
316 &&(a.mV[1] == b.mV[1])
317 &&(a.mV[2] == b.mV[2]));
318}
319
320inline bool operator!=(const LLVector3 &a, const LLVector3 &b)
321{
322 return ( (a.mV[0] != b.mV[0])
323 ||(a.mV[1] != b.mV[1])
324 ||(a.mV[2] != b.mV[2]));
325}
326
327inline bool operator<(const LLVector3 &a, const LLVector3 &b)
328{
329 return (a.mV[0] < b.mV[0]
330 || (a.mV[0] == b.mV[0]
331 && (a.mV[1] < b.mV[1]
332 || (a.mV[1] == b.mV[1])
333 && a.mV[2] < b.mV[2])));
334}
335
336inline const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b)
337{
338 a.mV[0] += b.mV[0];
339 a.mV[1] += b.mV[1];
340 a.mV[2] += b.mV[2];
341 return a;
342}
343
344inline const LLVector3& operator-=(LLVector3 &a, const LLVector3 &b)
345{
346 a.mV[0] -= b.mV[0];
347 a.mV[1] -= b.mV[1];
348 a.mV[2] -= b.mV[2];
349 return a;
350}
351
352inline const LLVector3& operator%=(LLVector3 &a, const LLVector3 &b)
353{
354 LLVector3 ret( a.mV[1]*b.mV[2] - b.mV[1]*a.mV[2], a.mV[2]*b.mV[0] - b.mV[2]*a.mV[0], a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1]);
355 a = ret;
356 return a;
357}
358
359inline const LLVector3& operator*=(LLVector3 &a, F32 k)
360{
361 a.mV[0] *= k;
362 a.mV[1] *= k;
363 a.mV[2] *= k;
364 return a;
365}
366
367inline const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b)
368{
369 a.mV[0] *= b.mV[0];
370 a.mV[1] *= b.mV[1];
371 a.mV[2] *= b.mV[2];
372 return a;
373}
374
375inline const LLVector3& operator/=(LLVector3 &a, F32 k)
376{
377 F32 t = 1.f / k;
378 a.mV[0] *= t;
379 a.mV[1] *= t;
380 a.mV[2] *= t;
381 return a;
382}
383
384inline LLVector3 operator-(const LLVector3 &a)
385{
386 return LLVector3( -a.mV[0], -a.mV[1], -a.mV[2] );
387}
388
389inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b)
390{
391 F32 x = a.mV[0] - b.mV[0];
392 F32 y = a.mV[1] - b.mV[1];
393 F32 z = a.mV[2] - b.mV[2];
394 return fsqrtf( x*x + y*y + z*z );
395}
396
397inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b)
398{
399 F32 x = a.mV[0] - b.mV[0];
400 F32 y = a.mV[1] - b.mV[1];
401 F32 z = a.mV[2] - b.mV[2];
402 return x*x + y*y + z*z;
403}
404
405inline F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b)
406{
407 F32 x = a.mV[0] - b.mV[0];
408 F32 y = a.mV[1] - b.mV[1];
409 return x*x + y*y;
410}
411
412inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b)
413{
414 LLVector3 project_axis = b;
415 project_axis.normVec();
416 return project_axis * (a * project_axis);
417}
418
419inline LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u)
420{
421 return LLVector3(
422 a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
423 a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u,
424 a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u);
425}
426
427
428inline BOOL LLVector3::isNull() const
429{
430 if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ] )
431 {
432 return TRUE;
433 }
434 return FALSE;
435}
436
437
438inline F32 angle_between(const LLVector3& a, const LLVector3& b)
439{
440 LLVector3 an = a;
441 LLVector3 bn = b;
442 an.normVec();
443 bn.normVec();
444 F32 cosine = an * bn;
445 F32 angle = (cosine >= 1.0f) ? 0.0f :
446 (cosine <= -1.0f) ? F_PI :
447 (F32)acos(cosine);
448 return angle;
449}
450
451inline BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon)
452{
453 LLVector3 an = a;
454 LLVector3 bn = b;
455 an.normVec();
456 bn.normVec();
457 F32 dot = an * bn;
458 if ( (1.0f - fabs(dot)) < epsilon)
459 {
460 return TRUE;
461 }
462 return FALSE;
463}
464
465#endif
diff --git a/linden/indra/llmath/v4color.cpp b/linden/indra/llmath/v4color.cpp
new file mode 100644
index 0000000..2732a60
--- /dev/null
+++ b/linden/indra/llmath/v4color.cpp
@@ -0,0 +1,580 @@
1/**
2 * @file v4color.cpp
3 * @brief LLColor4 class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llboost.h"
31
32#include "v4color.h"
33#include "v4coloru.h"
34#include "v3color.h"
35//#include "vmath.h"
36#include "llmath.h"
37
38// LLColor4
39
40//////////////////////////////////////////////////////////////////////////////
41
42LLColor4 LLColor4::red( 1.f, 0.f, 0.f, 1.f);
43LLColor4 LLColor4::green( 0.f, 1.f, 0.f, 1.f);
44LLColor4 LLColor4::blue( 0.f, 0.f, 1.f, 1.f);
45LLColor4 LLColor4::black( 0.f, 0.f, 0.f, 1.f);
46LLColor4 LLColor4::yellow( 1.f, 1.f, 0.f, 1.f);
47LLColor4 LLColor4::magenta( 1.0f, 0.0f, 1.0f, 1.0f);
48LLColor4 LLColor4::cyan( 0.0f, 1.0f, 1.0f, 1.0f);
49LLColor4 LLColor4::white( 1.f, 1.f, 1.f, 1.f);
50LLColor4 LLColor4::smoke( 0.5f, 0.5f, 0.5f, 0.5f);
51LLColor4 LLColor4::grey( 0.5f, 0.5f, 0.5f, 1.0f);
52LLColor4 LLColor4::orange( 1.f, 0.5, 0.f, 1.f );
53LLColor4 LLColor4::purple( 0.6f, 0.2f, 0.8f, 1.0f);
54LLColor4 LLColor4::pink( 1.0f, 0.5f, 0.8f, 1.0f);
55LLColor4 LLColor4::transparent( 0.f, 0.f, 0.f, 0.f );
56
57//////////////////////////////////////////////////////////////////////////////
58
59LLColor4 LLColor4::grey1(0.8f, 0.8f, 0.8f, 1.0f);
60LLColor4 LLColor4::grey2(0.6f, 0.6f, 0.6f, 1.0f);
61LLColor4 LLColor4::grey3(0.4f, 0.4f, 0.4f, 1.0f);
62LLColor4 LLColor4::grey4(0.3f, 0.3f, 0.3f, 1.0f);
63
64LLColor4 LLColor4::red1(1.0f, 0.0f, 0.0f, 1.0f);
65LLColor4 LLColor4::red2(0.6f, 0.0f, 0.0f, 1.0f);
66LLColor4 LLColor4::red3(1.0f, 0.2f, 0.2f, 1.0f);
67LLColor4 LLColor4::red4(0.5f, 0.1f, 0.1f, 1.0f);
68LLColor4 LLColor4::red5(0.8f, 0.1f, 0.0f, 1.0f);
69
70LLColor4 LLColor4::green1(0.0f, 1.0f, 0.0f, 1.0f);
71LLColor4 LLColor4::green2(0.0f, 0.6f, 0.0f, 1.0f);
72LLColor4 LLColor4::green3(0.0f, 0.4f, 0.0f, 1.0f);
73LLColor4 LLColor4::green4(0.0f, 1.0f, 0.4f, 1.0f);
74LLColor4 LLColor4::green5(0.2f, 0.6f, 0.4f, 1.0f);
75LLColor4 LLColor4::green6(0.4f, 0.6f, 0.2f, 1.0f);
76
77LLColor4 LLColor4::blue1(0.0f, 0.0f, 1.0f, 1.0f);
78LLColor4 LLColor4::blue2(0.0f, 0.4f, 1.0f, 1.0f);
79LLColor4 LLColor4::blue3(0.2f, 0.2f, 0.8f, 1.0f);
80LLColor4 LLColor4::blue4(0.0f, 0.0f, 0.6f, 1.0f);
81LLColor4 LLColor4::blue5(0.4f, 0.2f, 1.0f, 1.0f);
82LLColor4 LLColor4::blue6(0.4f, 0.5f, 1.0f, 1.0f);
83
84LLColor4 LLColor4::yellow1(1.0f, 1.0f, 0.0f, 1.0f);
85LLColor4 LLColor4::yellow2(0.6f, 0.6f, 0.0f, 1.0f);
86LLColor4 LLColor4::yellow3(0.8f, 1.0f, 0.2f, 1.0f);
87LLColor4 LLColor4::yellow4(1.0f, 1.0f, 0.4f, 1.0f);
88LLColor4 LLColor4::yellow5(0.6f, 0.4f, 0.2f, 1.0f);
89LLColor4 LLColor4::yellow6(1.0f, 0.8f, 0.4f, 1.0f);
90LLColor4 LLColor4::yellow7(0.8f, 0.8f, 0.0f, 1.0f);
91LLColor4 LLColor4::yellow8(0.8f, 0.8f, 0.2f, 1.0f);
92LLColor4 LLColor4::yellow9(0.8f, 0.8f, 0.4f, 1.0f);
93
94LLColor4 LLColor4::orange1(1.0f, 0.8f, 0.0f, 1.0f);
95LLColor4 LLColor4::orange2(1.0f, 0.6f, 0.0f, 1.0f);
96LLColor4 LLColor4::orange3(1.0f, 0.4f, 0.2f, 1.0f);
97LLColor4 LLColor4::orange4(0.8f, 0.4f, 0.0f, 1.0f);
98LLColor4 LLColor4::orange5(0.9f, 0.5f, 0.0f, 1.0f);
99LLColor4 LLColor4::orange6(1.0f, 0.8f, 0.2f, 1.0f);
100
101LLColor4 LLColor4::magenta1(1.0f, 0.0f, 1.0f, 1.0f);
102LLColor4 LLColor4::magenta2(0.6f, 0.2f, 0.4f, 1.0f);
103LLColor4 LLColor4::magenta3(1.0f, 0.4f, 0.6f, 1.0f);
104LLColor4 LLColor4::magenta4(1.0f, 0.2f, 0.8f, 1.0f);
105
106LLColor4 LLColor4::purple1(0.6f, 0.2f, 0.8f, 1.0f);
107LLColor4 LLColor4::purple2(0.8f, 0.2f, 1.0f, 1.0f);
108LLColor4 LLColor4::purple3(0.6f, 0.0f, 1.0f, 1.0f);
109LLColor4 LLColor4::purple4(0.4f, 0.0f, 0.8f, 1.0f);
110LLColor4 LLColor4::purple5(0.6f, 0.0f, 0.8f, 1.0f);
111LLColor4 LLColor4::purple6(0.8f, 0.0f, 0.6f, 1.0f);
112
113LLColor4 LLColor4::pink1(1.0f, 0.5f, 0.8f, 1.0f);
114LLColor4 LLColor4::pink2(1.0f, 0.8f, 0.9f, 1.0f);
115
116LLColor4 LLColor4::cyan1(0.0f, 1.0f, 1.0f, 1.0f);
117LLColor4 LLColor4::cyan2(0.4f, 0.8f, 0.8f, 1.0f);
118LLColor4 LLColor4::cyan3(0.0f, 1.0f, 0.6f, 1.0f);
119LLColor4 LLColor4::cyan4(0.6f, 1.0f, 1.0f, 1.0f);
120LLColor4 LLColor4::cyan5(0.2f, 0.6f, 1.0f, 1.0f);
121LLColor4 LLColor4::cyan6(0.2f, 0.6f, 0.6f, 1.0f);
122
123//////////////////////////////////////////////////////////////////////////////
124
125// conversion
126LLColor4::operator const LLColor4U() const
127{
128 return LLColor4U(
129 (U8)llclampb(llround(mV[VRED]*255.f)),
130 (U8)llclampb(llround(mV[VGREEN]*255.f)),
131 (U8)llclampb(llround(mV[VBLUE]*255.f)),
132 (U8)llclampb(llround(mV[VALPHA]*255.f)));
133}
134
135LLColor4::LLColor4(const LLColor3 &vec, F32 a)
136{
137 mV[VX] = vec.mV[VX];
138 mV[VY] = vec.mV[VY];
139 mV[VZ] = vec.mV[VZ];
140 mV[VW] = a;
141}
142
143LLColor4::LLColor4(const LLColor4U& color4u)
144{
145 const F32 SCALE = 1.f/255.f;
146 mV[VX] = color4u.mV[VX] * SCALE;
147 mV[VY] = color4u.mV[VY] * SCALE;
148 mV[VZ] = color4u.mV[VZ] * SCALE;
149 mV[VW] = color4u.mV[VW] * SCALE;
150}
151
152const LLColor4& LLColor4::setVec(const LLColor4U& color4u)
153{
154 const F32 SCALE = 1.f/255.f;
155 mV[VX] = color4u.mV[VX] * SCALE;
156 mV[VY] = color4u.mV[VY] * SCALE;
157 mV[VZ] = color4u.mV[VZ] * SCALE;
158 mV[VW] = color4u.mV[VW] * SCALE;
159 return (*this);
160}
161
162const LLColor4& LLColor4::setVec(const LLColor3 &vec)
163{
164 mV[VX] = vec.mV[VX];
165 mV[VY] = vec.mV[VY];
166 mV[VZ] = vec.mV[VZ];
167
168// no change to alpha!
169// mV[VW] = 1.f;
170
171 return (*this);
172}
173
174const LLColor4& LLColor4::setVec(const LLColor3 &vec, F32 a)
175{
176 mV[VX] = vec.mV[VX];
177 mV[VY] = vec.mV[VY];
178 mV[VZ] = vec.mV[VZ];
179 mV[VW] = a;
180 return (*this);
181}
182
183const LLColor4& LLColor4::operator=(const LLColor3 &a)
184{
185 mV[VX] = a.mV[VX];
186 mV[VY] = a.mV[VY];
187 mV[VZ] = a.mV[VZ];
188
189// converting from an rgb sets a=1 (opaque)
190 mV[VW] = 1.f;
191 return (*this);
192}
193
194
195std::ostream& operator<<(std::ostream& s, const LLColor4 &a)
196{
197 s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << ", " << a.mV[VW] << " }";
198 return s;
199}
200
201bool operator==(const LLColor4 &a, const LLColor3 &b)
202{
203 return ( (a.mV[VX] == b.mV[VX])
204 &&(a.mV[VY] == b.mV[VY])
205 &&(a.mV[VZ] == b.mV[VZ]));
206}
207
208bool operator!=(const LLColor4 &a, const LLColor3 &b)
209{
210 return ( (a.mV[VX] != b.mV[VX])
211 ||(a.mV[VY] != b.mV[VY])
212 ||(a.mV[VZ] != b.mV[VZ]));
213}
214
215LLColor3 vec4to3(const LLColor4 &vec)
216{
217 LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
218 return temp;
219}
220
221LLColor4 vec3to4(const LLColor3 &vec)
222{
223 LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
224 return temp;
225}
226
227// static
228BOOL LLColor4::parseColor(const char* buf, LLColor4* color)
229{
230 if( buf == NULL || buf[0] == '\0' || color == NULL)
231 {
232 return FALSE;
233 }
234
235 LLString full_string(buf);
236
237 boost_tokenizer tokens(full_string, boost::char_separator<char>(", "));
238 boost_tokenizer::iterator token_iter = tokens.begin();
239 if (token_iter == tokens.end())
240 {
241 return FALSE;
242 }
243
244 // Grab the first token into a string, since we don't know
245 // if this is a float or a color name.
246 LLString color_name( (*token_iter) );
247 ++token_iter;
248
249 if (token_iter != tokens.end())
250 {
251 // There are more tokens to read. This must be a vector.
252 LLColor4 v;
253 LLString::convertToF32( color_name, v.mV[VX] );
254 LLString::convertToF32( *token_iter, v.mV[VY] );
255 v.mV[VZ] = 0.0f;
256 v.mV[VW] = 1.0f;
257
258 ++token_iter;
259 if (token_iter == tokens.end())
260 {
261 // This is a malformed vector.
262 llwarns << "LLColor4::parseColor() malformed color " << full_string << llendl;
263 }
264 else
265 {
266 // There is a z-component.
267 LLString::convertToF32( *token_iter, v.mV[VZ] );
268
269 ++token_iter;
270 if (token_iter != tokens.end())
271 {
272 // There is an alpha component.
273 LLString::convertToF32( *token_iter, v.mV[VW] );
274 }
275 }
276
277 // Make sure all values are between 0 and 1.
278 if (v.mV[VX] > 1.f || v.mV[VY] > 1.f || v.mV[VZ] > 1.f || v.mV[VW] > 1.f)
279 {
280 v = v * (1.f / 255.f);
281 }
282 color->setVec( v );
283 }
284 else // Single value. Read as a named color.
285 {
286 // We have a color name
287 if ( "red" == color_name )
288 {
289 color->setVec(LLColor4::red);
290 }
291 else if ( "red1" == color_name )
292 {
293 color->setVec(LLColor4::red1);
294 }
295 else if ( "red2" == color_name )
296 {
297 color->setVec(LLColor4::red2);
298 }
299 else if ( "red3" == color_name )
300 {
301 color->setVec(LLColor4::red3);
302 }
303 else if ( "red4" == color_name )
304 {
305 color->setVec(LLColor4::red4);
306 }
307 else if ( "red5" == color_name )
308 {
309 color->setVec(LLColor4::red5);
310 }
311 else if( "green" == color_name )
312 {
313 color->setVec(LLColor4::green);
314 }
315 else if( "green1" == color_name )
316 {
317 color->setVec(LLColor4::green1);
318 }
319 else if( "green2" == color_name )
320 {
321 color->setVec(LLColor4::green2);
322 }
323 else if( "green3" == color_name )
324 {
325 color->setVec(LLColor4::green3);
326 }
327 else if( "green4" == color_name )
328 {
329 color->setVec(LLColor4::green4);
330 }
331 else if( "green5" == color_name )
332 {
333 color->setVec(LLColor4::green5);
334 }
335 else if( "green6" == color_name )
336 {
337 color->setVec(LLColor4::green6);
338 }
339 else if( "blue" == color_name )
340 {
341 color->setVec(LLColor4::blue);
342 }
343 else if( "blue1" == color_name )
344 {
345 color->setVec(LLColor4::blue1);
346 }
347 else if( "blue2" == color_name )
348 {
349 color->setVec(LLColor4::blue2);
350 }
351 else if( "blue3" == color_name )
352 {
353 color->setVec(LLColor4::blue3);
354 }
355 else if( "blue4" == color_name )
356 {
357 color->setVec(LLColor4::blue4);
358 }
359 else if( "blue5" == color_name )
360 {
361 color->setVec(LLColor4::blue5);
362 }
363 else if( "blue6" == color_name )
364 {
365 color->setVec(LLColor4::blue6);
366 }
367 else if( "black" == color_name )
368 {
369 color->setVec(LLColor4::black);
370 }
371 else if( "white" == color_name )
372 {
373 color->setVec(LLColor4::white);
374 }
375 else if( "yellow" == color_name )
376 {
377 color->setVec(LLColor4::yellow);
378 }
379 else if( "yellow1" == color_name )
380 {
381 color->setVec(LLColor4::yellow1);
382 }
383 else if( "yellow2" == color_name )
384 {
385 color->setVec(LLColor4::yellow2);
386 }
387 else if( "yellow3" == color_name )
388 {
389 color->setVec(LLColor4::yellow3);
390 }
391 else if( "yellow4" == color_name )
392 {
393 color->setVec(LLColor4::yellow4);
394 }
395 else if( "yellow5" == color_name )
396 {
397 color->setVec(LLColor4::yellow5);
398 }
399 else if( "yellow6" == color_name )
400 {
401 color->setVec(LLColor4::yellow6);
402 }
403 else if( "magenta" == color_name )
404 {
405 color->setVec(LLColor4::magenta);
406 }
407 else if( "magenta1" == color_name )
408 {
409 color->setVec(LLColor4::magenta1);
410 }
411 else if( "magenta2" == color_name )
412 {
413 color->setVec(LLColor4::magenta2);
414 }
415 else if( "magenta3" == color_name )
416 {
417 color->setVec(LLColor4::magenta3);
418 }
419 else if( "magenta4" == color_name )
420 {
421 color->setVec(LLColor4::magenta4);
422 }
423 else if( "purple" == color_name )
424 {
425 color->setVec(LLColor4::purple);
426 }
427 else if( "purple1" == color_name )
428 {
429 color->setVec(LLColor4::purple1);
430 }
431 else if( "purple2" == color_name )
432 {
433 color->setVec(LLColor4::purple2);
434 }
435 else if( "purple3" == color_name )
436 {
437 color->setVec(LLColor4::purple3);
438 }
439 else if( "purple4" == color_name )
440 {
441 color->setVec(LLColor4::purple4);
442 }
443 else if( "purple5" == color_name )
444 {
445 color->setVec(LLColor4::purple5);
446 }
447 else if( "purple6" == color_name )
448 {
449 color->setVec(LLColor4::purple6);
450 }
451 else if( "pink" == color_name )
452 {
453 color->setVec(LLColor4::pink);
454 }
455 else if( "pink1" == color_name )
456 {
457 color->setVec(LLColor4::pink1);
458 }
459 else if( "pink2" == color_name )
460 {
461 color->setVec(LLColor4::pink2);
462 }
463 else if( "cyan" == color_name )
464 {
465 color->setVec(LLColor4::cyan);
466 }
467 else if( "cyan1" == color_name )
468 {
469 color->setVec(LLColor4::cyan1);
470 }
471 else if( "cyan2" == color_name )
472 {
473 color->setVec(LLColor4::cyan2);
474 }
475 else if( "cyan3" == color_name )
476 {
477 color->setVec(LLColor4::cyan3);
478 }
479 else if( "cyan4" == color_name )
480 {
481 color->setVec(LLColor4::cyan4);
482 }
483 else if( "cyan5" == color_name )
484 {
485 color->setVec(LLColor4::cyan5);
486 }
487 else if( "cyan6" == color_name )
488 {
489 color->setVec(LLColor4::cyan6);
490 }
491 else if( "smoke" == color_name )
492 {
493 color->setVec(LLColor4::smoke);
494 }
495 else if( "grey" == color_name )
496 {
497 color->setVec(LLColor4::grey);
498 }
499 else if( "grey1" == color_name )
500 {
501 color->setVec(LLColor4::grey1);
502 }
503 else if( "grey2" == color_name )
504 {
505 color->setVec(LLColor4::grey2);
506 }
507 else if( "grey3" == color_name )
508 {
509 color->setVec(LLColor4::grey3);
510 }
511 else if( "grey4" == color_name )
512 {
513 color->setVec(LLColor4::grey4);
514 }
515 else if( "orange" == color_name )
516 {
517 color->setVec(LLColor4::orange);
518 }
519 else if( "orange1" == color_name )
520 {
521 color->setVec(LLColor4::orange1);
522 }
523 else if( "orange2" == color_name )
524 {
525 color->setVec(LLColor4::orange2);
526 }
527 else if( "orange3" == color_name )
528 {
529 color->setVec(LLColor4::orange3);
530 }
531 else if( "orange4" == color_name )
532 {
533 color->setVec(LLColor4::orange4);
534 }
535 else if( "orange5" == color_name )
536 {
537 color->setVec(LLColor4::orange5);
538 }
539 else if( "orange6" == color_name )
540 {
541 color->setVec(LLColor4::orange6);
542 }
543 else if ( "clear" == color_name )
544 {
545 color->setVec(0.f, 0.f, 0.f, 0.f);
546 }
547 else
548 {
549 llwarns << "invalid color " << color_name << llendl;
550 }
551 }
552
553 return TRUE;
554}
555
556// static
557BOOL LLColor4::parseColor4(const char* buf, LLColor4* value)
558{
559 if( buf == NULL || buf[0] == '\0' || value == NULL)
560 {
561 return FALSE;
562 }
563
564 LLColor4 v;
565 S32 count = sscanf( buf, "%f, %f, %f, %f", v.mV + 0, v.mV + 1, v.mV + 2, v.mV + 3 );
566 if (1 == count )
567 {
568 // try this format
569 count = sscanf( buf, "%f %f %f %f", v.mV + 0, v.mV + 1, v.mV + 2, v.mV + 3 );
570 }
571 if( 4 == count )
572 {
573 value->setVec( v );
574 return TRUE;
575 }
576
577 return FALSE;
578}
579
580// EOF
diff --git a/linden/indra/llmath/v4color.h b/linden/indra/llmath/v4color.h
new file mode 100644
index 0000000..d4130d6
--- /dev/null
+++ b/linden/indra/llmath/v4color.h
@@ -0,0 +1,558 @@
1/**
2 * @file v4color.h
3 * @brief LLColor4 class header file.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_V4COLOR_H
29#define LL_V4COLOR_H
30
31#include "llerror.h"
32//#include "vmath.h"
33#include "llmath.h"
34#include "llsd.h"
35
36class LLColor3;
37class LLColor4U;
38
39// LLColor4 = |x y z w|
40
41static const U32 LENGTHOFCOLOR4 = 4;
42
43static const U32 MAX_LENGTH_OF_COLOR_NAME = 15; //Give plenty of room for additional colors...
44
45class LLColor4
46{
47 public:
48 F32 mV[LENGTHOFCOLOR4];
49 LLColor4(); // Initializes LLColor4 to (0, 0, 0, 1)
50 LLColor4(F32 r, F32 g, F32 b); // Initializes LLColor4 to (r, g, b, 1)
51 LLColor4(F32 r, F32 g, F32 b, F32 a); // Initializes LLColor4 to (r. g, b, a)
52 LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc))
53 LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1)
54 LLColor4(const LLColor3 &vec, F32 a = 1.f); // Initializes LLColor4 to (vec, a)
55 LLColor4(const LLSD& sd);
56 explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion
57
58 LLSD getValue() const
59 {
60 LLSD ret;
61 ret[0] = mV[0];
62 ret[1] = mV[1];
63 ret[2] = mV[2];
64 ret[3] = mV[3];
65 return ret;
66 }
67
68 void setValue(const LLSD& sd)
69 {
70 mV[0] = (F32) sd[0].asReal();
71 mV[1] = (F32) sd[1].asReal();
72 mV[2] = (F32) sd[2].asReal();
73 mV[3] = (F32) sd[3].asReal();
74 }
75
76 const LLColor4& setToBlack(); // zero LLColor4 to (0, 0, 0, 1)
77 const LLColor4& setToWhite(); // zero LLColor4 to (0, 0, 0, 1)
78
79 const LLColor4& setVec(F32 r, F32 g, F32 b, F32 a); // Sets LLColor4 to (r, g, b, a)
80 const LLColor4& setVec(F32 r, F32 g, F32 b); // Sets LLColor4 to (r, g, b) (no change in a)
81 const LLColor4& setVec(const LLColor4 &vec); // Sets LLColor4 to vec
82 const LLColor4& setVec(const LLColor3 &vec); // Sets LLColor4 to LLColor3 vec (no change in alpha)
83 const LLColor4& setVec(const LLColor3 &vec, F32 a); // Sets LLColor4 to LLColor3 vec, with alpha specified
84 const LLColor4& setVec(const F32 *vec); // Sets LLColor4 to vec
85 const LLColor4& setVec(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled.
86
87
88 const LLColor4& setAlpha(F32 a);
89
90 F32 magVec() const; // Returns magnitude of LLColor4
91 F32 magVecSquared() const; // Returns magnitude squared of LLColor4
92 F32 normVec(); // Normalizes and returns the magnitude of LLColor4
93 const BOOL isOpaque() { return mV[VALPHA] == 1.f; }
94
95 F32 operator[](int idx) const { return mV[idx]; }
96 F32 &operator[](int idx) { return mV[idx]; }
97
98 const LLColor4& operator=(const LLColor3 &a); // Assigns vec3 to vec4 and returns vec4
99 const LLColor4& operator=(const LLSD& sd);
100
101 friend std::ostream& operator<<(std::ostream& s, const LLColor4 &a); // Print a
102 friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b); // Return vector a + b
103 friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b); // Return vector a minus b
104 friend LLColor4 operator*(const LLColor4 &a, const LLColor4 &b); // Return a * b
105 friend LLColor4 operator*(const LLColor4 &a, F32 k); // Return rgb times scaler k (no alpha change)
106 friend LLColor4 operator*(F32 k, const LLColor4 &a); // Return rgb times scaler k (no alpha change)
107 friend LLColor4 operator%(const LLColor4 &a, F32 k); // Return alpha times scaler k (no rgb change)
108 friend LLColor4 operator%(F32 k, const LLColor4 &a); // Return alpha times scaler k (no rgb change)
109 friend bool operator==(const LLColor4 &a, const LLColor4 &b); // Return a == b
110 friend bool operator!=(const LLColor4 &a, const LLColor4 &b); // Return a != b
111
112 friend bool operator==(const LLColor4 &a, const LLColor3 &b); // Return a == b
113 friend bool operator!=(const LLColor4 &a, const LLColor3 &b); // Return a != b
114
115 friend const LLColor4& operator+=(LLColor4 &a, const LLColor4 &b); // Return vector a + b
116 friend const LLColor4& operator-=(LLColor4 &a, const LLColor4 &b); // Return vector a minus b
117 friend const LLColor4& operator*=(LLColor4 &a, F32 k); // Return rgb times scaler k (no alpha change)
118 friend const LLColor4& operator%=(LLColor4 &a, F32 k); // Return alpha times scaler k (no rgb change)
119
120 friend const LLColor4& operator*=(LLColor4 &a, const LLColor4 &b); // Doesn't multiply alpha! (for lighting)
121
122 // conversion
123 operator const LLColor4U() const;
124
125 // Basic color values.
126 static LLColor4 red;
127 static LLColor4 green;
128 static LLColor4 blue;
129 static LLColor4 black;
130 static LLColor4 white;
131 static LLColor4 yellow;
132 static LLColor4 magenta;
133 static LLColor4 cyan;
134 static LLColor4 smoke;
135 static LLColor4 grey;
136 static LLColor4 orange;
137 static LLColor4 purple;
138 static LLColor4 pink;
139 static LLColor4 transparent;
140
141 // Extra color values.
142 static LLColor4 grey1;
143 static LLColor4 grey2;
144 static LLColor4 grey3;
145 static LLColor4 grey4;
146
147 static LLColor4 red1;
148 static LLColor4 red2;
149 static LLColor4 red3;
150 static LLColor4 red4;
151 static LLColor4 red5;
152
153 static LLColor4 green1;
154 static LLColor4 green2;
155 static LLColor4 green3;
156 static LLColor4 green4;
157 static LLColor4 green5;
158 static LLColor4 green6;
159
160 static LLColor4 blue1;
161 static LLColor4 blue2;
162 static LLColor4 blue3;
163 static LLColor4 blue4;
164 static LLColor4 blue5;
165 static LLColor4 blue6;
166
167 static LLColor4 yellow1;
168 static LLColor4 yellow2;
169 static LLColor4 yellow3;
170 static LLColor4 yellow4;
171 static LLColor4 yellow5;
172 static LLColor4 yellow6;
173 static LLColor4 yellow7;
174 static LLColor4 yellow8;
175 static LLColor4 yellow9;
176
177 static LLColor4 orange1;
178 static LLColor4 orange2;
179 static LLColor4 orange3;
180 static LLColor4 orange4;
181 static LLColor4 orange5;
182 static LLColor4 orange6;
183
184 static LLColor4 magenta1;
185 static LLColor4 magenta2;
186 static LLColor4 magenta3;
187 static LLColor4 magenta4;
188
189 static LLColor4 purple1;
190 static LLColor4 purple2;
191 static LLColor4 purple3;
192 static LLColor4 purple4;
193 static LLColor4 purple5;
194 static LLColor4 purple6;
195
196 static LLColor4 pink1;
197 static LLColor4 pink2;
198
199 static LLColor4 cyan1;
200 static LLColor4 cyan2;
201 static LLColor4 cyan3;
202 static LLColor4 cyan4;
203 static LLColor4 cyan5;
204 static LLColor4 cyan6;
205
206 static BOOL parseColor(const char* buf, LLColor4* color);
207 static BOOL parseColor4(const char* buf, LLColor4* color);
208
209 inline void clamp();
210};
211
212
213// Non-member functions
214F32 distVec(const LLColor4 &a, const LLColor4 &b); // Returns distance between a and b
215F32 distVec_squared(const LLColor4 &a, const LLColor4 &b); // Returns distance squared between a and b
216LLColor3 vec4to3(const LLColor4 &vec);
217LLColor4 vec3to4(const LLColor3 &vec);
218LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u);
219
220inline LLColor4::LLColor4(void)
221{
222 mV[VX] = 0.f;
223 mV[VY] = 0.f;
224 mV[VZ] = 0.f;
225 mV[VW] = 1.f;
226}
227
228inline LLColor4::LLColor4(const LLSD& sd)
229{
230 *this = sd;
231}
232
233inline LLColor4::LLColor4(F32 r, F32 g, F32 b)
234{
235 mV[VX] = r;
236 mV[VY] = g;
237 mV[VZ] = b;
238 mV[VW] = 1.f;
239}
240
241inline LLColor4::LLColor4(F32 r, F32 g, F32 b, F32 a)
242{
243 mV[VX] = r;
244 mV[VY] = g;
245 mV[VZ] = b;
246 mV[VW] = a;
247}
248
249inline LLColor4::LLColor4(U32 clr)
250{
251 mV[VX] = (clr&0xff) * (1.0f/255.0f);
252 mV[VY] = ((clr>>8)&0xff) * (1.0f/255.0f);
253 mV[VZ] = ((clr>>16)&0xff) * (1.0f/255.0f);
254 mV[VW] = (clr>>24) * (1.0f/255.0f);
255}
256
257inline LLColor4::LLColor4(const F32 *vec)
258{
259 mV[VX] = vec[VX];
260 mV[VY] = vec[VY];
261 mV[VZ] = vec[VZ];
262 mV[VW] = vec[VW];
263}
264
265inline const LLColor4& LLColor4::setToBlack(void)
266{
267 mV[VX] = 0.f;
268 mV[VY] = 0.f;
269 mV[VZ] = 0.f;
270 mV[VW] = 1.f;
271 return (*this);
272}
273
274inline const LLColor4& LLColor4::setToWhite(void)
275{
276 mV[VX] = 1.f;
277 mV[VY] = 1.f;
278 mV[VZ] = 1.f;
279 mV[VW] = 1.f;
280 return (*this);
281}
282
283inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z)
284{
285 mV[VX] = x;
286 mV[VY] = y;
287 mV[VZ] = z;
288
289// no change to alpha!
290// mV[VW] = 1.f;
291
292 return (*this);
293}
294
295inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z, F32 a)
296{
297 mV[VX] = x;
298 mV[VY] = y;
299 mV[VZ] = z;
300 mV[VW] = a;
301 return (*this);
302}
303
304inline const LLColor4& LLColor4::setVec(const LLColor4 &vec)
305{
306 mV[VX] = vec.mV[VX];
307 mV[VY] = vec.mV[VY];
308 mV[VZ] = vec.mV[VZ];
309 mV[VW] = vec.mV[VW];
310 return (*this);
311}
312
313
314inline const LLColor4& LLColor4::setVec(const F32 *vec)
315{
316 mV[VX] = vec[VX];
317 mV[VY] = vec[VY];
318 mV[VZ] = vec[VZ];
319 mV[VW] = vec[VW];
320 return (*this);
321}
322
323inline const LLColor4& LLColor4::setAlpha(F32 a)
324{
325 mV[VW] = a;
326 return (*this);
327}
328
329// LLColor4 Magnitude and Normalization Functions
330
331inline F32 LLColor4::magVec(void) const
332{
333 return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
334}
335
336inline F32 LLColor4::magVecSquared(void) const
337{
338 return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
339}
340
341inline F32 LLColor4::normVec(void)
342{
343 F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
344 F32 oomag;
345
346 if (mag)
347 {
348 oomag = 1.f/mag;
349 mV[VX] *= oomag;
350 mV[VY] *= oomag;
351 mV[VZ] *= oomag;
352 }
353 return (mag);
354}
355
356// LLColor4 Operators
357
358
359inline LLColor4 operator+(const LLColor4 &a, const LLColor4 &b)
360{
361 return LLColor4(
362 a.mV[VX] + b.mV[VX],
363 a.mV[VY] + b.mV[VY],
364 a.mV[VZ] + b.mV[VZ],
365 a.mV[VW] + b.mV[VW]);
366}
367
368inline LLColor4 operator-(const LLColor4 &a, const LLColor4 &b)
369{
370 return LLColor4(
371 a.mV[VX] - b.mV[VX],
372 a.mV[VY] - b.mV[VY],
373 a.mV[VZ] - b.mV[VZ],
374 a.mV[VW] - b.mV[VW]);
375}
376
377inline LLColor4 operator*(const LLColor4 &a, const LLColor4 &b)
378{
379 return LLColor4(
380 a.mV[VX] * b.mV[VX],
381 a.mV[VY] * b.mV[VY],
382 a.mV[VZ] * b.mV[VZ],
383 a.mV[VW] * b.mV[VW]);
384}
385
386inline LLColor4 operator*(const LLColor4 &a, F32 k)
387{
388 // only affects rgb (not a!)
389 return LLColor4(
390 a.mV[VX] * k,
391 a.mV[VY] * k,
392 a.mV[VZ] * k,
393 a.mV[VW]);
394}
395
396inline LLColor4 operator*(F32 k, const LLColor4 &a)
397{
398 // only affects rgb (not a!)
399 return LLColor4(
400 a.mV[VX] * k,
401 a.mV[VY] * k,
402 a.mV[VZ] * k,
403 a.mV[VW]);
404}
405
406inline LLColor4 operator%(F32 k, const LLColor4 &a)
407{
408 // only affects alpha (not rgb!)
409 return LLColor4(
410 a.mV[VX],
411 a.mV[VY],
412 a.mV[VZ],
413 a.mV[VW] * k);
414}
415
416inline LLColor4 operator%(const LLColor4 &a, F32 k)
417{
418 // only affects alpha (not rgb!)
419 return LLColor4(
420 a.mV[VX],
421 a.mV[VY],
422 a.mV[VZ],
423 a.mV[VW] * k);
424}
425
426inline bool operator==(const LLColor4 &a, const LLColor4 &b)
427{
428 return ( (a.mV[VX] == b.mV[VX])
429 &&(a.mV[VY] == b.mV[VY])
430 &&(a.mV[VZ] == b.mV[VZ])
431 &&(a.mV[VW] == b.mV[VW]));
432}
433
434inline bool operator!=(const LLColor4 &a, const LLColor4 &b)
435{
436 return ( (a.mV[VX] != b.mV[VX])
437 ||(a.mV[VY] != b.mV[VY])
438 ||(a.mV[VZ] != b.mV[VZ])
439 ||(a.mV[VW] != b.mV[VW]));
440}
441
442inline const LLColor4& operator+=(LLColor4 &a, const LLColor4 &b)
443{
444 a.mV[VX] += b.mV[VX];
445 a.mV[VY] += b.mV[VY];
446 a.mV[VZ] += b.mV[VZ];
447 a.mV[VW] += b.mV[VW];
448 return a;
449}
450
451inline const LLColor4& operator-=(LLColor4 &a, const LLColor4 &b)
452{
453 a.mV[VX] -= b.mV[VX];
454 a.mV[VY] -= b.mV[VY];
455 a.mV[VZ] -= b.mV[VZ];
456 a.mV[VW] -= b.mV[VW];
457 return a;
458}
459
460inline const LLColor4& operator*=(LLColor4 &a, F32 k)
461{
462 // only affects rgb (not a!)
463 a.mV[VX] *= k;
464 a.mV[VY] *= k;
465 a.mV[VZ] *= k;
466 return a;
467}
468
469inline const LLColor4& operator *=(LLColor4 &a, const LLColor4 &b)
470{
471 a.mV[VX] *= b.mV[VX];
472 a.mV[VY] *= b.mV[VY];
473 a.mV[VZ] *= b.mV[VZ];
474// a.mV[VW] *= b.mV[VW];
475 return a;
476}
477
478inline const LLColor4& operator%=(LLColor4 &a, F32 k)
479{
480 // only affects alpha (not rgb!)
481 a.mV[VW] *= k;
482 return a;
483}
484
485
486// Non-member functions
487
488inline F32 distVec(const LLColor4 &a, const LLColor4 &b)
489{
490 LLColor4 vec = a - b;
491 return (vec.magVec());
492}
493
494inline F32 distVec_squared(const LLColor4 &a, const LLColor4 &b)
495{
496 LLColor4 vec = a - b;
497 return (vec.magVecSquared());
498}
499
500inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u)
501{
502 return LLColor4(
503 a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
504 a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u,
505 a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u,
506 a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);
507}
508
509
510void LLColor4::clamp()
511{
512 // Clamp the color...
513 if (mV[0] < 0.f)
514 {
515 mV[0] = 0.f;
516 }
517 else if (mV[0] > 1.f)
518 {
519 mV[0] = 1.f;
520 }
521 if (mV[1] < 0.f)
522 {
523 mV[1] = 0.f;
524 }
525 else if (mV[1] > 1.f)
526 {
527 mV[1] = 1.f;
528 }
529 if (mV[2] < 0.f)
530 {
531 mV[2] = 0.f;
532 }
533 else if (mV[2] > 1.f)
534 {
535 mV[2] = 1.f;
536 }
537 if (mV[3] < 0.f)
538 {
539 mV[3] = 0.f;
540 }
541 else if (mV[3] > 1.f)
542 {
543 mV[3] = 1.f;
544 }
545}
546
547inline const LLColor4& LLColor4::operator=(const LLSD& sd)
548{
549 mV[0] = (F32) sd[0].asReal();
550 mV[1] = (F32) sd[1].asReal();
551 mV[2] = (F32) sd[2].asReal();
552 mV[3] = (F32) sd[3].asReal();
553
554 return *this;
555}
556
557#endif
558
diff --git a/linden/indra/llmath/v4coloru.cpp b/linden/indra/llmath/v4coloru.cpp
new file mode 100644
index 0000000..848a082
--- /dev/null
+++ b/linden/indra/llmath/v4coloru.cpp
@@ -0,0 +1,121 @@
1/**
2 * @file v4coloru.cpp
3 * @brief LLColor4U class implementation.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30//#include "v3coloru.h"
31#include "v4coloru.h"
32#include "v4color.h"
33//#include "vmath.h"
34#include "llmath.h"
35
36// LLColor4U
37LLColor4U LLColor4U::white(255, 255, 255, 255);
38LLColor4U LLColor4U::black( 0, 0, 0, 255);
39LLColor4U LLColor4U::red (255, 0, 0, 255);
40LLColor4U LLColor4U::green( 0, 255, 0, 255);
41LLColor4U LLColor4U::blue ( 0, 0, 255, 255);
42
43// conversion
44/* inlined to fix gcc compile link error
45LLColor4U::operator LLColor4()
46{
47 return(LLColor4((F32)mV[VRED]/255.f,(F32)mV[VGREEN]/255.f,(F32)mV[VBLUE]/255.f,(F32)mV[VALPHA]/255.f));
48}
49*/
50
51// Constructors
52
53
54/*
55LLColor4U::LLColor4U(const LLColor3 &vec)
56{
57 mV[VX] = vec.mV[VX];
58 mV[VY] = vec.mV[VY];
59 mV[VZ] = vec.mV[VZ];
60 mV[VW] = 255;
61}
62*/
63
64
65// Clear and Assignment Functions
66
67
68
69// LLColor4U Operators
70
71/*
72LLColor4U LLColor4U::operator=(const LLColor3 &a)
73{
74 mV[VX] = a.mV[VX];
75 mV[VY] = a.mV[VY];
76 mV[VZ] = a.mV[VZ];
77
78// converting from an rgb sets a=1 (opaque)
79 mV[VW] = 255;
80 return (*this);
81}
82*/
83
84
85std::ostream& operator<<(std::ostream& s, const LLColor4U &a)
86{
87 s << "{ " << (S32)a.mV[VX] << ", " << (S32)a.mV[VY] << ", " << (S32)a.mV[VZ] << ", " << (S32)a.mV[VW] << " }";
88 return s;
89}
90
91// static
92BOOL LLColor4U::parseColor4U(const char* buf, LLColor4U* value)
93{
94 if( buf == NULL || buf[0] == '\0' || value == NULL)
95 {
96 return FALSE;
97 }
98
99 U32 v[4];
100 S32 count = sscanf( buf, "%u, %u, %u, %u", v + 0, v + 1, v + 2, v + 3 );
101 if (1 == count )
102 {
103 // try this format
104 count = sscanf( buf, "%u %u %u %u", v + 0, v + 1, v + 2, v + 3 );
105 }
106 if( 4 != count )
107 {
108 return FALSE;
109 }
110
111 for( S32 i = 0; i < 4; i++ )
112 {
113 if( v[i] > U8_MAX )
114 {
115 return FALSE;
116 }
117 }
118
119 value->setVec( U8(v[0]), U8(v[1]), U8(v[2]), U8(v[3]) );
120 return TRUE;
121}
diff --git a/linden/indra/llmath/v4coloru.h b/linden/indra/llmath/v4coloru.h
new file mode 100644
index 0000000..a5124d0
--- /dev/null
+++ b/linden/indra/llmath/v4coloru.h
@@ -0,0 +1,520 @@
1/**
2 * @file v4coloru.h
3 * @brief The LLColor4U class.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_V4COLORU_H
29#define LL_V4COLORU_H
30
31#include "llerror.h"
32//#include "vmath.h"
33#include "llmath.h"
34//#include "v4color.h"
35
36#include "v3color.h"
37#include "v4color.h"
38
39//class LLColor3U;
40class LLColor4;
41
42// LLColor4U = | red green blue alpha |
43
44static const U32 LENGTHOFCOLOR4U = 4;
45
46
47class LLColor4U
48{
49public:
50
51 union
52 {
53 U8 mV[LENGTHOFCOLOR4U];
54 U32 mAll;
55 LLColor4* mSources;
56 LLColor4U* mSourcesU;
57 };
58
59
60 LLColor4U(); // Initializes LLColor4U to (0, 0, 0, 1)
61 LLColor4U(U8 r, U8 g, U8 b); // Initializes LLColor4U to (r, g, b, 1)
62 LLColor4U(U8 r, U8 g, U8 b, U8 a); // Initializes LLColor4U to (r. g, b, a)
63 LLColor4U(const U8 *vec); // Initializes LLColor4U to (vec[0]. vec[1], vec[2], 1)
64 LLColor4U(const LLSD& sd)
65 {
66 setValue(sd);
67 }
68
69 void setValue(const LLSD& sd)
70 {
71 mV[0] = sd[0].asInteger();
72 mV[1] = sd[1].asInteger();
73 mV[2] = sd[2].asInteger();
74 mV[3] = sd[3].asInteger();
75 }
76
77 const LLColor4U& operator=(const LLSD& sd)
78 {
79 setValue(sd);
80 return *this;
81 }
82
83 LLSD getValue() const
84 {
85 LLSD ret;
86 ret[0] = mV[0];
87 ret[1] = mV[1];
88 ret[2] = mV[2];
89 ret[3] = mV[3];
90 return ret;
91 }
92
93 const LLColor4U& setToBlack(); // zero LLColor4U to (0, 0, 0, 1)
94 const LLColor4U& setToWhite(); // zero LLColor4U to (0, 0, 0, 1)
95
96 const LLColor4U& setVec(U8 r, U8 g, U8 b, U8 a); // Sets LLColor4U to (r, g, b, a)
97 const LLColor4U& setVec(U8 r, U8 g, U8 b); // Sets LLColor4U to (r, g, b) (no change in a)
98 const LLColor4U& setVec(const LLColor4U &vec); // Sets LLColor4U to vec
99 const LLColor4U& setVec(const U8 *vec); // Sets LLColor4U to vec
100
101 const LLColor4U& setAlpha(U8 a);
102
103 F32 magVec() const; // Returns magnitude of LLColor4U
104 F32 magVecSquared() const; // Returns magnitude squared of LLColor4U
105
106 friend std::ostream& operator<<(std::ostream& s, const LLColor4U &a); // Print a
107 friend LLColor4U operator+(const LLColor4U &a, const LLColor4U &b); // Return vector a + b
108 friend LLColor4U operator-(const LLColor4U &a, const LLColor4U &b); // Return vector a minus b
109 friend LLColor4U operator*(const LLColor4U &a, const LLColor4U &b); // Return a * b
110 friend bool operator==(const LLColor4U &a, const LLColor4U &b); // Return a == b
111 friend bool operator!=(const LLColor4U &a, const LLColor4U &b); // Return a != b
112
113 friend const LLColor4U& operator+=(LLColor4U &a, const LLColor4U &b); // Return vector a + b
114 friend const LLColor4U& operator-=(LLColor4U &a, const LLColor4U &b); // Return vector a minus b
115 friend const LLColor4U& operator*=(LLColor4U &a, U8 k); // Return rgb times scaler k (no alpha change)
116 friend const LLColor4U& operator%=(LLColor4U &a, U8 k); // Return alpha times scaler k (no rgb change)
117
118 LLColor4U addClampMax(const LLColor4U &color); // Add and clamp the max
119
120 LLColor4U multAll(const F32 k); // Multiply ALL channels by scalar k
121 const LLColor4U& combine();
122
123 inline void setVecScaleClamp(const LLColor3 &color);
124 inline void setVecScaleClamp(const LLColor4 &color);
125
126 static BOOL parseColor4U(const char* buf, LLColor4U* value);
127
128 static LLColor4U white;
129 static LLColor4U black;
130 static LLColor4U red;
131 static LLColor4U green;
132 static LLColor4U blue;
133};
134
135
136// Non-member functions
137F32 distVec(const LLColor4U &a, const LLColor4U &b); // Returns distance between a and b
138F32 distVec_squared(const LLColor4U &a, const LLColor4U &b); // Returns distance squared between a and b
139
140
141inline LLColor4U::LLColor4U()
142{
143 mV[VX] = 0;
144 mV[VY] = 0;
145 mV[VZ] = 0;
146 mV[VW] = 255;
147}
148
149inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b)
150{
151 mV[VX] = r;
152 mV[VY] = g;
153 mV[VZ] = b;
154 mV[VW] = 255;
155}
156
157inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b, U8 a)
158{
159 mV[VX] = r;
160 mV[VY] = g;
161 mV[VZ] = b;
162 mV[VW] = a;
163}
164
165inline LLColor4U::LLColor4U(const U8 *vec)
166{
167 mV[VX] = vec[VX];
168 mV[VY] = vec[VY];
169 mV[VZ] = vec[VZ];
170 mV[VW] = vec[VW];
171}
172
173/*
174inline LLColor4U::operator LLColor4()
175{
176 return(LLColor4((F32)mV[VRED]/255.f,(F32)mV[VGREEN]/255.f,(F32)mV[VBLUE]/255.f,(F32)mV[VALPHA]/255.f));
177}
178*/
179
180inline const LLColor4U& LLColor4U::setToBlack(void)
181{
182 mV[VX] = 0;
183 mV[VY] = 0;
184 mV[VZ] = 0;
185 mV[VW] = 255;
186 return (*this);
187}
188
189inline const LLColor4U& LLColor4U::setToWhite(void)
190{
191 mV[VX] = 255;
192 mV[VY] = 255;
193 mV[VZ] = 255;
194 mV[VW] = 255;
195 return (*this);
196}
197
198inline const LLColor4U& LLColor4U::setVec(const U8 x, const U8 y, const U8 z)
199{
200 mV[VX] = x;
201 mV[VY] = y;
202 mV[VZ] = z;
203
204// no change to alpha!
205// mV[VW] = 255;
206
207 return (*this);
208}
209
210inline const LLColor4U& LLColor4U::setVec(const U8 r, const U8 g, const U8 b, U8 a)
211{
212 mV[0] = r;
213 mV[1] = g;
214 mV[2] = b;
215 mV[3] = a;
216 return (*this);
217}
218
219inline const LLColor4U& LLColor4U::setVec(const LLColor4U &vec)
220{
221 mV[VX] = vec.mV[VX];
222 mV[VY] = vec.mV[VY];
223 mV[VZ] = vec.mV[VZ];
224 mV[VW] = vec.mV[VW];
225 return (*this);
226}
227
228/*
229inline const LLColor4U& LLColor4U::setVec(const LLColor4 &vec)
230{
231 mV[VX] = (U8) (llmin(1.f, vec.mV[VX]) * 255.f);
232 mV[VY] = (U8) (llmin(1.f, vec.mV[VY]) * 255.f);
233 mV[VZ] = (U8) (llmin(1.f, vec.mV[VZ]) * 255.f);
234 mV[VW] = (U8) (llmin(1.f, vec.mV[VW]) * 255.f);
235 return (*this);
236}
237*/
238
239inline const LLColor4U& LLColor4U::setVec(const U8 *vec)
240{
241 mV[VX] = vec[VX];
242 mV[VY] = vec[VY];
243 mV[VZ] = vec[VZ];
244 mV[VW] = vec[VW];
245 return (*this);
246}
247
248inline const LLColor4U& LLColor4U::setAlpha(U8 a)
249{
250 mV[VW] = a;
251 return (*this);
252}
253
254// LLColor4U Magnitude and Normalization Functions
255// bookmark
256
257inline F32 LLColor4U::magVec(void) const
258{
259 return fsqrtf( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
260}
261
262inline F32 LLColor4U::magVecSquared(void) const
263{
264 return ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ];
265}
266
267inline LLColor4U operator+(const LLColor4U &a, const LLColor4U &b)
268{
269 return LLColor4U(
270 a.mV[VX] + b.mV[VX],
271 a.mV[VY] + b.mV[VY],
272 a.mV[VZ] + b.mV[VZ],
273 a.mV[VW] + b.mV[VW]);
274}
275
276inline LLColor4U operator-(const LLColor4U &a, const LLColor4U &b)
277{
278 return LLColor4U(
279 a.mV[VX] - b.mV[VX],
280 a.mV[VY] - b.mV[VY],
281 a.mV[VZ] - b.mV[VZ],
282 a.mV[VW] - b.mV[VW]);
283}
284
285inline LLColor4U operator*(const LLColor4U &a, const LLColor4U &b)
286{
287 return LLColor4U(
288 a.mV[VX] * b.mV[VX],
289 a.mV[VY] * b.mV[VY],
290 a.mV[VZ] * b.mV[VZ],
291 a.mV[VW] * b.mV[VW]);
292}
293
294inline LLColor4U LLColor4U::addClampMax(const LLColor4U &color)
295{
296 return LLColor4U(llmin((S32)mV[VX] + color.mV[VX], 255),
297 llmin((S32)mV[VY] + color.mV[VY], 255),
298 llmin((S32)mV[VZ] + color.mV[VZ], 255),
299 llmin((S32)mV[VW] + color.mV[VW], 255));
300}
301
302inline LLColor4U LLColor4U::multAll(const F32 k)
303{
304 // Round to nearest
305 return LLColor4U(
306 (U8)llround(mV[VX] * k),
307 (U8)llround(mV[VY] * k),
308 (U8)llround(mV[VZ] * k),
309 (U8)llround(mV[VW] * k));
310}
311/*
312inline LLColor4U operator*(const LLColor4U &a, U8 k)
313{
314 // only affects rgb (not a!)
315 return LLColor4U(
316 a.mV[VX] * k,
317 a.mV[VY] * k,
318 a.mV[VZ] * k,
319 a.mV[VW]);
320}
321
322inline LLColor4U operator*(U8 k, const LLColor4U &a)
323{
324 // only affects rgb (not a!)
325 return LLColor4U(
326 a.mV[VX] * k,
327 a.mV[VY] * k,
328 a.mV[VZ] * k,
329 a.mV[VW]);
330}
331
332inline LLColor4U operator%(U8 k, const LLColor4U &a)
333{
334 // only affects alpha (not rgb!)
335 return LLColor4U(
336 a.mV[VX],
337 a.mV[VY],
338 a.mV[VZ],
339 a.mV[VW] * k );
340}
341
342inline LLColor4U operator%(const LLColor4U &a, U8 k)
343{
344 // only affects alpha (not rgb!)
345 return LLColor4U(
346 a.mV[VX],
347 a.mV[VY],
348 a.mV[VZ],
349 a.mV[VW] * k );
350}
351*/
352
353inline bool operator==(const LLColor4U &a, const LLColor4U &b)
354{
355 return ( (a.mV[VX] == b.mV[VX])
356 &&(a.mV[VY] == b.mV[VY])
357 &&(a.mV[VZ] == b.mV[VZ])
358 &&(a.mV[VW] == b.mV[VW]));
359}
360
361inline bool operator!=(const LLColor4U &a, const LLColor4U &b)
362{
363 return ( (a.mV[VX] != b.mV[VX])
364 ||(a.mV[VY] != b.mV[VY])
365 ||(a.mV[VZ] != b.mV[VZ])
366 ||(a.mV[VW] != b.mV[VW]));
367}
368
369inline const LLColor4U& operator+=(LLColor4U &a, const LLColor4U &b)
370{
371 a.mV[VX] += b.mV[VX];
372 a.mV[VY] += b.mV[VY];
373 a.mV[VZ] += b.mV[VZ];
374 a.mV[VW] += b.mV[VW];
375 return a;
376}
377
378inline const LLColor4U& operator-=(LLColor4U &a, const LLColor4U &b)
379{
380 a.mV[VX] -= b.mV[VX];
381 a.mV[VY] -= b.mV[VY];
382 a.mV[VZ] -= b.mV[VZ];
383 a.mV[VW] -= b.mV[VW];
384 return a;
385}
386
387inline const LLColor4U& operator*=(LLColor4U &a, U8 k)
388{
389 // only affects rgb (not a!)
390 a.mV[VX] *= k;
391 a.mV[VY] *= k;
392 a.mV[VZ] *= k;
393 return a;
394}
395
396inline const LLColor4U& operator%=(LLColor4U &a, U8 k)
397{
398 // only affects alpha (not rgb!)
399 a.mV[VW] *= k;
400 return a;
401}
402
403inline F32 distVec(const LLColor4U &a, const LLColor4U &b)
404{
405 LLColor4U vec = a - b;
406 return (vec.magVec());
407}
408
409inline F32 distVec_squared(const LLColor4U &a, const LLColor4U &b)
410{
411 LLColor4U vec = a - b;
412 return (vec.magVecSquared());
413}
414
415void LLColor4U::setVecScaleClamp(const LLColor4& color)
416{
417 F32 color_scale_factor = 255.f;
418 F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]);
419 if (max_color > 1.f)
420 {
421 color_scale_factor /= max_color;
422 }
423 const S32 MAX_COLOR = 255;
424 S32 r = llround(color.mV[0] * color_scale_factor);
425 if (r > MAX_COLOR)
426 {
427 r = MAX_COLOR;
428 }
429 else if (r < 0)
430 {
431 r = 0;
432 }
433 mV[0] = r;
434
435 S32 g = llround(color.mV[1] * color_scale_factor);
436 if (g > MAX_COLOR)
437 {
438 g = MAX_COLOR;
439 }
440 else if (g < 0)
441 {
442 g = 0;
443 }
444 mV[1] = g;
445
446 S32 b = llround(color.mV[2] * color_scale_factor);
447 if (b > MAX_COLOR)
448 {
449 b = MAX_COLOR;
450 }
451 else if (b < 0)
452 {
453 b = 0;
454 }
455 mV[2] = b;
456
457 // Alpha shouldn't be scaled, just clamped...
458 S32 a = llround(color.mV[3] * MAX_COLOR);
459 if (a > MAX_COLOR)
460 {
461 a = MAX_COLOR;
462 }
463 else if (a < 0)
464 {
465 a = 0;
466 }
467 mV[3] = a;
468}
469
470void LLColor4U::setVecScaleClamp(const LLColor3& color)
471{
472 F32 color_scale_factor = 255.f;
473 F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]);
474 if (max_color > 1.f)
475 {
476 color_scale_factor /= max_color;
477 }
478
479 const S32 MAX_COLOR = 255;
480 S32 r = llround(color.mV[0] * color_scale_factor);
481 if (r > MAX_COLOR)
482 {
483 r = MAX_COLOR;
484 }
485 else
486 if (r < 0)
487 {
488 r = 0;
489 }
490 mV[0] = r;
491
492 S32 g = llround(color.mV[1] * color_scale_factor);
493 if (g > MAX_COLOR)
494 {
495 g = MAX_COLOR;
496 }
497 else
498 if (g < 0)
499 {
500 g = 0;
501 }
502 mV[1] = g;
503
504 S32 b = llround(color.mV[2] * color_scale_factor);
505 if (b > MAX_COLOR)
506 {
507 b = MAX_COLOR;
508 }
509 if (b < 0)
510 {
511 b = 0;
512 }
513 mV[2] = b;
514
515 mV[3] = 255;
516}
517
518
519#endif
520
diff --git a/linden/indra/llmath/v4math.cpp b/linden/indra/llmath/v4math.cpp
new file mode 100644
index 0000000..a4af47d
--- /dev/null
+++ b/linden/indra/llmath/v4math.cpp
@@ -0,0 +1,143 @@
1/**
2 * @file v4math.cpp
3 * @brief LLVector4 class implementation.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30//#include "vmath.h"
31#include "v3math.h"
32#include "v4math.h"
33#include "m4math.h"
34#include "m3math.h"
35#include "llquaternion.h"
36
37// LLVector4
38
39// Axis-Angle rotations
40
41/*
42const LLVector4& LLVector4::rotVec(F32 angle, const LLVector4 &vec)
43{
44 if ( !vec.isExactlyZero() && angle )
45 {
46 *this = *this * LLMatrix4(angle, vec);
47 }
48 return *this;
49}
50
51const LLVector4& LLVector4::rotVec(F32 angle, F32 x, F32 y, F32 z)
52{
53 LLVector3 vec(x, y, z);
54 if ( !vec.isExactlyZero() && angle )
55 {
56 *this = *this * LLMatrix4(angle, vec);
57 }
58 return *this;
59}
60*/
61
62const LLVector4& LLVector4::rotVec(const LLMatrix4 &mat)
63{
64 *this = *this * mat;
65 return *this;
66}
67
68const LLVector4& LLVector4::rotVec(const LLQuaternion &q)
69{
70 *this = *this * q;
71 return *this;
72}
73
74const LLVector4& LLVector4::scaleVec(const LLVector4& vec)
75{
76 mV[VX] *= vec.mV[VX];
77 mV[VY] *= vec.mV[VY];
78 mV[VZ] *= vec.mV[VZ];
79 mV[VW] *= vec.mV[VW];
80
81 return *this;
82}
83
84// Sets all values to absolute value of their original values
85// Returns TRUE if data changed
86BOOL LLVector4::abs()
87{
88 BOOL ret = FALSE;
89
90 if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = TRUE; }
91 if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = TRUE; }
92 if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = TRUE; }
93 if (mV[3] < 0.f) { mV[3] = -mV[3]; ret = TRUE; }
94
95 return ret;
96}
97
98
99std::ostream& operator<<(std::ostream& s, const LLVector4 &a)
100{
101 s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << ", " << a.mV[VW] << " }";
102 return s;
103}
104
105
106// Non-member functions
107
108F32 angle_between( const LLVector4& a, const LLVector4& b )
109{
110 LLVector4 an = a;
111 LLVector4 bn = b;
112 an.normVec();
113 bn.normVec();
114 F32 cosine = an * bn;
115 F32 angle = (cosine >= 1.0f) ? 0.0f :
116 (cosine <= -1.0f) ? F_PI :
117 acos(cosine);
118 return angle;
119}
120
121BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon)
122{
123 LLVector4 an = a;
124 LLVector4 bn = b;
125 an.normVec();
126 bn.normVec();
127 F32 dot = an * bn;
128 if ( (1.0f - fabs(dot)) < epsilon)
129 return TRUE;
130 return FALSE;
131}
132
133
134LLVector3 vec4to3(const LLVector4 &vec)
135{
136 return LLVector3( vec.mV[VX], vec.mV[VY], vec.mV[VZ] );
137}
138
139LLVector4 vec3to4(const LLVector3 &vec)
140{
141 return LLVector4(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
142}
143
diff --git a/linden/indra/llmath/v4math.h b/linden/indra/llmath/v4math.h
new file mode 100644
index 0000000..06ac777
--- /dev/null
+++ b/linden/indra/llmath/v4math.h
@@ -0,0 +1,404 @@
1/**
2 * @file v4math.h
3 * @brief LLVector4 class header file.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_V4MATH_H
29#define LL_V4MATH_H
30
31#include "llerror.h"
32#include "llmath.h"
33#include "v3math.h"
34
35class LLMatrix3;
36class LLMatrix4;
37class LLQuaternion;
38
39// LLVector4 = |x y z w|
40
41static const U32 LENGTHOFVECTOR4 = 4;
42
43#if LL_WINDOWS
44__declspec( align(16) )
45#endif
46
47class LLVector4
48{
49 public:
50 F32 mV[LENGTHOFVECTOR4];
51 LLVector4(); // Initializes LLVector4 to (0, 0, 0, 1)
52 explicit LLVector4(const F32 *vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2], 1)
53 explicit LLVector4(const LLVector3 &vec); // Initializes LLVector4 to (vec, 1)
54 explicit LLVector4(const LLVector3 &vec, F32 w); // Initializes LLVector4 to (vec, w)
55 LLVector4(F32 x, F32 y, F32 z); // Initializes LLVector4 to (x. y, z, 1)
56 LLVector4(F32 x, F32 y, F32 z, F32 w);
57
58 LLSD getValue() const
59 {
60 LLSD ret;
61 ret[0] = mV[0];
62 ret[1] = mV[1];
63 ret[2] = mV[2];
64 ret[3] = mV[3];
65 return ret;
66 }
67
68 inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite
69
70 inline void clearVec(); // Clears LLVector4 to (0, 0, 0, 1)
71 inline void zeroVec(); // zero LLVector4 to (0, 0, 0, 0)
72 inline void setVec(F32 x, F32 y, F32 z); // Sets LLVector4 to (x, y, z, 1)
73 inline void setVec(F32 x, F32 y, F32 z, F32 w); // Sets LLVector4 to (x, y, z, w)
74 inline void setVec(const LLVector4 &vec); // Sets LLVector4 to vec
75 inline void setVec(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec
76 inline void setVec(const F32 *vec); // Sets LLVector4 to vec
77
78 F32 magVec() const; // Returns magnitude of LLVector4
79 F32 magVecSquared() const; // Returns magnitude squared of LLVector4
80 F32 normVec(); // Normalizes and returns the magnitude of LLVector4
81
82 // Sets all values to absolute value of their original values
83 // Returns TRUE if data changed
84 BOOL abs();
85
86 BOOL isExactlyClear() const { return (mV[VW] == 1.0f) && !mV[VX] && !mV[VY] && !mV[VZ]; }
87 BOOL isExactlyZero() const { return !mV[VW] && !mV[VX] && !mV[VY] && !mV[VZ]; }
88
89 const LLVector4& rotVec(F32 angle, const LLVector4 &vec); // Rotates about vec by angle radians
90 const LLVector4& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
91 const LLVector4& rotVec(const LLMatrix4 &mat); // Rotates by MAT4 mat
92 const LLVector4& rotVec(const LLQuaternion &q); // Rotates by QUAT q
93
94 const LLVector4& scaleVec(const LLVector4& vec); // Scales component-wise by vec
95
96 F32 operator[](int idx) const { return mV[idx]; }
97 F32 &operator[](int idx) { return mV[idx]; }
98
99 friend std::ostream& operator<<(std::ostream& s, const LLVector4 &a); // Print a
100 friend LLVector4 operator+(const LLVector4 &a, const LLVector4 &b); // Return vector a + b
101 friend LLVector4 operator-(const LLVector4 &a, const LLVector4 &b); // Return vector a minus b
102 friend F32 operator*(const LLVector4 &a, const LLVector4 &b); // Return a dot b
103 friend LLVector4 operator%(const LLVector4 &a, const LLVector4 &b); // Return a cross b
104 friend LLVector4 operator/(const LLVector4 &a, F32 k); // Return a divided by scaler k
105 friend LLVector4 operator*(const LLVector4 &a, F32 k); // Return a times scaler k
106 friend LLVector4 operator*(F32 k, const LLVector4 &a); // Return a times scaler k
107 friend bool operator==(const LLVector4 &a, const LLVector4 &b); // Return a == b
108 friend bool operator!=(const LLVector4 &a, const LLVector4 &b); // Return a != b
109
110 friend const LLVector4& operator+=(LLVector4 &a, const LLVector4 &b); // Return vector a + b
111 friend const LLVector4& operator-=(LLVector4 &a, const LLVector4 &b); // Return vector a minus b
112 friend const LLVector4& operator%=(LLVector4 &a, const LLVector4 &b); // Return a cross b
113 friend const LLVector4& operator*=(LLVector4 &a, F32 k); // Return a times scaler k
114 friend const LLVector4& operator/=(LLVector4 &a, F32 k); // Return a divided by scaler k
115
116 friend LLVector4 operator-(const LLVector4 &a); // Return vector -a
117}
118#if LL_DARWIN
119__attribute__ ((aligned (16)))
120#endif
121;
122
123
124// Non-member functions
125F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b
126BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel
127F32 dist_vec(const LLVector4 &a, const LLVector4 &b); // Returns distance between a and b
128F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b); // Returns distance squared between a and b
129LLVector3 vec4to3(const LLVector4 &vec);
130LLVector4 vec3to4(const LLVector3 &vec);
131LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u); // Returns a vector that is a linear interpolation between a and b
132
133// Constructors
134
135inline LLVector4::LLVector4(void)
136{
137 mV[VX] = 0.f;
138 mV[VY] = 0.f;
139 mV[VZ] = 0.f;
140 mV[VW] = 1.f;
141}
142
143inline LLVector4::LLVector4(F32 x, F32 y, F32 z)
144{
145 mV[VX] = x;
146 mV[VY] = y;
147 mV[VZ] = z;
148 mV[VW] = 1.f;
149}
150
151inline LLVector4::LLVector4(F32 x, F32 y, F32 z, F32 w)
152{
153 mV[VX] = x;
154 mV[VY] = y;
155 mV[VZ] = z;
156 mV[VW] = w;
157}
158
159inline LLVector4::LLVector4(const F32 *vec)
160{
161 mV[VX] = vec[VX];
162 mV[VY] = vec[VY];
163 mV[VZ] = vec[VZ];
164 mV[VW] = vec[VW];
165}
166
167inline LLVector4::LLVector4(const LLVector3 &vec)
168{
169 mV[VX] = vec.mV[VX];
170 mV[VY] = vec.mV[VY];
171 mV[VZ] = vec.mV[VZ];
172 mV[VW] = 1.f;
173}
174
175inline LLVector4::LLVector4(const LLVector3 &vec, F32 w)
176{
177 mV[VX] = vec.mV[VX];
178 mV[VY] = vec.mV[VY];
179 mV[VZ] = vec.mV[VZ];
180 mV[VW] = w;
181}
182
183
184inline BOOL LLVector4::isFinite() const
185{
186 return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW]));
187}
188
189// Clear and Assignment Functions
190
191inline void LLVector4::clearVec(void)
192{
193 mV[VX] = 0.f;
194 mV[VY] = 0.f;
195 mV[VZ] = 0.f;
196 mV[VW] = 1.f;
197}
198
199inline void LLVector4::zeroVec(void)
200{
201 mV[VX] = 0.f;
202 mV[VY] = 0.f;
203 mV[VZ] = 0.f;
204 mV[VW] = 0.f;
205}
206
207inline void LLVector4::setVec(F32 x, F32 y, F32 z)
208{
209 mV[VX] = x;
210 mV[VY] = y;
211 mV[VZ] = z;
212 mV[VW] = 1.f;
213}
214
215inline void LLVector4::setVec(F32 x, F32 y, F32 z, F32 w)
216{
217 mV[VX] = x;
218 mV[VY] = y;
219 mV[VZ] = z;
220 mV[VW] = w;
221}
222
223inline void LLVector4::setVec(const LLVector4 &vec)
224{
225 mV[VX] = vec.mV[VX];
226 mV[VY] = vec.mV[VY];
227 mV[VZ] = vec.mV[VZ];
228 mV[VW] = vec.mV[VW];
229}
230
231inline void LLVector4::setVec(const LLVector3 &vec, F32 w)
232{
233 mV[VX] = vec.mV[VX];
234 mV[VY] = vec.mV[VY];
235 mV[VZ] = vec.mV[VZ];
236 mV[VW] = w;
237}
238
239inline void LLVector4::setVec(const F32 *vec)
240{
241 mV[VX] = vec[VX];
242 mV[VY] = vec[VY];
243 mV[VZ] = vec[VZ];
244 mV[VW] = vec[VW];
245}
246
247// LLVector4 Magnitude and Normalization Functions
248
249inline F32 LLVector4::magVec(void) const
250{
251 return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
252}
253
254inline F32 LLVector4::magVecSquared(void) const
255{
256 return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
257}
258
259// LLVector4 Operators
260
261inline LLVector4 operator+(const LLVector4 &a, const LLVector4 &b)
262{
263 LLVector4 c(a);
264 return c += b;
265}
266
267inline LLVector4 operator-(const LLVector4 &a, const LLVector4 &b)
268{
269 LLVector4 c(a);
270 return c -= b;
271}
272
273inline F32 operator*(const LLVector4 &a, const LLVector4 &b)
274{
275 return (a.mV[VX]*b.mV[VX] + a.mV[VY]*b.mV[VY] + a.mV[VZ]*b.mV[VZ]);
276}
277
278inline LLVector4 operator%(const LLVector4 &a, const LLVector4 &b)
279{
280 return LLVector4(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]);
281}
282
283inline LLVector4 operator/(const LLVector4 &a, F32 k)
284{
285 F32 t = 1.f / k;
286 return LLVector4( a.mV[VX] * t, a.mV[VY] * t, a.mV[VZ] * t );
287}
288
289
290inline LLVector4 operator*(const LLVector4 &a, F32 k)
291{
292 return LLVector4( a.mV[VX] * k, a.mV[VY] * k, a.mV[VZ] * k );
293}
294
295inline LLVector4 operator*(F32 k, const LLVector4 &a)
296{
297 return LLVector4( a.mV[VX] * k, a.mV[VY] * k, a.mV[VZ] * k );
298}
299
300inline bool operator==(const LLVector4 &a, const LLVector4 &b)
301{
302 return ( (a.mV[VX] == b.mV[VX])
303 &&(a.mV[VY] == b.mV[VY])
304 &&(a.mV[VZ] == b.mV[VZ]));
305}
306
307inline bool operator!=(const LLVector4 &a, const LLVector4 &b)
308{
309 return ( (a.mV[VX] != b.mV[VX])
310 ||(a.mV[VY] != b.mV[VY])
311 ||(a.mV[VZ] != b.mV[VZ]));
312}
313
314inline const LLVector4& operator+=(LLVector4 &a, const LLVector4 &b)
315{
316 a.mV[VX] += b.mV[VX];
317 a.mV[VY] += b.mV[VY];
318 a.mV[VZ] += b.mV[VZ];
319 return a;
320}
321
322inline const LLVector4& operator-=(LLVector4 &a, const LLVector4 &b)
323{
324 a.mV[VX] -= b.mV[VX];
325 a.mV[VY] -= b.mV[VY];
326 a.mV[VZ] -= b.mV[VZ];
327 return a;
328}
329
330inline const LLVector4& operator%=(LLVector4 &a, const LLVector4 &b)
331{
332 LLVector4 ret(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]);
333 a = ret;
334 return a;
335}
336
337inline const LLVector4& operator*=(LLVector4 &a, F32 k)
338{
339 a.mV[VX] *= k;
340 a.mV[VY] *= k;
341 a.mV[VZ] *= k;
342 return a;
343}
344
345inline const LLVector4& operator/=(LLVector4 &a, F32 k)
346{
347 F32 t = 1.f / k;
348 a.mV[VX] *= t;
349 a.mV[VY] *= t;
350 a.mV[VZ] *= t;
351 return a;
352}
353
354inline LLVector4 operator-(const LLVector4 &a)
355{
356 return LLVector4( -a.mV[VX], -a.mV[VY], -a.mV[VZ] );
357}
358
359inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b)
360{
361 LLVector4 vec = a - b;
362 return (vec.magVec());
363}
364
365inline F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b)
366{
367 LLVector4 vec = a - b;
368 return (vec.magVecSquared());
369}
370
371inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u)
372{
373 return LLVector4(
374 a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
375 a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u,
376 a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u,
377 a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);
378}
379
380inline F32 LLVector4::normVec(void)
381{
382 F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
383 F32 oomag;
384
385 if (mag > FP_MAG_THRESHOLD)
386 {
387 oomag = 1.f/mag;
388 mV[VX] *= oomag;
389 mV[VY] *= oomag;
390 mV[VZ] *= oomag;
391 }
392 else
393 {
394 mV[0] = 0.f;
395 mV[1] = 0.f;
396 mV[2] = 0.f;
397 mag = 0;
398 }
399 return (mag);
400}
401
402
403#endif
404
diff --git a/linden/indra/llmath/xform.cpp b/linden/indra/llmath/xform.cpp
new file mode 100644
index 0000000..fc2e060
--- /dev/null
+++ b/linden/indra/llmath/xform.cpp
@@ -0,0 +1,115 @@
1/**
2 * @file xform.cpp
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "xform.h"
30
31LLXform::LLXform()
32{
33 init();
34}
35
36LLXform::~LLXform()
37{
38}
39
40
41LLXform* LLXform::getRoot() const
42{
43 const LLXform* root = this;
44 while(root->mParent)
45 {
46 root = root->mParent;
47 }
48 return (LLXform*)root;
49}
50
51BOOL LLXform::isRoot() const
52{
53 return (!mParent);
54}
55
56BOOL LLXform::isRootEdit() const
57{
58 return (!mParent);
59}
60
61LLXformMatrix::~LLXformMatrix()
62{
63}
64
65void LLXformMatrix::update()
66{
67 if (mParent)
68 {
69 mWorldPosition = mPosition;
70 if (mParent->getScaleChildOffset())
71 {
72 mWorldPosition.scaleVec(mParent->getScale());
73 }
74 mWorldPosition *= mParent->getWorldRotation();
75 mWorldPosition += mParent->getWorldPosition();
76 mWorldRotation = mRotation * mParent->getWorldRotation();
77 }
78 else
79 {
80 mWorldPosition = mPosition;
81 mWorldRotation = mRotation;
82 }
83}
84
85void LLXformMatrix::updateMatrix(BOOL update_bounds)
86{
87 update();
88
89 mWorldMatrix.initAll(mScale, mWorldRotation, mWorldPosition);
90
91 if (update_bounds && (mChanged & MOVED))
92 {
93 mMin.mV[0] = mMax.mV[0] = mWorldMatrix.mMatrix[3][0];
94 mMin.mV[1] = mMax.mV[1] = mWorldMatrix.mMatrix[3][1];
95 mMin.mV[2] = mMax.mV[2] = mWorldMatrix.mMatrix[3][2];
96
97 F32 f0 = (fabs(mWorldMatrix.mMatrix[0][0])+fabs(mWorldMatrix.mMatrix[1][0])+fabs(mWorldMatrix.mMatrix[2][0])) * 0.5f;
98 F32 f1 = (fabs(mWorldMatrix.mMatrix[0][1])+fabs(mWorldMatrix.mMatrix[1][1])+fabs(mWorldMatrix.mMatrix[2][1])) * 0.5f;
99 F32 f2 = (fabs(mWorldMatrix.mMatrix[0][2])+fabs(mWorldMatrix.mMatrix[1][2])+fabs(mWorldMatrix.mMatrix[2][2])) * 0.5f;
100
101 mMin.mV[0] -= f0;
102 mMin.mV[1] -= f1;
103 mMin.mV[2] -= f2;
104
105 mMax.mV[0] += f0;
106 mMax.mV[1] += f1;
107 mMax.mV[2] += f2;
108 }
109}
110
111void LLXformMatrix::getMinMax(LLVector3& min, LLVector3& max) const
112{
113 min = mMin;
114 max = mMax;
115}
diff --git a/linden/indra/llmath/xform.h b/linden/indra/llmath/xform.h
new file mode 100644
index 0000000..af28e43
--- /dev/null
+++ b/linden/indra/llmath/xform.h
@@ -0,0 +1,288 @@
1/**
2 * @file xform.h
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#ifndef LL_XFORM_H
28#define LL_XFORM_H
29
30#include "v3math.h"
31#include "m4math.h"
32#include "llquaternion.h"
33
34#define CHECK_FOR_FINITE
35
36
37const F32 MAX_OBJECT_Z = 768.f;
38const F32 MIN_OBJECT_Z = -256.f;
39const F32 MIN_OBJECT_SCALE = 0.01f;
40const F32 MAX_OBJECT_SCALE = 10.f;
41
42class LLXform
43{
44protected:
45 LLVector3 mPosition;
46 LLQuaternion mRotation;
47 LLVector3 mScale;
48
49 //RN: TODO: move these world transform members to LLXformMatrix
50 // as they are *never* updated or accessed in the base class
51 LLVector3 mWorldPosition;
52 LLQuaternion mWorldRotation;
53
54 LLXform* mParent;
55 U32 mChanged;
56
57 BOOL mScaleChildOffset;
58
59public:
60 typedef enum e_changed_flags
61 {
62 UNCHANGED = 0x00,
63 TRANSLATED = 0x01,
64 ROTATED = 0x02,
65 SCALED = 0x04,
66 SHIFTED = 0x08,
67 GEOMETRY = 0x10,
68 TEXTURE = 0x20,
69 MOVED = TRANSLATED|ROTATED|SCALED,
70 SILHOUETTE = 0x40,
71 ALL_CHANGED = 0x7f
72 }EChangedFlags;
73
74 void init()
75 {
76 mParent = NULL;
77 mChanged = UNCHANGED;
78 mPosition.setVec(0,0,0);
79 mRotation.loadIdentity();
80 mScale. setVec(1,1,1);
81 mWorldPosition.clearVec();
82 mWorldRotation.loadIdentity();
83 mScaleChildOffset = FALSE;
84 }
85
86 LLXform();
87 virtual ~LLXform();
88
89 void getLocalMat4(LLMatrix4 &mat) const { mat.initAll(mScale, mRotation, mPosition); }
90
91 inline BOOL setParent(LLXform *parent);
92
93 inline void setPosition(const LLVector3& pos);
94 inline void setPosition(const F32 x, const F32 y, const F32 z);
95 inline void setPositionX(const F32 x);
96 inline void setPositionY(const F32 y);
97 inline void setPositionZ(const F32 z);
98 inline void addPosition(const LLVector3& pos);
99
100
101 inline void setScale(const LLVector3& scale);
102 inline void setScale(const F32 x, const F32 y, const F32 z);
103 inline void setRotation(const LLQuaternion& rot);
104 inline void setRotation(const F32 x, const F32 y, const F32 z);
105 inline void setRotation(const F32 x, const F32 y, const F32 z, const F32 s);
106
107 void setChanged(const U32 bits) { mChanged |= bits; }
108 BOOL isChanged() const { return mChanged; }
109 BOOL isChanged(const U32 bits) const { return mChanged & bits; }
110 void clearChanged() { mChanged = 0; }
111 void clearChanged(U32 bits) { mChanged &= ~bits; }
112
113 void setScaleChildOffset(BOOL scale) { mScaleChildOffset = scale; }
114 BOOL getScaleChildOffset() { return mScaleChildOffset; }
115
116 LLXform* getParent() const { return mParent; }
117 LLXform* getRoot() const;
118 virtual BOOL isRoot() const;
119 virtual BOOL isRootEdit() const;
120
121 const LLVector3& getPosition() const { return mPosition; }
122 const LLVector3& getScale() const { return mScale; }
123 const LLQuaternion& getRotation() const { return mRotation; }
124 const LLVector3& getPositionW() const { return mWorldPosition; }
125 const LLQuaternion& getWorldRotation() const { return mWorldRotation; }
126 const LLVector3& getWorldPosition() const { return mWorldPosition; }
127};
128
129class LLXformMatrix : public LLXform
130{
131public:
132 LLXformMatrix() : LLXform() {};
133 virtual ~LLXformMatrix();
134
135 const LLMatrix4& getWorldMatrix() const { return mWorldMatrix; }
136 void setWorldMatrix (const LLMatrix4& mat) { mWorldMatrix = mat; }
137
138 void init()
139 {
140 mWorldMatrix.identity();
141 mMin.clearVec();
142 mMax.clearVec();
143
144 LLXform::init();
145 }
146
147 void update();
148 void updateMatrix(BOOL update_bounds = TRUE);
149 void getMinMax(LLVector3& min,LLVector3& max) const;
150
151protected:
152 LLMatrix4 mWorldMatrix;
153 LLVector3 mMin;
154 LLVector3 mMax;
155
156};
157
158BOOL LLXform::setParent(LLXform* parent)
159{
160 // Validate and make sure we're not creating a loop
161 if (parent == mParent)
162 {
163 return TRUE;
164 }
165 if (parent)
166 {
167 LLXform *cur_par = parent->mParent;
168 while (cur_par)
169 {
170 if (cur_par == this)
171 {
172 llwarns << "LLXform::setParent Creating loop when setting parent!" << llendl;
173 return FALSE;
174 }
175 cur_par = cur_par->mParent;
176 }
177 }
178 mParent = parent;
179 return TRUE;
180}
181
182#ifdef CHECK_FOR_FINITE
183void LLXform::setPosition(const LLVector3& pos)
184{
185 setChanged(TRANSLATED);
186 if (pos.isFinite())
187 mPosition = pos;
188 else
189 llerror("Non Finite in LLXform::setPosition(LLVector3)", 0);
190}
191
192void LLXform::setPosition(const F32 x, const F32 y, const F32 z)
193{
194 setChanged(TRANSLATED);
195 if (llfinite(x) && llfinite(y) && llfinite(z))
196 mPosition.setVec(x,y,z);
197 else
198 llerror("Non Finite in LLXform::setPosition(F32,F32,F32)", 0);
199}
200
201void LLXform::setPositionX(const F32 x)
202{
203 setChanged(TRANSLATED);
204 if (llfinite(x))
205 mPosition.mV[VX] = x;
206 else
207 llerror("Non Finite in LLXform::setPositionX", 0);
208}
209
210void LLXform::setPositionY(const F32 y)
211{
212 setChanged(TRANSLATED);
213 if (llfinite(y))
214 mPosition.mV[VY] = y;
215 else
216 llerror("Non Finite in LLXform::setPositionY", 0);
217}
218
219void LLXform::setPositionZ(const F32 z)
220{
221 setChanged(TRANSLATED);
222 if (llfinite(z))
223 mPosition.mV[VZ] = z;
224 else
225 llerror("Non Finite in LLXform::setPositionZ", 0);
226}
227
228void LLXform::addPosition(const LLVector3& pos)
229{
230 setChanged(TRANSLATED);
231 if (pos.isFinite())
232 mPosition += pos;
233 else
234 llerror("Non Finite in LLXform::addPosition", 0);
235}
236
237void LLXform::setScale(const LLVector3& scale)
238{
239 setChanged(SCALED);
240 if (scale.isFinite())
241 mScale = scale;
242 else
243 llerror("Non Finite in LLXform::setScale", 0);
244}
245void LLXform::setScale(const F32 x, const F32 y, const F32 z)
246{
247 setChanged(SCALED);
248 if (llfinite(x) && llfinite(y) && llfinite(z))
249 mScale.setVec(x,y,z);
250 else
251 llerror("Non Finite in LLXform::setScale", 0);
252}
253void LLXform::setRotation(const LLQuaternion& rot)
254{
255 setChanged(ROTATED);
256 if (rot.isFinite())
257 mRotation = rot;
258 else
259 llerror("Non Finite in LLXform::setRotation", 0);
260}
261void LLXform::setRotation(const F32 x, const F32 y, const F32 z)
262{
263 setChanged(ROTATED);
264 if (llfinite(x) && llfinite(y) && llfinite(z))
265 {
266 mRotation.setQuat(x,y,z);
267 }
268 else
269 {
270 llerror("Non Finite in LLXform::setRotation", 0);
271 }
272}
273void LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s)
274{
275 setChanged(ROTATED);
276 if (llfinite(x) && llfinite(y) && llfinite(z) && llfinite(s))
277 {
278 mRotation.mQ[VX] = x; mRotation.mQ[VY] = y; mRotation.mQ[VZ] = z; mRotation.mQ[VS] = s;
279 }
280 else
281 {
282 llerror("Non Finite in LLXform::setRotation", 0);
283 }
284}
285
286#endif
287
288#endif