PageRenderTime 47ms CodeModel.GetById 21ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/lltextureatlas.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 417 lines | 307 code | 49 blank | 61 comment | 46 complexity | 479d6ea3e8e83dd6b2ec3c4966afe88a MD5 | raw file
  1/** 
  2 * @file lltextureatlas.cpp
  3 * @brief LLTextureAtlas class implementation.
  4 *
  5 * $LicenseInfo:firstyear=2002&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#include "llviewerprecompiledheaders.h"
 27#include "linden_common.h"
 28#include "llerror.h"
 29#include "llimage.h"
 30#include "llmath.h"
 31#include "llgl.h"
 32#include "llrender.h"
 33#include "lltextureatlas.h"
 34
 35//-------------------
 36S16 LLTextureAtlas::sMaxSubTextureSize = 64 ;
 37S16 LLTextureAtlas::sSlotSize = 32 ;
 38
 39#ifndef DEBUG_ATLAS
 40#define DEBUG_ATLAS 0
 41#endif
 42
 43#ifndef DEBUG_USAGE_BITS
 44#define DEBUG_USAGE_BITS 0
 45#endif
 46//**************************************************************************************************************
 47LLTextureAtlas::LLTextureAtlas(U8 ncomponents, S16 atlas_dim) : 
 48    LLViewerTexture(atlas_dim * sSlotSize, atlas_dim * sSlotSize, ncomponents, TRUE),
 49	mAtlasDim(atlas_dim),
 50	mNumSlotsReserved(0),
 51	mMaxSlotsInAtlas(atlas_dim * atlas_dim)
 52{
 53	generateEmptyUsageBits() ;
 54
 55	//generate an empty texture
 56	generateGLTexture() ;
 57	LLPointer<LLImageRaw> image_raw = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
 58	createGLTexture(0, image_raw, 0);
 59	image_raw = NULL;
 60}
 61
 62LLTextureAtlas::~LLTextureAtlas() 
 63{
 64	if(mSpatialGroupList.size() > 0)
 65	{
 66		llerrs << "Not clean up the spatial groups!" << llendl ;
 67	}
 68	releaseUsageBits() ;
 69}
 70
 71//virtual 
 72S8 LLTextureAtlas::getType() const
 73{
 74	return LLViewerTexture::ATLAS_TEXTURE ;
 75}
 76
 77void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset)
 78{
 79	xoffset = (F32)col / mAtlasDim ;
 80	yoffset = (F32)row / mAtlasDim ;	
 81}
 82
 83void LLTextureAtlas::getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale)
 84{
 85	xscale = (F32)w / (mAtlasDim * sSlotSize) ;
 86	yscale = (F32)h / (mAtlasDim * sSlotSize) ;	
 87}
 88
 89//insert a texture piece into the atlas
 90LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row)
 91{
 92	if(!getTexName())
 93	{
 94		return 0 ;
 95	}
 96
 97	S32 w = raw_image->getWidth() ;
 98	S32 h = raw_image->getHeight() ;
 99	if(w < 8 || w > sMaxSubTextureSize || h < 8 || h > sMaxSubTextureSize)
100	{
101		//size overflow
102		return 0 ;
103	}
104
105	BOOL res = gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getTexName());
106	if (!res) 
107	{
108		llerrs << "bindTexture failed" << llendl;
109	}
110	
111	GLint xoffset = sSlotSize * slot_col ;
112	GLint yoffset = sSlotSize * slot_row ;
113
114	if(!source_gl_tex->preAddToAtlas(discard_level, raw_image))
115	{
116		return 0 ;
117	}
118
119	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, TRUE);
120	glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h,
121						mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData());
122	
123	source_gl_tex->postAddToAtlas() ;
124	return getTexName();
125}
126	
127//release a sub-texture slot from the atlas
128void LLTextureAtlas::releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width)
129{
130	unmarkUsageBits(slot_width, slot_col, slot_row) ;
131	mNumSlotsReserved -= slot_width * slot_width ;
132}
133
134BOOL LLTextureAtlas::isEmpty() const 
135{
136	return !mNumSlotsReserved ;
137}
138	
139BOOL LLTextureAtlas::isFull(S8 to_be_reserved) const 
140{
141	return mNumSlotsReserved + to_be_reserved > mMaxSlotsInAtlas ;
142}
143F32  LLTextureAtlas::getFullness() const 
144{
145	return (F32)mNumSlotsReserved / mMaxSlotsInAtlas ;
146}
147
148void LLTextureAtlas::addSpatialGroup(LLSpatialGroup* groupp) 
149{
150	if(groupp && !hasSpatialGroup(groupp))
151	{
152		mSpatialGroupList.push_back(groupp);
153	}
154}
155
156void LLTextureAtlas::removeSpatialGroup(LLSpatialGroup* groupp) 
157{
158	if(groupp)
159	{
160		mSpatialGroupList.remove(groupp);
161	}
162}
163
164void LLTextureAtlas::clearSpatialGroup() 
165{
166	mSpatialGroupList.clear();
167}
168void LLTextureAtlas::removeLastSpatialGroup() 
169{
170	mSpatialGroupList.pop_back() ;
171}
172
173LLSpatialGroup* LLTextureAtlas::getLastSpatialGroup() 
174{
175	if(mSpatialGroupList.size() > 0)
176	{
177		return mSpatialGroupList.back() ;
178	}
179	return NULL ;
180}
181
182BOOL LLTextureAtlas::hasSpatialGroup(LLSpatialGroup* groupp) 
183{
184	for(std::list<LLSpatialGroup*>::iterator iter = mSpatialGroupList.begin(); iter != mSpatialGroupList.end() ; ++iter)
185	{
186		if(*iter == groupp)
187		{
188			return TRUE ;
189		}
190	}
191	return FALSE ;
192}
193
194//--------------------------------------------------------------------------------------
195//private
196void LLTextureAtlas::generateEmptyUsageBits()
197{
198	S32 col_len = (mAtlasDim + 7) >> 3 ;
199	mUsageBits = new U8*[mAtlasDim] ;
200	*mUsageBits = new U8[mAtlasDim * col_len] ;
201
202	mUsageBits[0] = *mUsageBits ;
203	for(S32 i = 1 ; i < mAtlasDim ; i++)
204	{
205	   mUsageBits[i] = mUsageBits[i-1] + col_len ;
206
207	   for(S32 j = 0 ; j < col_len ; j++)
208	   {
209		   //init by 0 for all bits.
210		   mUsageBits[i][j] = 0 ;
211	   }
212	}
213
214	//do not forget mUsageBits[0]!
215	for(S32 j = 0 ; j < col_len ; j++)
216	{
217		//init by 0 for all bits.
218		mUsageBits[0][j] = 0 ;
219	}
220
221	mTestBits = NULL ;
222#if DEBUG_USAGE_BITS
223	//------------
224	//test
225	mTestBits = new U8*[mAtlasDim] ;
226	*mTestBits = new U8[mAtlasDim * mAtlasDim] ;
227	mTestBits[0] = *mTestBits ;
228	for(S32 i = 1 ; i < mAtlasDim ; i++)
229	{
230	   mTestBits[i] = mTestBits[i-1] + mAtlasDim ;
231
232	   for(S32 j = 0 ; j < mAtlasDim ; j++)
233	   {
234		   //init by 0 for all bits.
235		   mTestBits[i][j] = 0 ;
236	   }
237	}
238
239	for(S32 j = 0 ; j < mAtlasDim ; j++)
240	{
241		//init by 0 for all bits.
242		mTestBits[0][j] = 0 ;
243	}
244#endif
245}
246
247void LLTextureAtlas::releaseUsageBits()
248{
249   if(mUsageBits)
250   {
251       delete[] *mUsageBits ;
252       delete[] mUsageBits ;
253   }
254   mUsageBits = NULL ;
255
256   //test
257   if( mTestBits)
258   {
259	   delete[] *mTestBits;
260	   delete[]  mTestBits;
261   }
262    mTestBits = NULL ;
263}
264
265void LLTextureAtlas::markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row)
266{
267	S16 x = col >> 3 ;
268	
269	for(S8 i = 0 ; i < bits_len ; i++)
270	{
271		mUsageBits[row + i][x] |= mask ;
272	}
273
274#if DEBUG_USAGE_BITS
275	//test
276	for(S8 i = row ; i < row + bits_len ; i++)
277	{
278		for(S8 j = col ; j < col + bits_len ; j++)
279		{
280			mTestBits[i][j] = 1 ;
281		}
282	}
283#endif
284}
285
286void LLTextureAtlas::unmarkUsageBits(S8 bits_len, S16 col, S16 row)
287{
288	S16 x = col >> 3 ;
289	U8  mask = 1 ;
290	for(S8 i = 1 ; i < bits_len ; i++)
291	{
292		mask |= (1 << i) ;
293	}
294	mask <<= (col & 7) ;
295	mask = ~mask ;
296	
297	for(S8 i = 0 ; i < bits_len ; i++)
298	{
299		mUsageBits[row + i][x] &= mask ;
300	}
301
302#if DEBUG_USAGE_BITS
303	//test
304	for(S8 i = row ; i < row + bits_len ; i++)
305	{
306		for(S8 j = col ; j < col + bits_len ; j++)
307		{
308			mTestBits[i][j] = 0 ;
309		}
310	}
311#endif
312}
313
314//return true if any of bits in the range marked.
315BOOL LLTextureAtlas::areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row)
316{
317	BOOL ret = FALSE ;	
318	S16 x = col >> 3 ;
319	
320	for(S8 i = 0 ; i < bits_len ; i++)
321	{
322		if(mUsageBits[row + i][x] & mask)
323		{
324			ret = TRUE ;
325			break ;
326			//return TRUE ;
327		}
328	}
329
330#if DEBUG_USAGE_BITS
331	//test
332	BOOL ret2 = FALSE ;
333	for(S8 i = row ; i < row + bits_len ; i++)
334	{
335		for(S8 j = col ; j < col + bits_len ; j++)
336		{
337			if(mTestBits[i][j])
338			{
339				ret2 = TRUE ;
340			}
341		}
342	}
343
344	if(ret != ret2)
345	{
346		llerrs << "bits map corrupted." << llendl ;
347	}
348#endif
349	return ret ;//FALSE ;
350}
351
352//----------------------------------------------------------------------
353//
354//index order: Z order, i.e.: 
355// |-----|-----|-----|-----|
356// |  10 |  11 | 14  | 15  |
357// |-----|-----|-----|-----|
358// |   8 |   9 | 12  | 13  |
359// |-----|-----|-----|-----|
360// |   2 |   3 |   6 |   7 |
361// |-----|-----|-----|-----|
362// |   0 |   1 |   4 |   5 |
363// |-----|-----|-----|-----|
364void LLTextureAtlas::getPositionFromIndex(S16 index, S16& col, S16& row)
365{
366	col = 0 ;
367	row = 0 ;
368
369	S16 index_copy = index ;
370	for(S16 i = 0 ; index_copy && i < 16 ; i += 2)
371	{
372		col |= ((index & (1 << i)) >> i) << (i >> 1) ;
373		row |= ((index & (1 << (i + 1))) >> (i + 1)) << (i >> 1) ;
374		index_copy >>= 2 ;
375	}
376}
377void LLTextureAtlas::getIndexFromPosition(S16 col, S16 row, S16& index)
378{
379	index = 0 ;
380	S16 col_copy = col ;
381	S16 row_copy = row ;
382	for(S16 i = 0 ; (col_copy || row_copy) && i < 16 ; i++)
383	{
384		index |= ((col & 1 << i) << i) | ((row & 1 << i) << ( i + 1)) ;
385		col_copy >>= 1 ;
386		row_copy >>= 1 ;
387	}
388}
389//----------------------------------------------------------------------
390//return TRUE if succeeds.
391BOOL LLTextureAtlas::getNextAvailableSlot(S8 bits_len, S16& col, S16& row)
392{
393    S16 index_step = bits_len * bits_len ;
394
395    U8 mask = 1 ;
396	for(S8 i = 1 ; i < bits_len ; i++)
397	{
398		mask |= (1 << i) ;
399	}	
400   
401	U8 cur_mask ;
402	for(S16 index = 0 ; index < mMaxSlotsInAtlas ; index += index_step)
403    {
404		getPositionFromIndex(index, col, row) ;
405		
406		cur_mask = mask << (col & 7) ;
407		if(!areUsageBitsMarked(bits_len, cur_mask, col, row))
408		{
409			markUsageBits(bits_len, cur_mask, col, row) ;
410			mNumSlotsReserved += bits_len * bits_len ;
411			
412			return TRUE ;
413		}
414    }
415
416   return FALSE ;
417}