aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lltextureatlasmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/lltextureatlasmanager.cpp')
-rw-r--r--linden/indra/newview/lltextureatlasmanager.cpp274
1 files changed, 274 insertions, 0 deletions
diff --git a/linden/indra/newview/lltextureatlasmanager.cpp b/linden/indra/newview/lltextureatlasmanager.cpp
new file mode 100644
index 0000000..df6a39d
--- /dev/null
+++ b/linden/indra/newview/lltextureatlasmanager.cpp
@@ -0,0 +1,274 @@
1/**
2 * @file lltextureatlasmanager.cpp
3 * @brief LLTextureAtlasManager class implementation.
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32#include "llviewerprecompiledheaders.h"
33#include "linden_common.h"
34#include "llerror.h"
35#include "llmath.h"
36#include "lltextureatlas.h"
37#include "lltextureatlasmanager.h"
38#include "llspatialpartition.h"
39
40const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
41const F32 MIN_ATLAS_FULLNESS = 0.6f ;
42
43//*********************************************************************************************
44//implementation of class LLTextureAtlasInfo
45//*********************************************************************************************
46LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) :
47 mAtlasp(atlasp),
48 mGroupp(groupp),
49 mCol(col),
50 mRow(row),
51 mReservedSlotWidth(slot_width),
52 mValid(FALSE),
53 mUpdatedTime(0),
54 mTexCoordOffset(xoffset, yoffset),
55 mTexCoordScale(1.f, 1.f)
56{
57 llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
58}
59
60LLTextureAtlasSlot::~LLTextureAtlasSlot()
61{
62 if(mAtlasp)
63 {
64 mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
65 if(mAtlasp->isEmpty())
66 {
67 LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
68 }
69 mAtlasp = NULL ;
70 }
71}
72
73//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp)
74//{
75// mAtlasp = atlasp ;
76//}
77//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row)
78//{
79// mCol = col ;
80// mRow = row ;
81//}
82//void LLTextureAtlasSlot::setSlotWidth(S8 width)
83//{
84// //slot is a square with each edge length a power-of-two number
85// mReservedSlotWidth = width ;
86//}
87//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset)
88//{
89// mTexCoordOffset.mV[0] = xoffset ;
90// mTexCoordOffset.mV[1] = yoffset ;
91//}
92
93void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp)
94{
95 mGroupp = groupp ;
96}
97void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale)
98{
99 mTexCoordScale.mV[0] = xscale ;
100 mTexCoordScale.mV[1] = yscale ;
101}
102//*********************************************************************************************
103//END of implementation of class LLTextureAtlasInfo
104//*********************************************************************************************
105
106//*********************************************************************************************
107//implementation of class LLTextureAtlasManager
108//*********************************************************************************************
109LLTextureAtlasManager::LLTextureAtlasManager() :
110 mAtlasMap(4),
111 mEmptyAtlasMap(4)
112{
113}
114
115LLTextureAtlasManager::~LLTextureAtlasManager()
116{
117 for(S32 i = 0 ; i < 4 ; i++)
118 {
119 for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
120 {
121 *j = NULL ;
122 }
123 for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
124 {
125 *j = NULL ;
126 }
127
128 mAtlasMap[i].clear() ;
129 mEmptyAtlasMap[i].clear() ;
130 }
131 mAtlasMap.clear() ;
132 mEmptyAtlasMap.clear() ;
133}
134
135//return TRUE if qualified
136BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target)
137{
138 if(ncomponents < 1 || ncomponents > 4)
139 {
140 return FALSE ;
141 }
142 //only support GL_TEXTURE_2D
143 if(GL_TEXTURE_2D != target)
144 {
145 return FALSE ;
146 }
147 //real image size overflows
148 if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
149 {
150 return FALSE ;
151 }
152
153 //if non-power-of-two number
154 if((w & (w - 1)) || (h & (h - 1)))
155 {
156 return FALSE ;
157 }
158
159 return TRUE ;
160}
161
162void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
163{
164 LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
165 while(groupp)
166 {
167 groupp->removeAtlas(atlasp, FALSE) ;
168 atlasp->removeLastSpatialGroup() ;
169
170 groupp = atlasp->getLastSpatialGroup() ;
171 }
172
173 S8 type = atlasp->getComponents() - 1 ;
174 //insert to the empty list
175 if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
176 {
177 mEmptyAtlasMap[type].push_back(atlasp) ;
178 }
179
180 //delete the atlasp
181 mAtlasMap[type].remove(atlasp) ;
182}
183
184//
185//this function reserves an appropriate slot from atlas pool for an image.
186//return non-NULL if succeeds.
187//Note:
188//1, this function does not check if the image this slot assigned for qualifies for atlas or not,
189// call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
190//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
191//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
192//
193LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents,
194 LLSpatialGroup* groupp, LLViewerImage* imagep)
195{
196 if(!groupp)
197 {
198 //do not insert to atlas if does not have a group.
199 return NULL ;
200 }
201
202 //bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
203 if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
204 {
205 sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
206 }
207 S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
208 if(bits_len < 1)
209 {
210 bits_len = 1 ;
211 }
212
213 S16 col = -1, row = -1;
214 S8 total_bits = bits_len * bits_len ;
215
216 //insert to the atlas reserved by the same spatial group
217 LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
218 if(atlasp.notNull())
219 {
220 if(!atlasp->getNextAvailableSlot(bits_len, col, row))
221 {
222 //failed
223 atlasp = NULL ;
224 }
225 }
226
227 //search an atlas to fit for 'size'
228 if(!atlasp)
229 {
230 S8 atlas_index = ncomponents - 1 ;
231 ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
232 for(; iter != mAtlasMap[atlas_index].end(); ++iter)
233 {
234 LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
235 if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
236 {
237 if(cur->getNextAvailableSlot(bits_len, col, row))
238 {
239 atlasp = cur ;
240 groupp->addAtlas(atlasp) ;
241 break ;
242 }
243 }
244 }
245 }
246
247 //create a new atlas if necessary
248 if(!atlasp)
249 {
250 if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
251 {
252 //there is an empty one
253 atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
254 mEmptyAtlasMap[ncomponents - 1].pop_back() ;
255 }
256 else
257 {
258 atlasp = new LLTextureAtlas(ncomponents, 16) ;
259 }
260 mAtlasMap[ncomponents - 1].push_back(atlasp) ;
261 atlasp->getNextAvailableSlot(bits_len, col, row) ;
262 groupp->addAtlas(atlasp) ;
263 }
264
265 F32 xoffset, yoffset ;
266 atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
267 LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
268
269 return slot_infop ;
270}
271
272//*********************************************************************************************
273//END of implementation of class LLTextureAtlasManager
274//*********************************************************************************************