diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llwearable.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llwearable.cpp | 971 |
1 files changed, 971 insertions, 0 deletions
diff --git a/linden/indra/newview/llwearable.cpp b/linden/indra/newview/llwearable.cpp new file mode 100644 index 0000000..62a1d20 --- /dev/null +++ b/linden/indra/newview/llwearable.cpp | |||
@@ -0,0 +1,971 @@ | |||
1 | /** | ||
2 | * @file llwearable.cpp | ||
3 | * @brief LLWearable class implementation | ||
4 | * | ||
5 | * Copyright (c) 2002-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 "imageids.h" | ||
31 | #include "llassetstorage.h" | ||
32 | #include "lldbstrings.h" | ||
33 | #include "lldir.h" | ||
34 | #include "llquantize.h" | ||
35 | |||
36 | #include "llagent.h" | ||
37 | #include "llviewerwindow.h" | ||
38 | #include "llfloatercustomize.h" | ||
39 | #include "llinventorymodel.h" | ||
40 | #include "llviewerimagelist.h" | ||
41 | #include "llviewerinventory.h" | ||
42 | #include "llvoavatar.h" | ||
43 | #include "llwearable.h" | ||
44 | |||
45 | //#include "viewer.h" | ||
46 | //#include "llvfs.h" | ||
47 | |||
48 | // static | ||
49 | S32 LLWearable::sCurrentDefinitionVersion = 1; | ||
50 | |||
51 | // static | ||
52 | const char* LLWearable::sTypeName[ WT_COUNT ] = | ||
53 | { | ||
54 | "shape", | ||
55 | "skin", | ||
56 | "hair", | ||
57 | "eyes", | ||
58 | "shirt", | ||
59 | "pants", | ||
60 | "shoes", | ||
61 | "socks", | ||
62 | "jacket", | ||
63 | "gloves", | ||
64 | "undershirt", | ||
65 | "underpants", | ||
66 | "skirt" | ||
67 | }; | ||
68 | |||
69 | // static | ||
70 | const char* LLWearable::sTypeLabel[ WT_COUNT ] = | ||
71 | { | ||
72 | "Shape", | ||
73 | "Skin", | ||
74 | "Hair", | ||
75 | "Eyes", | ||
76 | "Shirt", | ||
77 | "Pants", | ||
78 | "Shoes", | ||
79 | "Socks", | ||
80 | "Jacket", | ||
81 | "Gloves", | ||
82 | "Undershirt", | ||
83 | "Underpants", | ||
84 | "Skirt" | ||
85 | }; | ||
86 | |||
87 | |||
88 | // static | ||
89 | LLAssetType::EType LLWearable::typeToAssetType(EWearableType wearable_type) | ||
90 | { | ||
91 | switch( wearable_type ) | ||
92 | { | ||
93 | case WT_SHAPE: | ||
94 | case WT_SKIN: | ||
95 | case WT_HAIR: | ||
96 | case WT_EYES: | ||
97 | return LLAssetType::AT_BODYPART; | ||
98 | case WT_SHIRT: | ||
99 | case WT_PANTS: | ||
100 | case WT_SHOES: | ||
101 | case WT_SOCKS: | ||
102 | case WT_JACKET: | ||
103 | case WT_GLOVES: | ||
104 | case WT_UNDERSHIRT: | ||
105 | case WT_UNDERPANTS: | ||
106 | case WT_SKIRT: | ||
107 | return LLAssetType::AT_CLOTHING; | ||
108 | default: | ||
109 | return LLAssetType::AT_NONE; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | |||
114 | LLWearable::LLWearable(const LLTransactionID& transaction_id) : | ||
115 | mDefinitionVersion(LLWearable::sCurrentDefinitionVersion), | ||
116 | mType(WT_SHAPE) | ||
117 | { | ||
118 | mTransactionID = transaction_id; | ||
119 | mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); | ||
120 | } | ||
121 | |||
122 | LLWearable::LLWearable(const LLAssetID& asset_id) : | ||
123 | mDefinitionVersion( LLWearable::sCurrentDefinitionVersion ), | ||
124 | mType(WT_SHAPE) | ||
125 | { | ||
126 | mAssetID = asset_id; | ||
127 | mTransactionID.setNull(); | ||
128 | } | ||
129 | |||
130 | LLWearable::~LLWearable() | ||
131 | { | ||
132 | mVisualParamMap.deleteAllData(); | ||
133 | mTEMap.deleteAllData(); | ||
134 | } | ||
135 | |||
136 | |||
137 | // static | ||
138 | EWearableType LLWearable::typeNameToType( const LLString& type_name ) | ||
139 | { | ||
140 | for( S32 i = 0; i < WT_COUNT; i++ ) | ||
141 | { | ||
142 | if( type_name == LLWearable::sTypeName[ i ] ) | ||
143 | { | ||
144 | return (EWearableType)i; | ||
145 | } | ||
146 | } | ||
147 | return WT_INVALID; | ||
148 | } | ||
149 | |||
150 | |||
151 | const char* terse_F32_to_string( F32 f, char s[MAX_STRING] ) | ||
152 | { | ||
153 | char* r = s; | ||
154 | S32 len = sprintf( s, "%.2f", f ); | ||
155 | |||
156 | // "1.20" -> "1.2" | ||
157 | // "24.00" -> "24." | ||
158 | while( '0' == r[len - 1] ) | ||
159 | { | ||
160 | len--; | ||
161 | r[len] = '\0'; | ||
162 | } | ||
163 | |||
164 | if( '.' == r[len - 1] ) | ||
165 | { | ||
166 | // "24." -> "24" | ||
167 | len--; | ||
168 | r[len] = '\0'; | ||
169 | } | ||
170 | else | ||
171 | if( ('-' == r[0]) && ('0' == r[1]) ) | ||
172 | { | ||
173 | // "-0.59" -> "-.59" | ||
174 | r++; | ||
175 | r[0] = '-'; | ||
176 | } | ||
177 | else | ||
178 | if( '0' == r[0] ) | ||
179 | { | ||
180 | // "0.59" -> ".59" | ||
181 | r++; | ||
182 | } | ||
183 | |||
184 | return r; | ||
185 | } | ||
186 | |||
187 | BOOL LLWearable::exportFile( FILE* file ) | ||
188 | { | ||
189 | // header and version | ||
190 | if( fprintf( file, "LLWearable version %d\n", mDefinitionVersion ) < 0 ) | ||
191 | { | ||
192 | return FALSE; | ||
193 | } | ||
194 | |||
195 | // name | ||
196 | if( fprintf( file, "%s\n", mName.c_str() ) < 0 ) | ||
197 | { | ||
198 | return FALSE; | ||
199 | } | ||
200 | |||
201 | // description | ||
202 | if( fprintf( file, "%s\n", mDescription.c_str() ) < 0 ) | ||
203 | { | ||
204 | return FALSE; | ||
205 | } | ||
206 | |||
207 | // permissions | ||
208 | if( !mPermissions.exportFile( file ) ) | ||
209 | { | ||
210 | return FALSE; | ||
211 | } | ||
212 | |||
213 | // sale info | ||
214 | if( !mSaleInfo.exportFile( file ) ) | ||
215 | { | ||
216 | return FALSE; | ||
217 | } | ||
218 | |||
219 | // wearable type | ||
220 | S32 type = (S32)mType; | ||
221 | if( fprintf( file, "type %d\n", type ) < 0 ) | ||
222 | { | ||
223 | return FALSE; | ||
224 | } | ||
225 | |||
226 | // parameters | ||
227 | S32 num_parameters = mVisualParamMap.getLength(); | ||
228 | if( fprintf( file, "parameters %d\n", num_parameters ) < 0 ) | ||
229 | { | ||
230 | return FALSE; | ||
231 | } | ||
232 | |||
233 | char s[ MAX_STRING ]; | ||
234 | for( F32* param_weightp = mVisualParamMap.getFirstData(); param_weightp; param_weightp = mVisualParamMap.getNextData() ) | ||
235 | { | ||
236 | S32 param_id = mVisualParamMap.getCurrentKeyWithoutIncrement(); | ||
237 | if( fprintf( file, "%d %s\n", param_id, terse_F32_to_string( *param_weightp, s ) ) < 0 ) | ||
238 | { | ||
239 | return FALSE; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | // texture entries | ||
244 | S32 num_textures = mTEMap.getLength(); | ||
245 | if( fprintf( file, "textures %d\n", num_textures ) < 0 ) | ||
246 | { | ||
247 | return FALSE; | ||
248 | } | ||
249 | |||
250 | for( LLUUID* image_id = mTEMap.getFirstData(); image_id; image_id = mTEMap.getNextData() ) | ||
251 | { | ||
252 | S32 te = mTEMap.getCurrentKeyWithoutIncrement(); | ||
253 | char image_id_string[UUID_STR_LENGTH]; | ||
254 | image_id->toString( image_id_string ); | ||
255 | if( fprintf( file, "%d %s\n", te, image_id_string) < 0 ) | ||
256 | { | ||
257 | return FALSE; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | return TRUE; | ||
262 | } | ||
263 | |||
264 | |||
265 | |||
266 | BOOL LLWearable::importFile( FILE* file ) | ||
267 | { | ||
268 | char text_buffer[2048]; | ||
269 | S32 fields_read = 0; | ||
270 | |||
271 | // read header and version | ||
272 | fields_read = fscanf( file, "LLWearable version %d\n", &mDefinitionVersion ); | ||
273 | if( fields_read != 1 ) | ||
274 | { | ||
275 | // Shouldn't really log the asset id for security reasons, but | ||
276 | // we need it in this case. | ||
277 | llwarns << "Bad Wearable asset header: " << mAssetID << llendl; | ||
278 | //gVFS->dumpMap(); | ||
279 | return FALSE; | ||
280 | } | ||
281 | |||
282 | if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion ) | ||
283 | { | ||
284 | llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; | ||
285 | return FALSE; | ||
286 | } | ||
287 | |||
288 | // name | ||
289 | char next_char = fgetc( file ); | ||
290 | if( '\n' == next_char ) | ||
291 | { | ||
292 | // no name | ||
293 | mName = ""; | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | ungetc( next_char, file ); | ||
298 | fields_read = fscanf( file, "%[^\n]", text_buffer ); | ||
299 | if( (1 != fields_read) || (fgetc( file ) != '\n') ) | ||
300 | { | ||
301 | llwarns << "Bad Wearable asset: early end of file" << llendl; | ||
302 | return FALSE; | ||
303 | } | ||
304 | mName = text_buffer; | ||
305 | LLString::truncate(mName, DB_INV_ITEM_NAME_STR_LEN ); | ||
306 | } | ||
307 | |||
308 | // description | ||
309 | next_char = fgetc( file ); | ||
310 | if( '\n' == next_char ) | ||
311 | { | ||
312 | // no description | ||
313 | mDescription = ""; | ||
314 | } | ||
315 | else | ||
316 | { | ||
317 | ungetc( next_char, file ); | ||
318 | fields_read = fscanf( file, "%[^\n]", text_buffer ); | ||
319 | if( (1 != fields_read) || (fgetc( file ) != '\n') ) | ||
320 | { | ||
321 | llwarns << "Bad Wearable asset: early end of file" << llendl; | ||
322 | return FALSE; | ||
323 | } | ||
324 | mDescription = text_buffer; | ||
325 | LLString::truncate(mDescription, DB_INV_ITEM_DESC_STR_LEN ); | ||
326 | } | ||
327 | |||
328 | // permissions | ||
329 | S32 perm_version; | ||
330 | fields_read = fscanf( file, " permissions %d\n", &perm_version ); | ||
331 | if( (fields_read != 1) || (perm_version != 0) ) | ||
332 | { | ||
333 | llwarns << "Bad Wearable asset: missing permissions" << llendl; | ||
334 | return FALSE; | ||
335 | } | ||
336 | if( !mPermissions.importFile( file ) ) | ||
337 | { | ||
338 | return FALSE; | ||
339 | } | ||
340 | |||
341 | // sale info | ||
342 | S32 sale_info_version; | ||
343 | fields_read = fscanf( file, " sale_info %d\n", &sale_info_version ); | ||
344 | if( (fields_read != 1) || (sale_info_version != 0) ) | ||
345 | { | ||
346 | llwarns << "Bad Wearable asset: missing sale_info" << llendl; | ||
347 | return FALSE; | ||
348 | } | ||
349 | // Sale info used to contain next owner perm. It is now in the | ||
350 | // permissions. Thus, we read that out, and fix legacy | ||
351 | // objects. It's possible this op would fail, but it should pick | ||
352 | // up the vast majority of the tasks. | ||
353 | BOOL has_perm_mask = FALSE; | ||
354 | U32 perm_mask = 0; | ||
355 | if( !mSaleInfo.importFile(file, has_perm_mask, perm_mask) ) | ||
356 | { | ||
357 | return FALSE; | ||
358 | } | ||
359 | if(has_perm_mask) | ||
360 | { | ||
361 | // fair use fix. | ||
362 | if(!(perm_mask & PERM_COPY)) | ||
363 | { | ||
364 | perm_mask |= PERM_TRANSFER; | ||
365 | } | ||
366 | mPermissions.setMaskNext(perm_mask); | ||
367 | } | ||
368 | |||
369 | // wearable type | ||
370 | S32 type = -1; | ||
371 | fields_read = fscanf( file, "type %d\n", &type ); | ||
372 | if( fields_read != 1 ) | ||
373 | { | ||
374 | llwarns << "Bad Wearable asset: bad type" << llendl; | ||
375 | return FALSE; | ||
376 | } | ||
377 | if( 0 <= type && type < WT_COUNT ) | ||
378 | { | ||
379 | mType = (EWearableType)type; | ||
380 | } | ||
381 | else | ||
382 | { | ||
383 | llwarns << "Bad Wearable asset: bad type #" << type << llendl; | ||
384 | return FALSE; | ||
385 | } | ||
386 | |||
387 | |||
388 | // parameters header | ||
389 | S32 num_parameters = 0; | ||
390 | fields_read = fscanf( file, "parameters %d\n", &num_parameters ); | ||
391 | if( fields_read != 1 ) | ||
392 | { | ||
393 | llwarns << "Bad Wearable asset: missing parameters block" << llendl; | ||
394 | return FALSE; | ||
395 | } | ||
396 | |||
397 | // parameters | ||
398 | S32 i; | ||
399 | for( i = 0; i < num_parameters; i++ ) | ||
400 | { | ||
401 | S32 param_id = 0; | ||
402 | F32 param_weight = 0.f; | ||
403 | fields_read = fscanf( file, "%d %f\n", ¶m_id, ¶m_weight ); | ||
404 | if( fields_read != 2 ) | ||
405 | { | ||
406 | llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl; | ||
407 | return FALSE; | ||
408 | } | ||
409 | mVisualParamMap.addData( param_id, new F32(param_weight) ); | ||
410 | } | ||
411 | |||
412 | // textures header | ||
413 | S32 num_textures = 0; | ||
414 | fields_read = fscanf( file, "textures %d\n", &num_textures); | ||
415 | if( fields_read != 1 ) | ||
416 | { | ||
417 | llwarns << "Bad Wearable asset: missing textures block" << llendl; | ||
418 | return FALSE; | ||
419 | } | ||
420 | |||
421 | // textures | ||
422 | for( i = 0; i < num_textures; i++ ) | ||
423 | { | ||
424 | S32 te = 0; | ||
425 | fields_read = fscanf( file, "%d %s\n", &te, text_buffer); | ||
426 | if( fields_read != 2 ) | ||
427 | { | ||
428 | llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; | ||
429 | return FALSE; | ||
430 | } | ||
431 | |||
432 | if( !LLUUID::validate( text_buffer ) ) | ||
433 | { | ||
434 | llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; | ||
435 | return FALSE; | ||
436 | } | ||
437 | |||
438 | mTEMap.addData( te, new LLUUID( text_buffer ) ); | ||
439 | } | ||
440 | |||
441 | return TRUE; | ||
442 | } | ||
443 | |||
444 | |||
445 | // Avatar parameter and texture definitions can change over time. | ||
446 | // This function returns true if parameters or textures have been added or removed | ||
447 | // since this wearable was created. | ||
448 | BOOL LLWearable::isOldVersion() | ||
449 | { | ||
450 | LLVOAvatar* avatar = gAgent.getAvatarObject(); | ||
451 | llassert( avatar ); | ||
452 | if( !avatar ) | ||
453 | { | ||
454 | return FALSE; | ||
455 | } | ||
456 | |||
457 | if( LLWearable::sCurrentDefinitionVersion < mDefinitionVersion ) | ||
458 | { | ||
459 | llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; | ||
460 | llassert(0); | ||
461 | } | ||
462 | |||
463 | if( LLWearable::sCurrentDefinitionVersion != mDefinitionVersion ) | ||
464 | { | ||
465 | return TRUE; | ||
466 | } | ||
467 | |||
468 | S32 param_count = 0; | ||
469 | for( LLViewerVisualParam* param = (LLViewerVisualParam*) avatar->getFirstVisualParam(); | ||
470 | param; | ||
471 | param = (LLViewerVisualParam*) avatar->getNextVisualParam() ) | ||
472 | { | ||
473 | if( (param->getWearableType() == mType) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) ) | ||
474 | { | ||
475 | param_count++; | ||
476 | if( !mVisualParamMap.checkKey( param->getID() ) ) | ||
477 | { | ||
478 | return TRUE; | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | if( param_count != mVisualParamMap.getLength() ) | ||
483 | { | ||
484 | return TRUE; | ||
485 | } | ||
486 | |||
487 | |||
488 | S32 te_count = 0; | ||
489 | for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) | ||
490 | { | ||
491 | if( LLVOAvatar::getTEWearableType( te ) == mType ) | ||
492 | { | ||
493 | te_count++; | ||
494 | if( !mTEMap.checkKey( te ) ) | ||
495 | { | ||
496 | return TRUE; | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | if( te_count != mTEMap.getLength() ) | ||
501 | { | ||
502 | return TRUE; | ||
503 | } | ||
504 | |||
505 | return FALSE; | ||
506 | } | ||
507 | |||
508 | // Avatar parameter and texture definitions can change over time. | ||
509 | // * If parameters or textures have been REMOVED since the wearable was created, | ||
510 | // they're just ignored, so we consider the wearable clean even though isOldVersion() | ||
511 | // will return true. | ||
512 | // * If parameters or textures have been ADDED since the wearable was created, | ||
513 | // they are taken to have default values, so we consider the wearable clean | ||
514 | // only if those values are the same as the defaults. | ||
515 | BOOL LLWearable::isDirty() | ||
516 | { | ||
517 | LLVOAvatar* avatar = gAgent.getAvatarObject(); | ||
518 | llassert( avatar ); | ||
519 | if( !avatar ) | ||
520 | { | ||
521 | return FALSE; | ||
522 | } | ||
523 | |||
524 | |||
525 | for( LLViewerVisualParam* param = (LLViewerVisualParam*) avatar->getFirstVisualParam(); | ||
526 | param; | ||
527 | param = (LLViewerVisualParam*) avatar->getNextVisualParam() ) | ||
528 | { | ||
529 | if( (param->getWearableType() == mType) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) ) | ||
530 | { | ||
531 | F32* weightp = mVisualParamMap.getIfThere( param->getID() ); | ||
532 | F32 weight; | ||
533 | if( weightp ) | ||
534 | { | ||
535 | weight = llclamp( *weightp, param->getMinWeight(), param->getMaxWeight() ); | ||
536 | } | ||
537 | else | ||
538 | { | ||
539 | weight = param->getDefaultWeight(); | ||
540 | } | ||
541 | |||
542 | U8 a = F32_to_U8( param->getWeight(), param->getMinWeight(), param->getMaxWeight() ); | ||
543 | U8 b = F32_to_U8( weight, param->getMinWeight(), param->getMaxWeight() ); | ||
544 | if( a != b ) | ||
545 | { | ||
546 | return TRUE; | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | |||
551 | for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) | ||
552 | { | ||
553 | if( LLVOAvatar::getTEWearableType( te ) == mType ) | ||
554 | { | ||
555 | LLViewerImage* avatar_image = avatar->getTEImage( te ); | ||
556 | if( !avatar_image ) | ||
557 | { | ||
558 | llassert( 0 ); | ||
559 | continue; | ||
560 | } | ||
561 | LLUUID* mapped_image_id = mTEMap.getIfThere( te ); | ||
562 | const LLUUID& image_id = mapped_image_id ? *mapped_image_id : LLVOAvatar::getDefaultTEImageID( te ); | ||
563 | if( avatar_image->getID() != image_id ) | ||
564 | { | ||
565 | return TRUE; | ||
566 | } | ||
567 | } | ||
568 | } | ||
569 | |||
570 | //if( gFloaterCustomize ) | ||
571 | //{ | ||
572 | // if( mDescription != gFloaterCustomize->getWearableDescription( mType ) ) | ||
573 | // { | ||
574 | // return TRUE; | ||
575 | // } | ||
576 | //} | ||
577 | |||
578 | return FALSE; | ||
579 | } | ||
580 | |||
581 | |||
582 | void LLWearable::setParamsToDefaults() | ||
583 | { | ||
584 | LLVOAvatar* avatar = gAgent.getAvatarObject(); | ||
585 | llassert( avatar ); | ||
586 | if( !avatar ) | ||
587 | { | ||
588 | return; | ||
589 | } | ||
590 | |||
591 | mVisualParamMap.deleteAllData(); | ||
592 | for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() ) | ||
593 | { | ||
594 | if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) ) | ||
595 | { | ||
596 | mVisualParamMap.addData( param->getID(), new F32( param->getDefaultWeight() ) ); | ||
597 | } | ||
598 | } | ||
599 | } | ||
600 | |||
601 | void LLWearable::setTexturesToDefaults() | ||
602 | { | ||
603 | mTEMap.deleteAllData(); | ||
604 | for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) | ||
605 | { | ||
606 | if( LLVOAvatar::getTEWearableType( te ) == mType ) | ||
607 | { | ||
608 | mTEMap.addData( te, new LLUUID( LLVOAvatar::getDefaultTEImageID( te ) ) ); | ||
609 | } | ||
610 | } | ||
611 | } | ||
612 | |||
613 | // Updates the user's avatar's appearance | ||
614 | void LLWearable::writeToAvatar( BOOL set_by_user ) | ||
615 | { | ||
616 | LLVOAvatar* avatar = gAgent.getAvatarObject(); | ||
617 | llassert( avatar ); | ||
618 | if( !avatar ) | ||
619 | { | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | ESex old_sex = avatar->getSex(); | ||
624 | |||
625 | // Pull params | ||
626 | for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() ) | ||
627 | { | ||
628 | if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) ) | ||
629 | { | ||
630 | S32 param_id = param->getID(); | ||
631 | F32* weight = mVisualParamMap.getIfThere( param_id ); | ||
632 | if( weight ) | ||
633 | { | ||
634 | // only animate with user-originated changes | ||
635 | if (set_by_user) | ||
636 | { | ||
637 | param->setAnimationTarget(*weight, set_by_user); | ||
638 | } | ||
639 | else | ||
640 | { | ||
641 | avatar->setVisualParamWeight( param_id, *weight, set_by_user ); | ||
642 | } | ||
643 | } | ||
644 | else | ||
645 | { | ||
646 | // only animate with user-originated changes | ||
647 | if (set_by_user) | ||
648 | { | ||
649 | param->setAnimationTarget(param->getDefaultWeight(), set_by_user); | ||
650 | } | ||
651 | else | ||
652 | { | ||
653 | avatar->setVisualParamWeight( param_id, param->getDefaultWeight(), set_by_user ); | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | } | ||
658 | |||
659 | // only interpolate with user-originated changes | ||
660 | if (set_by_user) | ||
661 | { | ||
662 | avatar->startAppearanceAnimation(TRUE, TRUE); | ||
663 | } | ||
664 | |||
665 | // Pull texture entries | ||
666 | for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) | ||
667 | { | ||
668 | if( LLVOAvatar::getTEWearableType( te ) == mType ) | ||
669 | { | ||
670 | LLUUID* mapped_image_id = mTEMap.getIfThere( te ); | ||
671 | const LLUUID& image_id = mapped_image_id ? *mapped_image_id : LLVOAvatar::getDefaultTEImageID( te ); | ||
672 | LLViewerImage* image = gImageList.getImage( image_id ); | ||
673 | avatar->setLocTexTE( te, image, set_by_user ); | ||
674 | } | ||
675 | } | ||
676 | |||
677 | avatar->updateVisualParams(); | ||
678 | |||
679 | if( gFloaterCustomize ) | ||
680 | { | ||
681 | LLViewerInventoryItem* item; | ||
682 | item = (LLViewerInventoryItem*)gInventory.getItem(gAgent.getWearableItem(mType)); | ||
683 | U32 perm_mask = PERM_NONE; | ||
684 | BOOL is_complete = FALSE; | ||
685 | if(item) | ||
686 | { | ||
687 | perm_mask = item->getPermissions().getMaskOwner(); | ||
688 | is_complete = item->isComplete(); | ||
689 | if(!is_complete) | ||
690 | { | ||
691 | item->fetchFromServer(); | ||
692 | } | ||
693 | } | ||
694 | gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); | ||
695 | LLFloaterCustomize::setCurrentWearableType( mType ); | ||
696 | } | ||
697 | |||
698 | ESex new_sex = avatar->getSex(); | ||
699 | if( old_sex != new_sex ) | ||
700 | { | ||
701 | avatar->updateSexDependentLayerSets( set_by_user ); | ||
702 | } | ||
703 | |||
704 | avatar->updateMeshTextures(); | ||
705 | |||
706 | // if( set_by_user ) | ||
707 | // { | ||
708 | // gAgent.sendAgentSetAppearance(); | ||
709 | // } | ||
710 | } | ||
711 | |||
712 | // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values. | ||
713 | // static | ||
714 | void LLWearable::removeFromAvatar( EWearableType type, BOOL set_by_user ) | ||
715 | { | ||
716 | LLVOAvatar* avatar = gAgent.getAvatarObject(); | ||
717 | llassert( avatar ); | ||
718 | if( !avatar ) | ||
719 | { | ||
720 | return; | ||
721 | } | ||
722 | |||
723 | // You can't just remove body parts. | ||
724 | if( (type == WT_SHAPE) || | ||
725 | (type == WT_SKIN) || | ||
726 | (type == WT_HAIR) || | ||
727 | (type == WT_EYES) ) | ||
728 | { | ||
729 | return; | ||
730 | } | ||
731 | |||
732 | // Pull params | ||
733 | for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() ) | ||
734 | { | ||
735 | if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) ) | ||
736 | { | ||
737 | S32 param_id = param->getID(); | ||
738 | avatar->setVisualParamWeight( param_id, param->getDefaultWeight(), set_by_user ); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | // Pull textures | ||
743 | LLViewerImage* image = gImageList.getImage( IMG_DEFAULT_AVATAR ); | ||
744 | for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) | ||
745 | { | ||
746 | if( LLVOAvatar::getTEWearableType( te ) == type ) | ||
747 | { | ||
748 | avatar->setLocTexTE( te, image, set_by_user ); | ||
749 | } | ||
750 | } | ||
751 | |||
752 | if( gFloaterCustomize ) | ||
753 | { | ||
754 | gFloaterCustomize->setWearable(type, NULL, PERM_ALL, TRUE); | ||
755 | } | ||
756 | |||
757 | avatar->updateVisualParams(); | ||
758 | avatar->updateMeshTextures(); | ||
759 | |||
760 | // if( set_by_user ) | ||
761 | // { | ||
762 | // gAgent.sendAgentSetAppearance(); | ||
763 | // } | ||
764 | } | ||
765 | |||
766 | |||
767 | |||
768 | // Updates asset from the user's avatar | ||
769 | void LLWearable::readFromAvatar() | ||
770 | { | ||
771 | LLVOAvatar* avatar = gAgent.getAvatarObject(); | ||
772 | llassert( avatar ); | ||
773 | if( !avatar ) | ||
774 | { | ||
775 | return; | ||
776 | } | ||
777 | |||
778 | mDefinitionVersion = LLWearable::sCurrentDefinitionVersion; | ||
779 | |||
780 | mVisualParamMap.deleteAllData(); | ||
781 | for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() ) | ||
782 | { | ||
783 | if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) ) | ||
784 | { | ||
785 | mVisualParamMap.addData( param->getID(), new F32( param->getWeight() ) ); | ||
786 | } | ||
787 | } | ||
788 | |||
789 | mTEMap.deleteAllData(); | ||
790 | for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) | ||
791 | { | ||
792 | if( LLVOAvatar::getTEWearableType( te ) == mType ) | ||
793 | { | ||
794 | LLViewerImage* image = avatar->getTEImage( te ); | ||
795 | if( image ) | ||
796 | { | ||
797 | mTEMap.addData( te, new LLUUID( image->getID() ) ); | ||
798 | } | ||
799 | } | ||
800 | } | ||
801 | |||
802 | //if( gFloaterCustomize ) | ||
803 | //{ | ||
804 | // mDescription = gFloaterCustomize->getWearableDescription( mType ); | ||
805 | //} | ||
806 | } | ||
807 | |||
808 | // Does not copy mAssetID. | ||
809 | // Definition version is current: removes obsolete enties and creates default values for new ones. | ||
810 | void LLWearable::copyDataFrom( LLWearable* src ) | ||
811 | { | ||
812 | LLVOAvatar* avatar = gAgent.getAvatarObject(); | ||
813 | llassert( avatar ); | ||
814 | if( !avatar ) | ||
815 | { | ||
816 | return; | ||
817 | } | ||
818 | |||
819 | mDefinitionVersion = LLWearable::sCurrentDefinitionVersion; | ||
820 | |||
821 | mName = src->mName; | ||
822 | mDescription = src->mDescription; | ||
823 | mPermissions = src->mPermissions; | ||
824 | mSaleInfo = src->mSaleInfo; | ||
825 | mType = src->mType; | ||
826 | |||
827 | // Deep copy of mVisualParamMap (copies only those params that are current, filling in defaults where needed) | ||
828 | for( LLViewerVisualParam* param = (LLViewerVisualParam*) avatar->getFirstVisualParam(); | ||
829 | param; | ||
830 | param = (LLViewerVisualParam*) avatar->getNextVisualParam() ) | ||
831 | { | ||
832 | if( (param->getWearableType() == mType) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) ) | ||
833 | { | ||
834 | S32 id = param->getID(); | ||
835 | F32* weightp = src->mVisualParamMap.getIfThere( id ); | ||
836 | F32 weight = weightp ? *weightp : param->getDefaultWeight(); | ||
837 | mVisualParamMap.addData( id, new F32( weight ) ); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) | ||
842 | for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ ) | ||
843 | { | ||
844 | if( LLVOAvatar::getTEWearableType( te ) == mType ) | ||
845 | { | ||
846 | LLUUID* mapped_image_id = src->mTEMap.getIfThere( te ); | ||
847 | const LLUUID& image_id = mapped_image_id ? *mapped_image_id : LLVOAvatar::getDefaultTEImageID( te ); | ||
848 | mTEMap.addData( te, new LLUUID( image_id ) ); | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | |||
853 | struct LLWearableSaveData | ||
854 | { | ||
855 | EWearableType mType; | ||
856 | }; | ||
857 | |||
858 | void LLWearable::saveNewAsset() | ||
859 | { | ||
860 | // llinfos << "LLWearable::saveNewAsset() type: " << getTypeName() << llendl; | ||
861 | //dump(); | ||
862 | |||
863 | char new_asset_id_string[UUID_STR_LENGTH]; | ||
864 | mAssetID.toString(new_asset_id_string); | ||
865 | char filename[LL_MAX_PATH]; | ||
866 | sprintf(filename, "%s.wbl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,new_asset_id_string).c_str()); | ||
867 | FILE* fp = LLFile::fopen(filename, "wb"); | ||
868 | BOOL successful_save = FALSE; | ||
869 | if(fp && exportFile(fp)) | ||
870 | { | ||
871 | successful_save = TRUE; | ||
872 | } | ||
873 | if(fp) | ||
874 | { | ||
875 | fclose(fp); | ||
876 | fp = NULL; | ||
877 | } | ||
878 | if(!successful_save) | ||
879 | { | ||
880 | char buffer[2*MAX_STRING]; | ||
881 | sprintf(buffer, | ||
882 | "Unable to save '%s' to wearable file.", | ||
883 | mName.c_str()); | ||
884 | llwarns << buffer << llendl; | ||
885 | |||
886 | LLStringBase<char>::format_map_t args; | ||
887 | args["[NAME]"] = mName; | ||
888 | gViewerWindow->alertXml("CannotSaveWearableOutOfSpace", args); | ||
889 | return; | ||
890 | } | ||
891 | |||
892 | // save it out to database | ||
893 | if( gAssetStorage ) | ||
894 | { | ||
895 | LLWearableSaveData* data = new LLWearableSaveData; | ||
896 | data->mType = mType; | ||
897 | gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(), | ||
898 | &LLWearable::onSaveNewAssetComplete, | ||
899 | (void*)data); | ||
900 | } | ||
901 | } | ||
902 | |||
903 | // static | ||
904 | void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status) // StoreAssetData callback (fixed) | ||
905 | { | ||
906 | LLWearableSaveData* data = (LLWearableSaveData*)userdata; | ||
907 | const char* type_name = LLWearable::typeToTypeName(data->mType); | ||
908 | if(0 == status) | ||
909 | { | ||
910 | // Success | ||
911 | llinfos << "Saved wearable " << type_name << llendl; | ||
912 | } | ||
913 | else | ||
914 | { | ||
915 | char buffer[2*MAX_STRING]; | ||
916 | sprintf(buffer, | ||
917 | "Unable to save %s to central asset store.", | ||
918 | type_name); | ||
919 | llwarns << buffer << " Status: " << status << llendl; | ||
920 | LLStringBase<char>::format_map_t args; | ||
921 | args["[NAME]"] = type_name; | ||
922 | gViewerWindow->alertXml("CannotSaveToAssetStore", args); | ||
923 | } | ||
924 | |||
925 | // Delete temp file | ||
926 | char new_asset_id_string[UUID_STR_LENGTH]; | ||
927 | new_asset_id.toString(new_asset_id_string); | ||
928 | char src_filename[LL_MAX_PATH]; | ||
929 | sprintf(src_filename, "%s.wbl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,new_asset_id_string).c_str()); | ||
930 | LLFile::remove(src_filename); | ||
931 | |||
932 | // delete the context data | ||
933 | delete data; | ||
934 | } | ||
935 | |||
936 | BOOL LLWearable::isMatchedToInventoryItem( LLViewerInventoryItem* item ) | ||
937 | { | ||
938 | return | ||
939 | ( mName == item->getName() ) && | ||
940 | ( mDescription == item->getDescription() ) && | ||
941 | ( mPermissions == item->getPermissions() ) && | ||
942 | ( mSaleInfo == item->getSaleInfo() ); | ||
943 | } | ||
944 | |||
945 | void LLWearable::dump() | ||
946 | { | ||
947 | llinfos << "wearable " << LLWearable::typeToTypeName( mType ) << llendl; | ||
948 | llinfos << " Name: " << mName << llendl; | ||
949 | llinfos << " Desc: " << mDescription << llendl; | ||
950 | //mPermissions | ||
951 | //mSaleInfo | ||
952 | |||
953 | llinfos << " Params:" << llendl; | ||
954 | for( F32* param_weightp = mVisualParamMap.getFirstData(); | ||
955 | param_weightp; | ||
956 | param_weightp = mVisualParamMap.getNextData() ) | ||
957 | { | ||
958 | S32 param_id = mVisualParamMap.getCurrentKeyWithoutIncrement(); | ||
959 | llinfos << " " << param_id << " " << *param_weightp << llendl; | ||
960 | } | ||
961 | |||
962 | llinfos << " Textures:" << llendl; | ||
963 | for( LLUUID* image_id = mTEMap.getFirstData(); | ||
964 | image_id; | ||
965 | image_id = mTEMap.getNextData() ) | ||
966 | { | ||
967 | S32 te = mTEMap.getCurrentKeyWithoutIncrement(); | ||
968 | llinfos << " " << te << " " << *image_id << llendl; | ||
969 | } | ||
970 | } | ||
971 | |||