diff options
Diffstat (limited to 'linden/indra/newview/lltextureatlasmanager.cpp')
-rw-r--r-- | linden/indra/newview/lltextureatlasmanager.cpp | 274 |
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 | |||
40 | const S8 MAX_NUM_EMPTY_ATLAS = 2 ; | ||
41 | const F32 MIN_ATLAS_FULLNESS = 0.6f ; | ||
42 | |||
43 | //********************************************************************************************* | ||
44 | //implementation of class LLTextureAtlasInfo | ||
45 | //********************************************************************************************* | ||
46 | LLTextureAtlasSlot::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 | |||
60 | LLTextureAtlasSlot::~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 | |||
93 | void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp) | ||
94 | { | ||
95 | mGroupp = groupp ; | ||
96 | } | ||
97 | void 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 | //********************************************************************************************* | ||
109 | LLTextureAtlasManager::LLTextureAtlasManager() : | ||
110 | mAtlasMap(4), | ||
111 | mEmptyAtlasMap(4) | ||
112 | { | ||
113 | } | ||
114 | |||
115 | LLTextureAtlasManager::~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 | ||
136 | BOOL 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 | |||
162 | void 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 | // | ||
193 | LLPointer<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 | //********************************************************************************************* | ||