PageRenderTime 34ms CodeModel.GetById 2ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llvlcomposition.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 501 lines | 349 code | 82 blank | 70 comment | 42 complexity | 1697b735e6dbc7192db1cb668bf2df48 MD5 | raw file
  1/** 
  2 * @file llvlcomposition.cpp
  3 * @brief Viewer-side representation of a composition layer...
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llviewerprecompiledheaders.h"
 28
 29#include "llvlcomposition.h"
 30
 31#include "imageids.h"
 32#include "llerror.h"
 33#include "v3math.h"
 34#include "llsurface.h"
 35#include "lltextureview.h"
 36#include "llviewertexture.h"
 37#include "llviewertexturelist.h"
 38#include "llviewerregion.h"
 39#include "noise.h"
 40#include "llregionhandle.h" // for from_region_handle
 41#include "llviewercontrol.h"
 42
 43
 44
 45F32 bilinear(const F32 v00, const F32 v01, const F32 v10, const F32 v11, const F32 x_frac, const F32 y_frac)
 46{
 47	// Not sure if this is the right math...
 48	// Take weighted average of all four points (bilinear interpolation)
 49	F32 result;
 50
 51	const F32 inv_x_frac = 1.f - x_frac;
 52	const F32 inv_y_frac = 1.f - y_frac;
 53	result = inv_x_frac*inv_y_frac*v00
 54			+ x_frac*inv_y_frac*v10
 55			+ inv_x_frac*y_frac*v01
 56			+ x_frac*y_frac*v11;
 57
 58	return result;
 59}
 60
 61
 62LLVLComposition::LLVLComposition(LLSurface *surfacep, const U32 width, const F32 scale) :
 63	LLViewerLayer(width, scale),
 64	mParamsReady(FALSE)
 65{
 66	mSurfacep = surfacep;
 67
 68	// Load Terrain Textures - Original ones
 69	setDetailTextureID(0, TERRAIN_DIRT_DETAIL);
 70	setDetailTextureID(1, TERRAIN_GRASS_DETAIL);
 71	setDetailTextureID(2, TERRAIN_MOUNTAIN_DETAIL);
 72	setDetailTextureID(3, TERRAIN_ROCK_DETAIL);
 73
 74	// Initialize the texture matrix to defaults.
 75	for (S32 i = 0; i < CORNER_COUNT; ++i)
 76	{
 77		mStartHeight[i] = gSavedSettings.getF32("TerrainColorStartHeight");
 78		mHeightRange[i] = gSavedSettings.getF32("TerrainColorHeightRange");
 79	}
 80	mTexScaleX = 16.f;
 81	mTexScaleY = 16.f;
 82	mTexturesLoaded = FALSE;
 83}
 84
 85
 86LLVLComposition::~LLVLComposition()
 87{
 88}
 89
 90
 91void LLVLComposition::setSurface(LLSurface *surfacep)
 92{
 93	mSurfacep = surfacep;
 94}
 95
 96
 97void LLVLComposition::setDetailTextureID(S32 corner, const LLUUID& id)
 98{
 99	if(id.isNull())
100	{
101		return;
102	}
103	mDetailTextures[corner] = LLViewerTextureManager::getFetchedTexture(id);
104	mDetailTextures[corner]->setNoDelete() ;
105	mRawImages[corner] = NULL;
106}
107
108BOOL LLVLComposition::generateHeights(const F32 x, const F32 y,
109									  const F32 width, const F32 height)
110{
111	if (!mParamsReady)
112	{
113		// All the parameters haven't been set yet (we haven't gotten the message from the sim)
114		return FALSE;
115	}
116
117	llassert(mSurfacep);
118
119	if (!mSurfacep || !mSurfacep->getRegion()) 
120	{
121		// We don't always have the region yet here....
122		return FALSE;
123	}
124
125	S32 x_begin, y_begin, x_end, y_end;
126
127	x_begin = llround( x * mScaleInv );
128	y_begin = llround( y * mScaleInv );
129	x_end = llround( (x + width) * mScaleInv );
130	y_end = llround( (y + width) * mScaleInv );
131
132	if (x_end > mWidth)
133	{
134		x_end = mWidth;
135	}
136	if (y_end > mWidth)
137	{
138		y_end = mWidth;
139	}
140
141	LLVector3d origin_global = from_region_handle(mSurfacep->getRegion()->getHandle());
142
143	// For perlin noise generation...
144	const F32 slope_squared = 1.5f*1.5f;
145	const F32 xyScale = 4.9215f; //0.93284f;
146	const F32 zScale = 4; //0.92165f;
147	const F32 z_offset = 0.f;
148	const F32 noise_magnitude = 2.f;		//  Degree to which noise modulates composition layer (versus
149											//  simple height)
150
151	// Heights map into textures as 0-1 = first, 1-2 = second, etc.
152	// So we need to compress heights into this range.
153	const S32 NUM_TEXTURES = 4;
154
155	const F32 xyScaleInv = (1.f / xyScale);
156	const F32 zScaleInv = (1.f / zScale);
157
158	const F32 inv_width = 1.f/mWidth;
159
160	// OK, for now, just have the composition value equal the height at the point.
161	for (S32 j = y_begin; j < y_end; j++)
162	{
163		for (S32 i = x_begin; i < x_end; i++)
164		{
165
166			F32 vec[3];
167			F32 vec1[3];
168			F32 twiddle;
169
170			// Bilinearly interpolate the start height and height range of the textures
171			F32 start_height = bilinear(mStartHeight[SOUTHWEST],
172										mStartHeight[SOUTHEAST],
173										mStartHeight[NORTHWEST],
174										mStartHeight[NORTHEAST],
175										i*inv_width, j*inv_width); // These will be bilinearly interpolated
176			F32 height_range = bilinear(mHeightRange[SOUTHWEST],
177										mHeightRange[SOUTHEAST],
178										mHeightRange[NORTHWEST],
179										mHeightRange[NORTHEAST],
180										i*inv_width, j*inv_width); // These will be bilinearly interpolated
181
182			LLVector3 location(i*mScale, j*mScale, 0.f);
183
184			F32 height = mSurfacep->resolveHeightRegion(location) + z_offset;
185
186			// Step 0: Measure the exact height at this texel
187			vec[0] = (F32)(origin_global.mdV[VX]+location.mV[VX])*xyScaleInv;	//  Adjust to non-integer lattice
188			vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv;
189			vec[2] = height*zScaleInv;
190			//
191			//  Choose material value by adding to the exact height a random value 
192			//
193			vec1[0] = vec[0]*(0.2222222222f);
194			vec1[1] = vec[1]*(0.2222222222f);
195			vec1[2] = vec[2]*(0.2222222222f);
196			twiddle = noise2(vec1)*6.5f;					//  Low freq component for large divisions
197
198			twiddle += turbulence2(vec, 2)*slope_squared;	//  High frequency component
199			twiddle *= noise_magnitude;
200
201			F32 scaled_noisy_height = (height + twiddle - start_height) * F32(NUM_TEXTURES) / height_range;
202
203			scaled_noisy_height = llmax(0.f, scaled_noisy_height);
204			scaled_noisy_height = llmin(3.f, scaled_noisy_height);
205			*(mDatap + i + j*mWidth) = scaled_noisy_height;
206		}
207	}
208	return TRUE;
209}
210
211static const U32 BASE_SIZE = 128;
212
213BOOL LLVLComposition::generateComposition()
214{
215
216	if (!mParamsReady)
217	{
218		// All the parameters haven't been set yet (we haven't gotten the message from the sim)
219		return FALSE;
220	}
221
222	for (S32 i = 0; i < 4; i++)
223	{
224		if (mDetailTextures[i]->getDiscardLevel() < 0)
225		{
226			mDetailTextures[i]->setBoostLevel(LLViewerTexture::BOOST_TERRAIN); // in case we are at low detail
227			mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE);
228			return FALSE;
229		}
230		if ((mDetailTextures[i]->getDiscardLevel() != 0 &&
231			 (mDetailTextures[i]->getWidth() < BASE_SIZE ||
232			  mDetailTextures[i]->getHeight() < BASE_SIZE)))
233		{
234			S32 width = mDetailTextures[i]->getFullWidth();
235			S32 height = mDetailTextures[i]->getFullHeight();
236			S32 min_dim = llmin(width, height);
237			S32 ddiscard = 0;
238			while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
239			{
240				ddiscard++;
241				min_dim /= 2;
242			}
243			mDetailTextures[i]->setBoostLevel(LLViewerTexture::BOOST_TERRAIN); // in case we are at low detail
244			mDetailTextures[i]->setMinDiscardLevel(ddiscard);
245			return FALSE;
246		}
247	}
248	
249	return TRUE;
250}
251
252BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
253									  const F32 width, const F32 height)
254{
255	llassert(mSurfacep);
256	llassert(x >= 0.f);
257	llassert(y >= 0.f);
258
259	LLTimer gen_timer;
260
261	///////////////////////////
262	//
263	// Generate raw data arrays for surface textures
264	//
265	//
266
267	// These have already been validated by generateComposition.
268	U8* st_data[4];
269	S32 st_data_size[4]; // for debugging
270
271	for (S32 i = 0; i < 4; i++)
272	{
273		if (mRawImages[i].isNull())
274		{
275			// Read back a raw image for this discard level, if it exists
276			S32 min_dim = llmin(mDetailTextures[i]->getFullWidth(), mDetailTextures[i]->getFullHeight());
277			S32 ddiscard = 0;
278			while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
279			{
280				ddiscard++;
281				min_dim /= 2;
282			}
283
284			BOOL delete_raw = (mDetailTextures[i]->reloadRawImage(ddiscard) != NULL) ;
285			if(mDetailTextures[i]->getRawImageLevel() != ddiscard)//raw iamge is not ready, will enter here again later.
286			{
287				if(delete_raw)
288				{
289					mDetailTextures[i]->destroyRawImage() ;
290				}
291				lldebugs << "cached raw data for terrain detail texture is not ready yet: " << mDetailTextures[i]->getID() << llendl;
292				return FALSE;
293			}
294
295			mRawImages[i] = mDetailTextures[i]->getRawImage() ;
296			if(delete_raw)
297			{
298				mDetailTextures[i]->destroyRawImage() ;
299			}
300			if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE ||
301				mDetailTextures[i]->getHeight(ddiscard) != BASE_SIZE ||
302				mDetailTextures[i]->getComponents() != 3)
303			{
304				LLPointer<LLImageRaw> newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3);
305				newraw->composite(mRawImages[i]);
306				mRawImages[i] = newraw; // deletes old
307			}
308		}
309		st_data[i] = mRawImages[i]->getData();
310		st_data_size[i] = mRawImages[i]->getDataSize();
311	}
312
313	///////////////////////////////////////
314	//
315	// Generate and clamp x/y bounding box.
316	//
317	//
318
319	S32 x_begin, y_begin, x_end, y_end;
320	x_begin = (S32)(x * mScaleInv);
321	y_begin = (S32)(y * mScaleInv);
322	x_end = llround( (x + width) * mScaleInv );
323	y_end = llround( (y + width) * mScaleInv );
324
325	if (x_end > mWidth)
326	{
327		llwarns << "x end > width" << llendl;
328		x_end = mWidth;
329	}
330	if (y_end > mWidth)
331	{
332		llwarns << "y end > width" << llendl;
333		y_end = mWidth;
334	}
335
336
337	///////////////////////////////////////////
338	//
339	// Generate target texture information, stride ratios.
340	//
341	//
342
343	LLViewerTexture *texturep;
344	U32 tex_width, tex_height, tex_comps;
345	U32 tex_stride;
346	F32 tex_x_scalef, tex_y_scalef;
347	S32 tex_x_begin, tex_y_begin, tex_x_end, tex_y_end;
348	F32 tex_x_ratiof, tex_y_ratiof;
349
350	texturep = mSurfacep->getSTexture();
351	tex_width = texturep->getWidth();
352	tex_height = texturep->getHeight();
353	tex_comps = texturep->getComponents();
354	tex_stride = tex_width * tex_comps;
355
356	U32 st_comps = 3;
357	U32 st_width = BASE_SIZE;
358	U32 st_height = BASE_SIZE;
359	
360	if (tex_comps != st_comps)
361	{
362		llwarns << "Base texture comps != input texture comps" << llendl;
363		return FALSE;
364	}
365
366	tex_x_scalef = (F32)tex_width / (F32)mWidth;
367	tex_y_scalef = (F32)tex_height / (F32)mWidth;
368	tex_x_begin = (S32)((F32)x_begin * tex_x_scalef);
369	tex_y_begin = (S32)((F32)y_begin * tex_y_scalef);
370	tex_x_end = (S32)((F32)x_end * tex_x_scalef);
371	tex_y_end = (S32)((F32)y_end * tex_y_scalef);
372
373	tex_x_ratiof = (F32)mWidth*mScale / (F32)tex_width;
374	tex_y_ratiof = (F32)mWidth*mScale / (F32)tex_height;
375
376	LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps);
377	U8 *rawp = raw->getData();
378
379	F32 tex_width_inv = 1.f/tex_width;
380	F32 tex_height_inv = 1.f/tex_height;
381
382	F32 st_x_stride, st_y_stride;
383	st_x_stride = ((F32)st_width / (F32)mTexScaleX)*((F32)mWidth / (F32)tex_width);
384	st_y_stride = ((F32)st_height / (F32)mTexScaleY)*((F32)mWidth / (F32)tex_height);
385
386	llassert(st_x_stride > 0.f);
387	llassert(st_y_stride > 0.f);
388	////////////////////////////////
389	//
390	// Iterate through the target texture, striding through the
391	// subtextures and interpolating appropriately.
392	//
393	//
394
395	F32 sti, stj;
396	S32 st_offset;
397	sti = (tex_x_begin * st_x_stride) - st_width*(llfloor((tex_x_begin * st_x_stride)/st_width));
398	stj = (tex_y_begin * st_y_stride) - st_height*(llfloor((tex_y_begin * st_y_stride)/st_height));
399
400	st_offset = (llfloor(stj * st_width) + llfloor(sti)) * st_comps;
401	for (S32 j = tex_y_begin; j < tex_y_end; j++)
402	{
403		U32 offset = j * tex_stride + tex_x_begin * tex_comps;
404		sti = (tex_x_begin * st_x_stride) - st_width*((U32)(tex_x_begin * st_x_stride)/st_width);
405		for (S32 i = tex_x_begin; i < tex_x_end; i++)
406		{
407			S32 tex0, tex1;
408			F32 composition = getValueScaled(i*tex_x_ratiof, j*tex_y_ratiof);
409
410			tex0 = llfloor( composition );
411			tex0 = llclamp(tex0, 0, 3);
412			composition -= tex0;
413			tex1 = tex0 + 1;
414			tex1 = llclamp(tex1, 0, 3);
415
416			F32 xy_int_i, xy_int_j;
417
418			xy_int_i = i * tex_width_inv;
419			xy_int_j = j * tex_height_inv;
420
421			st_offset = (lltrunc(sti) + lltrunc(stj)*st_width) * st_comps;
422			for (U32 k = 0; k < tex_comps; k++)
423			{
424				// Linearly interpolate based on composition.
425				if (st_offset >= st_data_size[tex0] || st_offset >= st_data_size[tex1])
426				{
427					// SJB: This shouldn't be happening, but does... Rounding error?
428					//llwarns << "offset 0 [" << tex0 << "] =" << st_offset << " >= size=" << st_data_size[tex0] << llendl;
429					//llwarns << "offset 1 [" << tex1 << "] =" << st_offset << " >= size=" << st_data_size[tex1] << llendl;
430				}
431				else
432				{
433					F32 a = *(st_data[tex0] + st_offset);
434					F32 b = *(st_data[tex1] + st_offset);
435					rawp[ offset ] = (U8)lltrunc( a + composition * (b - a) );
436				}
437				offset++;
438				st_offset++;
439			}
440
441			sti += st_x_stride;
442			if (sti >= st_width)
443			{
444				sti -= st_width;
445			}
446		}
447
448		stj += st_y_stride;
449		if (stj >= st_height)
450		{
451			stj -= st_height;
452		}
453	}
454
455	if (!texturep->hasGLTexture())
456	{
457		texturep->createGLTexture(0, raw);
458	}
459	texturep->setSubImage(raw, tex_x_begin, tex_y_begin, tex_x_end - tex_x_begin, tex_y_end - tex_y_begin);
460	LLSurface::sTextureUpdateTime += gen_timer.getElapsedTimeF32();
461	LLSurface::sTexelsUpdated += (tex_x_end - tex_x_begin) * (tex_y_end - tex_y_begin);
462
463	for (S32 i = 0; i < 4; i++)
464	{
465		// Un-boost detatil textures (will get re-boosted if rendering in high detail)
466		mDetailTextures[i]->setBoostLevel(LLViewerTexture::BOOST_NONE);
467		mDetailTextures[i]->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1);
468	}
469	
470	return TRUE;
471}
472
473LLUUID LLVLComposition::getDetailTextureID(S32 corner)
474{
475	return mDetailTextures[corner]->getID();
476}
477
478LLViewerFetchedTexture* LLVLComposition::getDetailTexture(S32 corner)
479{
480	return mDetailTextures[corner];
481}
482
483F32 LLVLComposition::getStartHeight(S32 corner)
484{
485	return mStartHeight[corner];
486}
487
488void LLVLComposition::setStartHeight(S32 corner, const F32 start_height)
489{
490	mStartHeight[corner] = start_height;
491}
492
493F32 LLVLComposition::getHeightRange(S32 corner)
494{
495	return mHeightRange[corner];
496}
497
498void LLVLComposition::setHeightRange(S32 corner, const F32 range)
499{
500	mHeightRange[corner] = range;
501}