00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llfloaterimport.h"
00035
00036 #include "llapr.h"
00037
00038 #include "llimagebmp.h"
00039 #include "llimagetga.h"
00040 #include "llimagejpeg.h"
00041
00042 #include "llagent.h"
00043 #include "llbutton.h"
00044 #include "llcombobox.h"
00045 #include "lldrawable.h"
00046 #include "lldrawpoolavatar.h"
00047 #include "llface.h"
00048 #include "llinventorymodel.h"
00049 #include "lllineeditor.h"
00050 #include "llresourcedata.h"
00051 #include "lltextbox.h"
00052 #include "lltoolmgr.h"
00053 #include "llui.h"
00054 #include "lluploaddialog.h"
00055 #include "llviewercamera.h"
00056 #include "llviewermenufile.h"
00057 #include "llviewerwindow.h"
00058 #include "llvoavatar.h"
00059 #include "pipeline.h"
00060 #include "viewer.h"
00061 #include "llvieweruictrlfactory.h"
00062 #include "llmd5.h"
00063
00064 extern LLInventoryModel gInventory;
00065
00066
00067
00068 LLUUID LLFloaterImport::sImportRequestID;
00069 LLString LLFloaterImport::sOKText = LLString();
00070
00071 const S32 PREVIEW_BORDER_WIDTH = 2;
00072 const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
00073 const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
00074 const S32 PREF_BUTTON_HEIGHT = 16;
00075 const S32 PREVIEW_TEXTURE_HEIGHT = 300;
00076
00077
00078
00079
00080 LLFloaterImport::LLFloaterImport(const std::string filename)
00081 : LLFloater("Import")
00082 {
00083 mFilenameAndPath = filename;
00084
00085 char file_path[256];
00086 strncpy(file_path, mFilenameAndPath.c_str(), sizeof(file_path) -1);
00087 file_path[sizeof(file_path) -1] = '\0';
00088 char *file_name = strrchr( file_path, gDirUtilp->getDirDelimiter()[0]);
00089 file_name[0] = 0;
00090
00091 mFilename.assign(file_name + 1);
00092 mFilePath.assign(file_path);
00093
00094
00095
00096 LLXMLNode::parseFile(filename, mObjectFile, NULL);
00097 }
00098
00099
00100
00101
00102 BOOL LLFloaterImport::postBuild()
00103 {
00104 LLString asset_name = mFilename;
00105 LLString::replaceNonstandardASCII( asset_name, '?' );
00106 LLString::replaceChar(asset_name, '|', '?');
00107 LLString::stripNonprintable(asset_name);
00108 LLString::trim(asset_name);
00109
00110 char* asset_name_str = (char*)asset_name.c_str();
00111 char* end_p = strrchr(asset_name_str, '.');
00112 if( !end_p )
00113 {
00114 end_p = asset_name_str + strlen( asset_name_str );
00115 }
00116
00117 S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );
00118
00119 asset_name = asset_name.substr( 0, len );
00120
00121 setTitle(mFilename);
00122
00123 {
00124
00125 LLRect window_rect = gViewerWindow->getRootView()->getRect();
00126
00127 S32 dialog_left = window_rect.mLeft + (window_rect.getWidth() - mRect.getWidth()) / 2;
00128 S32 dialog_bottom = window_rect.mBottom + (window_rect.getHeight() - mRect.getHeight()) / 2;
00129
00130 translate( dialog_left - mRect.mLeft, dialog_bottom - mRect.mBottom );
00131 }
00132
00133 mNameEditor = LLViewerUICtrlFactory::getLineEditorByName(this, "name_form");
00134 mNameEditor->setMaxTextLength(DB_INV_ITEM_NAME_STR_LEN);
00135
00136 mNameEditor->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe);
00137
00138 mNameEditor->setText(asset_name);
00139
00140 mDescEditor = LLViewerUICtrlFactory::getLineEditorByName(this, "description_form");
00141 mDescEditor->setMaxTextLength(DB_INV_ITEM_DESC_STR_LEN);
00142
00143 mDescEditor->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe);
00144
00145
00146 mCancelBtn = LLViewerUICtrlFactory::getButtonByName(this, "cancel_btn");
00147 mCancelBtn->setClickedCallback(onBtnCancel);
00148 mCancelBtn->setCallbackUserData(this);
00149
00150
00151 mOKBtn = LLViewerUICtrlFactory::getButtonByName(this, "ok_btn");
00152 mOKBtn->setClickedCallback(onBtnOK);
00153 mOKBtn->setCallbackUserData(this);
00154 setDefaultBtn(mOKBtn);
00155
00156 mImageLabel = LLViewerUICtrlFactory::getTextBoxByName(this, "preview_label");
00157 mImportList = LLViewerUICtrlFactory::getScrollListByName(this, "upload_list");
00158
00159 bool object_file_read = false;
00160 int object_count = 0, image_count = 0;
00161 if (mObjectFile)
00162 {
00163 LLXMLNodeList object_list;
00164 mObjectFile->findName("object", object_list);
00165 LLXMLNodeList::iterator itor;
00166 LLXMLNodeList::iterator itor2;
00167 for (itor = object_list.begin(); itor != object_list.end(); ++itor)
00168 {
00169 LLXMLNode *object = itor->second;
00170 LLXMLNodeList tasks_list;
00171 object->getChildren("task", tasks_list, FALSE);
00172 for (itor2 = tasks_list.begin(); itor2 != tasks_list.end(); ++itor2)
00173 {
00174 LLXMLNode *task = itor2->second;
00175 LLXMLNodePtr temp_node;
00176 if (!task->getChild("root", temp_node, FALSE))
00177 {
00178
00179 LLString task_name = "(unnamed object)";
00180 LLXMLNodePtr task_name_node;
00181 if (task->getChild("name", task_name_node, FALSE))
00182 {
00183 task_name_node->getStringValue(1, &task_name);
00184 }
00185 {
00186 LLString output_line;
00187 char buffer[20];
00188 snprintf(buffer, sizeof(buffer), "%d", (S32)tasks_list.size());
00189 output_line.append(buffer);
00190 output_line.append(" prims");
00191
00192 LLSD row;
00193 row["columns"][0]["value"] = "OBJECT";
00194 row["columns"][0]["width"] = 60;
00195 row["columns"][1]["value"] = output_line;
00196 row["columns"][1]["width"] = 80;
00197 row["columns"][2]["value"] = task_name;
00198 row["enabled"] = false;
00199 mImportList->addElement(row);
00200 }
00201 mImportList->setCanSelect(TRUE);
00202 mImportList->setAllowMultipleSelection(TRUE);
00203 object_file_read = true;
00204 object_count++;
00205 break;
00206 }
00207 }
00208 }
00209
00210 if (object_count > 0)
00211 {
00212 std::string::size_type pos = mFilenameAndPath.rfind(".");
00213 if (pos != mFilenameAndPath.npos)
00214 {
00215 mInventoryPath = mFilenameAndPath.substr(0, pos);
00216 }
00217 else
00218 {
00219 mInventoryPath = mFilenameAndPath;
00220 }
00221 mInventoryPath.append("_inventory");
00222
00223 LLXMLNodeList image_list;
00224 mObjectFile->findName("sl:image", image_list);
00225 std::vector<LLString> unique_images;
00226 std::vector<LLUUID> unique_ids;
00227 std::vector<bool> image_changed;
00228 for (itor = image_list.begin(); itor != image_list.end(); ++itor)
00229 {
00230 LLXMLNode *image_node = itor->second;
00231 LLString image_id = image_node->getID();
00232
00233 LLUUID image_uuid;
00234 image_node->getUUIDValue(1, &image_uuid);
00235
00236 bool found_image = false;
00237 for (U32 image_num=0; image_num<unique_images.size(); ++image_num)
00238 {
00239 if (unique_images[image_num] == image_id)
00240 {
00241 found_image = true;
00242 continue;
00243 }
00244 }
00245 if (!found_image)
00246 {
00247 unique_images.push_back(image_id);
00248 unique_ids.push_back(image_uuid);
00249
00250 LLString node_hash = "00000000000000000000000000000000";
00251 LLXMLNodePtr image_hash_node;
00252 if (image_node->getChild("checksum", image_hash_node))
00253 {
00254 image_hash_node->getStringValue(1, &node_hash);
00255 }
00256
00257 llinfos << "Node hash: " << node_hash << llendl;
00258
00259
00260 LLString image_path = mInventoryPath;
00261 image_path.append(gDirUtilp->getDirDelimiter());
00262 image_path.append(image_id);
00263 image_path.append(".tga");
00264
00265 llinfos << "Getting hash for " << image_path << llendl;
00266
00267 char md5_hash_string[33];
00268 strcpy(md5_hash_string, "00000000000000000000000000000000");
00269 FILE* fCheck = LLFile::fopen(image_path.c_str(), "rb");
00270 if (fCheck)
00271 {
00272 LLMD5 my_md5_hash(fCheck);
00273 my_md5_hash.hex_digest(md5_hash_string);
00274
00275 llinfos << "hash: " << md5_hash_string << llendl;
00276 }
00277
00278 LoadPreviewImage(image_path, image_uuid);
00279
00280 if (memcmp(md5_hash_string, node_hash.c_str(), 32) == 0)
00281 {
00282
00283 image_changed.push_back(false);
00284 }
00285 else
00286 {
00287
00288 image_changed.push_back(true);
00289 }
00290 }
00291 }
00292 for (U32 image_num=0; image_num<unique_images.size(); ++image_num)
00293 {
00294 LLSD row;
00295 row["columns"][0]["value"] = "IMAGE";
00296 row["columns"][0]["width"] = 60;
00297 row["columns"][1]["value"] = image_changed[image_num]?"NEW":"NOT NEW";
00298 row["columns"][1]["width"] = 80;
00299 row["columns"][2]["value"] = unique_images[image_num];
00300 mImportList->addElement(row);
00301 mImportList->setCanSelect(TRUE);
00302 image_count++;
00303 }
00304 }
00305 }
00306
00307 if (!object_file_read)
00308 {
00309 mImportList->addSimpleItem("Error: Invalid object file.", ADD_BOTTOM, FALSE);
00310 mImportList->setCanSelect(FALSE);
00311 mOKBtn->setEnabled(FALSE);
00312 }
00313 else
00314 {
00315 recalcCost();
00316 }
00317
00318 return TRUE;
00319 }
00320
00321 void LLFloaterImport::LoadPreviewImage(LLString image_path, LLUUID image_uuid)
00322 {
00323 LLPointer<LLImageRaw> raw_image = new LLImageRaw;
00324 LLPointer<LLImageTGA> tga_image = new LLImageTGA;
00325
00326 if (!tga_image->load(image_path))
00327 {
00328 return;
00329 }
00330
00331 if (!tga_image->decode(raw_image))
00332 {
00333 return;
00334 }
00335
00336 if( (tga_image->getComponents() != 3) &&
00337 (tga_image->getComponents() != 4) )
00338 {
00339 tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
00340 return;
00341 }
00342
00343 raw_image->biasedScaleToPowerOfTwo(256);
00344
00345 mPreviewImages[image_uuid] = raw_image;
00346 }
00347
00348
00349
00350
00351 LLFloaterImport::~LLFloaterImport()
00352 {
00353 if (mGLName)
00354 {
00355 glDeleteTextures(1, &mGLName );
00356 }
00357 }
00358
00359
00360
00361
00362 void LLFloaterImport::recalcCost()
00363 {
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 }
00390
00391
00392
00393
00394 void LLFloaterImport::draw()
00395 {
00396 LLFloater::draw();
00397
00398 LLRect PreviewImageRect;
00399 BOOL has_rect = childGetRect("dummy_preview", PreviewImageRect);
00400
00401 if (mCurrentPreviewImage.notNull() && has_rect)
00402 {
00403 gl_rect_2d_checkerboard(PreviewImageRect);
00404
00405 GLenum format_options[4] = { GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA };
00406 GLenum format = format_options[mCurrentPreviewImage->getComponents()-1];
00407
00408 GLenum internal_format_options[4] = { GL_LUMINANCE8, GL_LUMINANCE8_ALPHA8, GL_RGB8, GL_RGBA8 };
00409 GLenum internal_format = internal_format_options[mCurrentPreviewImage->getComponents()-1];
00410
00411 if (mGLName)
00412 {
00413 LLImageGL::bindExternalTexture( mGLName, 0, GL_TEXTURE_2D );
00414 }
00415 else
00416 {
00417 glGenTextures(1, &mGLName );
00418 stop_glerror();
00419
00420 LLImageGL::bindExternalTexture( mGLName, 0, GL_TEXTURE_2D );
00421 stop_glerror();
00422
00423 glTexImage2D(
00424 GL_TEXTURE_2D, 0, internal_format,
00425 mCurrentPreviewImage->getWidth(), mCurrentPreviewImage->getHeight(),
00426 0, format, GL_UNSIGNED_BYTE, mCurrentPreviewImage->getData());
00427 stop_glerror();
00428
00429 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00430 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00431
00432 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00433 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00434 }
00435
00436 glColor3f(1.f, 1.f, 1.f);
00437 glBegin( GL_QUADS );
00438 {
00439 glTexCoord2f(0, 1);
00440 glVertex2i(PreviewImageRect.mLeft, PreviewImageRect.mTop);
00441 glTexCoord2f(0, 0);
00442 glVertex2i(PreviewImageRect.mLeft, PreviewImageRect.mBottom);
00443 glTexCoord2f(1, 0);
00444 glVertex2i(PreviewImageRect.mRight, PreviewImageRect.mBottom);
00445 glTexCoord2f(1, 1);
00446 glVertex2i(PreviewImageRect.mRight, PreviewImageRect.mTop);
00447 }
00448 glEnd();
00449
00450 LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
00451
00452 stop_glerror();
00453 }
00454 }
00455
00456
00457 void LLFloaterImport::finishImport(ImportAssetInfo *info)
00458 {
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 }
00514
00515
00516 void LLFloaterImport::asset_uploaded_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status)
00517 {
00518 llinfos << "LLFloaterImport: Finished uploading image." << llendl;
00519 LLResourceData *resource_data = (LLResourceData*)user_data;
00520 ImportAssetInfo *info = (ImportAssetInfo*)resource_data->mUserData;
00521
00522 info->NewImageIDList.push_back(resource_data->mAssetInfo.mUuid.asString());
00523
00524 LLUploadDialog::modalUploadFinished();
00525 if (info->ImageFileQueue.size() == 0)
00526 {
00527 finishImport(info);
00528 }
00529 else
00530 {
00531
00532 LLString current_image = info->ImageFileQueue[0].c_str();
00533 info->ImageFileQueue.erase(info->ImageFileQueue.begin());
00534
00535 upload_new_resource(current_image, info->Name,
00536 info->Desc, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE,
00537 PERM_NONE, LLString::null, asset_uploaded_callback, info);
00538 }
00539 }
00540
00541
00542
00543
00544 void LLFloaterImport::onBtnOK(void*userdata)
00545 {
00546 LLFloaterImport *fp =(LLFloaterImport*)userdata;
00547
00548 ImportAssetInfo *asset_info = new ImportAssetInfo();
00549 asset_info->Name = fp->mNameEditor->getText();
00550 asset_info->Desc = fp->mDescEditor->getText();
00551 asset_info->FilenameAndPath = fp->mFilenameAndPath;
00552 asset_info->SourcePath = fp->mInventoryPath;
00553
00554 std::vector<LLScrollListItem*> items = fp->mImportList->getAllSelected();
00555 std::vector<LLScrollListItem*>::iterator itor;
00556 if (items.size() > 0)
00557 {
00558 for (itor = items.begin(); itor != items.end(); ++itor)
00559 {
00560 LLUUID id = (*itor)->getUUID();
00561
00562
00563 LLString *image_id = (LLString *)(*itor)->getUserdata();
00564 if (image_id)
00565 {
00566 asset_info->OldImageIDList.push_back(id.asString());
00567 LLString image_file = fp->mInventoryPath;
00568 image_file.append(gDirUtilp->getDirDelimiter());
00569 image_file.append(*image_id);
00570 image_file.append(".tga");
00571 llinfos << "Uploading image " << image_file << "..." << llendl;
00572 asset_info->ImageFileQueue.push_back(image_file);
00573 }
00574 }
00575 if (asset_info->ImageFileQueue.size() == 0)
00576 {
00577 finishImport(asset_info);
00578 }
00579 else
00580 {
00581
00582 LLString current_image = asset_info->ImageFileQueue[0].c_str();
00583 asset_info->ImageFileQueue.erase(asset_info->ImageFileQueue.begin());
00584
00585 upload_new_resource(current_image, asset_info->Name,
00586 asset_info->Desc, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE,
00587 PERM_NONE, LLString::null, asset_uploaded_callback, asset_info);
00588 }
00589 }
00590 else
00591 {
00592 finishImport(asset_info);
00593 }
00594
00595 fp->close(false);
00596 }
00597
00598
00599
00600
00601 void LLFloaterImport::onBtnCancel(void*userdata)
00602 {
00603 LLFloaterImport *fp =(LLFloaterImport*)userdata;
00604 fp->close(false);
00605 }
00606
00607
00608
00609
00610
00611 BOOL LLFloaterImport::handleMouseDown(S32 x, S32 y, MASK mask)
00612 {
00613 BOOL ret = LLFloater::handleMouseDown(x, y, mask);
00614 recalcCost();
00615
00616 LLUUID current_preview_uuid;
00617 LLString current_preview_name = "none";
00618
00619 LLScrollListItem *item;
00620
00621
00622 item = mImportList->getLastSelectedItem();
00623 if (item)
00624 {
00625 current_preview_uuid = item->getUUID();
00626 current_preview_name = item->getColumn(2)->getText();
00627 }
00628 else
00629 {
00630
00631 std::vector<LLScrollListItem*> items = mImportList->getAllSelected();
00632 std::vector<LLScrollListItem*>::iterator itor;
00633 for (itor = items.begin(); itor != items.end(); ++itor)
00634 {
00635 if (current_preview_uuid.isNull())
00636 {
00637 current_preview_uuid = (*itor)->getUUID();
00638 current_preview_name = (*itor)->getColumn(2)->getText();
00639 }
00640 else
00641 {
00642
00643 current_preview_uuid.setNull();
00644 current_preview_name = "none";
00645 break;
00646 }
00647 }
00648 }
00649
00650 mCurrentPreviewImage = NULL;
00651 if (current_preview_uuid.notNull())
00652 {
00653 image_map_t::iterator itor;
00654 itor = mPreviewImages.find(current_preview_uuid);
00655 if (itor != mPreviewImages.end())
00656 {
00657 mCurrentPreviewImage = itor->second;
00658 if (mGLName)
00659 {
00660 glDeleteTextures(1, &mGLName );
00661 }
00662 mGLName = 0;
00663 }
00664 }
00665 LLString label_text = "Image Preview: ";
00666 label_text.append(current_preview_name);
00667 mImageLabel->setText(label_text);
00668
00669 return ret;
00670 }