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 1d4c7f0..762e22a 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(
@@ -399,62 +481,176 @@ namespace OpenSim.Region.ClientStack.Linden
399 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 481 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
400 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 482 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
401 483
484 // start by getting the client
485 IClientAPI client = null;
486 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
487
488 // check current state so we only have one service at a time
489 lock (m_ModelCost)
490 {
491 switch (m_FileAgentInventoryState)
492 {
493 case FileAgentInventoryState.processRequest:
494 case FileAgentInventoryState.processUpload:
495 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
496 resperror.message = "Uploader busy processing previus request";
497 resperror.identifier = UUID.Zero;
498
499 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
500 errorResponse.uploader = "";
501 errorResponse.state = "error";
502 errorResponse.error = resperror;
503 return errorResponse;
504 break;
505 case FileAgentInventoryState.waitUpload:
506 // todo stop current uploader server
507 break;
508 case FileAgentInventoryState.idle:
509 default:
510 break;
511 }
512
513 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
514 }
515
516 int cost = 0;
517 int nreqtextures = 0;
518 int nreqmeshs= 0;
519 int nreqinstances = 0;
520 bool IsAtestUpload = false;
521
522 string assetName = llsdRequest.name;
523
524 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
525
402 if (llsdRequest.asset_type == "texture" || 526 if (llsdRequest.asset_type == "texture" ||
403 llsdRequest.asset_type == "animation" || 527 llsdRequest.asset_type == "animation" ||
528 llsdRequest.asset_type == "mesh" ||
404 llsdRequest.asset_type == "sound") 529 llsdRequest.asset_type == "sound")
405 { 530 {
406 ScenePresence avatar = null; 531 ScenePresence avatar = null;
407 IClientAPI client = null;
408 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 532 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
409 533
410 // check user level 534 // check user level
411 if (avatar != null) 535 if (avatar != null)
412 { 536 {
413 client = avatar.ControllingClient;
414
415 if (avatar.UserLevel < m_levelUpload) 537 if (avatar.UserLevel < m_levelUpload)
416 { 538 {
417 if (client != null) 539 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
418 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 540 resperror.message = "Insufficient permissions to upload";
541 resperror.identifier = UUID.Zero;
419 542
420 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 543 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
421 errorResponse.uploader = ""; 544 errorResponse.uploader = "";
422 errorResponse.state = "error"; 545 errorResponse.state = "error";
546 errorResponse.error = resperror;
547 lock (m_ModelCost)
548 m_FileAgentInventoryState = FileAgentInventoryState.idle;
423 return errorResponse; 549 return errorResponse;
424 } 550 }
425 } 551 }
426 552
427 // check funds 553 // check test upload and funds
428 if (client != null) 554 if (client != null)
429 { 555 {
430 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 556 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
431 557
558 int baseCost = 0;
432 if (mm != null) 559 if (mm != null)
560 baseCost = mm.UploadCharge;
561
562 string warning = String.Empty;
563
564 if (llsdRequest.asset_type == "mesh")
433 { 565 {
434 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 566 string error;
567 int modelcost;
568
569 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
570 meshcostdata, out error, ref warning))
435 { 571 {
436 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 572 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
573 resperror.message = error;
574 resperror.identifier = UUID.Zero;
437 575
438 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 576 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
439 errorResponse.uploader = ""; 577 errorResponse.uploader = "";
440 errorResponse.state = "error"; 578 errorResponse.state = "error";
579 errorResponse.error = resperror;
580
581 lock (m_ModelCost)
582 m_FileAgentInventoryState = FileAgentInventoryState.idle;
441 return errorResponse; 583 return errorResponse;
442 } 584 }
585 cost = modelcost;
586 }
587 else
588 {
589 cost = baseCost;
590 }
591
592 if (cost > 0 && mm != null)
593 {
594 // check for test upload
595
596 if (m_ForceFreeTestUpload) // all are test
597 {
598 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
599 assetName = "TEST-" + assetName;
600
601 IsAtestUpload = true;
602 }
603
604 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
605 {
606
607 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
608 }
609
610
611 if(IsAtestUpload) // let user know, still showing cost estimation
612 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";
613
614 // check funds
615 else
616 {
617 if (!mm.UploadCovered(client.AgentId, (int)cost))
618 {
619 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
620 resperror.message = "Insuficient funds";
621 resperror.identifier = UUID.Zero;
622
623 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
624 errorResponse.uploader = "";
625 errorResponse.state = "error";
626 errorResponse.error = resperror;
627 lock (m_ModelCost)
628 m_FileAgentInventoryState = FileAgentInventoryState.idle;
629 return errorResponse;
630 }
631 }
443 } 632 }
633
634 if (client != null && warning != String.Empty)
635 client.SendAgentAlertMessage(warning, true);
444 } 636 }
445 } 637 }
446 638
447 string assetName = llsdRequest.name;
448 string assetDes = llsdRequest.description; 639 string assetDes = llsdRequest.description;
449 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 640 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
450 UUID newAsset = UUID.Random(); 641 UUID newAsset = UUID.Random();
451 UUID newInvItem = UUID.Random(); 642 UUID newInvItem = UUID.Random();
452 UUID parentFolder = llsdRequest.folder_id; 643 UUID parentFolder = llsdRequest.folder_id;
453 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 644 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
645 UUID texturesFolder = UUID.Zero;
646
647 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
648 texturesFolder = llsdRequest.texture_folder_id;
454 649
455 AssetUploader uploader = 650 AssetUploader uploader =
456 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 651 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
457 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 652 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
653 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
458 654
459 m_HostCapsObj.HttpListener.AddStreamHandler( 655 m_HostCapsObj.HttpListener.AddStreamHandler(
460 new BinaryStreamHandler( 656 new BinaryStreamHandler(
@@ -472,10 +668,22 @@ namespace OpenSim.Region.ClientStack.Linden
472 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 668 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
473 uploaderPath; 669 uploaderPath;
474 670
671
475 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 672 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
476 uploadResponse.uploader = uploaderURL; 673 uploadResponse.uploader = uploaderURL;
477 uploadResponse.state = "upload"; 674 uploadResponse.state = "upload";
675 uploadResponse.upload_price = (int)cost;
676
677 if (llsdRequest.asset_type == "mesh")
678 {
679 uploadResponse.data = meshcostdata;
680 }
681
478 uploader.OnUpLoad += UploadCompleteHandler; 682 uploader.OnUpLoad += UploadCompleteHandler;
683
684 lock (m_ModelCost)
685 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
686
479 return uploadResponse; 687 return uploadResponse;
480 } 688 }
481 689
@@ -487,8 +695,14 @@ namespace OpenSim.Region.ClientStack.Linden
487 /// <param name="data"></param> 695 /// <param name="data"></param>
488 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 696 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
489 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 697 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
490 string assetType) 698 string assetType, int cost,
699 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
700 bool IsAtestUpload, ref string error)
491 { 701 {
702
703 lock (m_ModelCost)
704 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
705
492 m_log.DebugFormat( 706 m_log.DebugFormat(
493 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 707 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
494 assetID, inventoryItem, inventoryType, assetType); 708 assetID, inventoryItem, inventoryType, assetType);
@@ -496,117 +710,247 @@ namespace OpenSim.Region.ClientStack.Linden
496 sbyte assType = 0; 710 sbyte assType = 0;
497 sbyte inType = 0; 711 sbyte inType = 0;
498 712
713 IClientAPI client = null;
714
715 UUID owner_id = m_HostCapsObj.AgentID;
716 UUID creatorID;
717
718 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
719
720 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
721
722 if (istest && m_testAssetsCreatorID != UUID.Zero)
723 creatorID = m_testAssetsCreatorID;
724 else
725 creatorID = owner_id;
726
727 string creatorIDstr = creatorID.ToString();
728
729 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
730 if (mm != null)
731 {
732 // make sure client still has enougth credit
733 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
734 {
735 error = "Insufficient funds.";
736 return;
737 }
738 }
739
740 // strings to types
499 if (inventoryType == "sound") 741 if (inventoryType == "sound")
500 { 742 {
501 inType = 1; 743 inType = (sbyte)InventoryType.Sound;
502 assType = 1; 744 assType = (sbyte)AssetType.Sound;
503 } 745 }
504 else if (inventoryType == "animation") 746 else if (inventoryType == "animation")
505 { 747 {
506 inType = 19; 748 inType = (sbyte)InventoryType.Animation;
507 assType = 20; 749 assType = (sbyte)AssetType.Animation;
508 } 750 }
509 else if (inventoryType == "wearable") 751 else if (inventoryType == "wearable")
510 { 752 {
511 inType = 18; 753 inType = (sbyte)InventoryType.Wearable;
512 switch (assetType) 754 switch (assetType)
513 { 755 {
514 case "bodypart": 756 case "bodypart":
515 assType = 13; 757 assType = (sbyte)AssetType.Bodypart;
516 break; 758 break;
517 case "clothing": 759 case "clothing":
518 assType = 5; 760 assType = (sbyte)AssetType.Clothing;
519 break; 761 break;
520 } 762 }
521 } 763 }
522 else if (inventoryType == "object") 764 else if (inventoryType == "object")
523 { 765 {
524 inType = (sbyte)InventoryType.Object; 766 if (assetType == "mesh") // this code for now is for mesh models uploads only
525 assType = (sbyte)AssetType.Object;
526
527 List<Vector3> positions = new List<Vector3>();
528 List<Quaternion> rotations = new List<Quaternion>();
529 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
530 OSDArray instance_list = (OSDArray)request["instance_list"];
531 OSDArray mesh_list = (OSDArray)request["mesh_list"];
532 OSDArray texture_list = (OSDArray)request["texture_list"];
533 SceneObjectGroup grp = null;
534
535 List<UUID> textures = new List<UUID>();
536 for (int i = 0; i < texture_list.Count; i++)
537 { 767 {
538 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 768 inType = (sbyte)InventoryType.Object;
539 textureAsset.Data = texture_list[i].AsBinary(); 769 assType = (sbyte)AssetType.Object;
540 m_assetService.Store(textureAsset);
541 textures.Add(textureAsset.FullID);
542 }
543 770
544 for (int i = 0; i < mesh_list.Count; i++) 771 List<Vector3> positions = new List<Vector3>();
545 { 772 List<Quaternion> rotations = new List<Quaternion>();
546 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 773 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
547 774
548 Primitive.TextureEntry textureEntry 775 // compare and get updated information
549 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
550 OSDMap inner_instance_list = (OSDMap)instance_list[i];
551 776
552 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 777 bool mismatchError = true;
553 for (uint face = 0; face < face_list.Count; face++) 778
779 while (mismatchError)
554 { 780 {
555 OSDMap faceMap = (OSDMap)face_list[(int)face]; 781 mismatchError = false;
556 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 782 }
557 if(faceMap.ContainsKey("fullbright"))
558 f.Fullbright = faceMap["fullbright"].AsBoolean();
559 if (faceMap.ContainsKey ("diffuse_color"))
560 f.RGBA = faceMap["diffuse_color"].AsColor4();
561 783
562 int textureNum = faceMap["image"].AsInteger(); 784 if (mismatchError)
563 float imagerot = faceMap["imagerot"].AsInteger(); 785 {
564 float offsets = (float)faceMap["offsets"].AsReal(); 786 error = "Upload and fee estimation information don't match";
565 float offsett = (float)faceMap["offsett"].AsReal(); 787 lock (m_ModelCost)
566 float scales = (float)faceMap["scales"].AsReal(); 788 m_FileAgentInventoryState = FileAgentInventoryState.idle;
567 float scalet = (float)faceMap["scalet"].AsReal();
568 789
569 if(imagerot != 0) 790 return;
570 f.Rotation = imagerot; 791 }
571 792
572 if(offsets != 0) 793 OSDArray instance_list = (OSDArray)request["instance_list"];
573 f.OffsetU = offsets; 794 OSDArray mesh_list = (OSDArray)request["mesh_list"];
795 OSDArray texture_list = (OSDArray)request["texture_list"];
796 SceneObjectGroup grp = null;
574 797
575 if (offsett != 0) 798 // create and store texture assets
576 f.OffsetV = offsett; 799 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
800 texturesFolder != UUID.Zero);
577 801
578 if (scales != 0)
579 f.RepeatU = scales;
580 802
581 if (scalet != 0) 803 List<UUID> textures = new List<UUID>();
582 f.RepeatV = scalet;
583 804
584 if (textures.Count > textureNum) 805
585 f.TextureID = textures[textureNum]; 806 if (doTextInv)
586 else 807 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
587 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
588 808
589 textureEntry.FaceTextures[face] = f; 809 if(client == null) // don't put textures in inventory if there is no client
810 doTextInv = false;
811
812 for (int i = 0; i < texture_list.Count; i++)
813 {
814 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
815 textureAsset.Data = texture_list[i].AsBinary();
816 if (istest)
817 textureAsset.Local = true;
818 m_assetService.Store(textureAsset);
819 textures.Add(textureAsset.FullID);
820
821 if (doTextInv)
822 {
823 string name = assetName;
824 if (name.Length > 25)
825 name = name.Substring(0, 24);
826 name += "_Texture#" + i.ToString();
827 InventoryItemBase texitem = new InventoryItemBase();
828 texitem.Owner = m_HostCapsObj.AgentID;
829 texitem.CreatorId = creatorIDstr;
830 texitem.CreatorData = String.Empty;
831 texitem.ID = UUID.Random();
832 texitem.AssetID = textureAsset.FullID;
833 texitem.Description = "mesh model texture";
834 texitem.Name = name;
835 texitem.AssetType = (int)AssetType.Texture;
836 texitem.InvType = (int)InventoryType.Texture;
837 texitem.Folder = texturesFolder;
838
839 texitem.CurrentPermissions
840 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
841
842 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
843 texitem.EveryOnePermissions = 0;
844 texitem.NextPermissions = (uint)PermissionMask.All;
845 texitem.CreationDate = Util.UnixTimeSinceEpoch();
846
847 m_Scene.AddInventoryItem(client, texitem);
848 texitem = null;
849 }
590 } 850 }
591 851
592 pbs.TextureEntry = textureEntry.GetBytes(); 852 // create and store meshs assets
853 List<UUID> meshAssets = new List<UUID>();
854 for (int i = 0; i < mesh_list.Count; i++)
855 {
856 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
857 meshAsset.Data = mesh_list[i].AsBinary();
858 if (istest)
859 meshAsset.Local = true;
860 m_assetService.Store(meshAsset);
861 meshAssets.Add(meshAsset.FullID);
862 }
863
864 int skipedMeshs = 0;
865 // build prims from instances
866 for (int i = 0; i < instance_list.Count; i++)
867 {
868 OSDMap inner_instance_list = (OSDMap)instance_list[i];
869
870 // skip prims that are 2 small
871 Vector3 scale = inner_instance_list["scale"].AsVector3();
872
873 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
874 {
875 skipedMeshs++;
876 continue;
877 }
878
879 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
880
881 Primitive.TextureEntry textureEntry
882 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
883
593 884
594 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 885 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
595 meshAsset.Data = mesh_list[i].AsBinary(); 886 for (uint face = 0; face < face_list.Count; face++)
596 m_assetService.Store(meshAsset); 887 {
888 OSDMap faceMap = (OSDMap)face_list[(int)face];
889 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
890 if (faceMap.ContainsKey("fullbright"))
891 f.Fullbright = faceMap["fullbright"].AsBoolean();
892 if (faceMap.ContainsKey("diffuse_color"))
893 f.RGBA = faceMap["diffuse_color"].AsColor4();
894
895 int textureNum = faceMap["image"].AsInteger();
896 float imagerot = faceMap["imagerot"].AsInteger();
897 float offsets = (float)faceMap["offsets"].AsReal();
898 float offsett = (float)faceMap["offsett"].AsReal();
899 float scales = (float)faceMap["scales"].AsReal();
900 float scalet = (float)faceMap["scalet"].AsReal();
901
902 if (imagerot != 0)
903 f.Rotation = imagerot;
904
905 if (offsets != 0)
906 f.OffsetU = offsets;
597 907
598 pbs.SculptEntry = true; 908 if (offsett != 0)
599 pbs.SculptTexture = meshAsset.FullID; 909 f.OffsetV = offsett;
600 pbs.SculptType = (byte)SculptType.Mesh;
601 pbs.SculptData = meshAsset.Data;
602 910
603 Vector3 position = inner_instance_list["position"].AsVector3(); 911 if (scales != 0)
604 Vector3 scale = inner_instance_list["scale"].AsVector3(); 912 f.RepeatU = scales;
605 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 913
914 if (scalet != 0)
915 f.RepeatV = scalet;
916
917 if (textures.Count > textureNum)
918 f.TextureID = textures[textureNum];
919 else
920 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
921
922 textureEntry.FaceTextures[face] = f;
923 }
924
925 pbs.TextureEntry = textureEntry.GetBytes();
926
927 bool hasmesh = false;
928 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
929 {
930 int meshindx = inner_instance_list["mesh"].AsInteger();
931 if (meshAssets.Count > meshindx)
932 {
933 pbs.SculptEntry = true;
934 pbs.SculptType = (byte)SculptType.Mesh;
935 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
936 // data will be requested from asset on rez (i hope)
937 hasmesh = true;
938 }
939 }
940
941 Vector3 position = inner_instance_list["position"].AsVector3();
942 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
943
944 // for now viwers do send fixed defaults
945 // but this may change
946// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
947 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
948 if(hasmesh)
949 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
950// int material = inner_instance_list["material"].AsInteger();
951 byte material = (byte)Material.Wood;
606 952
607// no longer used - begin ------------------------ 953// no longer used - begin ------------------------
608// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
609// int material = inner_instance_list["material"].AsInteger();
610// int mesh = inner_instance_list["mesh"].AsInteger(); 954// int mesh = inner_instance_list["mesh"].AsInteger();
611 955
612// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 956// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -621,24 +965,49 @@ namespace OpenSim.Region.ClientStack.Linden
621// UUID owner_id = permissions["owner_id"].AsUUID(); 965// UUID owner_id = permissions["owner_id"].AsUUID();
622// int owner_mask = permissions["owner_mask"].AsInteger(); 966// int owner_mask = permissions["owner_mask"].AsInteger();
623// no longer used - end ------------------------ 967// no longer used - end ------------------------
968
969
970 SceneObjectPart prim
971 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
972
973 prim.Scale = scale;
974 rotations.Add(rotation);
975 positions.Add(position);
976 prim.UUID = UUID.Random();
977 prim.CreatorID = creatorID;
978 prim.OwnerID = owner_id;
979 prim.GroupID = UUID.Zero;
980 prim.LastOwnerID = creatorID;
981 prim.CreationDate = Util.UnixTimeSinceEpoch();
982
983 if (grp == null)
984 prim.Name = assetName;
985 else
986 prim.Name = assetName + "#" + i.ToString();
624 987
625 UUID owner_id = m_HostCapsObj.AgentID; 988 prim.EveryoneMask = 0;
989 prim.GroupMask = 0;
626 990
627 SceneObjectPart prim 991 if (restrictPerms)
628 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 992 {
993 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
994 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
995 prim.NextOwnerMask = 0;
996 }
997 else
998 {
999 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1000 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1001 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1002 }
1003
1004 if(istest)
1005 prim.Description = "For testing only. Other uses are prohibited";
1006 else
1007 prim.Description = "";
629 1008
630 prim.Scale = scale; 1009 prim.Material = material;
631 //prim.OffsetPosition = position; 1010 prim.PhysicsShapeType = physicsShapeType;
632 rotations.Add(rotation);
633 positions.Add(position);
634 prim.UUID = UUID.Random();
635 prim.CreatorID = owner_id;
636 prim.OwnerID = owner_id;
637 prim.GroupID = UUID.Zero;
638 prim.LastOwnerID = prim.OwnerID;
639 prim.CreationDate = Util.UnixTimeSinceEpoch();
640 prim.Name = assetName;
641 prim.Description = "";
642 1011
643// prim.BaseMask = (uint)base_mask; 1012// prim.BaseMask = (uint)base_mask;
644// prim.EveryoneMask = (uint)everyone_mask; 1013// prim.EveryoneMask = (uint)everyone_mask;
@@ -646,52 +1015,64 @@ namespace OpenSim.Region.ClientStack.Linden
646// prim.NextOwnerMask = (uint)next_owner_mask; 1015// prim.NextOwnerMask = (uint)next_owner_mask;
647// prim.OwnerMask = (uint)owner_mask; 1016// prim.OwnerMask = (uint)owner_mask;
648 1017
649 if (grp == null) 1018 if (grp == null)
650 grp = new SceneObjectGroup(prim); 1019 {
651 else 1020 grp = new SceneObjectGroup(prim);
652 grp.AddPart(prim); 1021 grp.LastOwnerID = creatorID;
653 } 1022 }
1023 else
1024 grp.AddPart(prim);
1025 }
654 1026
655 Vector3 rootPos = positions[0]; 1027 Vector3 rootPos = positions[0];
656 1028
657 if (grp.Parts.Length > 1) 1029 if (grp.Parts.Length > 1)
658 { 1030 {
659 // Fix first link number 1031 // Fix first link number
660 grp.RootPart.LinkNum++; 1032 grp.RootPart.LinkNum++;
661 1033
662 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1034 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
663 Quaternion tmprot; 1035 Quaternion tmprot;
664 Vector3 offset; 1036 Vector3 offset;
665 1037
666 // fix children rotations and positions 1038 // fix children rotations and positions
667 for (int i = 1; i < rotations.Count; i++) 1039 for (int i = 1; i < rotations.Count; i++)
668 { 1040 {
669 tmprot = rotations[i]; 1041 tmprot = rotations[i];
670 tmprot = rootRotConj * tmprot; 1042 tmprot = rootRotConj * tmprot;
1043
1044 grp.Parts[i].RotationOffset = tmprot;
671 1045
672 grp.Parts[i].RotationOffset = tmprot; 1046 offset = positions[i] - rootPos;
673 1047
674 offset = positions[i] - rootPos; 1048 offset *= rootRotConj;
1049 grp.Parts[i].OffsetPosition = offset;
1050 }
675 1051
676 offset *= rootRotConj; 1052 grp.AbsolutePosition = rootPos;
677 grp.Parts[i].OffsetPosition = offset; 1053 grp.UpdateGroupRotationR(rotations[0]);
1054 }
1055 else
1056 {
1057 grp.AbsolutePosition = rootPos;
1058 grp.UpdateGroupRotationR(rotations[0]);
678 } 1059 }
679 1060
680 grp.AbsolutePosition = rootPos; 1061 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
681 grp.UpdateGroupRotationR(rotations[0]);
682 } 1062 }
683 else 1063
1064 else // not a mesh model
684 { 1065 {
685 grp.AbsolutePosition = rootPos; 1066 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
686 grp.UpdateGroupRotationR(rotations[0]); 1067 return;
687 } 1068 }
688
689 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
690 } 1069 }
691 1070
692 AssetBase asset; 1071 AssetBase asset;
693 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1072 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
694 asset.Data = data; 1073 asset.Data = data;
1074 if (istest)
1075 asset.Local = true;
695 if (AddNewAsset != null) 1076 if (AddNewAsset != null)
696 AddNewAsset(asset); 1077 AddNewAsset(asset);
697 else if (m_assetService != null) 1078 else if (m_assetService != null)
@@ -699,11 +1080,17 @@ namespace OpenSim.Region.ClientStack.Linden
699 1080
700 InventoryItemBase item = new InventoryItemBase(); 1081 InventoryItemBase item = new InventoryItemBase();
701 item.Owner = m_HostCapsObj.AgentID; 1082 item.Owner = m_HostCapsObj.AgentID;
702 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1083 item.CreatorId = creatorIDstr;
703 item.CreatorData = String.Empty; 1084 item.CreatorData = String.Empty;
704 item.ID = inventoryItem; 1085 item.ID = inventoryItem;
705 item.AssetID = asset.FullID; 1086 item.AssetID = asset.FullID;
706 item.Description = assetDescription; 1087 if (istest)
1088 {
1089 item.Description = "For testing only. Other uses are prohibited";
1090 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1091 }
1092 else
1093 item.Description = assetDescription;
707 item.Name = assetName; 1094 item.Name = assetName;
708 item.AssetType = assType; 1095 item.AssetType = assType;
709 item.InvType = inType; 1096 item.InvType = inType;
@@ -711,18 +1098,56 @@ namespace OpenSim.Region.ClientStack.Linden
711 1098
712 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1099 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
713 // (owner) permissions. This becomes a problem if next permissions are changed. 1100 // (owner) permissions. This becomes a problem if next permissions are changed.
714 item.CurrentPermissions
715 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
716 1101
717 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1102 if (restrictPerms)
718 item.EveryOnePermissions = 0; 1103 {
719 item.NextPermissions = (uint)PermissionMask.All; 1104 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1105 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1106 item.EveryOnePermissions = 0;
1107 item.NextPermissions = 0;
1108 }
1109 else
1110 {
1111 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1112 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1113 item.EveryOnePermissions = 0;
1114 item.NextPermissions = (uint)PermissionMask.Transfer;
1115 }
1116
720 item.CreationDate = Util.UnixTimeSinceEpoch(); 1117 item.CreationDate = Util.UnixTimeSinceEpoch();
721 1118
1119 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1120
722 if (AddNewInventoryItem != null) 1121 if (AddNewInventoryItem != null)
723 { 1122 {
724 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1123 if (istest)
1124 {
1125 m_Scene.AddInventoryItem(client, item);
1126/*
1127 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1128 if (client != null)
1129 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);
1130 */
1131 }
1132 else
1133 {
1134 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1135// if (client != null)
1136// {
1137// // let users see anything.. i don't so far
1138// string str;
1139// if (cost > 0)
1140// // dont remember where is money unit name to put here
1141// str = "Upload complete. charged " + cost.ToString() + "$";
1142// else
1143// str = "Upload complete";
1144// client.SendAgentAlertMessage(str, true);
1145// }
1146 }
725 } 1147 }
1148
1149 lock (m_ModelCost)
1150 m_FileAgentInventoryState = FileAgentInventoryState.idle;
726 } 1151 }
727 1152
728 /// <summary> 1153 /// <summary>
@@ -915,6 +1340,120 @@ namespace OpenSim.Region.ClientStack.Linden
915 return response; 1340 return response;
916 } 1341 }
917 1342
1343 public string GetObjectCost(string request, string path,
1344 string param, IOSHttpRequest httpRequest,
1345 IOSHttpResponse httpResponse)
1346 {
1347 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1348 OSDMap resp = new OSDMap();
1349
1350 OSDArray object_ids = (OSDArray)req["object_ids"];
1351
1352 for (int i = 0; i < object_ids.Count; i++)
1353 {
1354 UUID uuid = object_ids[i].AsUUID();
1355
1356 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1357
1358 if (part != null)
1359 {
1360 SceneObjectGroup grp = part.ParentGroup;
1361 if (grp != null)
1362 {
1363 float linksetCost;
1364 float linksetPhysCost;
1365 float partCost;
1366 float partPhysCost;
1367
1368 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1369
1370 OSDMap object_data = new OSDMap();
1371 object_data["linked_set_resource_cost"] = linksetCost;
1372 object_data["resource_cost"] = partCost;
1373 object_data["physics_cost"] = partPhysCost;
1374 object_data["linked_set_physics_cost"] = linksetPhysCost;
1375
1376 resp[uuid.ToString()] = object_data;
1377 }
1378 }
1379 }
1380
1381 string response = OSDParser.SerializeLLSDXmlString(resp);
1382 return response;
1383 }
1384
1385 public string ResourceCostSelected(string request, string path,
1386 string param, IOSHttpRequest httpRequest,
1387 IOSHttpResponse httpResponse)
1388 {
1389 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1390 OSDMap resp = new OSDMap();
1391
1392
1393 float phys=0;
1394 float stream=0;
1395 float simul=0;
1396
1397 if (req.ContainsKey("selected_roots"))
1398 {
1399 OSDArray object_ids = (OSDArray)req["selected_roots"];
1400
1401 // should go by SOG suming costs for all parts
1402 // ll v3 works ok with several objects select we get the list and adds ok
1403 // FS calls per object so results are wrong guess fs bug
1404 for (int i = 0; i < object_ids.Count; i++)
1405 {
1406 UUID uuid = object_ids[i].AsUUID();
1407 float Physc;
1408 float simulc;
1409 float streamc;
1410
1411 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1412 if (grp != null)
1413 {
1414 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1415 phys += Physc;
1416 stream += streamc;
1417 simul += simulc;
1418 }
1419 }
1420 }
1421 else if (req.ContainsKey("selected_prims"))
1422 {
1423 OSDArray object_ids = (OSDArray)req["selected_prims"];
1424
1425 // don't see in use in any of the 2 viewers
1426 // guess it should be for edit linked but... nothing
1427 // should go to SOP per part
1428 for (int i = 0; i < object_ids.Count; i++)
1429 {
1430 UUID uuid = object_ids[i].AsUUID();
1431
1432 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1433 if (part != null)
1434 {
1435 phys += part.PhysicsCost;
1436 stream += part.StreamingCost;
1437 simul += part.SimulationCost;
1438 }
1439 }
1440 }
1441
1442 if (simul != 0)
1443 {
1444 OSDMap object_data = new OSDMap();
1445
1446 object_data["physics"] = phys;
1447 object_data["streaming"] = stream;
1448 object_data["simulation"] = simul;
1449
1450 resp["selected"] = object_data;
1451 }
1452
1453 string response = OSDParser.SerializeLLSDXmlString(resp);
1454 return response;
1455 }
1456
918 public string UpdateAgentInformation(string request, string path, 1457 public string UpdateAgentInformation(string request, string path,
919 string param, IOSHttpRequest httpRequest, 1458 string param, IOSHttpRequest httpRequest,
920 IOSHttpResponse httpResponse) 1459 IOSHttpResponse httpResponse)
@@ -934,6 +1473,10 @@ namespace OpenSim.Region.ClientStack.Linden
934 1473
935 public class AssetUploader 1474 public class AssetUploader
936 { 1475 {
1476 private static readonly ILog m_log =
1477 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1478
1479
937 public event UpLoadedAsset OnUpLoad; 1480 public event UpLoadedAsset OnUpLoad;
938 private UpLoadedAsset handlerUpLoad = null; 1481 private UpLoadedAsset handlerUpLoad = null;
939 1482
@@ -948,10 +1491,21 @@ namespace OpenSim.Region.ClientStack.Linden
948 1491
949 private string m_invType = String.Empty; 1492 private string m_invType = String.Empty;
950 private string m_assetType = String.Empty; 1493 private string m_assetType = String.Empty;
1494 private int m_cost;
1495 private string m_error = String.Empty;
1496
1497 private Timer m_timeoutTimer = new Timer();
1498 private UUID m_texturesFolder;
1499 private int m_nreqtextures;
1500 private int m_nreqmeshs;
1501 private int m_nreqinstances;
1502 private bool m_IsAtestUpload;
951 1503
952 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1504 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
953 UUID parentFolderID, string invType, string assetType, string path, 1505 UUID parentFolderID, string invType, string assetType, string path,
954 IHttpServer httpServer, bool dumpAssetsToFile) 1506 IHttpServer httpServer, bool dumpAssetsToFile,
1507 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1508 bool IsAtestUpload)
955 { 1509 {
956 m_assetName = assetName; 1510 m_assetName = assetName;
957 m_assetDes = description; 1511 m_assetDes = description;
@@ -963,6 +1517,18 @@ namespace OpenSim.Region.ClientStack.Linden
963 m_assetType = assetType; 1517 m_assetType = assetType;
964 m_invType = invType; 1518 m_invType = invType;
965 m_dumpAssetsToFile = dumpAssetsToFile; 1519 m_dumpAssetsToFile = dumpAssetsToFile;
1520 m_cost = totalCost;
1521
1522 m_texturesFolder = texturesFolder;
1523 m_nreqtextures = nreqtextures;
1524 m_nreqmeshs = nreqmeshs;
1525 m_nreqinstances = nreqinstances;
1526 m_IsAtestUpload = IsAtestUpload;
1527
1528 m_timeoutTimer.Elapsed += TimedOut;
1529 m_timeoutTimer.Interval = 120000;
1530 m_timeoutTimer.AutoReset = false;
1531 m_timeoutTimer.Start();
966 } 1532 }
967 1533
968 /// <summary> 1534 /// <summary>
@@ -977,12 +1543,14 @@ namespace OpenSim.Region.ClientStack.Linden
977 UUID inv = inventoryItemID; 1543 UUID inv = inventoryItemID;
978 string res = String.Empty; 1544 string res = String.Empty;
979 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1545 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1546/*
980 uploadComplete.new_asset = newAssetID.ToString(); 1547 uploadComplete.new_asset = newAssetID.ToString();
981 uploadComplete.new_inventory_item = inv; 1548 uploadComplete.new_inventory_item = inv;
982 uploadComplete.state = "complete"; 1549 uploadComplete.state = "complete";
983 1550
984 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1551 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
985 1552*/
1553 m_timeoutTimer.Stop();
986 httpListener.RemoveStreamHandler("POST", uploaderPath); 1554 httpListener.RemoveStreamHandler("POST", uploaderPath);
987 1555
988 // TODO: probably make this a better set of extensions here 1556 // TODO: probably make this a better set of extensions here
@@ -999,12 +1567,49 @@ namespace OpenSim.Region.ClientStack.Linden
999 handlerUpLoad = OnUpLoad; 1567 handlerUpLoad = OnUpLoad;
1000 if (handlerUpLoad != null) 1568 if (handlerUpLoad != null)
1001 { 1569 {
1002 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1570 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1571 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1572 }
1573 if (m_IsAtestUpload)
1574 {
1575 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1576 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1577 resperror.identifier = inv;
1578
1579 uploadComplete.error = resperror;
1580 uploadComplete.state = "Upload4Testing";
1003 } 1581 }
1582 else
1583 {
1584 if (m_error == String.Empty)
1585 {
1586 uploadComplete.new_asset = newAssetID.ToString();
1587 uploadComplete.new_inventory_item = inv;
1588 // if (m_texturesFolder != UUID.Zero)
1589 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1590 uploadComplete.state = "complete";
1591 }
1592 else
1593 {
1594 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1595 resperror.message = m_error;
1596 resperror.identifier = inv;
1004 1597
1598 uploadComplete.error = resperror;
1599 uploadComplete.state = "failed";
1600 }
1601 }
1602
1603 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1005 return res; 1604 return res;
1006 } 1605 }
1007 1606
1607 private void TimedOut(object sender, ElapsedEventArgs args)
1608 {
1609 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1610 httpListener.RemoveStreamHandler("POST", uploaderPath);
1611 }
1612
1008 ///Left this in and commented in case there are unforseen issues 1613 ///Left this in and commented in case there are unforseen issues
1009 //private void SaveAssetToFile(string filename, byte[] data) 1614 //private void SaveAssetToFile(string filename, byte[] data)
1010 //{ 1615 //{
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}