diff options
Diffstat (limited to 'linden/indra/llmath')
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 @@ | |||
1 | llmath/llbboxlocal.cpp | ||
2 | llmath/llcamera.cpp | ||
3 | llmath/llcoordframe.cpp | ||
4 | llmath/llcrc.cpp | ||
5 | llmath/llmd5.cpp | ||
6 | llmath/llperlin.cpp | ||
7 | llmath/llquaternion.cpp | ||
8 | llmath/llrand.cpp | ||
9 | llmath/llrect.cpp | ||
10 | llmath/lluuid.cpp | ||
11 | llmath/llvolume.cpp | ||
12 | llmath/llvolumemgr.cpp | ||
13 | llmath/m3math.cpp | ||
14 | llmath/m4math.cpp | ||
15 | llmath/raytrace.cpp | ||
16 | llmath/v2math.cpp | ||
17 | llmath/v3color.cpp | ||
18 | llmath/v3dmath.cpp | ||
19 | llmath/v3math.cpp | ||
20 | llmath/v4color.cpp | ||
21 | llmath/v4coloru.cpp | ||
22 | llmath/v4math.cpp | ||
23 | llmath/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 | |||
33 | void 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 | |||
43 | void 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 | |||
53 | LLBBoxLocal 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 | |||
33 | class LLMatrix4; | ||
34 | |||
35 | class LLBBoxLocal | ||
36 | { | ||
37 | public: | ||
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 | |||
61 | private: | ||
62 | LLVector3 mMin; | ||
63 | LLVector3 mMax; | ||
64 | }; | ||
65 | |||
66 | LLBBoxLocal 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 | |||
35 | LLCamera::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 | |||
48 | LLCamera::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 | |||
77 | void 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 | |||
85 | void 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 | |||
93 | void 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 | |||
102 | void 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 | |||
111 | void 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 | |||
122 | size_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 | |||
134 | size_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 | |||
149 | int LLCamera::AABBInFrustum(const LLVector3 ¢er, 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 | |||
190 | int 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. | ||
209 | int 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. | ||
305 | int 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 | ||
329 | F32 LLCamera::heightInPixels(const LLVector3 ¢er, 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 | ||
361 | F32 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 | ||
393 | F32 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 | |||
420 | std::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 | |||
451 | void 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 | |||
468 | LLPlane 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 | |||
477 | void 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 | |||
530 | void 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) | ||
560 | void 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 | |||
574 | void 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 | |||
36 | const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD; | ||
37 | const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f; | ||
38 | const F32 DEFAULT_NEAR_PLANE = 0.25f; | ||
39 | const F32 DEFAULT_FAR_PLANE = 64.f; // far reaches across two horizontal, not diagonal, regions | ||
40 | |||
41 | const F32 MAX_FIELD_OF_VIEW = F_PI; | ||
42 | const F32 MAX_ASPECT_RATIO = 50.0f; | ||
43 | const F32 MAX_NEAR_PLANE = 10.f; | ||
44 | const F32 MAX_FAR_PLANE = 100000.0f; //1000000.0f; // Max allowed. Not good Z precision though. | ||
45 | const F32 MAX_FAR_CLIP = 1024.0f; | ||
46 | |||
47 | const F32 MIN_FIELD_OF_VIEW = 0.1f; | ||
48 | const F32 MIN_ASPECT_RATIO = 0.02f; | ||
49 | const F32 MIN_NEAR_PLANE = 0.1f; | ||
50 | const F32 MIN_FAR_PLANE = 0.2f; | ||
51 | |||
52 | static const LLVector3 X_AXIS(1.f,0.f,0.f); | ||
53 | static const LLVector3 Y_AXIS(0.f,1.f,0.f); | ||
54 | static const LLVector3 Z_AXIS(0.f,0.f,1.f); | ||
55 | |||
56 | static const LLVector3 NEG_X_AXIS(-1.f,0.f,0.f); | ||
57 | static const LLVector3 NEG_Y_AXIS(0.f,-1.f,0.f); | ||
58 | static 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 | |||
71 | class LLCamera | ||
72 | : public LLCoordFrame | ||
73 | { | ||
74 | public: | ||
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 | |||
100 | protected: | ||
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) | ||
116 | public: | ||
117 | LLVector3 mAgentFrustum[8]; | ||
118 | |||
119 | public: | ||
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 ¢er, const F32 radius) const; | ||
159 | S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const; | ||
160 | S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); } | ||
161 | S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); } | ||
162 | S32 AABBInFrustum(const LLVector3 ¢er, 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 ¢er, 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 | |||
177 | protected: | ||
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 | ||
31 | class LLCoord | ||
32 | { | ||
33 | public: | ||
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 | ||
50 | class LLCoordGL : public LLCoord | ||
51 | { | ||
52 | public: | ||
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. | ||
62 | class LLCoordWindow : public LLCoord | ||
63 | { | ||
64 | public: | ||
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 | ||
73 | class LLCoordScreen : public LLCoord | ||
74 | { | ||
75 | public: | ||
76 | LLCoordScreen() : LLCoord() | ||
77 | {} | ||
78 | LLCoordScreen(S32 x, S32 y) : LLCoord(x, y) | ||
79 | {} | ||
80 | }; | ||
81 | |||
82 | class LLCoordFont : public LLCoord | ||
83 | { | ||
84 | public: | ||
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 | |||
46 | LLCoordFrame::LLCoordFrame() : | ||
47 | mOrigin(0.f, 0.f, 0.f), | ||
48 | mXAxis(X_AXIS), | ||
49 | mYAxis(Y_AXIS), | ||
50 | mZAxis(Z_AXIS) | ||
51 | { | ||
52 | } | ||
53 | |||
54 | LLCoordFrame::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 | |||
66 | LLCoordFrame::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 | |||
77 | LLCoordFrame::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 | |||
91 | LLCoordFrame::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 | |||
107 | LLCoordFrame::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 | |||
120 | LLCoordFrame::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 | |||
134 | LLCoordFrame::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 | |||
148 | LLCoordFrame::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 | /* | ||
163 | LLCoordFrame::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 | /* | ||
177 | LLCoordFrame::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 | |||
191 | void LLCoordFrame::reset() | ||
192 | { | ||
193 | mOrigin.setVec(0.0f, 0.0f, 0.0f); | ||
194 | resetAxes(); | ||
195 | } | ||
196 | |||
197 | |||
198 | void 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 | |||
207 | void 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 | |||
217 | void 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 | |||
226 | void 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 | |||
238 | void 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 | |||
251 | void 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 | |||
265 | void 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 | |||
277 | void 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 | |||
288 | void 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 | |||
307 | void 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 | |||
322 | void 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 | |||
335 | void 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 | |||
346 | void 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 | |||
361 | void 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 | |||
368 | void LLCoordFrame::rotate(F32 angle, const LLVector3 &rotation_axis) | ||
369 | { | ||
370 | LLQuaternion q(angle, rotation_axis); | ||
371 | rotate(q); | ||
372 | } | ||
373 | |||
374 | |||
375 | void LLCoordFrame::rotate(const LLQuaternion &q) | ||
376 | { | ||
377 | LLMatrix3 rotation_matrix(q); | ||
378 | rotate(rotation_matrix); | ||
379 | } | ||
380 | |||
381 | |||
382 | void 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 | |||
395 | void 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 | |||
407 | void 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 | |||
419 | void 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 | |||
434 | LLQuaternion LLCoordFrame::getQuaternion() const | ||
435 | { | ||
436 | LLQuaternion quat(mXAxis, mYAxis, mZAxis); | ||
437 | return quat; | ||
438 | } | ||
439 | |||
440 | |||
441 | void 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 | |||
453 | void 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 | |||
461 | size_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 | |||
474 | size_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 | |||
495 | LLVector3 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 | |||
504 | LLVector4 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 | |||
521 | LLVector3 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 | |||
537 | LLVector4 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 | |||
554 | void 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 | |||
564 | LLVector3 LLCoordFrame::transformToLocal(const LLVector3 &absolute_vector) const | ||
565 | { | ||
566 | return rotateToLocal(absolute_vector - mOrigin); | ||
567 | } | ||
568 | |||
569 | |||
570 | LLVector4 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 | |||
580 | LLVector3 LLCoordFrame::transformToAbsolute(const LLVector3 &local_vector) const | ||
581 | { | ||
582 | return (rotateToAbsolute(local_vector) + mOrigin); | ||
583 | } | ||
584 | |||
585 | |||
586 | LLVector4 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 | |||
613 | void 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 | |||
637 | void 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 | |||
662 | void 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 | ||
687 | void 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 | |||
705 | void LLCoordFrame::lookDir(const LLVector3 &xuv) | ||
706 | { | ||
707 | static LLVector3 up_direction(0.0f, 0.0f, 1.0f); | ||
708 | lookDir(xuv, up_direction); | ||
709 | } | ||
710 | |||
711 | void 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 | |||
719 | void 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 | |||
732 | std::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 | |||
41 | class LLCoordFrame | ||
42 | { | ||
43 | public: | ||
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 | |||
89 | static U32 crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ | ||
90 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | ||
91 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, | ||
92 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, | ||
93 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, | ||
94 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, | ||
95 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, | ||
96 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, | ||
97 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, | ||
98 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, | ||
99 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, | ||
100 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, | ||
101 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, | ||
102 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, | ||
103 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, | ||
104 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, | ||
105 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | ||
106 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, | ||
107 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, | ||
108 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, | ||
109 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, | ||
110 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | ||
111 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, | ||
112 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, | ||
113 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, | ||
114 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, | ||
115 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, | ||
116 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, | ||
117 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | ||
118 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, | ||
119 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, | ||
120 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, | ||
121 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, | ||
122 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, | ||
123 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, | ||
124 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, | ||
125 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | ||
126 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, | ||
127 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, | ||
128 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, | ||
129 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, | ||
130 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, | ||
131 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, | ||
132 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | ||
133 | }; | ||
134 | |||
135 | |||
136 | ///---------------------------------------------------------------------------- | ||
137 | /// Class llcrc | ||
138 | ///---------------------------------------------------------------------------- | ||
139 | |||
140 | // Default constructor | ||
141 | LLCRC::LLCRC() : mCurrent(0xffffffff) | ||
142 | { | ||
143 | } | ||
144 | |||
145 | |||
146 | U32 LLCRC::getCRC() const | ||
147 | { | ||
148 | return ~mCurrent; | ||
149 | } | ||
150 | |||
151 | void LLCRC::update(U8 next_byte) | ||
152 | { | ||
153 | mCurrent = UPDC32(next_byte, mCurrent); | ||
154 | } | ||
155 | |||
156 | void 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 | |||
164 | void 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 | ||
186 | BOOL 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 | |||
48 | class LLCRC | ||
49 | { | ||
50 | protected: | ||
51 | U32 mCurrent; | ||
52 | |||
53 | public: | ||
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 | |||
34 | class LLInterpVal | ||
35 | { | ||
36 | public: | ||
37 | virtual ~LLInterpVal() {} | ||
38 | virtual void interp(LLInterpVal &target, const F32 frac); // Linear interpolation for each type | ||
39 | }; | ||
40 | |||
41 | template <typename Type> | ||
42 | class LLInterp | ||
43 | { | ||
44 | public: | ||
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 | |||
67 | protected: | ||
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 | |||
81 | template <typename Type> | ||
82 | class LLInterpLinear : public LLInterp<Type> | ||
83 | { | ||
84 | public: | ||
85 | /*virtual*/ void start(); | ||
86 | void update(const F32 time); | ||
87 | F32 getCurFrac() const; | ||
88 | protected: | ||
89 | F32 mCurFrac; | ||
90 | }; | ||
91 | |||
92 | template <typename Type> | ||
93 | class LLInterpExp : public LLInterpLinear<Type> | ||
94 | { | ||
95 | public: | ||
96 | void update(const F32 time); | ||
97 | protected: | ||
98 | }; | ||
99 | |||
100 | template <typename Type> | ||
101 | class LLInterpAttractor : public LLInterp<Type> | ||
102 | { | ||
103 | public: | ||
104 | LLInterpAttractor(); | ||
105 | /*virtual*/ void start(); | ||
106 | void setStartVel(const Type &vel); | ||
107 | void setForce(const F32 force); | ||
108 | void update(const F32 time); | ||
109 | protected: | ||
110 | F32 mForce; | ||
111 | Type mStartVel; | ||
112 | Type mVelocity; | ||
113 | }; | ||
114 | |||
115 | template <typename Type> | ||
116 | class LLInterpFunc : public LLInterp<Type> | ||
117 | { | ||
118 | public: | ||
119 | LLInterpFunc(); | ||
120 | void update(const F32 time); | ||
121 | |||
122 | void setFunc(Type (*)(const F32, void *data), void *data); | ||
123 | protected: | ||
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 | |||
140 | template <typename Type> | ||
141 | LLInterp<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 | |||
151 | template <class Type> | ||
152 | void LLInterp<Type>::setStartVal(const Type &start_val) | ||
153 | { | ||
154 | mStartVal = start_val; | ||
155 | } | ||
156 | |||
157 | template <class Type> | ||
158 | void LLInterp<Type>::start() | ||
159 | { | ||
160 | mCurVal = mStartVal; | ||
161 | mCurTime = mStartTime; | ||
162 | mDone = FALSE; | ||
163 | mActive = FALSE; | ||
164 | } | ||
165 | |||
166 | template <class Type> | ||
167 | const Type &LLInterp<Type>::getStartVal() const | ||
168 | { | ||
169 | return mStartVal; | ||
170 | } | ||
171 | |||
172 | template <class Type> | ||
173 | void LLInterp<Type>::setEndVal(const Type &end_val) | ||
174 | { | ||
175 | mEndVal = end_val; | ||
176 | } | ||
177 | |||
178 | template <class Type> | ||
179 | const Type &LLInterp<Type>::getEndVal() const | ||
180 | { | ||
181 | return mEndVal; | ||
182 | } | ||
183 | |||
184 | template <class Type> | ||
185 | const Type &LLInterp<Type>::getCurVal() const | ||
186 | { | ||
187 | return mCurVal; | ||
188 | } | ||
189 | |||
190 | |||
191 | template <class Type> | ||
192 | void LLInterp<Type>::setStartTime(const F32 start_time) | ||
193 | { | ||
194 | mStartTime = start_time; | ||
195 | mDuration = mEndTime - mStartTime; | ||
196 | } | ||
197 | |||
198 | template <class Type> | ||
199 | F32 LLInterp<Type>::getStartTime() const | ||
200 | { | ||
201 | return mStartTime; | ||
202 | } | ||
203 | |||
204 | |||
205 | template <class Type> | ||
206 | void LLInterp<Type>::setEndTime(const F32 end_time) | ||
207 | { | ||
208 | mEndTime = end_time; | ||
209 | mDuration = mEndTime - mStartTime; | ||
210 | } | ||
211 | |||
212 | |||
213 | template <class Type> | ||
214 | F32 LLInterp<Type>::getEndTime() const | ||
215 | { | ||
216 | return mEndTime; | ||
217 | } | ||
218 | |||
219 | |||
220 | template <class Type> | ||
221 | BOOL LLInterp<Type>::isDone() const | ||
222 | { | ||
223 | return mDone; | ||
224 | } | ||
225 | |||
226 | template <class Type> | ||
227 | BOOL LLInterp<Type>::isActive() const | ||
228 | { | ||
229 | return mActive; | ||
230 | } | ||
231 | |||
232 | ////////////////////////////// | ||
233 | // | ||
234 | // LLInterpLinear derived class implementation. | ||
235 | // | ||
236 | template <typename Type> | ||
237 | void LLInterpLinear<Type>::start() | ||
238 | { | ||
239 | LLInterp<Type>::start(); | ||
240 | mCurFrac = 0.f; | ||
241 | } | ||
242 | |||
243 | template <typename Type> | ||
244 | void 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 | |||
282 | template <class Type> | ||
283 | F32 LLInterpLinear<Type>::getCurFrac() const | ||
284 | { | ||
285 | return mCurFrac; | ||
286 | } | ||
287 | |||
288 | |||
289 | ////////////////////////////// | ||
290 | // | ||
291 | // LLInterpAttractor derived class implementation. | ||
292 | // | ||
293 | |||
294 | |||
295 | template <class Type> | ||
296 | LLInterpAttractor<Type>::LLInterpAttractor() : LLInterp<Type>() | ||
297 | { | ||
298 | mForce = 0.1f; | ||
299 | mVelocity *= 0.f; | ||
300 | mStartVel *= 0.f; | ||
301 | } | ||
302 | |||
303 | template <class Type> | ||
304 | void LLInterpAttractor<Type>::start() | ||
305 | { | ||
306 | LLInterp<Type>::start(); | ||
307 | mVelocity = mStartVel; | ||
308 | } | ||
309 | |||
310 | |||
311 | template <class Type> | ||
312 | void LLInterpAttractor<Type>::setStartVel(const Type &vel) | ||
313 | { | ||
314 | mStartVel = vel; | ||
315 | } | ||
316 | |||
317 | template <class Type> | ||
318 | void LLInterpAttractor<Type>::setForce(const F32 force) | ||
319 | { | ||
320 | mForce = force; | ||
321 | } | ||
322 | |||
323 | template <class Type> | ||
324 | void 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 | |||
355 | template <class Type> | ||
356 | LLInterpFunc<Type>::LLInterpFunc() : LLInterp<Type>() | ||
357 | { | ||
358 | mFunc = NULL; | ||
359 | mData = NULL; | ||
360 | } | ||
361 | |||
362 | template <class Type> | ||
363 | void LLInterpFunc<Type>::setFunc(Type (*func)(const F32, void *data), void *data) | ||
364 | { | ||
365 | mFunc = func; | ||
366 | mData = data; | ||
367 | } | ||
368 | |||
369 | template <class Type> | ||
370 | void 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 | |||
395 | template <class Type> | ||
396 | void 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 | |||
74 | const F32 GRAVITY = -9.8f; | ||
75 | |||
76 | // mathematical constants | ||
77 | const F32 F_PI = 3.1415926535897932384626433832795f; | ||
78 | const F32 F_TWO_PI = 6.283185307179586476925286766559f; | ||
79 | const F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f; | ||
80 | const F32 F_SQRT2 = 1.4142135623730950488016887242097f; | ||
81 | const F32 F_SQRT3 = 1.73205080756888288657986402541f; | ||
82 | const F32 OO_SQRT2 = 0.7071067811865475244008443621049f; | ||
83 | const F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; | ||
84 | const F32 RAD_TO_DEG = 57.295779513082320876798154814105f; | ||
85 | const F32 F_APPROXIMATELY_ZERO = 0.00001f; | ||
86 | const F32 F_LN2 = 0.69314718056f; | ||
87 | const F32 OO_LN2 = 1.4426950408889634073599246810019f; | ||
88 | |||
89 | // BUG: Eliminate in favor of F_APPROXIMATELY_ZERO above? | ||
90 | const F32 FP_MAG_THRESHOLD = 0.0000001f; | ||
91 | |||
92 | // TODO: Replace with logic like is_approx_equal | ||
93 | inline BOOL is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } | ||
94 | |||
95 | inline 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 | |||
101 | inline S32 llabs(const S32 a) | ||
102 | { | ||
103 | return S32(labs(a)); | ||
104 | } | ||
105 | |||
106 | inline F32 llabs(const F32 a) | ||
107 | { | ||
108 | return F32(fabs(a)); | ||
109 | } | ||
110 | |||
111 | inline F64 llabs(const F64 a) | ||
112 | { | ||
113 | return F64(fabs(a)); | ||
114 | } | ||
115 | |||
116 | inline 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 | |||
137 | inline S32 lltrunc( F64 f ) | ||
138 | { | ||
139 | return (S32)f; | ||
140 | } | ||
141 | |||
142 | inline 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 | |||
162 | inline 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) | ||
171 | inline 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. | ||
180 | inline 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 | ||
203 | inline 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 | |||
219 | inline F32 llround( F32 val, F32 nearest ) | ||
220 | { | ||
221 | return F32(floor(val * (1.0f / nearest) + 0.5f)) * nearest; | ||
222 | } | ||
223 | |||
224 | inline 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 | |||
235 | const F32 FAST_MAG_ALPHA = 0.960433870103f; | ||
236 | const 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 | |||
247 | inline 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 | |||
262 | const F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor | ||
263 | const 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 | // ================================================================================================ | ||
278 | inline 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 | // ================================================================================================ | ||
287 | inline 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 | ||
300 | static 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 | |||
320 | inline F32 llfastpow(const F32 x, const F32 y) | ||
321 | { | ||
322 | return (F32)(LL_FAST_EXP(y * log(x))); | ||
323 | } | ||
324 | |||
325 | |||
326 | inline 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 | |||
342 | inline F32 lerp(F32 a, F32 b, F32 u) | ||
343 | { | ||
344 | return a + ((b - a) * u); | ||
345 | } | ||
346 | |||
347 | inline 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 | |||
355 | inline F32 ramp(F32 x, F32 a, F32 b) | ||
356 | { | ||
357 | return (a == b) ? 0.0f : ((a - x) / (a - b)); | ||
358 | } | ||
359 | |||
360 | inline F32 rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2) | ||
361 | { | ||
362 | return lerp(y1, y2, ramp(x, x1, x2)); | ||
363 | } | ||
364 | |||
365 | inline 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 | |||
378 | inline 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 | |||
391 | inline F32 cubic_step( F32 x ) | ||
392 | { | ||
393 | x = llclampf(x); | ||
394 | |||
395 | return (x * x) * (3.0f - 2.0f * x); | ||
396 | } | ||
397 | |||
398 | inline 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 | |||
412 | inline 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 | ||
50 | rights reserved. | ||
51 | |||
52 | License to copy and use this software is granted provided that it | ||
53 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest | ||
54 | Algorithm" in all material mentioning or referencing this software | ||
55 | or this function. | ||
56 | |||
57 | License is also granted to make and use derivative works provided | ||
58 | that such works are identified as "derived from the RSA Data | ||
59 | Security, Inc. MD5 Message-Digest Algorithm" in all material | ||
60 | mentioning or referencing the derived work. | ||
61 | |||
62 | RSA Data Security, Inc. makes no representations concerning either | ||
63 | the merchantability of this software or the suitability of this | ||
64 | software for any particular purpose. It is provided "as is" | ||
65 | without express or implied warranty of any kind. | ||
66 | |||
67 | These notices must be retained in any copies of any part of this | ||
68 | documentation 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 | |||
88 | LLMD5::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 | |||
100 | void 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 | |||
148 | void 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 | |||
168 | void 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 | |||
189 | void 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 | |||
211 | void 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 | |||
250 | LLMD5::LLMD5(FILE *file){ | ||
251 | |||
252 | init(); // must be called be all constructors | ||
253 | update(file); | ||
254 | finalize (); | ||
255 | } | ||
256 | |||
257 | |||
258 | |||
259 | |||
260 | LLMD5::LLMD5(std::istream& stream){ | ||
261 | |||
262 | init(); // must called by all constructors | ||
263 | update (stream); | ||
264 | finalize(); | ||
265 | } | ||
266 | |||
267 | |||
268 | |||
269 | LLMD5::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)) | ||
277 | LLMD5::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 | ||
290 | LLMD5::LLMD5(const unsigned char *s) | ||
291 | { | ||
292 | init(); | ||
293 | update(s, (U32)strlen((const char *) s)); | ||
294 | finalize(); | ||
295 | } | ||
296 | |||
297 | void 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 | |||
313 | void 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 | |||
339 | std::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 | |||
354 | void 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. | ||
395 | void 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. | ||
489 | void 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. | ||
506 | void 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 | |||
521 | inline 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 | |||
530 | inline unsigned int LLMD5::F (uint4 x, uint4 y, uint4 z){ | ||
531 | return (x & y) | (~x & z); | ||
532 | } | ||
533 | |||
534 | inline unsigned int LLMD5::G (uint4 x, uint4 y, uint4 z){ | ||
535 | return (x & z) | (y & ~z); | ||
536 | } | ||
537 | |||
538 | inline unsigned int LLMD5::H (uint4 x, uint4 y, uint4 z){ | ||
539 | return x ^ y ^ z; | ||
540 | } | ||
541 | |||
542 | inline 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 | |||
552 | inline 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 | |||
558 | inline 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 | |||
564 | inline 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 | |||
570 | inline 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 | ||
49 | rights reserved. | ||
50 | |||
51 | License to copy and use this software is granted provided that it | ||
52 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest | ||
53 | Algorithm" in all material mentioning or referencing this software | ||
54 | or this function. | ||
55 | |||
56 | License is also granted to make and use derivative works provided | ||
57 | that such works are identified as "derived from the RSA Data | ||
58 | Security, Inc. MD5 Message-Digest Algorithm" in all material | ||
59 | mentioning or referencing the derived work. | ||
60 | |||
61 | RSA Data Security, Inc. makes no representations concerning either | ||
62 | the merchantability of this software or the suitability of this | ||
63 | software for any particular purpose. It is provided "as is" | ||
64 | without express or implied warranty of any kind. | ||
65 | |||
66 | These notices must be retained in any copies of any part of this | ||
67 | documentation and/or software. | ||
68 | |||
69 | */ | ||
70 | |||
71 | #include <stdio.h> | ||
72 | #include <iosfwd> | ||
73 | |||
74 | // use for the raw digest output | ||
75 | const int MD5RAW_BYTES = 16; | ||
76 | |||
77 | // use for outputting hex digests | ||
78 | const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null | ||
79 | const int MD5HEX_STR_BYTES = 32; // message system fixed size | ||
80 | |||
81 | class 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 | |||
87 | public: | ||
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 | |||
111 | private: | ||
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 | |||
44 | template <class T> class LLOctreeState; | ||
45 | template <class T> class LLOctreeNode; | ||
46 | |||
47 | template <class T> | ||
48 | class LLOctreeListener: public LLTreeListener<T> | ||
49 | { | ||
50 | public: | ||
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 | |||
60 | template <class T> | ||
61 | class LLOctreeNode : public LLTreeNode<T> | ||
62 | { | ||
63 | public: | ||
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 ¢er, 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 | |||
213 | protected: | ||
214 | oct_node* mParent; | ||
215 | LLVector3d mCenter; | ||
216 | LLVector3d mSize; | ||
217 | LLVector3d mMax; | ||
218 | LLVector3d mMin; | ||
219 | U8 mOctant; | ||
220 | }; | ||
221 | |||
222 | template <class T> | ||
223 | class LLOctreeTraveler : public LLTreeTraveler<T> | ||
224 | { | ||
225 | public: | ||
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 | ||
232 | template <class T> | ||
233 | class LLOctreeState : public LLTreeState<T> | ||
234 | { | ||
235 | public: | ||
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 | |||
575 | protected: | ||
576 | child_list mChild; | ||
577 | element_list mData; | ||
578 | }; | ||
579 | |||
580 | //just like a branch, except it might expand the node it points to | ||
581 | template <class T> | ||
582 | class LLOctreeRoot : public LLOctreeState<T> | ||
583 | { | ||
584 | public: | ||
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 | //======================== | ||
701 | template <class T> | ||
702 | void 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 | |||
39 | static S32 p[B + B + 2]; | ||
40 | static F32 g3[B + B + 2][3]; | ||
41 | static F32 g2[B + B + 2][2]; | ||
42 | static F32 g1[B + B + 2]; | ||
43 | |||
44 | bool LLPerlinNoise::sInitialized = 0; | ||
45 | |||
46 | static 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 | |||
53 | static 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 | |||
61 | static 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 | |||
74 | void 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 | |||
121 | F32 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 | |||
143 | static F32 fast_at2(F32 rx, F32 ry, F32 *q) | ||
144 | { | ||
145 | return rx * q[0] + ry * q[1]; | ||
146 | } | ||
147 | |||
148 | F32 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 | |||
188 | static 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 | |||
193 | F32 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 | |||
250 | F32 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 | |||
263 | F32 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 | |||
280 | F32 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 | ||
33 | class LLPerlinNoise | ||
34 | { | ||
35 | public: | ||
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); | ||
42 | private: | ||
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 | |||
40 | class LLPlane : public LLVector4 | ||
41 | { | ||
42 | public: | ||
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 | |||
32 | const U16 U16MAX = 65535; | ||
33 | const F32 OOU16MAX = 1.f/(F32)(U16MAX); | ||
34 | |||
35 | const U8 U8MAX = 255; | ||
36 | const F32 OOU8MAX = 1.f/(F32)(U8MAX); | ||
37 | |||
38 | const U8 FIRSTVALIDCHAR = 54; | ||
39 | const U8 MAXSTRINGVAL = U8MAX - FIRSTVALIDCHAR; //we don't allow newline or null | ||
40 | |||
41 | |||
42 | inline 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 | |||
53 | inline 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 | |||
69 | inline 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 | |||
80 | inline 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 | |||
96 | inline 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 | |||
109 | inline 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. | ||
43 | const LLQuaternion LLQuaternion::DEFAULT; | ||
44 | |||
45 | // Constructors | ||
46 | |||
47 | LLQuaternion::LLQuaternion(const LLMatrix4 &mat) | ||
48 | { | ||
49 | *this = mat.quaternion(); | ||
50 | normQuat(); | ||
51 | } | ||
52 | |||
53 | LLQuaternion::LLQuaternion(const LLMatrix3 &mat) | ||
54 | { | ||
55 | *this = mat.quaternion(); | ||
56 | normQuat(); | ||
57 | } | ||
58 | |||
59 | LLQuaternion::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 | |||
75 | LLQuaternion::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 | |||
91 | LLQuaternion::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 | ||
102 | void 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 | |||
120 | void 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 | |||
133 | const 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 | |||
152 | const 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 | |||
171 | const 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 | |||
189 | const 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 :) | ||
251 | LLMatrix3 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 | |||
283 | LLMatrix4 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 | ||
324 | void 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 | ||
391 | const 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 | |||
420 | std::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 | ||
430 | LLQuaternion 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 | /* | ||
444 | LLMatrix4 operator*(const LLMatrix4 &m, const LLQuaternion &q) | ||
445 | { | ||
446 | LLMatrix4 qmat(q); | ||
447 | return (m*qmat); | ||
448 | } | ||
449 | */ | ||
450 | |||
451 | |||
452 | |||
453 | LLVector4 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 | |||
467 | LLVector3 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 | |||
481 | LLVector3d 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 | |||
495 | F32 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 | ||
507 | LLQuaternion 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 | ||
517 | LLQuaternion 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 | |||
528 | LLQuaternion 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 | ||
545 | LLQuaternion 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 | ||
591 | LLQuaternion 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 | |||
603 | LLQuaternion 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 | ||
616 | LLQuaternion 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 | |||
656 | LLQuaternion 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 | |||
686 | const 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 | |||
714 | LLQuaternion::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 | |||
737 | const LLQuaternion& LLQuaternion::setQuat(const LLMatrix3 &mat) | ||
738 | { | ||
739 | *this = mat.quaternion(); | ||
740 | normQuat(); | ||
741 | return (*this); | ||
742 | } | ||
743 | |||
744 | const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat) | ||
745 | { | ||
746 | *this = mat.quaternion(); | ||
747 | normQuat(); | ||
748 | return (*this); | ||
749 | } | ||
750 | |||
751 | void 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 | ||
772 | void 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 | ||
799 | LLVector3 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 | ||
812 | void 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 | |||
830 | BOOL 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 | |||
33 | class LLVector4; | ||
34 | class LLVector3; | ||
35 | class LLVector3d; | ||
36 | class LLMatrix4; | ||
37 | class 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 | |||
44 | static const U32 LENGTHOFQUAT = 4; | ||
45 | |||
46 | class LLQuaternion | ||
47 | { | ||
48 | public: | ||
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 | ||
147 | inline BOOL LLQuaternion::isFinite() const | ||
148 | { | ||
149 | return (llfinite(mQ[VX]) && llfinite(mQ[VY]) && llfinite(mQ[VZ]) && llfinite(mQ[VS])); | ||
150 | } | ||
151 | |||
152 | inline 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 | |||
161 | inline 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 | |||
172 | inline 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 | |||
180 | inline 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 | |||
197 | inline 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 | |||
214 | inline 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 | |||
223 | inline 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 | |||
233 | inline 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 | |||
243 | inline 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 | ||
256 | inline 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 | |||
275 | inline 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 | ||
284 | inline 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 | |||
293 | inline 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 | |||
303 | inline 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 | |||
313 | inline 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 | |||
323 | inline 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 | |||
333 | inline 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 | |||
342 | inline LLQuaternion operator~(const LLQuaternion &a) | ||
343 | { | ||
344 | LLQuaternion q(a); | ||
345 | q.conjQuat(); | ||
346 | return q; | ||
347 | } | ||
348 | |||
349 | inline 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 | |||
357 | inline 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 | |||
365 | inline 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 | |||
381 | inline 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 | |||
404 | LLQuaternion::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 | |||
41 | void 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 | |||
67 | LLRand gLindenLabRandomNumber(LLUUID::getRandomSeed()); | ||
68 | |||
69 | F32 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) | ||
38 | void slamFPCW( void ); | ||
39 | |||
40 | class LLRand | ||
41 | { | ||
42 | public: | ||
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 | |||
80 | public: | ||
81 | U64 mSeed; | ||
82 | }; | ||
83 | |||
84 | F32 frand(F32 val); | ||
85 | |||
86 | extern 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 | ||
37 | template <class Type> class LLRectBase | ||
38 | { | ||
39 | public: | ||
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 | |||
284 | template <class Type> LLRectBase<Type> LLRectBase<Type>::null(0,0,0,0); | ||
285 | |||
286 | typedef LLRectBase<S32> LLRect; | ||
287 | typedef 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 | |||
34 | template <class T> class LLTreeNode; | ||
35 | template <class T> class LLTreeTraveler; | ||
36 | template <class T> class LLTreeListener; | ||
37 | |||
38 | template <class T> | ||
39 | class LLTreeState | ||
40 | { | ||
41 | public: | ||
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; | ||
52 | private: | ||
53 | LLTreeNode<T>* mNode; | ||
54 | }; | ||
55 | |||
56 | template <class T> | ||
57 | class LLTreeListener | ||
58 | { | ||
59 | public: | ||
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 | |||
67 | template <class T> | ||
68 | class LLTreeNode | ||
69 | { | ||
70 | public: | ||
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 | |||
85 | protected: | ||
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; | ||
96 | public: | ||
97 | std::vector<LLTreeListener<T>*> mListeners; | ||
98 | }; | ||
99 | |||
100 | template <class T> | ||
101 | class LLTreeTraveler | ||
102 | { | ||
103 | public: | ||
104 | virtual ~LLTreeTraveler() { }; | ||
105 | virtual void traverse(const LLTreeNode<T>* node) = 0; | ||
106 | virtual void visit(const LLTreeState<T>* state) = 0; | ||
107 | }; | ||
108 | |||
109 | template <class T> | ||
110 | LLTreeNode<T>::~LLTreeNode() | ||
111 | { | ||
112 | destroyListeners(); | ||
113 | }; | ||
114 | |||
115 | template <class T> | ||
116 | void 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 | |||
127 | template <class T> | ||
128 | bool LLTreeNode<T>::remove(T* data) | ||
129 | { | ||
130 | if (mState->remove(data)) | ||
131 | { | ||
132 | return true; | ||
133 | } | ||
134 | return false; | ||
135 | }; | ||
136 | |||
137 | template <class T> | ||
138 | void 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 | |||
146 | template <class T> | ||
147 | void 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 | |||
164 | template <class T> | ||
165 | void LLTreeState<T>::setNode(LLTreeNode<T>* node) | ||
166 | { | ||
167 | mNode = node; | ||
168 | if (node && node->getState() != this) | ||
169 | { | ||
170 | node->setState(this); | ||
171 | } | ||
172 | }; | ||
173 | |||
174 | template <class T> | ||
175 | LLTreeListener<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 | |||
47 | const LLUUID LLUUID::null; | ||
48 | const LLTransactionID LLTransactionID::tnull; | ||
49 | |||
50 | /* | ||
51 | |||
52 | NOT DONE YET!!! | ||
53 | |||
54 | static 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 | |||
67 | void encode( char * fiveChars, unsigned int word ) throw( ) | ||
68 | { | ||
69 | for( int ix = 0; ix < 5; ++ix ) { | ||
70 | fiveChars[4-ix] = encodeTable[ word % 85]; | ||
71 | word /= 85; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | To decode: | ||
76 | unsigned int decode( char const * fiveChars ) throw( bad_input_data ) | ||
77 | { | ||
78 | unsigned int ret = 0; | ||
79 | for( int ix = 0; ix < 5; ++ix ) { | ||
80 | char * s = strchr( encodeTable, fiveChars[ ix ] ); | ||
81 | if( s == 0 ) throw bad_input_data(); | ||
82 | ret = ret * 85 + (s-encodeTable); | ||
83 | } | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | void 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 | |||
101 | unsigned 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 | ||
115 | void 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 | |||
137 | void LLUUID::toCompressedString(char *out) const | ||
138 | { | ||
139 | memcpy(out, mData, UUID_BYTES); | ||
140 | out[UUID_BYTES] = '\0'; | ||
141 | } | ||
142 | |||
143 | LLString LLUUID::getString() const | ||
144 | { | ||
145 | char str[UUID_STR_SIZE]; | ||
146 | toString(str); | ||
147 | return LLString(str); | ||
148 | } | ||
149 | |||
150 | BOOL LLUUID::set(const std::string& in_string, BOOL emit) | ||
151 | { | ||
152 | return set(in_string.c_str(), emit); | ||
153 | } | ||
154 | |||
155 | BOOL 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 | |||
264 | BOOL LLUUID::validate(const std::string& in_string) | ||
265 | { | ||
266 | return validate(in_string.c_str()); | ||
267 | } | ||
268 | |||
269 | BOOL 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 | |||
337 | const 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 | |||
348 | LLUUID LLUUID::operator^(const LLUUID& rhs) const | ||
349 | { | ||
350 | LLUUID id(*this); | ||
351 | id ^= rhs; | ||
352 | return id; | ||
353 | } | ||
354 | |||
355 | void 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 | |||
364 | LLUUID LLUUID::combine(const LLUUID &other) const | ||
365 | { | ||
366 | LLUUID combination; | ||
367 | combine(other, combination); | ||
368 | return combination; | ||
369 | } | ||
370 | |||
371 | std::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 | |||
380 | std::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 | |||
393 | static 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 | ||
404 | typedef struct _ASTAT_ | ||
405 | { | ||
406 | ADAPTER_STATUS adapt; | ||
407 | NAME_BUFFER NameBuff [30]; | ||
408 | }ASTAT, * PASTAT; | ||
409 | |||
410 | // static | ||
411 | S32 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 | ||
485 | S32 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 | ||
574 | S32 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 | |||
646 | S32 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 | |||
657 | void 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 | |||
688 | void 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 | |||
739 | void 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(×tamp); | ||
774 | |||
775 | // if clock went backward change clockseq | ||
776 | if (cmpTime(×tamp, &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 | |||
817 | U32 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 | |||
835 | BOOL 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 | |||
852 | LLAssetID 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 | |||
35 | const S32 UUID_BYTES = 16; | ||
36 | const S32 UUID_WORDS = 4; | ||
37 | const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below | ||
38 | const S32 UUID_STR_SIZE = 37; | ||
39 | const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL. | ||
40 | |||
41 | struct uuid_time_t { | ||
42 | U32 high; | ||
43 | U32 low; | ||
44 | }; | ||
45 | |||
46 | class LLUUID | ||
47 | { | ||
48 | public: | ||
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 | ||
125 | inline LLUUID::LLUUID() | ||
126 | { | ||
127 | setNull(); | ||
128 | } | ||
129 | |||
130 | |||
131 | // Faster than copying from memory | ||
132 | inline 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 | ||
143 | inline 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 | |||
156 | inline 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(). | ||
171 | inline LLUUID::operator bool() const | ||
172 | { | ||
173 | U32 *word = (U32 *)mData; | ||
174 | return (word[0] | word[1] | word[2] | word[3]) > 0; | ||
175 | } | ||
176 | */ | ||
177 | |||
178 | inline 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. | ||
186 | inline 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 | ||
194 | inline 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 | |||
204 | inline LLUUID::~LLUUID() | ||
205 | { | ||
206 | } | ||
207 | |||
208 | // Assignment | ||
209 | inline 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 | |||
223 | inline 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 | |||
234 | inline 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 | ||
247 | inline 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 | |||
260 | inline 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 | |||
273 | inline 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 | |||
289 | inline 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; | ||
298 | struct lluuid_less | ||
299 | { | ||
300 | bool operator()(const LLUUID& lhs, const LLUUID& rhs) const | ||
301 | { | ||
302 | return (lhs < rhs) ? true : false; | ||
303 | } | ||
304 | }; | ||
305 | |||
306 | typedef std::set<LLUUID, lluuid_less> uuid_list_t; | ||
307 | |||
308 | /* | ||
309 | * Sub-classes for keeping transaction IDs and asset IDs | ||
310 | * straight. | ||
311 | */ | ||
312 | typedef LLUUID LLAssetID; | ||
313 | |||
314 | class LLTransactionID : public LLUUID | ||
315 | { | ||
316 | public: | ||
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 | |||
48 | const F32 CUT_MIN = 0.f; | ||
49 | const F32 CUT_MAX = 1.f; | ||
50 | const F32 MIN_CUT_DELTA = 0.02f; | ||
51 | |||
52 | const F32 HOLLOW_MIN = 0.f; | ||
53 | const F32 HOLLOW_MAX = 0.95f; | ||
54 | const F32 HOLLOW_MAX_SQUARE = 0.7f; | ||
55 | |||
56 | const F32 TWIST_MIN = -1.f; | ||
57 | const F32 TWIST_MAX = 1.f; | ||
58 | |||
59 | const F32 RATIO_MIN = 0.f; | ||
60 | const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper | ||
61 | |||
62 | const F32 HOLE_X_MIN= 0.05f; | ||
63 | const F32 HOLE_X_MAX= 1.0f; | ||
64 | |||
65 | const F32 HOLE_Y_MIN= 0.05f; | ||
66 | const F32 HOLE_Y_MAX= 0.5f; | ||
67 | |||
68 | const F32 SHEAR_MIN = -0.5f; | ||
69 | const F32 SHEAR_MAX = 0.5f; | ||
70 | |||
71 | const F32 REV_MIN = 1.f; | ||
72 | const F32 REV_MAX = 4.f; | ||
73 | |||
74 | const F32 TAPER_MIN = -1.f; | ||
75 | const F32 TAPER_MAX = 1.f; | ||
76 | |||
77 | const F32 SKEW_MIN = -0.95f; | ||
78 | const F32 SKEW_MAX = 0.95f; | ||
79 | |||
80 | BOOL 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 | ||
97 | BOOL 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 | |||
145 | LLProfile::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 | |||
157 | LLProfile::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 | ||
174 | void 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 | |||
319 | void 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. | ||
420 | LLProfile::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 | |||
456 | BOOL 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 | |||
724 | BOOL 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 | |||
781 | BOOL 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 | |||
794 | BOOL 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 | |||
851 | BOOL 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 | |||
863 | LLSD 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 | |||
874 | bool 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 | |||
883 | void LLProfileParams::copyParams(const LLProfileParams ¶ms) | ||
884 | { | ||
885 | setCurveType(params.getCurveType()); | ||
886 | setBegin(params.getBegin()); | ||
887 | setEnd(params.getEnd()); | ||
888 | setHollow(params.getHollow()); | ||
889 | } | ||
890 | |||
891 | |||
892 | LLPath::~LLPath() | ||
893 | { | ||
894 | } | ||
895 | |||
896 | void 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 | |||
1045 | const 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 | |||
1059 | const 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 | |||
1073 | BOOL 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 | |||
1193 | BOOL 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 | |||
1214 | BOOL 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 | |||
1328 | BOOL 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 | |||
1353 | BOOL 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 | |||
1467 | BOOL 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 | |||
1491 | LLSD 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 | |||
1512 | bool 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 | |||
1531 | void LLPathParams::copyParams(const LLPathParams ¶ms) | ||
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 | |||
1546 | LLProfile::~LLProfile() | ||
1547 | { | ||
1548 | |||
1549 | } | ||
1550 | |||
1551 | |||
1552 | S32 LLVolume::mNumMeshPoints = 0; | ||
1553 | |||
1554 | LLVolume::LLVolume(const LLVolumeParams ¶ms, 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 | |||
1578 | void LLVolume::regen() | ||
1579 | { | ||
1580 | generate(); | ||
1581 | createVolumeFaces(); | ||
1582 | } | ||
1583 | |||
1584 | LLVolume::~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 | |||
1596 | BOOL 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 | |||
1682 | void 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 | |||
1772 | BOOL LLVolume::isCap(S32 face) | ||
1773 | { | ||
1774 | return mProfilep->mFaces[face].mCap; | ||
1775 | } | ||
1776 | |||
1777 | BOOL LLVolume::isFlat(S32 face) | ||
1778 | { | ||
1779 | return mProfilep->mFaces[face].mFlat; | ||
1780 | } | ||
1781 | |||
1782 | |||
1783 | bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const | ||
1784 | { | ||
1785 | return (getPathParams() == params.getPathParams()) && | ||
1786 | (getProfileParams() == params.getProfileParams()); | ||
1787 | } | ||
1788 | |||
1789 | bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const | ||
1790 | { | ||
1791 | return (getPathParams() != params.getPathParams()) || | ||
1792 | (getProfileParams() != params.getProfileParams()); | ||
1793 | } | ||
1794 | |||
1795 | bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) 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 | |||
1807 | void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) | ||
1808 | { | ||
1809 | mProfileParams.copyParams(params.mProfileParams); | ||
1810 | mPathParams.copyParams(params.mPathParams); | ||
1811 | } | ||
1812 | |||
1813 | // return true if in range (or nearly so) | ||
1814 | static 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 | |||
1833 | bool 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 | |||
1853 | bool 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 | |||
1873 | bool 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 | |||
1900 | bool 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 | |||
1908 | bool 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 | |||
1916 | bool 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 | |||
1945 | bool 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 | |||
1955 | bool 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 | |||
1963 | bool 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 | |||
1971 | bool 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 | |||
1979 | bool 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 | |||
2028 | bool 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 | |||
2062 | bool 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 | ||
2103 | bool 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 | ||
2162 | S32 *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]; | ||
2794 | noindices: | ||
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 | //----------------------------------------------------------------------------- | ||
2809 | void 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 | |||
2994 | S32 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 | |||
3037 | class LLVertexIndexPair | ||
3038 | { | ||
3039 | public: | ||
3040 | LLVertexIndexPair(const LLVector3 &vertex, const S32 index); | ||
3041 | |||
3042 | LLVector3 mVertex; | ||
3043 | S32 mIndex; | ||
3044 | }; | ||
3045 | |||
3046 | LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) | ||
3047 | { | ||
3048 | mVertex = vertex; | ||
3049 | mIndex = index; | ||
3050 | } | ||
3051 | |||
3052 | const F32 VERTEX_SLOP = 0.00001f; | ||
3053 | const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP; | ||
3054 | |||
3055 | struct 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 | |||
3092 | struct 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 | |||
3127 | BOOL 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 | |||
3136 | BOOL 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 | |||
3338 | BOOL 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 | |||
3379 | BOOL 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 | |||
3390 | BOOL 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 | |||
3431 | BOOL 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 | |||
3441 | LLSD LLVolumeParams::asLLSD() const | ||
3442 | { | ||
3443 | LLSD sd = LLSD(); | ||
3444 | sd["path"] = mPathParams; | ||
3445 | sd["profile"] = mProfileParams; | ||
3446 | return sd; | ||
3447 | } | ||
3448 | |||
3449 | bool LLVolumeParams::fromLLSD(LLSD& sd) | ||
3450 | { | ||
3451 | mPathParams.fromLLSD(sd["path"]); | ||
3452 | mProfileParams.fromLLSD(sd["profile"]); | ||
3453 | return true; | ||
3454 | } | ||
3455 | |||
3456 | void 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 | |||
3472 | void 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 | |||
3488 | BOOL 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 | |||
3534 | LLFaceID 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 | |||
3588 | BOOL 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 | |||
3599 | BOOL 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 | |||
3609 | std::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 | |||
3620 | std::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 | |||
3638 | std::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 | |||
3647 | std::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 | |||
3658 | std::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 | |||
3668 | std::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 | |||
3678 | std::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 | |||
3688 | LLVolumeFace::LLVolumeFace() | ||
3689 | { | ||
3690 | mTypeMask = 0; | ||
3691 | mID = 0; | ||
3692 | mBeginS = 0; | ||
3693 | mBeginT = 0; | ||
3694 | mNumS = 0; | ||
3695 | mNumT = 0; | ||
3696 | } | ||
3697 | |||
3698 | |||
3699 | BOOL 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 | |||
3716 | void 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 | |||
3729 | BOOL 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 | |||
3837 | BOOL 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 | |||
4213 | BOOL 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 | ||
4475 | BOOL 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. | ||
4539 | LLVector3 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 | |||
33 | class LLProfileParams; | ||
34 | class LLPathParams; | ||
35 | class LLVolumeParams; | ||
36 | class LLProfile; | ||
37 | class LLPath; | ||
38 | class LLVolumeFace; | ||
39 | class 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 | |||
54 | const S32 MIN_DETAIL_FACES = 6; | ||
55 | const S32 MIN_LOD = 0; | ||
56 | const 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. | ||
61 | const F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; | ||
62 | const F32 MIN_VOLUME_PATH_WIDTH = 0.05f; | ||
63 | |||
64 | const F32 CUT_QUANTA = 0.005f; | ||
65 | const F32 SCALE_QUANTA = 0.01f; | ||
66 | const F32 SHEAR_QUANTA = 0.01f; | ||
67 | const F32 TAPER_QUANTA = 0.01f; | ||
68 | const F32 REV_QUANTA = 0.015f; | ||
69 | |||
70 | |||
71 | //============================================================================ | ||
72 | |||
73 | // useful masks | ||
74 | const LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness | ||
75 | const LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) | ||
76 | const LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) | ||
77 | const LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum | ||
78 | const LLPCode LL_PCODE_BASE_MASK = 0x0F; | ||
79 | |||
80 | // primitive shapes | ||
81 | const LLPCode LL_PCODE_CUBE = 1; | ||
82 | const LLPCode LL_PCODE_PRISM = 2; | ||
83 | const LLPCode LL_PCODE_TETRAHEDRON = 3; | ||
84 | const LLPCode LL_PCODE_PYRAMID = 4; | ||
85 | const LLPCode LL_PCODE_CYLINDER = 5; | ||
86 | const LLPCode LL_PCODE_CONE = 6; | ||
87 | const LLPCode LL_PCODE_SPHERE = 7; | ||
88 | const LLPCode LL_PCODE_TORUS = 8; | ||
89 | const 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 | |||
96 | const LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) | ||
97 | const LLPCode LL_PCODE_LEGACY = 15; | ||
98 | |||
99 | // Pcodes for legacy objects | ||
100 | //const LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR | ||
101 | const 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 | ||
104 | const LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS | ||
105 | const LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees | ||
106 | //const LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE | ||
107 | const LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS | ||
108 | const 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 | ||
113 | const LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE | ||
114 | const LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE | ||
115 | |||
116 | // hemis | ||
117 | const LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; | ||
118 | const LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; | ||
119 | const LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; | ||
120 | const 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 | ||
126 | const U8 LL_PCODE_PROFILE_MASK = 0x0f; | ||
127 | const U8 LL_PCODE_PROFILE_MIN = 0x00; | ||
128 | const U8 LL_PCODE_PROFILE_CIRCLE = 0x00; | ||
129 | const U8 LL_PCODE_PROFILE_SQUARE = 0x01; | ||
130 | const U8 LL_PCODE_PROFILE_ISOTRI = 0x02; | ||
131 | const U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; | ||
132 | const U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; | ||
133 | const U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; | ||
134 | const U8 LL_PCODE_PROFILE_MAX = 0x05; | ||
135 | |||
136 | // Stored in the profile byte | ||
137 | const U8 LL_PCODE_HOLE_MASK = 0xf0; | ||
138 | const U8 LL_PCODE_HOLE_MIN = 0x00; | ||
139 | const U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile | ||
140 | const U8 LL_PCODE_HOLE_CIRCLE = 0x10; | ||
141 | const U8 LL_PCODE_HOLE_SQUARE = 0x20; | ||
142 | const U8 LL_PCODE_HOLE_TRIANGLE = 0x30; | ||
143 | const U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max | ||
144 | |||
145 | const U8 LL_PCODE_PATH_IGNORE = 0x00; | ||
146 | const U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max | ||
147 | const U8 LL_PCODE_PATH_LINE = 0x10; | ||
148 | const U8 LL_PCODE_PATH_CIRCLE = 0x20; | ||
149 | const U8 LL_PCODE_PATH_CIRCLE2 = 0x30; | ||
150 | const U8 LL_PCODE_PATH_TEST = 0x40; | ||
151 | const U8 LL_PCODE_PATH_FLEXIBLE = 0x80; | ||
152 | const U8 LL_PCODE_PATH_MAX = 0x08; | ||
153 | |||
154 | //============================================================================ | ||
155 | |||
156 | // face identifiers | ||
157 | typedef U16 LLFaceID; | ||
158 | |||
159 | const LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; | ||
160 | const LLFaceID LL_FACE_PATH_END = 0x1 << 1; | ||
161 | const LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; | ||
162 | const LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; | ||
163 | const LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; | ||
164 | const LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; | ||
165 | const LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; | ||
166 | const LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; | ||
167 | const LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; | ||
168 | |||
169 | //============================================================================ | ||
170 | |||
171 | class LLProfileParams | ||
172 | { | ||
173 | public: | ||
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 ¶ms) const; | ||
211 | bool operator!=(const LLProfileParams ¶ms) const; | ||
212 | bool operator<(const LLProfileParams ¶ms) const; | ||
213 | |||
214 | void copyParams(const LLProfileParams ¶ms); | ||
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 | |||
238 | protected: | ||
239 | // Profile params | ||
240 | U8 mCurveType; | ||
241 | F32 mBegin; | ||
242 | F32 mEnd; | ||
243 | F32 mHollow; | ||
244 | |||
245 | U32 mCRC; | ||
246 | }; | ||
247 | |||
248 | inline bool LLProfileParams::operator==(const LLProfileParams ¶ms) const | ||
249 | { | ||
250 | return | ||
251 | (getCurveType() == params.getCurveType()) && | ||
252 | (getBegin() == params.getBegin()) && | ||
253 | (getEnd() == params.getEnd()) && | ||
254 | (getHollow() == params.getHollow()); | ||
255 | } | ||
256 | |||
257 | inline bool LLProfileParams::operator!=(const LLProfileParams ¶ms) const | ||
258 | { | ||
259 | return | ||
260 | (getCurveType() != params.getCurveType()) || | ||
261 | (getBegin() != params.getBegin()) || | ||
262 | (getEnd() != params.getEnd()) || | ||
263 | (getHollow() != params.getHollow()); | ||
264 | } | ||
265 | |||
266 | |||
267 | inline bool LLProfileParams::operator<(const LLProfileParams ¶ms) 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 | |||
291 | class LLPathParams | ||
292 | { | ||
293 | public: | ||
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 ¶ms) const; | ||
336 | bool operator!=(const LLPathParams ¶ms) const; | ||
337 | bool operator<(const LLPathParams ¶ms) const; | ||
338 | |||
339 | void copyParams(const LLPathParams ¶ms); | ||
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 | |||
396 | protected: | ||
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 | |||
414 | inline bool LLPathParams::operator==(const LLPathParams ¶ms) 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 | |||
430 | inline bool LLPathParams::operator!=(const LLPathParams ¶ms) 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 | |||
447 | inline bool LLPathParams::operator<(const LLPathParams ¶ms) 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 | |||
504 | typedef LLVolumeParams* LLVolumeParamsPtr; | ||
505 | typedef const LLVolumeParams* const_LLVolumeParamsPtr; | ||
506 | |||
507 | class LLVolumeParams | ||
508 | { | ||
509 | public: | ||
510 | LLVolumeParams() | ||
511 | { | ||
512 | } | ||
513 | |||
514 | LLVolumeParams(LLProfileParams &profile, LLPathParams &path) | ||
515 | : mProfileParams(profile), mPathParams(path) | ||
516 | { | ||
517 | } | ||
518 | |||
519 | bool operator==(const LLVolumeParams ¶ms) const; | ||
520 | bool operator!=(const LLVolumeParams ¶ms) const; | ||
521 | bool operator<(const LLVolumeParams ¶ms) const; | ||
522 | |||
523 | |||
524 | void copyParams(const LLVolumeParams ¶ms); | ||
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 | |||
612 | protected: | ||
613 | LLProfileParams mProfileParams; | ||
614 | LLPathParams mPathParams; | ||
615 | }; | ||
616 | |||
617 | |||
618 | class LLProfile | ||
619 | { | ||
620 | public: | ||
621 | LLProfile(const LLProfileParams ¶ms) : 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; } | ||
639 | public: | ||
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 | |||
662 | protected: | ||
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 | |||
670 | protected: | ||
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 | |||
683 | class LLPath | ||
684 | { | ||
685 | public: | ||
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 | |||
695 | public: | ||
696 | LLPath(const LLPathParams ¶ms) : 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 | |||
718 | public: | ||
719 | const LLPathParams &mParams; | ||
720 | std::vector<PathPt> mPath; | ||
721 | |||
722 | protected: | ||
723 | BOOL mOpen; | ||
724 | S32 mTotal; | ||
725 | BOOL mDirty; | ||
726 | F32 mStep; | ||
727 | }; | ||
728 | |||
729 | class LLDynamicPath : public LLPath | ||
730 | { | ||
731 | public: | ||
732 | LLDynamicPath(const LLPathParams ¶ms) : 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) | ||
737 | class LLVolumeFace | ||
738 | { | ||
739 | public: | ||
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 | |||
767 | public: | ||
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 | |||
787 | protected: | ||
788 | BOOL createUnCutCubeCap(); | ||
789 | BOOL createCap(); | ||
790 | BOOL createSide(); | ||
791 | }; | ||
792 | |||
793 | class LLVolume : public LLRefCount | ||
794 | { | ||
795 | friend class LLVolumeLODGroup; | ||
796 | |||
797 | private: | ||
798 | LLVolume(const LLVolume&); // Don't implement | ||
799 | ~LLVolume(); // use unref | ||
800 | |||
801 | public: | ||
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 ¶ms, 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 | |||
874 | protected: | ||
875 | BOOL generate(); | ||
876 | void createVolumeFaces(); | ||
877 | |||
878 | protected: | ||
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 | |||
891 | std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); | ||
892 | |||
893 | LLVector3 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 | |||
35 | LLVolumeMgr* gVolumeMgr = 0; | ||
36 | |||
37 | const F32 BASE_THRESHOLD = 0.03f; | ||
38 | |||
39 | //static | ||
40 | F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD, | ||
41 | 2*BASE_THRESHOLD, | ||
42 | 8*BASE_THRESHOLD, | ||
43 | 100*BASE_THRESHOLD}; | ||
44 | |||
45 | //static | ||
46 | F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f}; | ||
47 | |||
48 | //============================================================================ | ||
49 | //static | ||
50 | void LLVolumeMgr::initClass() | ||
51 | { | ||
52 | gVolumeMgr = new LLVolumeMgr(); | ||
53 | } | ||
54 | |||
55 | //static | ||
56 | BOOL 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 | |||
69 | LLVolumeMgr::LLVolumeMgr() | ||
70 | { | ||
71 | mDataMutex = new LLMutex(gAPRPoolp); | ||
72 | // mNumVolumes = 0; | ||
73 | } | ||
74 | |||
75 | LLVolumeMgr::~LLVolumeMgr() | ||
76 | { | ||
77 | cleanup(); | ||
78 | delete mDataMutex; | ||
79 | } | ||
80 | |||
81 | BOOL 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 | |||
109 | LLVolume *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 | |||
136 | void 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 | |||
174 | void 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 | |||
191 | std::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 | |||
213 | LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams ¶ms) | ||
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 | |||
226 | LLVolumeLODGroup::~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 | |||
237 | LLVolume * 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 | |||
249 | BOOL 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 | |||
268 | S32 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 | |||
282 | F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail) | ||
283 | { | ||
284 | return mDetailScales[detail]; | ||
285 | } | ||
286 | |||
287 | F32 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 | |||
306 | std::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 | |||
37 | class LLVolumeParams; | ||
38 | class LLVolumeLODGroup; | ||
39 | |||
40 | class LLVolumeLODGroup : public LLThreadSafeRefCount | ||
41 | { | ||
42 | protected: | ||
43 | ~LLVolumeLODGroup(); | ||
44 | |||
45 | public: | ||
46 | enum | ||
47 | { | ||
48 | NUM_LODS = 4 | ||
49 | }; | ||
50 | |||
51 | LLVolumeLODGroup(const LLVolumeParams ¶ms); | ||
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 | |||
63 | protected: | ||
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 | |||
73 | class LLVolumeMgr | ||
74 | { | ||
75 | public: | ||
76 | static void initClass(); | ||
77 | static BOOL cleanupClass(); | ||
78 | |||
79 | public: | ||
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 | |||
89 | protected: | ||
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 | |||
99 | extern 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 | |||
53 | LLMatrix3::LLMatrix3(const LLQuaternion &q) | ||
54 | { | ||
55 | *this = q.getMatrix3(); | ||
56 | } | ||
57 | |||
58 | |||
59 | LLMatrix3::LLMatrix3(const F32 angle, const LLVector3 &vec) | ||
60 | { | ||
61 | LLQuaternion quat(angle, vec); | ||
62 | *this = setRot(quat); | ||
63 | } | ||
64 | |||
65 | LLMatrix3::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 | |||
73 | LLMatrix3::LLMatrix3(const F32 angle, const LLVector4 &vec) | ||
74 | { | ||
75 | LLQuaternion quat(angle, vec); | ||
76 | *this = setRot(quat); | ||
77 | } | ||
78 | |||
79 | LLMatrix3::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 | |||
86 | LLMatrix3::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 | ||
127 | void 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 | |||
170 | const 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 | |||
186 | const 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 | |||
204 | const 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 | |||
215 | F32 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 | ||
225 | const 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 | ||
236 | const 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 :) | ||
258 | LLQuaternion 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 | ||
308 | const 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 | |||
315 | const LLMatrix3& LLMatrix3::setRot(const F32 angle, const LLVector3 &vec) | ||
316 | { | ||
317 | LLMatrix3 mat(angle, vec); | ||
318 | *this = mat; | ||
319 | return *this; | ||
320 | } | ||
321 | |||
322 | const 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 | |||
330 | const LLMatrix3& LLMatrix3::setRot(const LLQuaternion &q) | ||
331 | { | ||
332 | LLMatrix3 mat(q); | ||
333 | *this = mat; | ||
334 | return *this; | ||
335 | } | ||
336 | |||
337 | |||
338 | const 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 | ||
357 | const 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 | |||
365 | const LLMatrix3& LLMatrix3::rotate(const F32 angle, const LLVector3 &vec) | ||
366 | { | ||
367 | LLMatrix3 mat(angle, vec); | ||
368 | *this *= mat; | ||
369 | return *this; | ||
370 | } | ||
371 | |||
372 | |||
373 | const 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 | |||
381 | const LLMatrix3& LLMatrix3::rotate(const LLQuaternion &q) | ||
382 | { | ||
383 | LLMatrix3 mat(q); | ||
384 | *this *= mat; | ||
385 | return *this; | ||
386 | } | ||
387 | |||
388 | |||
389 | LLVector3 LLMatrix3::getFwdRow() const | ||
390 | { | ||
391 | return LLVector3(mMatrix[VX]); | ||
392 | } | ||
393 | |||
394 | LLVector3 LLMatrix3::getLeftRow() const | ||
395 | { | ||
396 | return LLVector3(mMatrix[VY]); | ||
397 | } | ||
398 | |||
399 | LLVector3 LLMatrix3::getUpRow() const | ||
400 | { | ||
401 | return LLVector3(mMatrix[VZ]); | ||
402 | } | ||
403 | |||
404 | |||
405 | |||
406 | const 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 | |||
423 | LLMatrix3 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. | ||
441 | LLVector3 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 | |||
461 | LLVector3 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 | |||
478 | LLVector3d 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 | |||
495 | bool 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 | |||
509 | bool 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 | |||
523 | const 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 | |||
540 | std::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 | |||
33 | class LLVector4; | ||
34 | class LLVector3; | ||
35 | class LLVector3d; | ||
36 | class 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 | |||
53 | static const U32 NUM_VALUES_IN_MAT3 = 3; | ||
54 | #if LL_WINDOWS | ||
55 | __declspec( align(16) ) | ||
56 | #endif | ||
57 | class 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 | |||
147 | inline 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 | |||
162 | inline 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 | |||
45 | LLMatrix4::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 | |||
68 | LLMatrix4::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 | |||
91 | LLMatrix4::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 | |||
114 | LLMatrix4::LLMatrix4(const LLQuaternion &q) | ||
115 | { | ||
116 | *this = initRotation(q); | ||
117 | } | ||
118 | |||
119 | LLMatrix4::LLMatrix4(const LLQuaternion &q, const LLVector4 &pos) | ||
120 | { | ||
121 | *this = initRotTrans(q, pos); | ||
122 | } | ||
123 | |||
124 | LLMatrix4::LLMatrix4(const F32 angle, const LLVector4 &vec, const LLVector4 &pos) | ||
125 | { | ||
126 | initRotTrans(LLQuaternion(angle, vec), pos); | ||
127 | } | ||
128 | |||
129 | LLMatrix4::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 | |||
139 | LLMatrix4::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 | |||
145 | LLMatrix4::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 | |||
156 | LLMatrix4::~LLMatrix4(void) | ||
157 | { | ||
158 | } | ||
159 | |||
160 | // Clear and Assignment Functions | ||
161 | |||
162 | const 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 | |||
189 | const 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 | |||
217 | F32 LLMatrix4::determinant() const | ||
218 | { | ||
219 | llerrs << "Not implemented!" << llendl; | ||
220 | return 0.f; | ||
221 | } | ||
222 | |||
223 | // Only works for pure orthonormal, homogeneous transform matrices. | ||
224 | const 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 | |||
253 | LLVector4 LLMatrix4::getFwdRow4() const | ||
254 | { | ||
255 | return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]); | ||
256 | } | ||
257 | |||
258 | LLVector4 LLMatrix4::getLeftRow4() const | ||
259 | { | ||
260 | return LLVector4(mMatrix[VY][VX], mMatrix[VY][VY], mMatrix[VY][VZ], mMatrix[VY][VW]); | ||
261 | } | ||
262 | |||
263 | LLVector4 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 :) | ||
273 | LLQuaternion 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 | |||
323 | void 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 | |||
350 | const 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 | |||
357 | const LLMatrix4& LLMatrix4::initRotation(F32 angle, const LLVector4 &vec) | ||
358 | { | ||
359 | LLMatrix3 mat(angle, vec); | ||
360 | return initMatrix(mat); | ||
361 | } | ||
362 | |||
363 | |||
364 | const 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 | |||
371 | const LLMatrix4& LLMatrix4::initRotation(const LLQuaternion &q) | ||
372 | { | ||
373 | LLMatrix3 mat(q); | ||
374 | return initMatrix(mat); | ||
375 | } | ||
376 | |||
377 | |||
378 | // Position and Rotation | ||
379 | const 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 | |||
389 | const 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 | |||
397 | const 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 | /* | ||
406 | const 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 | |||
418 | const 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 | |||
426 | const 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 | ||
469 | const 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 | |||
477 | const LLMatrix4& LLMatrix4::rotate(const F32 angle, const LLVector4 &vec) | ||
478 | { | ||
479 | LLMatrix4 mat(angle, vec); | ||
480 | *this *= mat; | ||
481 | return *this; | ||
482 | } | ||
483 | |||
484 | const 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 | |||
491 | const LLMatrix4& LLMatrix4::rotate(const LLQuaternion &q) | ||
492 | { | ||
493 | LLMatrix4 mat(q); | ||
494 | *this *= mat; | ||
495 | return *this; | ||
496 | } | ||
497 | |||
498 | |||
499 | const 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 | |||
508 | void 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 | |||
515 | void 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 | |||
522 | void 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 | |||
530 | void 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 | |||
537 | void 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 | |||
544 | void 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 | |||
552 | const 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 | |||
560 | const 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 | |||
568 | const 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 | ||
577 | LLMatrix3 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 | |||
596 | const 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 | |||
620 | const 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. | ||
649 | LLVector4 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 | |||
677 | LLVector4 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 | |||
703 | LLVector4 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 | |||
727 | LLVector3 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 | |||
746 | bool 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 | |||
760 | bool 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 | |||
774 | const 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 | |||
787 | std::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 | |||
33 | class LLVector4; | ||
34 | class LLMatrix3; | ||
35 | class 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 | |||
93 | static const U32 NUM_VALUES_IN_MAT4 = 4; | ||
94 | |||
95 | #if LL_WINDOWS | ||
96 | __declspec(align(16)) | ||
97 | #endif | ||
98 | class LLMatrix4 | ||
99 | { | ||
100 | public: | ||
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 | |||
247 | inline LLMatrix4::LLMatrix4() | ||
248 | { | ||
249 | identity(); | ||
250 | } | ||
251 | |||
252 | inline 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 | |||
276 | inline 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 | /* | ||
299 | inline 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 | |||
318 | inline 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 | |||
336 | inline 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 | |||
351 | inline 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 | |||
366 | inline 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 | |||
38 | BOOL 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 | |||
58 | BOOL 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 | |||
84 | BOOL 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 | |||
99 | BOOL 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 | ||
124 | BOOL 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 | |||
151 | BOOL 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 | |||
203 | BOOL 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 | |||
414 | U32 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 | |||
714 | BOOL 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 | |||
864 | BOOL 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 | |||
978 | BOOL 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 | |||
1108 | BOOL 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 | |||
1126 | BOOL 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 | |||
1144 | BOOL 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 | |||
1162 | BOOL 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 | |||
1180 | BOOL 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 | |||
1198 | U32 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 | |||
1219 | BOOL 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 | |||
1237 | BOOL 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 | |||
1255 | BOOL 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 | |||
31 | class LLVector3; | ||
32 | class 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. | ||
66 | BOOL 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. | ||
72 | BOOL ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, | ||
73 | const LLVector3 &plane_point, const LLVector3 plane_normal, | ||
74 | LLVector3 &intersection); | ||
75 | |||
76 | |||
77 | BOOL 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 | ||
83 | BOOL 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 | ||
92 | BOOL 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 | |||
97 | BOOL 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" | ||
104 | BOOL 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. | ||
115 | U32 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 | ||
121 | BOOL 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 | |||
126 | BOOL 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 | |||
133 | BOOL 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 | |||
138 | BOOL 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 | |||
143 | BOOL 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 | ||
150 | BOOL 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 | |||
156 | BOOL 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 | |||
161 | BOOL 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 | |||
167 | BOOL 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 | |||
174 | BOOL 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 | ||
180 | BOOL 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 | ||
189 | BOOL 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 | |||
194 | BOOL 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" | ||
201 | BOOL 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. | ||
212 | U32 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 | |||
217 | BOOL 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 | |||
222 | BOOL 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 | |||
227 | BOOL 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 | |||
39 | LLVector2 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 | ||
46 | BOOL 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 | |||
57 | F32 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 | |||
70 | BOOL 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 | |||
85 | F32 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 | |||
92 | F32 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 | |||
99 | F32 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 | |||
106 | LLVector2 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 | |||
35 | class LLVector4; | ||
36 | class LLMatrix3; | ||
37 | class LLQuaternion; | ||
38 | |||
39 | // Llvector2 = |x y z w| | ||
40 | |||
41 | static const U32 LENGTHOFVECTOR2 = 2; | ||
42 | |||
43 | class 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 | |||
103 | F32 angle_between(const LLVector2 &a, const LLVector2 &b); // Returns angle (radians) between a and b | ||
104 | BOOL are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel | ||
105 | F32 dist_vec(const LLVector2 &a, const LLVector2 &b); // Returns distance between a and b | ||
106 | F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b);// Returns distance sqaured between a and b | ||
107 | F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b);// Returns distance sqaured between a and b ignoring Z component | ||
108 | LLVector2 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 | |||
112 | inline LLVector2::LLVector2(void) | ||
113 | { | ||
114 | mV[VX] = 0.f; | ||
115 | mV[VY] = 0.f; | ||
116 | } | ||
117 | |||
118 | inline LLVector2::LLVector2(F32 x, F32 y) | ||
119 | { | ||
120 | mV[VX] = x; | ||
121 | mV[VY] = y; | ||
122 | } | ||
123 | |||
124 | inline 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 | |||
133 | inline void LLVector2::clearVec(void) | ||
134 | { | ||
135 | mV[VX] = 0.f; | ||
136 | mV[VY] = 0.f; | ||
137 | } | ||
138 | |||
139 | inline void LLVector2::zeroVec(void) | ||
140 | { | ||
141 | mV[VX] = 0.f; | ||
142 | mV[VY] = 0.f; | ||
143 | } | ||
144 | |||
145 | inline void LLVector2::setVec(F32 x, F32 y) | ||
146 | { | ||
147 | mV[VX] = x; | ||
148 | mV[VY] = y; | ||
149 | } | ||
150 | |||
151 | inline void LLVector2::setVec(const LLVector2 &vec) | ||
152 | { | ||
153 | mV[VX] = vec.mV[VX]; | ||
154 | mV[VY] = vec.mV[VY]; | ||
155 | } | ||
156 | |||
157 | inline 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 | |||
165 | inline F32 LLVector2::magVec(void) const | ||
166 | { | ||
167 | return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); | ||
168 | } | ||
169 | |||
170 | inline F32 LLVector2::magVecSquared(void) const | ||
171 | { | ||
172 | return mV[0]*mV[0] + mV[1]*mV[1]; | ||
173 | } | ||
174 | |||
175 | inline 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 | |||
195 | inline 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 | |||
203 | inline 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. | ||
216 | inline 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 | |||
229 | inline LLVector2 operator+(const LLVector2 &a, const LLVector2 &b) | ||
230 | { | ||
231 | LLVector2 c(a); | ||
232 | return c += b; | ||
233 | } | ||
234 | |||
235 | inline LLVector2 operator-(const LLVector2 &a, const LLVector2 &b) | ||
236 | { | ||
237 | LLVector2 c(a); | ||
238 | return c -= b; | ||
239 | } | ||
240 | |||
241 | inline 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 | |||
246 | inline 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 | |||
251 | inline 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 | |||
257 | inline LLVector2 operator*(const LLVector2 &a, F32 k) | ||
258 | { | ||
259 | return LLVector2( a.mV[0] * k, a.mV[1] * k ); | ||
260 | } | ||
261 | |||
262 | inline LLVector2 operator*(F32 k, const LLVector2 &a) | ||
263 | { | ||
264 | return LLVector2( a.mV[0] * k, a.mV[1] * k ); | ||
265 | } | ||
266 | |||
267 | inline 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 | |||
273 | inline 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 | |||
279 | inline 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 | |||
286 | inline 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 | |||
293 | inline 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 | |||
300 | inline const LLVector2& operator*=(LLVector2 &a, F32 k) | ||
301 | { | ||
302 | a.mV[0] *= k; | ||
303 | a.mV[1] *= k; | ||
304 | return a; | ||
305 | } | ||
306 | |||
307 | inline 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 | |||
315 | inline LLVector2 operator-(const LLVector2 &a) | ||
316 | { | ||
317 | return LLVector2( -a.mV[0], -a.mV[1] ); | ||
318 | } | ||
319 | |||
320 | inline 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 | |||
33 | LLColor3 LLColor3::white(1.0f, 1.0f, 1.0f); | ||
34 | LLColor3 LLColor3::black(0.0f, 0.0f, 0.0f); | ||
35 | LLColor3 LLColor3::grey (0.5f, 0.5f, 0.5f); | ||
36 | |||
37 | LLColor3::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 | |||
44 | LLColor3::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 | |||
51 | const 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 | |||
59 | std::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 | |||
31 | class LLColor4; | ||
32 | |||
33 | #include "llerror.h" | ||
34 | #include "llmath.h" | ||
35 | #include "llsd.h" | ||
36 | |||
37 | // LLColor3 = |r g b| | ||
38 | |||
39 | static const U32 LENGTHOFCOLOR3 = 3; | ||
40 | |||
41 | class LLColor3 | ||
42 | { | ||
43 | public: | ||
44 | F32 mV[LENGTHOFCOLOR3]; | ||
45 | |||
46 | static LLColor3 white; | ||
47 | static LLColor3 black; | ||
48 | static LLColor3 grey; | ||
49 | |||
50 | public: | ||
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 | |||
110 | LLColor3 lerp(const LLColor3 &a, const LLColor3 &b, F32 u); | ||
111 | |||
112 | |||
113 | void 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 | ||
143 | F32 distVec(const LLColor3 &a, const LLColor3 &b); // Returns distance between a and b | ||
144 | F32 distVec_squared(const LLColor3 &a, const LLColor3 &b);// Returns distance sqaured between a and b | ||
145 | |||
146 | inline LLColor3::LLColor3(void) | ||
147 | { | ||
148 | mV[0] = 0.f; | ||
149 | mV[1] = 0.f; | ||
150 | mV[2] = 0.f; | ||
151 | } | ||
152 | |||
153 | inline LLColor3::LLColor3(F32 r, F32 g, F32 b) | ||
154 | { | ||
155 | mV[VX] = r; | ||
156 | mV[VY] = g; | ||
157 | mV[VZ] = b; | ||
158 | } | ||
159 | |||
160 | inline LLColor3::LLColor3(const F32 *vec) | ||
161 | { | ||
162 | mV[VX] = vec[VX]; | ||
163 | mV[VY] = vec[VY]; | ||
164 | mV[VZ] = vec[VZ]; | ||
165 | } | ||
166 | |||
167 | inline 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 | |||
187 | inline 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 | |||
195 | inline 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 | |||
203 | inline 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 | |||
211 | inline 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 | |||
219 | inline 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 | |||
227 | inline F32 LLColor3::magVec(void) const | ||
228 | { | ||
229 | return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); | ||
230 | } | ||
231 | |||
232 | inline F32 LLColor3::magVecSquared(void) const | ||
233 | { | ||
234 | return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; | ||
235 | } | ||
236 | |||
237 | inline 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 | |||
252 | inline 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 | |||
266 | inline 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 | |||
274 | inline 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 | |||
282 | inline 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 | |||
290 | inline 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 | |||
295 | inline 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 | |||
300 | inline 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 | |||
307 | inline 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 | |||
314 | inline 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 | |||
322 | inline 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 | |||
330 | inline 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 | |||
338 | inline 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 | |||
346 | inline 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 | |||
356 | inline 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 | |||
364 | inline 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 | |||
372 | inline 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. | ||
46 | const LLVector3d LLVector3d::zero(0,0,0); | ||
47 | const LLVector3d LLVector3d::x_axis(1, 0, 0); | ||
48 | const LLVector3d LLVector3d::y_axis(0, 1, 0); | ||
49 | const LLVector3d LLVector3d::z_axis(0, 0, 1); | ||
50 | const LLVector3d LLVector3d::x_axis_neg(-1, 0, 0); | ||
51 | const LLVector3d LLVector3d::y_axis_neg(0, -1, 0); | ||
52 | const LLVector3d LLVector3d::z_axis_neg(0, 0, -1); | ||
53 | |||
54 | |||
55 | // Clamps each values to range (min,max). | ||
56 | // Returns TRUE if data changed. | ||
57 | BOOL 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 | ||
74 | BOOL 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 | |||
85 | std::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 | |||
91 | const 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 | |||
99 | const LLVector3d& LLVector3d::rotVec(const LLMatrix3 &mat) | ||
100 | { | ||
101 | *this = *this * mat; | ||
102 | return *this; | ||
103 | } | ||
104 | |||
105 | const LLVector3d& LLVector3d::rotVec(const LLQuaternion &q) | ||
106 | { | ||
107 | *this = *this * q; | ||
108 | return *this; | ||
109 | } | ||
110 | |||
111 | const 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 | |||
120 | const 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 | |||
131 | BOOL 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 | |||
34 | class 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 | |||
130 | typedef LLVector3d LLGlobalVec; | ||
131 | |||
132 | const 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 | |||
141 | inline LLVector3d::LLVector3d(void) | ||
142 | { | ||
143 | mdV[0] = 0.f; | ||
144 | mdV[1] = 0.f; | ||
145 | mdV[2] = 0.f; | ||
146 | } | ||
147 | |||
148 | inline 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 | |||
155 | inline LLVector3d::LLVector3d(const F64 *vec) | ||
156 | { | ||
157 | mdV[VX] = vec[VX]; | ||
158 | mdV[VY] = vec[VY]; | ||
159 | mdV[VZ] = vec[VZ]; | ||
160 | } | ||
161 | |||
162 | inline 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 | /* | ||
170 | inline LLVector3d::LLVector3d(const LLVector3d ©) | ||
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 | ||
181 | inline 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 | |||
189 | inline 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 | |||
197 | inline 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 | |||
205 | inline 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 | |||
213 | inline 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 | |||
221 | inline 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 | |||
229 | inline 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 | |||
253 | inline F64 LLVector3d::magVec(void) const | ||
254 | { | ||
255 | return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); | ||
256 | } | ||
257 | |||
258 | inline F64 LLVector3d::magVecSquared(void) const | ||
259 | { | ||
260 | return mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]; | ||
261 | } | ||
262 | |||
263 | inline LLVector3d operator+(const LLVector3d &a, const LLVector3d &b) | ||
264 | { | ||
265 | LLVector3d c(a); | ||
266 | return c += b; | ||
267 | } | ||
268 | |||
269 | inline LLVector3d operator-(const LLVector3d &a, const LLVector3d &b) | ||
270 | { | ||
271 | LLVector3d c(a); | ||
272 | return c -= b; | ||
273 | } | ||
274 | |||
275 | inline 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 | |||
280 | inline 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 | |||
285 | inline 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 | |||
291 | inline 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 | |||
296 | inline 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 | |||
301 | inline 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 | |||
308 | inline 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 | |||
315 | inline 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 | |||
323 | inline 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 | |||
331 | inline 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 | |||
338 | inline 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 | |||
346 | inline 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 | |||
355 | inline LLVector3d operator-(const LLVector3d &a) | ||
356 | { | ||
357 | return LLVector3d( -a.mdV[0], -a.mdV[1], -a.mdV[2] ); | ||
358 | } | ||
359 | |||
360 | inline 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 | |||
368 | inline 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 | |||
376 | inline 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 | |||
383 | inline 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 | |||
392 | inline 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 | |||
402 | inline 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 | |||
415 | inline 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 | |||
430 | inline 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. | ||
45 | const LLVector3 LLVector3::zero(0,0,0); | ||
46 | const LLVector3 LLVector3::x_axis(1.f, 0, 0); | ||
47 | const LLVector3 LLVector3::y_axis(0, 1.f, 0); | ||
48 | const LLVector3 LLVector3::z_axis(0, 0, 1.f); | ||
49 | const LLVector3 LLVector3::x_axis_neg(-1.f, 0, 0); | ||
50 | const LLVector3 LLVector3::y_axis_neg(0, -1.f, 0); | ||
51 | const LLVector3 LLVector3::z_axis_neg(0, 0, -1.f); | ||
52 | const 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. | ||
57 | BOOL 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 | ||
74 | BOOL 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 | ||
86 | void 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 | |||
101 | void 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 | |||
109 | void 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 | |||
117 | std::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 | |||
124 | const LLVector3& LLVector3::rotVec(const LLMatrix3 &mat) | ||
125 | { | ||
126 | *this = *this * mat; | ||
127 | return *this; | ||
128 | } | ||
129 | |||
130 | const LLVector3& LLVector3::rotVec(const LLQuaternion &q) | ||
131 | { | ||
132 | *this = *this * q; | ||
133 | return *this; | ||
134 | } | ||
135 | |||
136 | const 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 | |||
145 | const 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 | |||
155 | const 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 | |||
164 | LLVector3 LLVector3::scaledVec(const LLVector3& vec) const | ||
165 | { | ||
166 | LLVector3 ret = LLVector3(*this); | ||
167 | ret.scaleVec(vec); | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | const 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 | |||
179 | const 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 | |||
187 | LLVector3::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 | |||
194 | LLVector3::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 | |||
201 | const 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 | ||
216 | BOOL 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" | ||
35 | class LLVector4; | ||
36 | class LLMatrix3; | ||
37 | class LLVector3d; | ||
38 | class LLQuaternion; | ||
39 | |||
40 | // Llvector3 = |x y z w| | ||
41 | |||
42 | static const U32 LENGTHOFVECTOR3 = 3; | ||
43 | |||
44 | class 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 | |||
153 | typedef LLVector3 LLSimLocalVec; | ||
154 | |||
155 | // Non-member functions | ||
156 | |||
157 | F32 angle_between(const LLVector3 &a, const LLVector3 &b); // Returns angle (radians) between a and b | ||
158 | BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel | ||
159 | F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance between a and b | ||
160 | F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance sqaured between a and b | ||
161 | F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance sqaured between a and b ignoring Z component | ||
162 | LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b | ||
163 | LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b | ||
164 | |||
165 | inline LLVector3::LLVector3(void) | ||
166 | { | ||
167 | mV[0] = 0.f; | ||
168 | mV[1] = 0.f; | ||
169 | mV[2] = 0.f; | ||
170 | } | ||
171 | |||
172 | inline 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 | |||
179 | inline LLVector3::LLVector3(const F32 *vec) | ||
180 | { | ||
181 | mV[VX] = vec[VX]; | ||
182 | mV[VY] = vec[VY]; | ||
183 | mV[VZ] = vec[VZ]; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | inline LLVector3::LLVector3(const LLVector3 ©) | ||
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 | ||
198 | inline 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 | |||
206 | inline void LLVector3::clearVec(void) | ||
207 | { | ||
208 | mV[0] = 0.f; | ||
209 | mV[1] = 0.f; | ||
210 | mV[2] = 0.f; | ||
211 | } | ||
212 | |||
213 | inline void LLVector3::zeroVec(void) | ||
214 | { | ||
215 | mV[0] = 0.f; | ||
216 | mV[1] = 0.f; | ||
217 | mV[2] = 0.f; | ||
218 | } | ||
219 | |||
220 | inline void LLVector3::setVec(F32 x, F32 y, F32 z) | ||
221 | { | ||
222 | mV[VX] = x; | ||
223 | mV[VY] = y; | ||
224 | mV[VZ] = z; | ||
225 | } | ||
226 | |||
227 | inline 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 | |||
234 | inline void LLVector3::setVec(const F32 *vec) | ||
235 | { | ||
236 | mV[0] = vec[0]; | ||
237 | mV[1] = vec[1]; | ||
238 | mV[2] = vec[2]; | ||
239 | } | ||
240 | |||
241 | inline 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 | |||
265 | inline F32 LLVector3::magVec(void) const | ||
266 | { | ||
267 | return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); | ||
268 | } | ||
269 | |||
270 | inline F32 LLVector3::magVecSquared(void) const | ||
271 | { | ||
272 | return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; | ||
273 | } | ||
274 | |||
275 | inline LLVector3 operator+(const LLVector3 &a, const LLVector3 &b) | ||
276 | { | ||
277 | LLVector3 c(a); | ||
278 | return c += b; | ||
279 | } | ||
280 | |||
281 | inline LLVector3 operator-(const LLVector3 &a, const LLVector3 &b) | ||
282 | { | ||
283 | LLVector3 c(a); | ||
284 | return c -= b; | ||
285 | } | ||
286 | |||
287 | inline 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 | |||
292 | inline 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 | |||
297 | inline 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 | |||
303 | inline 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 | |||
308 | inline 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 | |||
313 | inline 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 | |||
320 | inline 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 | |||
327 | inline 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 | |||
336 | inline 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 | |||
344 | inline 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 | |||
352 | inline 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 | |||
359 | inline 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 | |||
367 | inline 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 | |||
375 | inline 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 | |||
384 | inline LLVector3 operator-(const LLVector3 &a) | ||
385 | { | ||
386 | return LLVector3( -a.mV[0], -a.mV[1], -a.mV[2] ); | ||
387 | } | ||
388 | |||
389 | inline 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 | |||
397 | inline 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 | |||
405 | inline 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 | |||
412 | inline 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 | |||
419 | inline 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 | |||
428 | inline 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 | |||
438 | inline 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 | |||
451 | inline 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 | |||
42 | LLColor4 LLColor4::red( 1.f, 0.f, 0.f, 1.f); | ||
43 | LLColor4 LLColor4::green( 0.f, 1.f, 0.f, 1.f); | ||
44 | LLColor4 LLColor4::blue( 0.f, 0.f, 1.f, 1.f); | ||
45 | LLColor4 LLColor4::black( 0.f, 0.f, 0.f, 1.f); | ||
46 | LLColor4 LLColor4::yellow( 1.f, 1.f, 0.f, 1.f); | ||
47 | LLColor4 LLColor4::magenta( 1.0f, 0.0f, 1.0f, 1.0f); | ||
48 | LLColor4 LLColor4::cyan( 0.0f, 1.0f, 1.0f, 1.0f); | ||
49 | LLColor4 LLColor4::white( 1.f, 1.f, 1.f, 1.f); | ||
50 | LLColor4 LLColor4::smoke( 0.5f, 0.5f, 0.5f, 0.5f); | ||
51 | LLColor4 LLColor4::grey( 0.5f, 0.5f, 0.5f, 1.0f); | ||
52 | LLColor4 LLColor4::orange( 1.f, 0.5, 0.f, 1.f ); | ||
53 | LLColor4 LLColor4::purple( 0.6f, 0.2f, 0.8f, 1.0f); | ||
54 | LLColor4 LLColor4::pink( 1.0f, 0.5f, 0.8f, 1.0f); | ||
55 | LLColor4 LLColor4::transparent( 0.f, 0.f, 0.f, 0.f ); | ||
56 | |||
57 | ////////////////////////////////////////////////////////////////////////////// | ||
58 | |||
59 | LLColor4 LLColor4::grey1(0.8f, 0.8f, 0.8f, 1.0f); | ||
60 | LLColor4 LLColor4::grey2(0.6f, 0.6f, 0.6f, 1.0f); | ||
61 | LLColor4 LLColor4::grey3(0.4f, 0.4f, 0.4f, 1.0f); | ||
62 | LLColor4 LLColor4::grey4(0.3f, 0.3f, 0.3f, 1.0f); | ||
63 | |||
64 | LLColor4 LLColor4::red1(1.0f, 0.0f, 0.0f, 1.0f); | ||
65 | LLColor4 LLColor4::red2(0.6f, 0.0f, 0.0f, 1.0f); | ||
66 | LLColor4 LLColor4::red3(1.0f, 0.2f, 0.2f, 1.0f); | ||
67 | LLColor4 LLColor4::red4(0.5f, 0.1f, 0.1f, 1.0f); | ||
68 | LLColor4 LLColor4::red5(0.8f, 0.1f, 0.0f, 1.0f); | ||
69 | |||
70 | LLColor4 LLColor4::green1(0.0f, 1.0f, 0.0f, 1.0f); | ||
71 | LLColor4 LLColor4::green2(0.0f, 0.6f, 0.0f, 1.0f); | ||
72 | LLColor4 LLColor4::green3(0.0f, 0.4f, 0.0f, 1.0f); | ||
73 | LLColor4 LLColor4::green4(0.0f, 1.0f, 0.4f, 1.0f); | ||
74 | LLColor4 LLColor4::green5(0.2f, 0.6f, 0.4f, 1.0f); | ||
75 | LLColor4 LLColor4::green6(0.4f, 0.6f, 0.2f, 1.0f); | ||
76 | |||
77 | LLColor4 LLColor4::blue1(0.0f, 0.0f, 1.0f, 1.0f); | ||
78 | LLColor4 LLColor4::blue2(0.0f, 0.4f, 1.0f, 1.0f); | ||
79 | LLColor4 LLColor4::blue3(0.2f, 0.2f, 0.8f, 1.0f); | ||
80 | LLColor4 LLColor4::blue4(0.0f, 0.0f, 0.6f, 1.0f); | ||
81 | LLColor4 LLColor4::blue5(0.4f, 0.2f, 1.0f, 1.0f); | ||
82 | LLColor4 LLColor4::blue6(0.4f, 0.5f, 1.0f, 1.0f); | ||
83 | |||
84 | LLColor4 LLColor4::yellow1(1.0f, 1.0f, 0.0f, 1.0f); | ||
85 | LLColor4 LLColor4::yellow2(0.6f, 0.6f, 0.0f, 1.0f); | ||
86 | LLColor4 LLColor4::yellow3(0.8f, 1.0f, 0.2f, 1.0f); | ||
87 | LLColor4 LLColor4::yellow4(1.0f, 1.0f, 0.4f, 1.0f); | ||
88 | LLColor4 LLColor4::yellow5(0.6f, 0.4f, 0.2f, 1.0f); | ||
89 | LLColor4 LLColor4::yellow6(1.0f, 0.8f, 0.4f, 1.0f); | ||
90 | LLColor4 LLColor4::yellow7(0.8f, 0.8f, 0.0f, 1.0f); | ||
91 | LLColor4 LLColor4::yellow8(0.8f, 0.8f, 0.2f, 1.0f); | ||
92 | LLColor4 LLColor4::yellow9(0.8f, 0.8f, 0.4f, 1.0f); | ||
93 | |||
94 | LLColor4 LLColor4::orange1(1.0f, 0.8f, 0.0f, 1.0f); | ||
95 | LLColor4 LLColor4::orange2(1.0f, 0.6f, 0.0f, 1.0f); | ||
96 | LLColor4 LLColor4::orange3(1.0f, 0.4f, 0.2f, 1.0f); | ||
97 | LLColor4 LLColor4::orange4(0.8f, 0.4f, 0.0f, 1.0f); | ||
98 | LLColor4 LLColor4::orange5(0.9f, 0.5f, 0.0f, 1.0f); | ||
99 | LLColor4 LLColor4::orange6(1.0f, 0.8f, 0.2f, 1.0f); | ||
100 | |||
101 | LLColor4 LLColor4::magenta1(1.0f, 0.0f, 1.0f, 1.0f); | ||
102 | LLColor4 LLColor4::magenta2(0.6f, 0.2f, 0.4f, 1.0f); | ||
103 | LLColor4 LLColor4::magenta3(1.0f, 0.4f, 0.6f, 1.0f); | ||
104 | LLColor4 LLColor4::magenta4(1.0f, 0.2f, 0.8f, 1.0f); | ||
105 | |||
106 | LLColor4 LLColor4::purple1(0.6f, 0.2f, 0.8f, 1.0f); | ||
107 | LLColor4 LLColor4::purple2(0.8f, 0.2f, 1.0f, 1.0f); | ||
108 | LLColor4 LLColor4::purple3(0.6f, 0.0f, 1.0f, 1.0f); | ||
109 | LLColor4 LLColor4::purple4(0.4f, 0.0f, 0.8f, 1.0f); | ||
110 | LLColor4 LLColor4::purple5(0.6f, 0.0f, 0.8f, 1.0f); | ||
111 | LLColor4 LLColor4::purple6(0.8f, 0.0f, 0.6f, 1.0f); | ||
112 | |||
113 | LLColor4 LLColor4::pink1(1.0f, 0.5f, 0.8f, 1.0f); | ||
114 | LLColor4 LLColor4::pink2(1.0f, 0.8f, 0.9f, 1.0f); | ||
115 | |||
116 | LLColor4 LLColor4::cyan1(0.0f, 1.0f, 1.0f, 1.0f); | ||
117 | LLColor4 LLColor4::cyan2(0.4f, 0.8f, 0.8f, 1.0f); | ||
118 | LLColor4 LLColor4::cyan3(0.0f, 1.0f, 0.6f, 1.0f); | ||
119 | LLColor4 LLColor4::cyan4(0.6f, 1.0f, 1.0f, 1.0f); | ||
120 | LLColor4 LLColor4::cyan5(0.2f, 0.6f, 1.0f, 1.0f); | ||
121 | LLColor4 LLColor4::cyan6(0.2f, 0.6f, 0.6f, 1.0f); | ||
122 | |||
123 | ////////////////////////////////////////////////////////////////////////////// | ||
124 | |||
125 | // conversion | ||
126 | LLColor4::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 | |||
135 | LLColor4::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 | |||
143 | LLColor4::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 | |||
152 | const 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 | |||
162 | const 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 | |||
174 | const 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 | |||
183 | const 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 | |||
195 | std::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 | |||
201 | bool 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 | |||
208 | bool 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 | |||
215 | LLColor3 vec4to3(const LLColor4 &vec) | ||
216 | { | ||
217 | LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); | ||
218 | return temp; | ||
219 | } | ||
220 | |||
221 | LLColor4 vec3to4(const LLColor3 &vec) | ||
222 | { | ||
223 | LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); | ||
224 | return temp; | ||
225 | } | ||
226 | |||
227 | // static | ||
228 | BOOL 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 | ||
557 | BOOL 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 | |||
36 | class LLColor3; | ||
37 | class LLColor4U; | ||
38 | |||
39 | // LLColor4 = |x y z w| | ||
40 | |||
41 | static const U32 LENGTHOFCOLOR4 = 4; | ||
42 | |||
43 | static const U32 MAX_LENGTH_OF_COLOR_NAME = 15; //Give plenty of room for additional colors... | ||
44 | |||
45 | class 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 | ||
214 | F32 distVec(const LLColor4 &a, const LLColor4 &b); // Returns distance between a and b | ||
215 | F32 distVec_squared(const LLColor4 &a, const LLColor4 &b); // Returns distance squared between a and b | ||
216 | LLColor3 vec4to3(const LLColor4 &vec); | ||
217 | LLColor4 vec3to4(const LLColor3 &vec); | ||
218 | LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u); | ||
219 | |||
220 | inline 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 | |||
228 | inline LLColor4::LLColor4(const LLSD& sd) | ||
229 | { | ||
230 | *this = sd; | ||
231 | } | ||
232 | |||
233 | inline 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 | |||
241 | inline 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 | |||
249 | inline 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 | |||
257 | inline 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 | |||
265 | inline 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 | |||
274 | inline 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 | |||
283 | inline 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 | |||
295 | inline 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 | |||
304 | inline 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 | |||
314 | inline 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 | |||
323 | inline const LLColor4& LLColor4::setAlpha(F32 a) | ||
324 | { | ||
325 | mV[VW] = a; | ||
326 | return (*this); | ||
327 | } | ||
328 | |||
329 | // LLColor4 Magnitude and Normalization Functions | ||
330 | |||
331 | inline F32 LLColor4::magVec(void) const | ||
332 | { | ||
333 | return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); | ||
334 | } | ||
335 | |||
336 | inline F32 LLColor4::magVecSquared(void) const | ||
337 | { | ||
338 | return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; | ||
339 | } | ||
340 | |||
341 | inline 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 | |||
359 | inline 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 | |||
368 | inline 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 | |||
377 | inline 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 | |||
386 | inline 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 | |||
396 | inline 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 | |||
406 | inline 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 | |||
416 | inline 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 | |||
426 | inline 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 | |||
434 | inline 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 | |||
442 | inline 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 | |||
451 | inline 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 | |||
460 | inline 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 | |||
469 | inline 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 | |||
478 | inline 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 | |||
488 | inline F32 distVec(const LLColor4 &a, const LLColor4 &b) | ||
489 | { | ||
490 | LLColor4 vec = a - b; | ||
491 | return (vec.magVec()); | ||
492 | } | ||
493 | |||
494 | inline F32 distVec_squared(const LLColor4 &a, const LLColor4 &b) | ||
495 | { | ||
496 | LLColor4 vec = a - b; | ||
497 | return (vec.magVecSquared()); | ||
498 | } | ||
499 | |||
500 | inline 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 | |||
510 | void 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 | |||
547 | inline 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 | ||
37 | LLColor4U LLColor4U::white(255, 255, 255, 255); | ||
38 | LLColor4U LLColor4U::black( 0, 0, 0, 255); | ||
39 | LLColor4U LLColor4U::red (255, 0, 0, 255); | ||
40 | LLColor4U LLColor4U::green( 0, 255, 0, 255); | ||
41 | LLColor4U LLColor4U::blue ( 0, 0, 255, 255); | ||
42 | |||
43 | // conversion | ||
44 | /* inlined to fix gcc compile link error | ||
45 | LLColor4U::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 | /* | ||
55 | LLColor4U::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 | /* | ||
72 | LLColor4U 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 | |||
85 | std::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 | ||
92 | BOOL 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; | ||
40 | class LLColor4; | ||
41 | |||
42 | // LLColor4U = | red green blue alpha | | ||
43 | |||
44 | static const U32 LENGTHOFCOLOR4U = 4; | ||
45 | |||
46 | |||
47 | class LLColor4U | ||
48 | { | ||
49 | public: | ||
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 | ||
137 | F32 distVec(const LLColor4U &a, const LLColor4U &b); // Returns distance between a and b | ||
138 | F32 distVec_squared(const LLColor4U &a, const LLColor4U &b); // Returns distance squared between a and b | ||
139 | |||
140 | |||
141 | inline LLColor4U::LLColor4U() | ||
142 | { | ||
143 | mV[VX] = 0; | ||
144 | mV[VY] = 0; | ||
145 | mV[VZ] = 0; | ||
146 | mV[VW] = 255; | ||
147 | } | ||
148 | |||
149 | inline 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 | |||
157 | inline 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 | |||
165 | inline 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 | /* | ||
174 | inline 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 | |||
180 | inline 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 | |||
189 | inline 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 | |||
198 | inline 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 | |||
210 | inline 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 | |||
219 | inline 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 | /* | ||
229 | inline 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 | |||
239 | inline 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 | |||
248 | inline 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 | |||
257 | inline 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 | |||
262 | inline 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 | |||
267 | inline 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 | |||
276 | inline 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 | |||
285 | inline 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 | |||
294 | inline 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 | |||
302 | inline 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 | /* | ||
312 | inline 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 | |||
322 | inline 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 | |||
332 | inline 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 | |||
342 | inline 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 | |||
353 | inline 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 | |||
361 | inline 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 | |||
369 | inline 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 | |||
378 | inline 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 | |||
387 | inline 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 | |||
396 | inline const LLColor4U& operator%=(LLColor4U &a, U8 k) | ||
397 | { | ||
398 | // only affects alpha (not rgb!) | ||
399 | a.mV[VW] *= k; | ||
400 | return a; | ||
401 | } | ||
402 | |||
403 | inline F32 distVec(const LLColor4U &a, const LLColor4U &b) | ||
404 | { | ||
405 | LLColor4U vec = a - b; | ||
406 | return (vec.magVec()); | ||
407 | } | ||
408 | |||
409 | inline F32 distVec_squared(const LLColor4U &a, const LLColor4U &b) | ||
410 | { | ||
411 | LLColor4U vec = a - b; | ||
412 | return (vec.magVecSquared()); | ||
413 | } | ||
414 | |||
415 | void 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 | |||
470 | void 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 | /* | ||
42 | const 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 | |||
51 | const 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 | |||
62 | const LLVector4& LLVector4::rotVec(const LLMatrix4 &mat) | ||
63 | { | ||
64 | *this = *this * mat; | ||
65 | return *this; | ||
66 | } | ||
67 | |||
68 | const LLVector4& LLVector4::rotVec(const LLQuaternion &q) | ||
69 | { | ||
70 | *this = *this * q; | ||
71 | return *this; | ||
72 | } | ||
73 | |||
74 | const 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 | ||
86 | BOOL 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 | |||
99 | std::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 | |||
108 | F32 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 | |||
121 | BOOL 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 | |||
134 | LLVector3 vec4to3(const LLVector4 &vec) | ||
135 | { | ||
136 | return LLVector3( vec.mV[VX], vec.mV[VY], vec.mV[VZ] ); | ||
137 | } | ||
138 | |||
139 | LLVector4 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 | |||
35 | class LLMatrix3; | ||
36 | class LLMatrix4; | ||
37 | class LLQuaternion; | ||
38 | |||
39 | // LLVector4 = |x y z w| | ||
40 | |||
41 | static const U32 LENGTHOFVECTOR4 = 4; | ||
42 | |||
43 | #if LL_WINDOWS | ||
44 | __declspec( align(16) ) | ||
45 | #endif | ||
46 | |||
47 | class 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 | ||
125 | F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b | ||
126 | BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel | ||
127 | F32 dist_vec(const LLVector4 &a, const LLVector4 &b); // Returns distance between a and b | ||
128 | F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b); // Returns distance squared between a and b | ||
129 | LLVector3 vec4to3(const LLVector4 &vec); | ||
130 | LLVector4 vec3to4(const LLVector3 &vec); | ||
131 | LLVector4 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 | |||
135 | inline 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 | |||
143 | inline 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 | |||
151 | inline 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 | |||
159 | inline 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 | |||
167 | inline 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 | |||
175 | inline 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 | |||
184 | inline 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 | |||
191 | inline 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 | |||
199 | inline 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 | |||
207 | inline 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 | |||
215 | inline 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 | |||
223 | inline 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 | |||
231 | inline 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 | |||
239 | inline 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 | |||
249 | inline F32 LLVector4::magVec(void) const | ||
250 | { | ||
251 | return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); | ||
252 | } | ||
253 | |||
254 | inline 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 | |||
261 | inline LLVector4 operator+(const LLVector4 &a, const LLVector4 &b) | ||
262 | { | ||
263 | LLVector4 c(a); | ||
264 | return c += b; | ||
265 | } | ||
266 | |||
267 | inline LLVector4 operator-(const LLVector4 &a, const LLVector4 &b) | ||
268 | { | ||
269 | LLVector4 c(a); | ||
270 | return c -= b; | ||
271 | } | ||
272 | |||
273 | inline 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 | |||
278 | inline 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 | |||
283 | inline 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 | |||
290 | inline 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 | |||
295 | inline 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 | |||
300 | inline 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 | |||
307 | inline 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 | |||
314 | inline 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 | |||
322 | inline 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 | |||
330 | inline 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 | |||
337 | inline 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 | |||
345 | inline 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 | |||
354 | inline LLVector4 operator-(const LLVector4 &a) | ||
355 | { | ||
356 | return LLVector4( -a.mV[VX], -a.mV[VY], -a.mV[VZ] ); | ||
357 | } | ||
358 | |||
359 | inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b) | ||
360 | { | ||
361 | LLVector4 vec = a - b; | ||
362 | return (vec.magVec()); | ||
363 | } | ||
364 | |||
365 | inline F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b) | ||
366 | { | ||
367 | LLVector4 vec = a - b; | ||
368 | return (vec.magVecSquared()); | ||
369 | } | ||
370 | |||
371 | inline 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 | |||
380 | inline 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 | |||
31 | LLXform::LLXform() | ||
32 | { | ||
33 | init(); | ||
34 | } | ||
35 | |||
36 | LLXform::~LLXform() | ||
37 | { | ||
38 | } | ||
39 | |||
40 | |||
41 | LLXform* 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 | |||
51 | BOOL LLXform::isRoot() const | ||
52 | { | ||
53 | return (!mParent); | ||
54 | } | ||
55 | |||
56 | BOOL LLXform::isRootEdit() const | ||
57 | { | ||
58 | return (!mParent); | ||
59 | } | ||
60 | |||
61 | LLXformMatrix::~LLXformMatrix() | ||
62 | { | ||
63 | } | ||
64 | |||
65 | void 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 | |||
85 | void 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 | |||
111 | void 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 | |||
37 | const F32 MAX_OBJECT_Z = 768.f; | ||
38 | const F32 MIN_OBJECT_Z = -256.f; | ||
39 | const F32 MIN_OBJECT_SCALE = 0.01f; | ||
40 | const F32 MAX_OBJECT_SCALE = 10.f; | ||
41 | |||
42 | class LLXform | ||
43 | { | ||
44 | protected: | ||
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 | |||
59 | public: | ||
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 | |||
129 | class LLXformMatrix : public LLXform | ||
130 | { | ||
131 | public: | ||
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 | |||
151 | protected: | ||
152 | LLMatrix4 mWorldMatrix; | ||
153 | LLVector3 mMin; | ||
154 | LLVector3 mMax; | ||
155 | |||
156 | }; | ||
157 | |||
158 | BOOL 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 | ||
183 | void 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 | |||
192 | void 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 | |||
201 | void 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 | |||
210 | void 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 | |||
219 | void 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 | |||
228 | void 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 | |||
237 | void 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 | } | ||
245 | void 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 | } | ||
253 | void 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 | } | ||
261 | void 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 | } | ||
273 | void 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 | ||