aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llvlcomposition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llvlcomposition.cpp')
-rw-r--r--linden/indra/newview/llvlcomposition.cpp479
1 files changed, 479 insertions, 0 deletions
diff --git a/linden/indra/newview/llvlcomposition.cpp b/linden/indra/newview/llvlcomposition.cpp
new file mode 100644
index 0000000..f2fa1e6
--- /dev/null
+++ b/linden/indra/newview/llvlcomposition.cpp
@@ -0,0 +1,479 @@
1/**
2 * @file llvlcomposition.cpp
3 * @brief Viewer-side representation of a composition layer...
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 "llviewerprecompiledheaders.h"
29
30#include "llvlcomposition.h"
31#include "llerror.h"
32#include "v3math.h"
33#include "llsurface.h"
34#include "lltextureview.h"
35#include "llviewerimage.h"
36#include "llviewerimagelist.h"
37#include "llviewerregion.h"
38#include "noise.h"
39#include "llregionhandle.h" // for from_region_handle
40#include "llviewercontrol.h"
41
42
43
44F32 bilinear(const F32 v00, const F32 v01, const F32 v10, const F32 v11, const F32 x_frac, const F32 y_frac)
45{
46 // Not sure if this is the right math...
47 // Take weighted average of all four points (bilinear interpolation)
48 F32 result;
49
50 const F32 inv_x_frac = 1.f - x_frac;
51 const F32 inv_y_frac = 1.f - y_frac;
52 result = inv_x_frac*inv_y_frac*v00
53 + x_frac*inv_y_frac*v10
54 + inv_x_frac*y_frac*v01
55 + x_frac*y_frac*v11;
56
57 return result;
58}
59
60
61LLVLComposition::LLVLComposition(LLSurface *surfacep, const U32 width, const F32 scale) :
62 LLViewerLayer(width, scale),
63 mParamsReady(FALSE)
64{
65 mSurfacep = surfacep;
66
67 // Load Terrain Textures - Original ones
68 LLUUID id;
69 // Dirt
70 id.set( gViewerArt.getString("terrain_dirt_detail.tga") );
71 setDetailTextureID(0, id);
72
73 // Grass
74 id.set( gViewerArt.getString("terrain_grass_detail.tga") );
75 setDetailTextureID(1, id);
76
77 // Rock mountain
78 id.set( gViewerArt.getString("terrain_mountain_detail.tga") );
79 setDetailTextureID(2, id);
80
81 // Rock face
82 id.set( gViewerArt.getString("terrain_rock_detail.tga") );
83 setDetailTextureID(3, id);
84
85 // Initialize the texture matrix to defaults.
86 for (S32 i = 0; i < CORNER_COUNT; ++i)
87 {
88 mStartHeight[i] = gSavedSettings.getF32("TerrainColorStartHeight");
89 mHeightRange[i] = gSavedSettings.getF32("TerrainColorHeightRange");
90 }
91 mTexScaleX = 16.f;
92 mTexScaleY = 16.f;
93 mTexturesLoaded = FALSE;
94}
95
96
97LLVLComposition::~LLVLComposition()
98{
99}
100
101
102void LLVLComposition::setSurface(LLSurface *surfacep)
103{
104 mSurfacep = surfacep;
105}
106
107
108void LLVLComposition::setDetailTextureID(S32 corner, const LLUUID& id)
109{
110 if(id.isNull())
111 {
112 return;
113 }
114 mDetailTextures[corner] = gImageList.getImage(id);
115 mRawImages[corner] = NULL;
116}
117
118BOOL LLVLComposition::generateHeights(const F32 x, const F32 y,
119 const F32 width, const F32 height)
120{
121 if (!mParamsReady)
122 {
123 // All the parameters haven't been set yet (we haven't gotten the message from the sim)
124 return FALSE;
125 }
126
127 llassert(mSurfacep);
128 S32 x_begin, y_begin, x_end, y_end;
129
130 x_begin = llround( x * mScaleInv );
131 y_begin = llround( y * mScaleInv );
132 x_end = llround( (x + width) * mScaleInv );
133 y_end = llround( (y + width) * mScaleInv );
134
135 if (x_end > mWidth)
136 {
137 x_end = mWidth;
138 }
139 if (y_end > mWidth)
140 {
141 y_end = mWidth;
142 }
143
144 LLVector3d origin_global = from_region_handle(mSurfacep->getRegion()->getHandle());
145
146 // For perlin noise generation...
147 const F32 slope_squared = 1.5f*1.5f;
148 const F32 xyScale = 4.9215f; //0.93284f;
149 const F32 zScale = 4; //0.92165f;
150 const F32 z_offset = 0.f;
151 const F32 noise_magnitude = 2.f; // Degree to which noise modulates composition layer (versus
152 // simple height)
153
154 // Heights map into textures as 0-1 = first, 1-2 = second, etc.
155 // So we need to compress heights into this range.
156 const S32 NUM_TEXTURES = 4;
157
158 const F32 xyScaleInv = (1.f / xyScale);
159 const F32 zScaleInv = (1.f / zScale);
160
161 const F32 inv_width = 1.f/mWidth;
162
163 // OK, for now, just have the composition value equal the height at the point.
164 for (S32 j = y_begin; j < y_end; j++)
165 {
166 for (S32 i = x_begin; i < x_end; i++)
167 {
168
169 F32 vec[3];
170 F32 vec1[3];
171 F32 twiddle;
172
173 // Bilinearly interpolate the start height and height range of the textures
174 F32 start_height = bilinear(mStartHeight[SOUTHWEST],
175 mStartHeight[SOUTHEAST],
176 mStartHeight[NORTHWEST],
177 mStartHeight[NORTHEAST],
178 i*inv_width, j*inv_width); // These will be bilinearly interpolated
179 F32 height_range = bilinear(mHeightRange[SOUTHWEST],
180 mHeightRange[SOUTHEAST],
181 mHeightRange[NORTHWEST],
182 mHeightRange[NORTHEAST],
183 i*inv_width, j*inv_width); // These will be bilinearly interpolated
184
185 LLVector3 location(i*mScale, j*mScale, 0.f);
186
187 F32 height = mSurfacep->resolveHeightRegion(location) + z_offset;
188
189 // Step 0: Measure the exact height at this texel
190 vec[0] = (F32)(origin_global.mdV[VX]+location.mV[VX])*xyScaleInv; // Adjust to non-integer lattice
191 vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv;
192 vec[2] = height*zScaleInv;
193 //
194 // Choose material value by adding to the exact height a random value
195 //
196 vec1[0] = vec[0]*(0.2222222222f);
197 vec1[1] = vec[1]*(0.2222222222f);
198 vec1[2] = vec[2]*(0.2222222222f);
199 twiddle = noise2(vec1)*6.5f; // Low freq component for large divisions
200
201 twiddle += turbulence2(vec, 2)*slope_squared; // High frequency component
202 twiddle *= noise_magnitude;
203
204 F32 scaled_noisy_height = (height + twiddle - start_height) * F32(NUM_TEXTURES) / height_range;
205
206 scaled_noisy_height = llmax(0.f, scaled_noisy_height);
207 scaled_noisy_height = llmin(3.f, scaled_noisy_height);
208 *(mDatap + i + j*mWidth) = scaled_noisy_height;
209 }
210 }
211 return TRUE;
212}
213
214static const S32 BASE_SIZE = 128;
215
216BOOL LLVLComposition::generateComposition()
217{
218
219 if (!mParamsReady)
220 {
221 // All the parameters haven't been set yet (we haven't gotten the message from the sim)
222 return FALSE;
223 }
224
225 for (S32 i = 0; i < 4; i++)
226 {
227 if (mDetailTextures[i]->getDiscardLevel() < 0)
228 {
229 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); // in case we are at low detail
230 mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE);
231 return FALSE;
232 }
233 if ((mDetailTextures[i]->getDiscardLevel() != 0 &&
234 (mDetailTextures[i]->getWidth() < BASE_SIZE ||
235 mDetailTextures[i]->getHeight() < BASE_SIZE)))
236 {
237 S32 width = mDetailTextures[i]->getWidth(0);
238 S32 height = mDetailTextures[i]->getHeight(0);
239 S32 min_dim = llmin(width, height);
240 S32 ddiscard = 0;
241 while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
242 {
243 ddiscard++;
244 min_dim /= 2;
245 }
246 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); // in case we are at low detail
247 mDetailTextures[i]->setMinDiscardLevel(ddiscard);
248 return FALSE;
249 }
250 }
251
252 return TRUE;
253}
254
255BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
256 const F32 width, const F32 height)
257{
258 llassert(mSurfacep);
259 llassert(x >= 0.f);
260 llassert(y >= 0.f);
261
262 LLTimer gen_timer;
263
264 ///////////////////////////
265 //
266 // Generate raw data arrays for surface textures
267 //
268 //
269
270 // These have already been validated by generateComposition.
271 U8* st_data[4];
272
273 for (S32 i = 0; i < 4; i++)
274 {
275 if (mRawImages[i].isNull())
276 {
277 // Read back a raw image for this discard level, if it exists
278 mRawImages[i] = new LLImageRaw;
279 S32 min_dim = llmin(mDetailTextures[i]->getWidth(0), mDetailTextures[i]->getHeight(0));
280 S32 ddiscard = 0;
281 while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
282 {
283 ddiscard++;
284 min_dim /= 2;
285 }
286 if (!mDetailTextures[i]->readBackRaw(ddiscard, mRawImages[i]))
287 {
288 llwarns << "Unable to read raw data for terrain detail texture: " << mDetailTextures[i]->getID() << llendl;
289 mRawImages[i] = NULL;
290 return FALSE;
291 }
292 if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE ||
293 mDetailTextures[i]->getHeight(ddiscard) != BASE_SIZE ||
294 mDetailTextures[i]->getComponents() != 3)
295 {
296 LLPointer<LLImageRaw> newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3);
297 newraw->composite(mRawImages[i]);
298 mRawImages[i] = newraw; // deletes old
299 }
300 }
301 st_data[i] = mRawImages[i]->getData();
302 }
303
304 ///////////////////////////////////////
305 //
306 // Generate and clamp x/y bounding box.
307 //
308 //
309
310 S32 x_begin, y_begin, x_end, y_end;
311 x_begin = (S32)(x * mScaleInv);
312 y_begin = (S32)(y * mScaleInv);
313 x_end = llround( (x + width) * mScaleInv );
314 y_end = llround( (y + width) * mScaleInv );
315
316 if (x_end > mWidth)
317 {
318 llwarns << "x end > width" << llendl;
319 x_end = mWidth;
320 }
321 if (y_end > mWidth)
322 {
323 llwarns << "y end > width" << llendl;
324 y_end = mWidth;
325 }
326
327
328 ///////////////////////////////////////////
329 //
330 // Generate target texture information, stride ratios.
331 //
332 //
333
334 LLViewerImage *texturep;
335 U32 tex_width, tex_height, tex_comps;
336 U32 tex_stride;
337 F32 tex_x_scalef, tex_y_scalef;
338 S32 tex_x_begin, tex_y_begin, tex_x_end, tex_y_end;
339 F32 tex_x_ratiof, tex_y_ratiof;
340
341 texturep = mSurfacep->getSTexture();
342 tex_width = texturep->getWidth();
343 tex_height = texturep->getHeight();
344 tex_comps = texturep->getComponents();
345 tex_stride = tex_width * tex_comps;
346
347 S32 st_comps = 3;
348 S32 st_width = BASE_SIZE;
349 S32 st_height = BASE_SIZE;
350
351 if (tex_comps != st_comps)
352 {
353 llwarns << "Base texture comps != input texture comps" << llendl;
354 return FALSE;
355 }
356
357 tex_x_scalef = (F32)tex_width / (F32)mWidth;
358 tex_y_scalef = (F32)tex_height / (F32)mWidth;
359 tex_x_begin = (S32)((F32)x_begin * tex_x_scalef);
360 tex_y_begin = (S32)((F32)y_begin * tex_y_scalef);
361 tex_x_end = (S32)((F32)x_end * tex_x_scalef);
362 tex_y_end = (S32)((F32)y_end * tex_y_scalef);
363
364 tex_x_ratiof = (F32)mWidth*mScale / (F32)tex_width;
365 tex_y_ratiof = (F32)mWidth*mScale / (F32)tex_height;
366
367 LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps);
368 U8 *rawp = raw->getData();
369
370 F32 tex_width_inv = 1.f/tex_width;
371 F32 tex_height_inv = 1.f/tex_height;
372
373 F32 st_x_stride, st_y_stride;
374 st_x_stride = ((F32)st_width / (F32)mTexScaleX)*((F32)mWidth / (F32)tex_width);
375 st_y_stride = ((F32)st_height / (F32)mTexScaleY)*((F32)mWidth / (F32)tex_height);
376
377 llassert(st_x_stride > 0.f);
378 llassert(st_y_stride > 0.f);
379 ////////////////////////////////
380 //
381 // Iterate through the target texture, striding through the
382 // subtextures and interpolating appropriately.
383 //
384 //
385
386 F32 sti, stj;
387 S32 st_offset;
388 sti = (tex_x_begin * st_x_stride) - st_width*(llfloor((tex_x_begin * st_x_stride)/st_width));
389 stj = (tex_y_begin * st_y_stride) - st_height*(llfloor((tex_y_begin * st_y_stride)/st_height));
390
391 st_offset = (llfloor(stj * st_width) + llfloor(sti)) * st_comps;
392 for (S32 j = tex_y_begin; j < tex_y_end; j++)
393 {
394 U32 offset = j * tex_stride + tex_x_begin * tex_comps;
395 sti = (tex_x_begin * st_x_stride) - st_width*((U32)(tex_x_begin * st_x_stride)/st_width);
396 for (S32 i = tex_x_begin; i < tex_x_end; i++)
397 {
398 S32 tex0, tex1;
399 F32 composition = getValueScaled(i*tex_x_ratiof, j*tex_y_ratiof);
400
401 tex0 = llfloor( composition );
402 tex0 = llclamp(tex0, 0, 3);
403 composition -= tex0;
404 tex1 = tex0 + 1;
405 tex1 = llclamp(tex1, 0, 3);
406
407 F32 xy_int_i, xy_int_j;
408
409 xy_int_i = i * tex_width_inv;
410 xy_int_j = j * tex_height_inv;
411
412 st_offset = (lltrunc(sti) + lltrunc(stj)*st_width) * st_comps;
413 for (U32 k = 0; k < tex_comps; k++)
414 {
415 // Linearly interpolate based on composition.
416 F32 a = *(st_data[tex0] + st_offset);
417 F32 b = *(st_data[tex1] + st_offset);
418 rawp[ offset ] = (U8)lltrunc( a + composition * (b - a) );
419 offset++;
420 st_offset++;
421 }
422
423 sti += st_x_stride;
424 if (sti >= st_width)
425 {
426 sti -= st_width;
427 }
428 }
429
430 stj += st_y_stride;
431 if (stj >= st_height)
432 {
433 stj -= st_height;
434 }
435 }
436
437 texturep->setSubImage(raw, tex_x_begin, tex_y_begin, tex_x_end - tex_x_begin, tex_y_end - tex_y_begin);
438 LLSurface::sTextureUpdateTime += gen_timer.getElapsedTimeF32();
439 LLSurface::sTexelsUpdated += (tex_x_end - tex_x_begin) * (tex_y_end - tex_y_begin);
440
441 for (S32 i = 0; i < 4; i++)
442 {
443 // Un-boost detatil textures (will get re-boosted if rendering in high detail)
444 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_NONE);
445 mDetailTextures[i]->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1);
446 }
447
448 return TRUE;
449}
450
451LLUUID LLVLComposition::getDetailTextureID(S32 corner)
452{
453 return mDetailTextures[corner]->getID();
454}
455
456LLViewerImage* LLVLComposition::getDetailTexture(S32 corner)
457{
458 return mDetailTextures[corner];
459}
460
461F32 LLVLComposition::getStartHeight(S32 corner)
462{
463 return mStartHeight[corner];
464}
465
466void LLVLComposition::setStartHeight(S32 corner, const F32 start_height)
467{
468 mStartHeight[corner] = start_height;
469}
470
471F32 LLVLComposition::getHeightRange(S32 corner)
472{
473 return mHeightRange[corner];
474}
475
476void LLVLComposition::setHeightRange(S32 corner, const F32 range)
477{
478 mHeightRange[corner] = range;
479}