aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs897
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
2 files changed, 1422 insertions, 146 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 5c6bc1c..98ab433 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Timers;
29using System.Collections; 30using System.Collections;
30using System.Collections.Generic; 31using System.Collections.Generic;
31using System.IO; 32using System.IO;
@@ -54,14 +55,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
54namespace OpenSim.Region.ClientStack.Linden 55namespace OpenSim.Region.ClientStack.Linden
55{ 56{
56 public delegate void UpLoadedAsset( 57 public delegate void UpLoadedAsset(
57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 58 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
58 byte[] data, string inventoryType, string assetType); 59 byte[] data, string inventoryType, string assetType,
60 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
61 bool IsAtestUpload, ref string error);
59 62
60 public delegate UUID UpdateItem(UUID itemID, byte[] data); 63 public delegate UUID UpdateItem(UUID itemID, byte[] data);
61 64
62 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 65 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
63 66
64 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 67 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
65 68
66 public delegate void NewAsset(AssetBase asset); 69 public delegate void NewAsset(AssetBase asset);
67 70
@@ -87,6 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden
87 90
88 private Scene m_Scene; 91 private Scene m_Scene;
89 private Caps m_HostCapsObj; 92 private Caps m_HostCapsObj;
93 private ModelCost m_ModelCost;
90 94
91 private static readonly string m_requestPath = "0000/"; 95 private static readonly string m_requestPath = "0000/";
92 // private static readonly string m_mapLayerPath = "0001/"; 96 // private static readonly string m_mapLayerPath = "0001/";
@@ -98,7 +102,8 @@ namespace OpenSim.Region.ClientStack.Linden
98 private static readonly string m_copyFromNotecardPath = "0007/"; 102 private static readonly string m_copyFromNotecardPath = "0007/";
99 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 103 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
100 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 104 private static readonly string m_getObjectPhysicsDataPath = "0101/";
101 /* 0102 - 0103 RESERVED */ 105 private static readonly string m_getObjectCostPath = "0102/";
106 private static readonly string m_ResourceCostSelectedPath = "0103/";
102 private static readonly string m_UpdateAgentInformationPath = "0500/"; 107 private static readonly string m_UpdateAgentInformationPath = "0500/";
103 108
104 // These are callbacks which will be setup by the scene so that we can update scene data when we 109 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -114,12 +119,50 @@ namespace OpenSim.Region.ClientStack.Linden
114 private IAssetService m_assetService; 119 private IAssetService m_assetService;
115 private bool m_dumpAssetsToFile = false; 120 private bool m_dumpAssetsToFile = false;
116 private string m_regionName; 121 private string m_regionName;
122
117 private int m_levelUpload = 0; 123 private int m_levelUpload = 0;
118 124
125 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
126 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
127
128 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
129 // may not be visible till relog
130
131 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
132 private UUID m_testAssetsCreatorID = UUID.Zero;
133
134 private float m_PrimScaleMin = 0.001f;
135
136 private enum FileAgentInventoryState : int
137 {
138 idle = 0,
139 processRequest = 1,
140 waitUpload = 2,
141 processUpload = 3
142 }
143 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
144
119 public BunchOfCaps(Scene scene, Caps caps) 145 public BunchOfCaps(Scene scene, Caps caps)
120 { 146 {
121 m_Scene = scene; 147 m_Scene = scene;
122 m_HostCapsObj = caps; 148 m_HostCapsObj = caps;
149
150 // create a model upload cost provider
151 m_ModelCost = new ModelCost();
152 // tell it about scene object limits
153 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
154 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
155
156// m_ModelCost.ObjectLinkedPartsMax = ??
157// m_ModelCost.PrimScaleMin = ??
158
159 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
160 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
161 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
162 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
163 float modelPrimCreationCost = m_ModelCost.primCreationCost;
164 float modelMeshByteCost = m_ModelCost.bytecost;
165
123 IConfigSource config = m_Scene.Config; 166 IConfigSource config = m_Scene.Config;
124 if (config != null) 167 if (config != null)
125 { 168 {
@@ -134,6 +177,37 @@ namespace OpenSim.Region.ClientStack.Linden
134 { 177 {
135 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 178 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
136 } 179 }
180 // economy for model upload
181 IConfig EconomyConfig = config.Configs["Economy"];
182 if (EconomyConfig != null)
183 {
184 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
185 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
186 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
187 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
188 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
189 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
190
191 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
192
193 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
194 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
195 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
196 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
197 if (testcreator != "")
198 {
199 UUID id;
200 UUID.TryParse(testcreator, out id);
201 if (id != null)
202 m_testAssetsCreatorID = id;
203 }
204
205 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
206 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
207 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
208 m_ModelCost.primCreationCost = modelPrimCreationCost;
209 m_ModelCost.bytecost = modelMeshByteCost;
210 }
137 } 211 }
138 212
139 m_assetService = m_Scene.AssetService; 213 m_assetService = m_Scene.AssetService;
@@ -145,6 +219,8 @@ namespace OpenSim.Region.ClientStack.Linden
145 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 219 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
146 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 220 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
147 GetClient = m_Scene.SceneGraph.GetControllingClient; 221 GetClient = m_Scene.SceneGraph.GetControllingClient;
222
223 m_FileAgentInventoryState = FileAgentInventoryState.idle;
148 } 224 }
149 225
150 /// <summary> 226 /// <summary>
@@ -190,7 +266,6 @@ namespace OpenSim.Region.ClientStack.Linden
190 { 266 {
191 try 267 try
192 { 268 {
193 // I don't think this one works...
194 m_HostCapsObj.RegisterHandler( 269 m_HostCapsObj.RegisterHandler(
195 "NewFileAgentInventory", 270 "NewFileAgentInventory",
196 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 271 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -212,6 +287,10 @@ namespace OpenSim.Region.ClientStack.Linden
212 = new RestStreamHandler( 287 = new RestStreamHandler(
213 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); 288 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
214 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 289 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
290 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
291 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
292 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
293 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
215 294
216 IRequestHandler UpdateAgentInformationHandler 295 IRequestHandler UpdateAgentInformationHandler
217 = new RestStreamHandler( 296 = new RestStreamHandler(
@@ -270,6 +349,9 @@ namespace OpenSim.Region.ClientStack.Linden
270 m_log.DebugFormat( 349 m_log.DebugFormat(
271 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 350 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
272 351
352 if (!m_HostCapsObj.WaitForActivation())
353 return string.Empty;
354
273 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 355 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
274 { 356 {
275 m_log.WarnFormat( 357 m_log.WarnFormat(
@@ -410,62 +492,176 @@ namespace OpenSim.Region.ClientStack.Linden
410 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 492 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
411 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 493 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
412 494
495 // start by getting the client
496 IClientAPI client = null;
497 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
498
499 // check current state so we only have one service at a time
500 lock (m_ModelCost)
501 {
502 switch (m_FileAgentInventoryState)
503 {
504 case FileAgentInventoryState.processRequest:
505 case FileAgentInventoryState.processUpload:
506 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
507 resperror.message = "Uploader busy processing previus request";
508 resperror.identifier = UUID.Zero;
509
510 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
511 errorResponse.uploader = "";
512 errorResponse.state = "error";
513 errorResponse.error = resperror;
514 return errorResponse;
515 break;
516 case FileAgentInventoryState.waitUpload:
517 // todo stop current uploader server
518 break;
519 case FileAgentInventoryState.idle:
520 default:
521 break;
522 }
523
524 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
525 }
526
527 int cost = 0;
528 int nreqtextures = 0;
529 int nreqmeshs= 0;
530 int nreqinstances = 0;
531 bool IsAtestUpload = false;
532
533 string assetName = llsdRequest.name;
534
535 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
536
413 if (llsdRequest.asset_type == "texture" || 537 if (llsdRequest.asset_type == "texture" ||
414 llsdRequest.asset_type == "animation" || 538 llsdRequest.asset_type == "animation" ||
539 llsdRequest.asset_type == "mesh" ||
415 llsdRequest.asset_type == "sound") 540 llsdRequest.asset_type == "sound")
416 { 541 {
417 ScenePresence avatar = null; 542 ScenePresence avatar = null;
418 IClientAPI client = null;
419 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 543 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
420 544
421 // check user level 545 // check user level
422 if (avatar != null) 546 if (avatar != null)
423 { 547 {
424 client = avatar.ControllingClient;
425
426 if (avatar.UserLevel < m_levelUpload) 548 if (avatar.UserLevel < m_levelUpload)
427 { 549 {
428 if (client != null) 550 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
429 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 551 resperror.message = "Insufficient permissions to upload";
552 resperror.identifier = UUID.Zero;
430 553
431 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 554 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
432 errorResponse.uploader = ""; 555 errorResponse.uploader = "";
433 errorResponse.state = "error"; 556 errorResponse.state = "error";
557 errorResponse.error = resperror;
558 lock (m_ModelCost)
559 m_FileAgentInventoryState = FileAgentInventoryState.idle;
434 return errorResponse; 560 return errorResponse;
435 } 561 }
436 } 562 }
437 563
438 // check funds 564 // check test upload and funds
439 if (client != null) 565 if (client != null)
440 { 566 {
441 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 567 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
442 568
569 int baseCost = 0;
443 if (mm != null) 570 if (mm != null)
571 baseCost = mm.UploadCharge;
572
573 string warning = String.Empty;
574
575 if (llsdRequest.asset_type == "mesh")
444 { 576 {
445 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 577 string error;
578 int modelcost;
579
580 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
581 meshcostdata, out error, ref warning))
446 { 582 {
447 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 583 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
584 resperror.message = error;
585 resperror.identifier = UUID.Zero;
448 586
449 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 587 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
450 errorResponse.uploader = ""; 588 errorResponse.uploader = "";
451 errorResponse.state = "error"; 589 errorResponse.state = "error";
590 errorResponse.error = resperror;
591
592 lock (m_ModelCost)
593 m_FileAgentInventoryState = FileAgentInventoryState.idle;
452 return errorResponse; 594 return errorResponse;
453 } 595 }
596 cost = modelcost;
597 }
598 else
599 {
600 cost = baseCost;
601 }
602
603 if (cost > 0 && mm != null)
604 {
605 // check for test upload
606
607 if (m_ForceFreeTestUpload) // all are test
608 {
609 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
610 assetName = "TEST-" + assetName;
611
612 IsAtestUpload = true;
613 }
614
615 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
616 {
617
618 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
619 }
620
621
622 if(IsAtestUpload) // let user know, still showing cost estimation
623 warning += "Upload will have no cost, for testing purposes only. Other uses are prohibited. Items will not work after 48 hours or on other regions";
624
625 // check funds
626 else
627 {
628 if (!mm.UploadCovered(client.AgentId, (int)cost))
629 {
630 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
631 resperror.message = "Insuficient funds";
632 resperror.identifier = UUID.Zero;
633
634 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
635 errorResponse.uploader = "";
636 errorResponse.state = "error";
637 errorResponse.error = resperror;
638 lock (m_ModelCost)
639 m_FileAgentInventoryState = FileAgentInventoryState.idle;
640 return errorResponse;
641 }
642 }
454 } 643 }
644
645 if (client != null && warning != String.Empty)
646 client.SendAgentAlertMessage(warning, true);
455 } 647 }
456 } 648 }
457 649
458 string assetName = llsdRequest.name;
459 string assetDes = llsdRequest.description; 650 string assetDes = llsdRequest.description;
460 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 651 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
461 UUID newAsset = UUID.Random(); 652 UUID newAsset = UUID.Random();
462 UUID newInvItem = UUID.Random(); 653 UUID newInvItem = UUID.Random();
463 UUID parentFolder = llsdRequest.folder_id; 654 UUID parentFolder = llsdRequest.folder_id;
464 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 655 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
656 UUID texturesFolder = UUID.Zero;
657
658 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
659 texturesFolder = llsdRequest.texture_folder_id;
465 660
466 AssetUploader uploader = 661 AssetUploader uploader =
467 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 662 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
468 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 663 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
664 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
469 665
470 m_HostCapsObj.HttpListener.AddStreamHandler( 666 m_HostCapsObj.HttpListener.AddStreamHandler(
471 new BinaryStreamHandler( 667 new BinaryStreamHandler(
@@ -483,10 +679,22 @@ namespace OpenSim.Region.ClientStack.Linden
483 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 679 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
484 uploaderPath; 680 uploaderPath;
485 681
682
486 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 683 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
487 uploadResponse.uploader = uploaderURL; 684 uploadResponse.uploader = uploaderURL;
488 uploadResponse.state = "upload"; 685 uploadResponse.state = "upload";
686 uploadResponse.upload_price = (int)cost;
687
688 if (llsdRequest.asset_type == "mesh")
689 {
690 uploadResponse.data = meshcostdata;
691 }
692
489 uploader.OnUpLoad += UploadCompleteHandler; 693 uploader.OnUpLoad += UploadCompleteHandler;
694
695 lock (m_ModelCost)
696 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
697
490 return uploadResponse; 698 return uploadResponse;
491 } 699 }
492 700
@@ -498,8 +706,14 @@ namespace OpenSim.Region.ClientStack.Linden
498 /// <param name="data"></param> 706 /// <param name="data"></param>
499 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 707 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
500 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 708 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
501 string assetType) 709 string assetType, int cost,
710 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
711 bool IsAtestUpload, ref string error)
502 { 712 {
713
714 lock (m_ModelCost)
715 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
716
503 m_log.DebugFormat( 717 m_log.DebugFormat(
504 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 718 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
505 assetID, inventoryItem, inventoryType, assetType); 719 assetID, inventoryItem, inventoryType, assetType);
@@ -507,117 +721,247 @@ namespace OpenSim.Region.ClientStack.Linden
507 sbyte assType = 0; 721 sbyte assType = 0;
508 sbyte inType = 0; 722 sbyte inType = 0;
509 723
724 IClientAPI client = null;
725
726 UUID owner_id = m_HostCapsObj.AgentID;
727 UUID creatorID;
728
729 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
730
731 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
732
733 if (istest && m_testAssetsCreatorID != UUID.Zero)
734 creatorID = m_testAssetsCreatorID;
735 else
736 creatorID = owner_id;
737
738 string creatorIDstr = creatorID.ToString();
739
740 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
741 if (mm != null)
742 {
743 // make sure client still has enougth credit
744 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
745 {
746 error = "Insufficient funds.";
747 return;
748 }
749 }
750
751 // strings to types
510 if (inventoryType == "sound") 752 if (inventoryType == "sound")
511 { 753 {
512 inType = 1; 754 inType = (sbyte)InventoryType.Sound;
513 assType = 1; 755 assType = (sbyte)AssetType.Sound;
514 } 756 }
515 else if (inventoryType == "animation") 757 else if (inventoryType == "animation")
516 { 758 {
517 inType = 19; 759 inType = (sbyte)InventoryType.Animation;
518 assType = 20; 760 assType = (sbyte)AssetType.Animation;
519 } 761 }
520 else if (inventoryType == "wearable") 762 else if (inventoryType == "wearable")
521 { 763 {
522 inType = 18; 764 inType = (sbyte)InventoryType.Wearable;
523 switch (assetType) 765 switch (assetType)
524 { 766 {
525 case "bodypart": 767 case "bodypart":
526 assType = 13; 768 assType = (sbyte)AssetType.Bodypart;
527 break; 769 break;
528 case "clothing": 770 case "clothing":
529 assType = 5; 771 assType = (sbyte)AssetType.Clothing;
530 break; 772 break;
531 } 773 }
532 } 774 }
533 else if (inventoryType == "object") 775 else if (inventoryType == "object")
534 { 776 {
535 inType = (sbyte)InventoryType.Object; 777 if (assetType == "mesh") // this code for now is for mesh models uploads only
536 assType = (sbyte)AssetType.Object;
537
538 List<Vector3> positions = new List<Vector3>();
539 List<Quaternion> rotations = new List<Quaternion>();
540 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
541 OSDArray instance_list = (OSDArray)request["instance_list"];
542 OSDArray mesh_list = (OSDArray)request["mesh_list"];
543 OSDArray texture_list = (OSDArray)request["texture_list"];
544 SceneObjectGroup grp = null;
545
546 List<UUID> textures = new List<UUID>();
547 for (int i = 0; i < texture_list.Count; i++)
548 { 778 {
549 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 779 inType = (sbyte)InventoryType.Object;
550 textureAsset.Data = texture_list[i].AsBinary(); 780 assType = (sbyte)AssetType.Object;
551 m_assetService.Store(textureAsset);
552 textures.Add(textureAsset.FullID);
553 }
554 781
555 for (int i = 0; i < mesh_list.Count; i++) 782 List<Vector3> positions = new List<Vector3>();
556 { 783 List<Quaternion> rotations = new List<Quaternion>();
557 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 784 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
558 785
559 Primitive.TextureEntry textureEntry 786 // compare and get updated information
560 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
561 OSDMap inner_instance_list = (OSDMap)instance_list[i];
562 787
563 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 788 bool mismatchError = true;
564 for (uint face = 0; face < face_list.Count; face++) 789
790 while (mismatchError)
565 { 791 {
566 OSDMap faceMap = (OSDMap)face_list[(int)face]; 792 mismatchError = false;
567 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 793 }
568 if(faceMap.ContainsKey("fullbright"))
569 f.Fullbright = faceMap["fullbright"].AsBoolean();
570 if (faceMap.ContainsKey ("diffuse_color"))
571 f.RGBA = faceMap["diffuse_color"].AsColor4();
572 794
573 int textureNum = faceMap["image"].AsInteger(); 795 if (mismatchError)
574 float imagerot = faceMap["imagerot"].AsInteger(); 796 {
575 float offsets = (float)faceMap["offsets"].AsReal(); 797 error = "Upload and fee estimation information don't match";
576 float offsett = (float)faceMap["offsett"].AsReal(); 798 lock (m_ModelCost)
577 float scales = (float)faceMap["scales"].AsReal(); 799 m_FileAgentInventoryState = FileAgentInventoryState.idle;
578 float scalet = (float)faceMap["scalet"].AsReal();
579 800
580 if(imagerot != 0) 801 return;
581 f.Rotation = imagerot; 802 }
582 803
583 if(offsets != 0) 804 OSDArray instance_list = (OSDArray)request["instance_list"];
584 f.OffsetU = offsets; 805 OSDArray mesh_list = (OSDArray)request["mesh_list"];
806 OSDArray texture_list = (OSDArray)request["texture_list"];
807 SceneObjectGroup grp = null;
585 808
586 if (offsett != 0) 809 // create and store texture assets
587 f.OffsetV = offsett; 810 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
811 texturesFolder != UUID.Zero);
588 812
589 if (scales != 0)
590 f.RepeatU = scales;
591 813
592 if (scalet != 0) 814 List<UUID> textures = new List<UUID>();
593 f.RepeatV = scalet;
594 815
595 if (textures.Count > textureNum) 816
596 f.TextureID = textures[textureNum]; 817 if (doTextInv)
597 else 818 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
598 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
599 819
600 textureEntry.FaceTextures[face] = f; 820 if(client == null) // don't put textures in inventory if there is no client
821 doTextInv = false;
822
823 for (int i = 0; i < texture_list.Count; i++)
824 {
825 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
826 textureAsset.Data = texture_list[i].AsBinary();
827 if (istest)
828 textureAsset.Local = true;
829 m_assetService.Store(textureAsset);
830 textures.Add(textureAsset.FullID);
831
832 if (doTextInv)
833 {
834 string name = assetName;
835 if (name.Length > 25)
836 name = name.Substring(0, 24);
837 name += "_Texture#" + i.ToString();
838 InventoryItemBase texitem = new InventoryItemBase();
839 texitem.Owner = m_HostCapsObj.AgentID;
840 texitem.CreatorId = creatorIDstr;
841 texitem.CreatorData = String.Empty;
842 texitem.ID = UUID.Random();
843 texitem.AssetID = textureAsset.FullID;
844 texitem.Description = "mesh model texture";
845 texitem.Name = name;
846 texitem.AssetType = (int)AssetType.Texture;
847 texitem.InvType = (int)InventoryType.Texture;
848 texitem.Folder = texturesFolder;
849
850 texitem.CurrentPermissions
851 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
852
853 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
854 texitem.EveryOnePermissions = 0;
855 texitem.NextPermissions = (uint)PermissionMask.All;
856 texitem.CreationDate = Util.UnixTimeSinceEpoch();
857
858 m_Scene.AddInventoryItem(client, texitem);
859 texitem = null;
860 }
601 } 861 }
602 862
603 pbs.TextureEntry = textureEntry.GetBytes(); 863 // create and store meshs assets
864 List<UUID> meshAssets = new List<UUID>();
865 for (int i = 0; i < mesh_list.Count; i++)
866 {
867 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
868 meshAsset.Data = mesh_list[i].AsBinary();
869 if (istest)
870 meshAsset.Local = true;
871 m_assetService.Store(meshAsset);
872 meshAssets.Add(meshAsset.FullID);
873 }
874
875 int skipedMeshs = 0;
876 // build prims from instances
877 for (int i = 0; i < instance_list.Count; i++)
878 {
879 OSDMap inner_instance_list = (OSDMap)instance_list[i];
880
881 // skip prims that are 2 small
882 Vector3 scale = inner_instance_list["scale"].AsVector3();
883
884 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
885 {
886 skipedMeshs++;
887 continue;
888 }
889
890 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
891
892 Primitive.TextureEntry textureEntry
893 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
894
604 895
605 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 896 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
606 meshAsset.Data = mesh_list[i].AsBinary(); 897 for (uint face = 0; face < face_list.Count; face++)
607 m_assetService.Store(meshAsset); 898 {
899 OSDMap faceMap = (OSDMap)face_list[(int)face];
900 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
901 if (faceMap.ContainsKey("fullbright"))
902 f.Fullbright = faceMap["fullbright"].AsBoolean();
903 if (faceMap.ContainsKey("diffuse_color"))
904 f.RGBA = faceMap["diffuse_color"].AsColor4();
905
906 int textureNum = faceMap["image"].AsInteger();
907 float imagerot = faceMap["imagerot"].AsInteger();
908 float offsets = (float)faceMap["offsets"].AsReal();
909 float offsett = (float)faceMap["offsett"].AsReal();
910 float scales = (float)faceMap["scales"].AsReal();
911 float scalet = (float)faceMap["scalet"].AsReal();
912
913 if (imagerot != 0)
914 f.Rotation = imagerot;
915
916 if (offsets != 0)
917 f.OffsetU = offsets;
608 918
609 pbs.SculptEntry = true; 919 if (offsett != 0)
610 pbs.SculptTexture = meshAsset.FullID; 920 f.OffsetV = offsett;
611 pbs.SculptType = (byte)SculptType.Mesh;
612 pbs.SculptData = meshAsset.Data;
613 921
614 Vector3 position = inner_instance_list["position"].AsVector3(); 922 if (scales != 0)
615 Vector3 scale = inner_instance_list["scale"].AsVector3(); 923 f.RepeatU = scales;
616 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 924
925 if (scalet != 0)
926 f.RepeatV = scalet;
927
928 if (textures.Count > textureNum)
929 f.TextureID = textures[textureNum];
930 else
931 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
932
933 textureEntry.FaceTextures[face] = f;
934 }
935
936 pbs.TextureEntry = textureEntry.GetBytes();
937
938 bool hasmesh = false;
939 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
940 {
941 int meshindx = inner_instance_list["mesh"].AsInteger();
942 if (meshAssets.Count > meshindx)
943 {
944 pbs.SculptEntry = true;
945 pbs.SculptType = (byte)SculptType.Mesh;
946 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
947 // data will be requested from asset on rez (i hope)
948 hasmesh = true;
949 }
950 }
951
952 Vector3 position = inner_instance_list["position"].AsVector3();
953 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
954
955 // for now viwers do send fixed defaults
956 // but this may change
957// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
958 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
959 if(hasmesh)
960 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
961// int material = inner_instance_list["material"].AsInteger();
962 byte material = (byte)Material.Wood;
617 963
618// no longer used - begin ------------------------ 964// no longer used - begin ------------------------
619// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
620// int material = inner_instance_list["material"].AsInteger();
621// int mesh = inner_instance_list["mesh"].AsInteger(); 965// int mesh = inner_instance_list["mesh"].AsInteger();
622 966
623// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 967// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -632,24 +976,49 @@ namespace OpenSim.Region.ClientStack.Linden
632// UUID owner_id = permissions["owner_id"].AsUUID(); 976// UUID owner_id = permissions["owner_id"].AsUUID();
633// int owner_mask = permissions["owner_mask"].AsInteger(); 977// int owner_mask = permissions["owner_mask"].AsInteger();
634// no longer used - end ------------------------ 978// no longer used - end ------------------------
979
980
981 SceneObjectPart prim
982 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
983
984 prim.Scale = scale;
985 rotations.Add(rotation);
986 positions.Add(position);
987 prim.UUID = UUID.Random();
988 prim.CreatorID = creatorID;
989 prim.OwnerID = owner_id;
990 prim.GroupID = UUID.Zero;
991 prim.LastOwnerID = creatorID;
992 prim.CreationDate = Util.UnixTimeSinceEpoch();
993
994 if (grp == null)
995 prim.Name = assetName;
996 else
997 prim.Name = assetName + "#" + i.ToString();
635 998
636 UUID owner_id = m_HostCapsObj.AgentID; 999 prim.EveryoneMask = 0;
1000 prim.GroupMask = 0;
637 1001
638 SceneObjectPart prim 1002 if (restrictPerms)
639 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 1003 {
1004 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1005 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1006 prim.NextOwnerMask = 0;
1007 }
1008 else
1009 {
1010 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1011 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1012 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1013 }
1014
1015 if(istest)
1016 prim.Description = "For testing only. Other uses are prohibited";
1017 else
1018 prim.Description = "";
640 1019
641 prim.Scale = scale; 1020 prim.Material = material;
642 //prim.OffsetPosition = position; 1021 prim.PhysicsShapeType = physicsShapeType;
643 rotations.Add(rotation);
644 positions.Add(position);
645 prim.UUID = UUID.Random();
646 prim.CreatorID = owner_id;
647 prim.OwnerID = owner_id;
648 prim.GroupID = UUID.Zero;
649 prim.LastOwnerID = prim.OwnerID;
650 prim.CreationDate = Util.UnixTimeSinceEpoch();
651 prim.Name = assetName;
652 prim.Description = "";
653 1022
654// prim.BaseMask = (uint)base_mask; 1023// prim.BaseMask = (uint)base_mask;
655// prim.EveryoneMask = (uint)everyone_mask; 1024// prim.EveryoneMask = (uint)everyone_mask;
@@ -657,52 +1026,64 @@ namespace OpenSim.Region.ClientStack.Linden
657// prim.NextOwnerMask = (uint)next_owner_mask; 1026// prim.NextOwnerMask = (uint)next_owner_mask;
658// prim.OwnerMask = (uint)owner_mask; 1027// prim.OwnerMask = (uint)owner_mask;
659 1028
660 if (grp == null) 1029 if (grp == null)
661 grp = new SceneObjectGroup(prim); 1030 {
662 else 1031 grp = new SceneObjectGroup(prim);
663 grp.AddPart(prim); 1032 grp.LastOwnerID = creatorID;
664 } 1033 }
1034 else
1035 grp.AddPart(prim);
1036 }
665 1037
666 Vector3 rootPos = positions[0]; 1038 Vector3 rootPos = positions[0];
667 1039
668 if (grp.Parts.Length > 1) 1040 if (grp.Parts.Length > 1)
669 { 1041 {
670 // Fix first link number 1042 // Fix first link number
671 grp.RootPart.LinkNum++; 1043 grp.RootPart.LinkNum++;
672 1044
673 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1045 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
674 Quaternion tmprot; 1046 Quaternion tmprot;
675 Vector3 offset; 1047 Vector3 offset;
676 1048
677 // fix children rotations and positions 1049 // fix children rotations and positions
678 for (int i = 1; i < rotations.Count; i++) 1050 for (int i = 1; i < rotations.Count; i++)
679 { 1051 {
680 tmprot = rotations[i]; 1052 tmprot = rotations[i];
681 tmprot = rootRotConj * tmprot; 1053 tmprot = rootRotConj * tmprot;
1054
1055 grp.Parts[i].RotationOffset = tmprot;
682 1056
683 grp.Parts[i].RotationOffset = tmprot; 1057 offset = positions[i] - rootPos;
684 1058
685 offset = positions[i] - rootPos; 1059 offset *= rootRotConj;
1060 grp.Parts[i].OffsetPosition = offset;
1061 }
686 1062
687 offset *= rootRotConj; 1063 grp.AbsolutePosition = rootPos;
688 grp.Parts[i].OffsetPosition = offset; 1064 grp.UpdateGroupRotationR(rotations[0]);
1065 }
1066 else
1067 {
1068 grp.AbsolutePosition = rootPos;
1069 grp.UpdateGroupRotationR(rotations[0]);
689 } 1070 }
690 1071
691 grp.AbsolutePosition = rootPos; 1072 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
692 grp.UpdateGroupRotationR(rotations[0]);
693 } 1073 }
694 else 1074
1075 else // not a mesh model
695 { 1076 {
696 grp.AbsolutePosition = rootPos; 1077 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
697 grp.UpdateGroupRotationR(rotations[0]); 1078 return;
698 } 1079 }
699
700 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
701 } 1080 }
702 1081
703 AssetBase asset; 1082 AssetBase asset;
704 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1083 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
705 asset.Data = data; 1084 asset.Data = data;
1085 if (istest)
1086 asset.Local = true;
706 if (AddNewAsset != null) 1087 if (AddNewAsset != null)
707 AddNewAsset(asset); 1088 AddNewAsset(asset);
708 else if (m_assetService != null) 1089 else if (m_assetService != null)
@@ -710,11 +1091,17 @@ namespace OpenSim.Region.ClientStack.Linden
710 1091
711 InventoryItemBase item = new InventoryItemBase(); 1092 InventoryItemBase item = new InventoryItemBase();
712 item.Owner = m_HostCapsObj.AgentID; 1093 item.Owner = m_HostCapsObj.AgentID;
713 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1094 item.CreatorId = creatorIDstr;
714 item.CreatorData = String.Empty; 1095 item.CreatorData = String.Empty;
715 item.ID = inventoryItem; 1096 item.ID = inventoryItem;
716 item.AssetID = asset.FullID; 1097 item.AssetID = asset.FullID;
717 item.Description = assetDescription; 1098 if (istest)
1099 {
1100 item.Description = "For testing only. Other uses are prohibited";
1101 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1102 }
1103 else
1104 item.Description = assetDescription;
718 item.Name = assetName; 1105 item.Name = assetName;
719 item.AssetType = assType; 1106 item.AssetType = assType;
720 item.InvType = inType; 1107 item.InvType = inType;
@@ -722,18 +1109,56 @@ namespace OpenSim.Region.ClientStack.Linden
722 1109
723 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1110 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
724 // (owner) permissions. This becomes a problem if next permissions are changed. 1111 // (owner) permissions. This becomes a problem if next permissions are changed.
725 item.CurrentPermissions
726 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
727 1112
728 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1113 if (restrictPerms)
729 item.EveryOnePermissions = 0; 1114 {
730 item.NextPermissions = (uint)PermissionMask.All; 1115 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1116 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1117 item.EveryOnePermissions = 0;
1118 item.NextPermissions = 0;
1119 }
1120 else
1121 {
1122 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1123 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1124 item.EveryOnePermissions = 0;
1125 item.NextPermissions = (uint)PermissionMask.Transfer;
1126 }
1127
731 item.CreationDate = Util.UnixTimeSinceEpoch(); 1128 item.CreationDate = Util.UnixTimeSinceEpoch();
732 1129
1130 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1131
733 if (AddNewInventoryItem != null) 1132 if (AddNewInventoryItem != null)
734 { 1133 {
735 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1134 if (istest)
1135 {
1136 m_Scene.AddInventoryItem(client, item);
1137/*
1138 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1139 if (client != null)
1140 client.SendAgentAlertMessage("Upload will have no cost, for personal test purposes only. Other uses are forbiden. Items may not work on a another region" , true);
1141 */
1142 }
1143 else
1144 {
1145 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1146// if (client != null)
1147// {
1148// // let users see anything.. i don't so far
1149// string str;
1150// if (cost > 0)
1151// // dont remember where is money unit name to put here
1152// str = "Upload complete. charged " + cost.ToString() + "$";
1153// else
1154// str = "Upload complete";
1155// client.SendAgentAlertMessage(str, true);
1156// }
1157 }
736 } 1158 }
1159
1160 lock (m_ModelCost)
1161 m_FileAgentInventoryState = FileAgentInventoryState.idle;
737 } 1162 }
738 1163
739 /// <summary> 1164 /// <summary>
@@ -926,6 +1351,120 @@ namespace OpenSim.Region.ClientStack.Linden
926 return response; 1351 return response;
927 } 1352 }
928 1353
1354 public string GetObjectCost(string request, string path,
1355 string param, IOSHttpRequest httpRequest,
1356 IOSHttpResponse httpResponse)
1357 {
1358 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1359 OSDMap resp = new OSDMap();
1360
1361 OSDArray object_ids = (OSDArray)req["object_ids"];
1362
1363 for (int i = 0; i < object_ids.Count; i++)
1364 {
1365 UUID uuid = object_ids[i].AsUUID();
1366
1367 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1368
1369 if (part != null)
1370 {
1371 SceneObjectGroup grp = part.ParentGroup;
1372 if (grp != null)
1373 {
1374 float linksetCost;
1375 float linksetPhysCost;
1376 float partCost;
1377 float partPhysCost;
1378
1379 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1380
1381 OSDMap object_data = new OSDMap();
1382 object_data["linked_set_resource_cost"] = linksetCost;
1383 object_data["resource_cost"] = partCost;
1384 object_data["physics_cost"] = partPhysCost;
1385 object_data["linked_set_physics_cost"] = linksetPhysCost;
1386
1387 resp[uuid.ToString()] = object_data;
1388 }
1389 }
1390 }
1391
1392 string response = OSDParser.SerializeLLSDXmlString(resp);
1393 return response;
1394 }
1395
1396 public string ResourceCostSelected(string request, string path,
1397 string param, IOSHttpRequest httpRequest,
1398 IOSHttpResponse httpResponse)
1399 {
1400 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1401 OSDMap resp = new OSDMap();
1402
1403
1404 float phys=0;
1405 float stream=0;
1406 float simul=0;
1407
1408 if (req.ContainsKey("selected_roots"))
1409 {
1410 OSDArray object_ids = (OSDArray)req["selected_roots"];
1411
1412 // should go by SOG suming costs for all parts
1413 // ll v3 works ok with several objects select we get the list and adds ok
1414 // FS calls per object so results are wrong guess fs bug
1415 for (int i = 0; i < object_ids.Count; i++)
1416 {
1417 UUID uuid = object_ids[i].AsUUID();
1418 float Physc;
1419 float simulc;
1420 float streamc;
1421
1422 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1423 if (grp != null)
1424 {
1425 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1426 phys += Physc;
1427 stream += streamc;
1428 simul += simulc;
1429 }
1430 }
1431 }
1432 else if (req.ContainsKey("selected_prims"))
1433 {
1434 OSDArray object_ids = (OSDArray)req["selected_prims"];
1435
1436 // don't see in use in any of the 2 viewers
1437 // guess it should be for edit linked but... nothing
1438 // should go to SOP per part
1439 for (int i = 0; i < object_ids.Count; i++)
1440 {
1441 UUID uuid = object_ids[i].AsUUID();
1442
1443 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1444 if (part != null)
1445 {
1446 phys += part.PhysicsCost;
1447 stream += part.StreamingCost;
1448 simul += part.SimulationCost;
1449 }
1450 }
1451 }
1452
1453 if (simul != 0)
1454 {
1455 OSDMap object_data = new OSDMap();
1456
1457 object_data["physics"] = phys;
1458 object_data["streaming"] = stream;
1459 object_data["simulation"] = simul;
1460
1461 resp["selected"] = object_data;
1462 }
1463
1464 string response = OSDParser.SerializeLLSDXmlString(resp);
1465 return response;
1466 }
1467
929 public string UpdateAgentInformation(string request, string path, 1468 public string UpdateAgentInformation(string request, string path,
930 string param, IOSHttpRequest httpRequest, 1469 string param, IOSHttpRequest httpRequest,
931 IOSHttpResponse httpResponse) 1470 IOSHttpResponse httpResponse)
@@ -945,6 +1484,10 @@ namespace OpenSim.Region.ClientStack.Linden
945 1484
946 public class AssetUploader 1485 public class AssetUploader
947 { 1486 {
1487 private static readonly ILog m_log =
1488 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1489
1490
948 public event UpLoadedAsset OnUpLoad; 1491 public event UpLoadedAsset OnUpLoad;
949 private UpLoadedAsset handlerUpLoad = null; 1492 private UpLoadedAsset handlerUpLoad = null;
950 1493
@@ -959,10 +1502,21 @@ namespace OpenSim.Region.ClientStack.Linden
959 1502
960 private string m_invType = String.Empty; 1503 private string m_invType = String.Empty;
961 private string m_assetType = String.Empty; 1504 private string m_assetType = String.Empty;
1505 private int m_cost;
1506 private string m_error = String.Empty;
1507
1508 private Timer m_timeoutTimer = new Timer();
1509 private UUID m_texturesFolder;
1510 private int m_nreqtextures;
1511 private int m_nreqmeshs;
1512 private int m_nreqinstances;
1513 private bool m_IsAtestUpload;
962 1514
963 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1515 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
964 UUID parentFolderID, string invType, string assetType, string path, 1516 UUID parentFolderID, string invType, string assetType, string path,
965 IHttpServer httpServer, bool dumpAssetsToFile) 1517 IHttpServer httpServer, bool dumpAssetsToFile,
1518 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1519 bool IsAtestUpload)
966 { 1520 {
967 m_assetName = assetName; 1521 m_assetName = assetName;
968 m_assetDes = description; 1522 m_assetDes = description;
@@ -974,6 +1528,18 @@ namespace OpenSim.Region.ClientStack.Linden
974 m_assetType = assetType; 1528 m_assetType = assetType;
975 m_invType = invType; 1529 m_invType = invType;
976 m_dumpAssetsToFile = dumpAssetsToFile; 1530 m_dumpAssetsToFile = dumpAssetsToFile;
1531 m_cost = totalCost;
1532
1533 m_texturesFolder = texturesFolder;
1534 m_nreqtextures = nreqtextures;
1535 m_nreqmeshs = nreqmeshs;
1536 m_nreqinstances = nreqinstances;
1537 m_IsAtestUpload = IsAtestUpload;
1538
1539 m_timeoutTimer.Elapsed += TimedOut;
1540 m_timeoutTimer.Interval = 120000;
1541 m_timeoutTimer.AutoReset = false;
1542 m_timeoutTimer.Start();
977 } 1543 }
978 1544
979 /// <summary> 1545 /// <summary>
@@ -988,12 +1554,14 @@ namespace OpenSim.Region.ClientStack.Linden
988 UUID inv = inventoryItemID; 1554 UUID inv = inventoryItemID;
989 string res = String.Empty; 1555 string res = String.Empty;
990 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1556 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1557/*
991 uploadComplete.new_asset = newAssetID.ToString(); 1558 uploadComplete.new_asset = newAssetID.ToString();
992 uploadComplete.new_inventory_item = inv; 1559 uploadComplete.new_inventory_item = inv;
993 uploadComplete.state = "complete"; 1560 uploadComplete.state = "complete";
994 1561
995 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1562 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
996 1563*/
1564 m_timeoutTimer.Stop();
997 httpListener.RemoveStreamHandler("POST", uploaderPath); 1565 httpListener.RemoveStreamHandler("POST", uploaderPath);
998 1566
999 // TODO: probably make this a better set of extensions here 1567 // TODO: probably make this a better set of extensions here
@@ -1010,12 +1578,49 @@ namespace OpenSim.Region.ClientStack.Linden
1010 handlerUpLoad = OnUpLoad; 1578 handlerUpLoad = OnUpLoad;
1011 if (handlerUpLoad != null) 1579 if (handlerUpLoad != null)
1012 { 1580 {
1013 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1581 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1582 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1583 }
1584 if (m_IsAtestUpload)
1585 {
1586 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1587 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1588 resperror.identifier = inv;
1589
1590 uploadComplete.error = resperror;
1591 uploadComplete.state = "Upload4Testing";
1014 } 1592 }
1593 else
1594 {
1595 if (m_error == String.Empty)
1596 {
1597 uploadComplete.new_asset = newAssetID.ToString();
1598 uploadComplete.new_inventory_item = inv;
1599 // if (m_texturesFolder != UUID.Zero)
1600 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1601 uploadComplete.state = "complete";
1602 }
1603 else
1604 {
1605 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1606 resperror.message = m_error;
1607 resperror.identifier = inv;
1015 1608
1609 uploadComplete.error = resperror;
1610 uploadComplete.state = "failed";
1611 }
1612 }
1613
1614 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1016 return res; 1615 return res;
1017 } 1616 }
1018 1617
1618 private void TimedOut(object sender, ElapsedEventArgs args)
1619 {
1620 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1621 httpListener.RemoveStreamHandler("POST", uploaderPath);
1622 }
1623
1019 ///Left this in and commented in case there are unforseen issues 1624 ///Left this in and commented in case there are unforseen issues
1020 //private void SaveAssetToFile(string filename, byte[] data) 1625 //private void SaveAssetToFile(string filename, byte[] data)
1021 //{ 1626 //{
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
new file mode 100644
index 0000000..4a3fae6
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
@@ -0,0 +1,671 @@
1// Proprietary code of Avination Virtual Limited
2// (c) 2012 Melanie Thielker, Leal Duarte
3//
4
5using System;
6using System.IO;
7using System.Collections;
8using System.Collections.Generic;
9using System.Text;
10
11using OpenMetaverse;
12using OpenMetaverse.StructuredData;
13
14using OpenSim.Framework;
15using OpenSim.Region.Framework;
16using OpenSim.Region.Framework.Scenes;
17using OpenSim.Framework.Capabilities;
18
19using ComponentAce.Compression.Libs.zlib;
20
21using OSDArray = OpenMetaverse.StructuredData.OSDArray;
22using OSDMap = OpenMetaverse.StructuredData.OSDMap;
23
24namespace OpenSim.Region.ClientStack.Linden
25{
26 public struct ModelPrimLimits
27 {
28
29 }
30
31 public class ModelCost
32 {
33
34 // upload fee defaults
35 // fees are normalized to 1.0
36 // this parameters scale them to basic cost ( so 1.0 translates to 10 )
37
38 public float ModelMeshCostFactor = 0.0f; // scale total cost relative to basic (excluding textures)
39 public float ModelTextureCostFactor = 1.0f; // scale textures fee to basic.
40 public float ModelMinCostFactor = 0.0f; // 0.5f; // minimum total model free excluding textures
41
42 // itens costs in normalized values
43 // ie will be multiplied by basicCost and factors above
44 public float primCreationCost = 0.002f; // extra cost for each prim creation overhead
45 // weigthed size to normalized cost
46 public float bytecost = 1e-5f;
47
48 // mesh upload fees based on compressed data sizes
49 // several data sections are counted more that once
50 // to promote user optimization
51 // following parameters control how many extra times they are added
52 // to global size.
53 // LOD meshs
54 const float medSizeWth = 1f; // 2x
55 const float lowSizeWth = 1.5f; // 2.5x
56 const float lowestSizeWth = 2f; // 3x
57 // favor potencially physical optimized meshs versus automatic decomposition
58 const float physMeshSizeWth = 6f; // counts 7x
59 const float physHullSizeWth = 8f; // counts 9x
60
61 // stream cost area factors
62 // more or less like SL
63 const float highLodFactor = 17.36f;
64 const float midLodFactor = 277.78f;
65 const float lowLodFactor = 1111.11f;
66
67 // physics cost is below, identical to SL, assuming shape type convex
68 // server cost is below identical to SL assuming non scripted non physical object
69
70 // internal
71 const int bytesPerCoord = 6; // 3 coords, 2 bytes per each
72
73 // control prims dimensions
74 public float PrimScaleMin = 0.001f;
75 public float NonPhysicalPrimScaleMax = 256f;
76 public float PhysicalPrimScaleMax = 10f;
77 public int ObjectLinkedPartsMax = 512;
78
79 // storage for a single mesh asset cost parameters
80 private class ameshCostParam
81 {
82 // LOD sizes for size dependent streaming cost
83 public int highLODSize;
84 public int medLODSize;
85 public int lowLODSize;
86 public int lowestLODSize;
87 // normalized fee based on compressed data sizes
88 public float costFee;
89 // physics cost
90 public float physicsCost;
91 }
92
93 // calculates a mesh model costs
94 // returns false on error, with a reason on parameter error
95 // resources input LLSD request
96 // basicCost input region assets upload cost
97 // totalcost returns model total upload fee
98 // meshcostdata returns detailed costs for viewer
99 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost,
100 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
101 {
102 totalcost = 0;
103 error = string.Empty;
104
105 if (resources == null ||
106 resources.instance_list == null ||
107 resources.instance_list.Array.Count == 0)
108 {
109 error = "missing model information.";
110 return false;
111 }
112
113 int numberInstances = resources.instance_list.Array.Count;
114
115 if( numberInstances > ObjectLinkedPartsMax )
116 {
117 error = "Model whould have more than " + ObjectLinkedPartsMax.ToString() + " linked prims";
118 return false;
119 }
120
121 meshcostdata.model_streaming_cost = 0.0;
122 meshcostdata.simulation_cost = 0.0;
123 meshcostdata.physics_cost = 0.0;
124 meshcostdata.resource_cost = 0.0;
125
126 meshcostdata.upload_price_breakdown.mesh_instance = 0;
127 meshcostdata.upload_price_breakdown.mesh_physics = 0;
128 meshcostdata.upload_price_breakdown.mesh_streaming = 0;
129 meshcostdata.upload_price_breakdown.model = 0;
130
131 int itmp;
132
133 // textures cost
134 if (resources.texture_list != null && resources.texture_list.Array.Count > 0)
135 {
136 float textures_cost = (float)(resources.texture_list.Array.Count * basicCost);
137 textures_cost *= ModelTextureCostFactor;
138
139 itmp = (int)(textures_cost + 0.5f); // round
140 meshcostdata.upload_price_breakdown.texture = itmp;
141 totalcost += itmp;
142 }
143
144 // meshs assets cost
145 float meshsfee = 0;
146 int numberMeshs = 0;
147 bool haveMeshs = false;
148 List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
149
150 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
151 {
152 numberMeshs = resources.mesh_list.Array.Count;
153
154 for (int i = 0; i < numberMeshs; i++)
155 {
156 ameshCostParam curCost = new ameshCostParam();
157 byte[] data = (byte[])resources.mesh_list.Array[i];
158
159 if (!MeshCost(data, curCost, out error))
160 {
161 return false;
162 }
163 meshsCosts.Add(curCost);
164 meshsfee += curCost.costFee;
165 }
166 haveMeshs = true;
167 }
168
169 // instances (prims) cost
170
171
172 int mesh;
173 int skipedSmall = 0;
174 for (int i = 0; i < numberInstances; i++)
175 {
176 Hashtable inst = (Hashtable)resources.instance_list.Array[i];
177
178 ArrayList ascale = (ArrayList)inst["scale"];
179 Vector3 scale;
180 double tmp;
181 tmp = (double)ascale[0];
182 scale.X = (float)tmp;
183 tmp = (double)ascale[1];
184 scale.Y = (float)tmp;
185 tmp = (double)ascale[2];
186 scale.Z = (float)tmp;
187
188 if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin)
189 {
190 skipedSmall++;
191 continue;
192 }
193
194 if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax)
195 {
196 error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale";
197 return false;
198 }
199
200 if (haveMeshs && inst.ContainsKey("mesh"))
201 {
202 mesh = (int)inst["mesh"];
203
204 if (mesh >= numberMeshs)
205 {
206 error = "Incoerent model information.";
207 return false;
208 }
209
210 // streamming cost
211
212 float sqdiam = scale.LengthSquared();
213
214 ameshCostParam curCost = meshsCosts[mesh];
215 float mesh_streaming = streamingCost(curCost, sqdiam);
216
217 meshcostdata.model_streaming_cost += mesh_streaming;
218 meshcostdata.physics_cost += curCost.physicsCost;
219 }
220 else // instance as no mesh ??
221 {
222 // to do later if needed
223 meshcostdata.model_streaming_cost += 0.5f;
224 meshcostdata.physics_cost += 1.0f;
225 }
226
227 // assume unscripted and static prim server cost
228 meshcostdata.simulation_cost += 0.5f;
229 // charge for prims creation
230 meshsfee += primCreationCost;
231 }
232
233 if (skipedSmall > 0)
234 {
235 if (skipedSmall > numberInstances / 2)
236 {
237 error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() +
238 "m minimum allowed size. Please check scalling";
239 return false;
240 }
241 else
242 warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() +
243 " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() +
244 "m minimum allowed size. Please check scalling ";
245 }
246
247 if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost)
248 meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
249 else
250 meshcostdata.resource_cost = meshcostdata.physics_cost;
251
252 if (meshcostdata.resource_cost < meshcostdata.simulation_cost)
253 meshcostdata.resource_cost = meshcostdata.simulation_cost;
254
255 // scale cost
256 // at this point a cost of 1.0 whould mean basic cost
257 meshsfee *= ModelMeshCostFactor;
258
259 if (meshsfee < ModelMinCostFactor)
260 meshsfee = ModelMinCostFactor;
261
262 // actually scale it to basic cost
263 meshsfee *= (float)basicCost;
264
265 meshsfee += 0.5f; // rounding
266
267 totalcost += (int)meshsfee;
268
269 // breakdown prices
270 // don't seem to be in use so removed code for now
271
272 return true;
273 }
274
275 // single mesh asset cost
276 private bool MeshCost(byte[] data, ameshCostParam cost, out string error)
277 {
278 cost.highLODSize = 0;
279 cost.medLODSize = 0;
280 cost.lowLODSize = 0;
281 cost.lowestLODSize = 0;
282 cost.physicsCost = 0.0f;
283 cost.costFee = 0.0f;
284
285 error = string.Empty;
286
287 if (data == null || data.Length == 0)
288 {
289 error = "Missing model information.";
290 return false;
291 }
292
293 OSD meshOsd = null;
294 int start = 0;
295
296 error = "Invalid model data";
297
298 using (MemoryStream ms = new MemoryStream(data))
299 {
300 try
301 {
302 OSD osd = OSDParser.DeserializeLLSDBinary(ms);
303 if (osd is OSDMap)
304 meshOsd = (OSDMap)osd;
305 else
306 return false;
307 }
308 catch (Exception e)
309 {
310 return false;
311 }
312 start = (int)ms.Position;
313 }
314
315 OSDMap map = (OSDMap)meshOsd;
316 OSDMap tmpmap;
317
318 int highlod_size = 0;
319 int medlod_size = 0;
320 int lowlod_size = 0;
321 int lowestlod_size = 0;
322 int skin_size = 0;
323
324 int hulls_size = 0;
325 int phys_nhulls;
326 int phys_hullsvertices = 0;
327
328 int physmesh_size = 0;
329 int phys_ntriangles = 0;
330
331 int submesh_offset = -1;
332
333 if (map.ContainsKey("physics_convex"))
334 {
335 tmpmap = (OSDMap)map["physics_convex"];
336 if (tmpmap.ContainsKey("offset"))
337 submesh_offset = tmpmap["offset"].AsInteger() + start;
338 if (tmpmap.ContainsKey("size"))
339 hulls_size = tmpmap["size"].AsInteger();
340 }
341
342 if (submesh_offset < 0 || hulls_size == 0)
343 {
344 error = "Missing physics_convex block";
345 return false;
346 }
347
348 if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
349 {
350 error = "Bad physics_convex block";
351 return false;
352 }
353
354 submesh_offset = -1;
355
356 // only look for LOD meshs sizes
357
358 if (map.ContainsKey("high_lod"))
359 {
360 tmpmap = (OSDMap)map["high_lod"];
361 // see at least if there is a offset for this one
362 if (tmpmap.ContainsKey("offset"))
363 submesh_offset = tmpmap["offset"].AsInteger() + start;
364 if (tmpmap.ContainsKey("size"))
365 highlod_size = tmpmap["size"].AsInteger();
366 }
367
368 if (submesh_offset < 0 || highlod_size <= 0)
369 {
370 error = "Missing high_lod block";
371 return false;
372 }
373
374 bool haveprev = true;
375
376 if (map.ContainsKey("medium_lod"))
377 {
378 tmpmap = (OSDMap)map["medium_lod"];
379 if (tmpmap.ContainsKey("size"))
380 medlod_size = tmpmap["size"].AsInteger();
381 else
382 haveprev = false;
383 }
384
385 if (haveprev && map.ContainsKey("low_lod"))
386 {
387 tmpmap = (OSDMap)map["low_lod"];
388 if (tmpmap.ContainsKey("size"))
389 lowlod_size = tmpmap["size"].AsInteger();
390 else
391 haveprev = false;
392 }
393
394 if (haveprev && map.ContainsKey("lowest_lod"))
395 {
396 tmpmap = (OSDMap)map["lowest_lod"];
397 if (tmpmap.ContainsKey("size"))
398 lowestlod_size = tmpmap["size"].AsInteger();
399 }
400
401 if (map.ContainsKey("skin"))
402 {
403 tmpmap = (OSDMap)map["skin"];
404 if (tmpmap.ContainsKey("size"))
405 skin_size = tmpmap["size"].AsInteger();
406 }
407
408 cost.highLODSize = highlod_size;
409 cost.medLODSize = medlod_size;
410 cost.lowLODSize = lowlod_size;
411 cost.lowestLODSize = lowestlod_size;
412
413 submesh_offset = -1;
414
415 tmpmap = null;
416 if(map.ContainsKey("physics_mesh"))
417 tmpmap = (OSDMap)map["physics_mesh"];
418 else if (map.ContainsKey("physics_shape")) // old naming
419 tmpmap = (OSDMap)map["physics_shape"];
420
421 if(tmpmap != null)
422 {
423 if (tmpmap.ContainsKey("offset"))
424 submesh_offset = tmpmap["offset"].AsInteger() + start;
425 if (tmpmap.ContainsKey("size"))
426 physmesh_size = tmpmap["size"].AsInteger();
427
428 if (submesh_offset >= 0 || physmesh_size > 0)
429 {
430
431 if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
432 {
433 error = "Model data parsing error";
434 return false;
435 }
436 }
437 }
438
439 // upload is done in convex shape type so only one hull
440 phys_hullsvertices++;
441 cost.physicsCost = 0.04f * phys_hullsvertices;
442
443 float sfee;
444
445 sfee = data.Length; // start with total compressed data size
446
447 // penalize lod meshs that should be more builder optimized
448 sfee += medSizeWth * medlod_size;
449 sfee += lowSizeWth * lowlod_size;
450 sfee += lowestSizeWth * lowlod_size;
451
452 // physics
453 // favor potencial optimized meshs versus automatic decomposition
454 if (physmesh_size != 0)
455 sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull
456 else
457 sfee += physHullSizeWth * hulls_size;
458
459 // bytes to money
460 sfee *= bytecost;
461
462 cost.costFee = sfee;
463 return true;
464 }
465
466 // parses a LOD or physics mesh component
467 private bool submesh(byte[] data, int offset, int size, out int ntriangles)
468 {
469 ntriangles = 0;
470
471 OSD decodedMeshOsd = new OSD();
472 byte[] meshBytes = new byte[size];
473 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
474 try
475 {
476 using (MemoryStream inMs = new MemoryStream(meshBytes))
477 {
478 using (MemoryStream outMs = new MemoryStream())
479 {
480 using (ZOutputStream zOut = new ZOutputStream(outMs))
481 {
482 byte[] readBuffer = new byte[4096];
483 int readLen = 0;
484 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
485 {
486 zOut.Write(readBuffer, 0, readLen);
487 }
488 zOut.Flush();
489 outMs.Seek(0, SeekOrigin.Begin);
490
491 byte[] decompressedBuf = outMs.GetBuffer();
492 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
493 }
494 }
495 }
496 }
497 catch (Exception e)
498 {
499 return false;
500 }
501
502 OSDArray decodedMeshOsdArray = null;
503 if ((!decodedMeshOsd is OSDArray))
504 return false;
505
506 byte[] dummy;
507
508 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
509 foreach (OSD subMeshOsd in decodedMeshOsdArray)
510 {
511 if (subMeshOsd is OSDMap)
512 {
513 OSDMap subtmpmap = (OSDMap)subMeshOsd;
514 if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"]))
515 continue;
516
517 if (!subtmpmap.ContainsKey("Position"))
518 return false;
519
520 if (subtmpmap.ContainsKey("TriangleList"))
521 {
522 dummy = subtmpmap["TriangleList"].AsBinary();
523 ntriangles += dummy.Length / bytesPerCoord;
524 }
525 else
526 return false;
527 }
528 }
529
530 return true;
531 }
532
533 // parses convex hulls component
534 private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls)
535 {
536 nvertices = 0;
537 nhulls = 1;
538
539 OSD decodedMeshOsd = new OSD();
540 byte[] meshBytes = new byte[size];
541 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
542 try
543 {
544 using (MemoryStream inMs = new MemoryStream(meshBytes))
545 {
546 using (MemoryStream outMs = new MemoryStream())
547 {
548 using (ZOutputStream zOut = new ZOutputStream(outMs))
549 {
550 byte[] readBuffer = new byte[4096];
551 int readLen = 0;
552 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
553 {
554 zOut.Write(readBuffer, 0, readLen);
555 }
556 zOut.Flush();
557 outMs.Seek(0, SeekOrigin.Begin);
558
559 byte[] decompressedBuf = outMs.GetBuffer();
560 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
561 }
562 }
563 }
564 }
565 catch (Exception e)
566 {
567 return false;
568 }
569
570 OSDMap cmap = (OSDMap)decodedMeshOsd;
571 if (cmap == null)
572 return false;
573
574 byte[] dummy;
575
576 // must have one of this
577 if (cmap.ContainsKey("BoundingVerts"))
578 {
579 dummy = cmap["BoundingVerts"].AsBinary();
580 nvertices = dummy.Length / bytesPerCoord;
581 }
582 else
583 return false;
584
585/* upload is done with convex shape type
586 if (cmap.ContainsKey("HullList"))
587 {
588 dummy = cmap["HullList"].AsBinary();
589 nhulls += dummy.Length;
590 }
591
592
593 if (cmap.ContainsKey("Positions"))
594 {
595 dummy = cmap["Positions"].AsBinary();
596 nvertices = dummy.Length / bytesPerCoord;
597 }
598 */
599
600 return true;
601 }
602
603 // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length
604 private float streamingCost(ameshCostParam curCost, float sqdiam)
605 {
606 // compute efective areas
607 float ma = 262144f;
608
609 float mh = sqdiam * highLodFactor;
610 if (mh > ma)
611 mh = ma;
612 float mm = sqdiam * midLodFactor;
613 if (mm > ma)
614 mm = ma;
615
616 float ml = sqdiam * lowLodFactor;
617 if (ml > ma)
618 ml = ma;
619
620 float mlst = ma;
621
622 mlst -= ml;
623 ml -= mm;
624 mm -= mh;
625
626 if (mlst < 1.0f)
627 mlst = 1.0f;
628 if (ml < 1.0f)
629 ml = 1.0f;
630 if (mm < 1.0f)
631 mm = 1.0f;
632 if (mh < 1.0f)
633 mh = 1.0f;
634
635 ma = mlst + ml + mm + mh;
636
637 // get LODs compressed sizes
638 // giving 384 bytes bonus
639 int lst = curCost.lowestLODSize - 384;
640 int l = curCost.lowLODSize - 384;
641 int m = curCost.medLODSize - 384;
642 int h = curCost.highLODSize - 384;
643
644 // use previus higher LOD size on missing ones
645 if (m <= 0)
646 m = h;
647 if (l <= 0)
648 l = m;
649 if (lst <= 0)
650 lst = l;
651
652 // force minumum sizes
653 if (lst < 16)
654 lst = 16;
655 if (l < 16)
656 l = 16;
657 if (m < 16)
658 m = 16;
659 if (h < 16)
660 h = 16;
661
662 // compute cost weighted by relative effective areas
663 float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh;
664 cost /= ma;
665
666 cost *= 0.004f; // overall tunning parameter
667
668 return cost;
669 }
670 }
671}