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.cs894
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
2 files changed, 1419 insertions, 146 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 20df8a6..eadca9b 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;
@@ -53,14 +54,16 @@ using OSDMap = OpenMetaverse.StructuredData.OSDMap;
53namespace OpenSim.Region.ClientStack.Linden 54namespace OpenSim.Region.ClientStack.Linden
54{ 55{
55 public delegate void UpLoadedAsset( 56 public delegate void UpLoadedAsset(
56 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
57 byte[] data, string inventoryType, string assetType); 58 byte[] data, string inventoryType, string assetType,
59 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
60 bool IsAtestUpload, ref string error);
58 61
59 public delegate UUID UpdateItem(UUID itemID, byte[] data); 62 public delegate UUID UpdateItem(UUID itemID, byte[] data);
60 63
61 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 64 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
62 65
63 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 66 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
64 67
65 public delegate void NewAsset(AssetBase asset); 68 public delegate void NewAsset(AssetBase asset);
66 69
@@ -86,6 +89,7 @@ namespace OpenSim.Region.ClientStack.Linden
86 89
87 private Scene m_Scene; 90 private Scene m_Scene;
88 private Caps m_HostCapsObj; 91 private Caps m_HostCapsObj;
92 private ModelCost m_ModelCost;
89 93
90 private static readonly string m_requestPath = "0000/"; 94 private static readonly string m_requestPath = "0000/";
91 // private static readonly string m_mapLayerPath = "0001/"; 95 // private static readonly string m_mapLayerPath = "0001/";
@@ -97,7 +101,8 @@ namespace OpenSim.Region.ClientStack.Linden
97 private static readonly string m_copyFromNotecardPath = "0007/"; 101 private static readonly string m_copyFromNotecardPath = "0007/";
98 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 102 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
99 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 103 private static readonly string m_getObjectPhysicsDataPath = "0101/";
100 /* 0102 - 0103 RESERVED */ 104 private static readonly string m_getObjectCostPath = "0102/";
105 private static readonly string m_ResourceCostSelectedPath = "0103/";
101 private static readonly string m_UpdateAgentInformationPath = "0500/"; 106 private static readonly string m_UpdateAgentInformationPath = "0500/";
102 107
103 // These are callbacks which will be setup by the scene so that we can update scene data when we 108 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -113,12 +118,50 @@ namespace OpenSim.Region.ClientStack.Linden
113 private IAssetService m_assetService; 118 private IAssetService m_assetService;
114 private bool m_dumpAssetsToFile = false; 119 private bool m_dumpAssetsToFile = false;
115 private string m_regionName; 120 private string m_regionName;
121
116 private int m_levelUpload = 0; 122 private int m_levelUpload = 0;
117 123
124 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
125 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
126
127 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
128 // may not be visible till relog
129
130 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
131 private UUID m_testAssetsCreatorID = UUID.Zero;
132
133 private float m_PrimScaleMin = 0.001f;
134
135 private enum FileAgentInventoryState : int
136 {
137 idle = 0,
138 processRequest = 1,
139 waitUpload = 2,
140 processUpload = 3
141 }
142 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
143
118 public BunchOfCaps(Scene scene, Caps caps) 144 public BunchOfCaps(Scene scene, Caps caps)
119 { 145 {
120 m_Scene = scene; 146 m_Scene = scene;
121 m_HostCapsObj = caps; 147 m_HostCapsObj = caps;
148
149 // create a model upload cost provider
150 m_ModelCost = new ModelCost();
151 // tell it about scene object limits
152 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
153 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
154
155// m_ModelCost.ObjectLinkedPartsMax = ??
156// m_ModelCost.PrimScaleMin = ??
157
158 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
159 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
160 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
161 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
162 float modelPrimCreationCost = m_ModelCost.primCreationCost;
163 float modelMeshByteCost = m_ModelCost.bytecost;
164
122 IConfigSource config = m_Scene.Config; 165 IConfigSource config = m_Scene.Config;
123 if (config != null) 166 if (config != null)
124 { 167 {
@@ -133,6 +176,37 @@ namespace OpenSim.Region.ClientStack.Linden
133 { 176 {
134 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 177 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
135 } 178 }
179 // economy for model upload
180 IConfig EconomyConfig = config.Configs["Economy"];
181 if (EconomyConfig != null)
182 {
183 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
184 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
185 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
186 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
187 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
188 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
189
190 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
191
192 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
193 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
194 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
195 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
196 if (testcreator != "")
197 {
198 UUID id;
199 UUID.TryParse(testcreator, out id);
200 if (id != null)
201 m_testAssetsCreatorID = id;
202 }
203
204 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
205 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
206 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
207 m_ModelCost.primCreationCost = modelPrimCreationCost;
208 m_ModelCost.bytecost = modelMeshByteCost;
209 }
136 } 210 }
137 211
138 m_assetService = m_Scene.AssetService; 212 m_assetService = m_Scene.AssetService;
@@ -144,6 +218,8 @@ namespace OpenSim.Region.ClientStack.Linden
144 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 218 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
145 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 219 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
146 GetClient = m_Scene.SceneGraph.GetControllingClient; 220 GetClient = m_Scene.SceneGraph.GetControllingClient;
221
222 m_FileAgentInventoryState = FileAgentInventoryState.idle;
147 } 223 }
148 224
149 /// <summary> 225 /// <summary>
@@ -189,7 +265,6 @@ namespace OpenSim.Region.ClientStack.Linden
189 { 265 {
190 try 266 try
191 { 267 {
192 // I don't think this one works...
193 m_HostCapsObj.RegisterHandler( 268 m_HostCapsObj.RegisterHandler(
194 "NewFileAgentInventory", 269 "NewFileAgentInventory",
195 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 270 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -208,6 +283,10 @@ namespace OpenSim.Region.ClientStack.Linden
208 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 283 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
209 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 284 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
210 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 285 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
286 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
287 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
288 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
289 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
211 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 290 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
212 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 291 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
213 292
@@ -263,6 +342,9 @@ namespace OpenSim.Region.ClientStack.Linden
263 m_log.DebugFormat( 342 m_log.DebugFormat(
264 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 343 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
265 344
345 if (!m_HostCapsObj.WaitForActivation())
346 return string.Empty;
347
266 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 348 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
267 { 349 {
268 m_log.WarnFormat( 350 m_log.WarnFormat(
@@ -392,62 +474,176 @@ namespace OpenSim.Region.ClientStack.Linden
392 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 474 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
393 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 475 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
394 476
477 // start by getting the client
478 IClientAPI client = null;
479 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
480
481 // check current state so we only have one service at a time
482 lock (m_ModelCost)
483 {
484 switch (m_FileAgentInventoryState)
485 {
486 case FileAgentInventoryState.processRequest:
487 case FileAgentInventoryState.processUpload:
488 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
489 resperror.message = "Uploader busy processing previus request";
490 resperror.identifier = UUID.Zero;
491
492 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
493 errorResponse.uploader = "";
494 errorResponse.state = "error";
495 errorResponse.error = resperror;
496 return errorResponse;
497 break;
498 case FileAgentInventoryState.waitUpload:
499 // todo stop current uploader server
500 break;
501 case FileAgentInventoryState.idle:
502 default:
503 break;
504 }
505
506 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
507 }
508
509 int cost = 0;
510 int nreqtextures = 0;
511 int nreqmeshs= 0;
512 int nreqinstances = 0;
513 bool IsAtestUpload = false;
514
515 string assetName = llsdRequest.name;
516
517 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
518
395 if (llsdRequest.asset_type == "texture" || 519 if (llsdRequest.asset_type == "texture" ||
396 llsdRequest.asset_type == "animation" || 520 llsdRequest.asset_type == "animation" ||
521 llsdRequest.asset_type == "mesh" ||
397 llsdRequest.asset_type == "sound") 522 llsdRequest.asset_type == "sound")
398 { 523 {
399 ScenePresence avatar = null; 524 ScenePresence avatar = null;
400 IClientAPI client = null;
401 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 525 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
402 526
403 // check user level 527 // check user level
404 if (avatar != null) 528 if (avatar != null)
405 { 529 {
406 client = avatar.ControllingClient;
407
408 if (avatar.UserLevel < m_levelUpload) 530 if (avatar.UserLevel < m_levelUpload)
409 { 531 {
410 if (client != null) 532 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
411 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 533 resperror.message = "Insufficient permissions to upload";
534 resperror.identifier = UUID.Zero;
412 535
413 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 536 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
414 errorResponse.uploader = ""; 537 errorResponse.uploader = "";
415 errorResponse.state = "error"; 538 errorResponse.state = "error";
539 errorResponse.error = resperror;
540 lock (m_ModelCost)
541 m_FileAgentInventoryState = FileAgentInventoryState.idle;
416 return errorResponse; 542 return errorResponse;
417 } 543 }
418 } 544 }
419 545
420 // check funds 546 // check test upload and funds
421 if (client != null) 547 if (client != null)
422 { 548 {
423 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 549 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
424 550
551 int baseCost = 0;
425 if (mm != null) 552 if (mm != null)
553 baseCost = mm.UploadCharge;
554
555 string warning = String.Empty;
556
557 if (llsdRequest.asset_type == "mesh")
426 { 558 {
427 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 559 string error;
560 int modelcost;
561
562 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
563 meshcostdata, out error, ref warning))
428 { 564 {
429 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 565 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
566 resperror.message = error;
567 resperror.identifier = UUID.Zero;
430 568
431 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 569 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
432 errorResponse.uploader = ""; 570 errorResponse.uploader = "";
433 errorResponse.state = "error"; 571 errorResponse.state = "error";
572 errorResponse.error = resperror;
573
574 lock (m_ModelCost)
575 m_FileAgentInventoryState = FileAgentInventoryState.idle;
434 return errorResponse; 576 return errorResponse;
435 } 577 }
578 cost = modelcost;
579 }
580 else
581 {
582 cost = baseCost;
583 }
584
585 if (cost > 0 && mm != null)
586 {
587 // check for test upload
588
589 if (m_ForceFreeTestUpload) // all are test
590 {
591 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
592 assetName = "TEST-" + assetName;
593
594 IsAtestUpload = true;
595 }
596
597 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
598 {
599
600 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
601 }
602
603
604 if(IsAtestUpload) // let user know, still showing cost estimation
605 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";
606
607 // check funds
608 else
609 {
610 if (!mm.UploadCovered(client.AgentId, (int)cost))
611 {
612 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
613 resperror.message = "Insuficient funds";
614 resperror.identifier = UUID.Zero;
615
616 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
617 errorResponse.uploader = "";
618 errorResponse.state = "error";
619 errorResponse.error = resperror;
620 lock (m_ModelCost)
621 m_FileAgentInventoryState = FileAgentInventoryState.idle;
622 return errorResponse;
623 }
624 }
436 } 625 }
626
627 if (client != null && warning != String.Empty)
628 client.SendAgentAlertMessage(warning, true);
437 } 629 }
438 } 630 }
439 631
440 string assetName = llsdRequest.name;
441 string assetDes = llsdRequest.description; 632 string assetDes = llsdRequest.description;
442 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 633 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
443 UUID newAsset = UUID.Random(); 634 UUID newAsset = UUID.Random();
444 UUID newInvItem = UUID.Random(); 635 UUID newInvItem = UUID.Random();
445 UUID parentFolder = llsdRequest.folder_id; 636 UUID parentFolder = llsdRequest.folder_id;
446 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 637 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
638 UUID texturesFolder = UUID.Zero;
639
640 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
641 texturesFolder = llsdRequest.texture_folder_id;
447 642
448 AssetUploader uploader = 643 AssetUploader uploader =
449 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 644 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
450 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 645 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
646 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
451 647
452 m_HostCapsObj.HttpListener.AddStreamHandler( 648 m_HostCapsObj.HttpListener.AddStreamHandler(
453 new BinaryStreamHandler( 649 new BinaryStreamHandler(
@@ -465,10 +661,22 @@ namespace OpenSim.Region.ClientStack.Linden
465 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 661 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
466 uploaderPath; 662 uploaderPath;
467 663
664
468 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 665 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
469 uploadResponse.uploader = uploaderURL; 666 uploadResponse.uploader = uploaderURL;
470 uploadResponse.state = "upload"; 667 uploadResponse.state = "upload";
668 uploadResponse.upload_price = (int)cost;
669
670 if (llsdRequest.asset_type == "mesh")
671 {
672 uploadResponse.data = meshcostdata;
673 }
674
471 uploader.OnUpLoad += UploadCompleteHandler; 675 uploader.OnUpLoad += UploadCompleteHandler;
676
677 lock (m_ModelCost)
678 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
679
472 return uploadResponse; 680 return uploadResponse;
473 } 681 }
474 682
@@ -480,8 +688,14 @@ namespace OpenSim.Region.ClientStack.Linden
480 /// <param name="data"></param> 688 /// <param name="data"></param>
481 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 689 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
482 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 690 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
483 string assetType) 691 string assetType, int cost,
692 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
693 bool IsAtestUpload, ref string error)
484 { 694 {
695
696 lock (m_ModelCost)
697 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
698
485 m_log.DebugFormat( 699 m_log.DebugFormat(
486 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 700 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
487 assetID, inventoryItem, inventoryType, assetType); 701 assetID, inventoryItem, inventoryType, assetType);
@@ -489,117 +703,247 @@ namespace OpenSim.Region.ClientStack.Linden
489 sbyte assType = 0; 703 sbyte assType = 0;
490 sbyte inType = 0; 704 sbyte inType = 0;
491 705
706 IClientAPI client = null;
707
708 UUID owner_id = m_HostCapsObj.AgentID;
709 UUID creatorID;
710
711 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
712
713 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
714
715 if (istest && m_testAssetsCreatorID != UUID.Zero)
716 creatorID = m_testAssetsCreatorID;
717 else
718 creatorID = owner_id;
719
720 string creatorIDstr = creatorID.ToString();
721
722 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
723 if (mm != null)
724 {
725 // make sure client still has enougth credit
726 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
727 {
728 error = "Insufficient funds.";
729 return;
730 }
731 }
732
733 // strings to types
492 if (inventoryType == "sound") 734 if (inventoryType == "sound")
493 { 735 {
494 inType = 1; 736 inType = (sbyte)InventoryType.Sound;
495 assType = 1; 737 assType = (sbyte)AssetType.Sound;
496 } 738 }
497 else if (inventoryType == "animation") 739 else if (inventoryType == "animation")
498 { 740 {
499 inType = 19; 741 inType = (sbyte)InventoryType.Animation;
500 assType = 20; 742 assType = (sbyte)AssetType.Animation;
501 } 743 }
502 else if (inventoryType == "wearable") 744 else if (inventoryType == "wearable")
503 { 745 {
504 inType = 18; 746 inType = (sbyte)InventoryType.Wearable;
505 switch (assetType) 747 switch (assetType)
506 { 748 {
507 case "bodypart": 749 case "bodypart":
508 assType = 13; 750 assType = (sbyte)AssetType.Bodypart;
509 break; 751 break;
510 case "clothing": 752 case "clothing":
511 assType = 5; 753 assType = (sbyte)AssetType.Clothing;
512 break; 754 break;
513 } 755 }
514 } 756 }
515 else if (inventoryType == "object") 757 else if (inventoryType == "object")
516 { 758 {
517 inType = (sbyte)InventoryType.Object; 759 if (assetType == "mesh") // this code for now is for mesh models uploads only
518 assType = (sbyte)AssetType.Object;
519
520 List<Vector3> positions = new List<Vector3>();
521 List<Quaternion> rotations = new List<Quaternion>();
522 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
523 OSDArray instance_list = (OSDArray)request["instance_list"];
524 OSDArray mesh_list = (OSDArray)request["mesh_list"];
525 OSDArray texture_list = (OSDArray)request["texture_list"];
526 SceneObjectGroup grp = null;
527
528 List<UUID> textures = new List<UUID>();
529 for (int i = 0; i < texture_list.Count; i++)
530 { 760 {
531 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 761 inType = (sbyte)InventoryType.Object;
532 textureAsset.Data = texture_list[i].AsBinary(); 762 assType = (sbyte)AssetType.Object;
533 m_assetService.Store(textureAsset);
534 textures.Add(textureAsset.FullID);
535 }
536 763
537 for (int i = 0; i < mesh_list.Count; i++) 764 List<Vector3> positions = new List<Vector3>();
538 { 765 List<Quaternion> rotations = new List<Quaternion>();
539 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 766 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
767
768 // compare and get updated information
540 769
541 Primitive.TextureEntry textureEntry 770 bool mismatchError = true;
542 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
543 OSDMap inner_instance_list = (OSDMap)instance_list[i];
544 771
545 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 772 while (mismatchError)
546 for (uint face = 0; face < face_list.Count; face++)
547 { 773 {
548 OSDMap faceMap = (OSDMap)face_list[(int)face]; 774 mismatchError = false;
549 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 775 }
550 if(faceMap.ContainsKey("fullbright"))
551 f.Fullbright = faceMap["fullbright"].AsBoolean();
552 if (faceMap.ContainsKey ("diffuse_color"))
553 f.RGBA = faceMap["diffuse_color"].AsColor4();
554 776
555 int textureNum = faceMap["image"].AsInteger(); 777 if (mismatchError)
556 float imagerot = faceMap["imagerot"].AsInteger(); 778 {
557 float offsets = (float)faceMap["offsets"].AsReal(); 779 error = "Upload and fee estimation information don't match";
558 float offsett = (float)faceMap["offsett"].AsReal(); 780 lock (m_ModelCost)
559 float scales = (float)faceMap["scales"].AsReal(); 781 m_FileAgentInventoryState = FileAgentInventoryState.idle;
560 float scalet = (float)faceMap["scalet"].AsReal();
561 782
562 if(imagerot != 0) 783 return;
563 f.Rotation = imagerot; 784 }
564 785
565 if(offsets != 0) 786 OSDArray instance_list = (OSDArray)request["instance_list"];
566 f.OffsetU = offsets; 787 OSDArray mesh_list = (OSDArray)request["mesh_list"];
788 OSDArray texture_list = (OSDArray)request["texture_list"];
789 SceneObjectGroup grp = null;
567 790
568 if (offsett != 0) 791 // create and store texture assets
569 f.OffsetV = offsett; 792 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
793 texturesFolder != UUID.Zero);
570 794
571 if (scales != 0)
572 f.RepeatU = scales;
573 795
574 if (scalet != 0) 796 List<UUID> textures = new List<UUID>();
575 f.RepeatV = scalet;
576 797
577 if (textures.Count > textureNum) 798
578 f.TextureID = textures[textureNum]; 799 if (doTextInv)
579 else 800 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
580 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; 801
802 if(client == null) // don't put textures in inventory if there is no client
803 doTextInv = false;
804
805 for (int i = 0; i < texture_list.Count; i++)
806 {
807 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
808 textureAsset.Data = texture_list[i].AsBinary();
809 if (istest)
810 textureAsset.Local = true;
811 m_assetService.Store(textureAsset);
812 textures.Add(textureAsset.FullID);
813
814 if (doTextInv)
815 {
816 string name = assetName;
817 if (name.Length > 25)
818 name = name.Substring(0, 24);
819 name += "_Texture#" + i.ToString();
820 InventoryItemBase texitem = new InventoryItemBase();
821 texitem.Owner = m_HostCapsObj.AgentID;
822 texitem.CreatorId = creatorIDstr;
823 texitem.CreatorData = String.Empty;
824 texitem.ID = UUID.Random();
825 texitem.AssetID = textureAsset.FullID;
826 texitem.Description = "mesh model texture";
827 texitem.Name = name;
828 texitem.AssetType = (int)AssetType.Texture;
829 texitem.InvType = (int)InventoryType.Texture;
830 texitem.Folder = texturesFolder;
831
832 texitem.CurrentPermissions
833 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
834
835 texitem.BasePermissions = (uint)PermissionMask.All;
836 texitem.EveryOnePermissions = 0;
837 texitem.NextPermissions = (uint)PermissionMask.All;
838 texitem.CreationDate = Util.UnixTimeSinceEpoch();
839
840 m_Scene.AddInventoryItem(client, texitem);
841 texitem = null;
842 }
843 }
581 844
582 textureEntry.FaceTextures[face] = f; 845 // create and store meshs assets
846 List<UUID> meshAssets = new List<UUID>();
847 for (int i = 0; i < mesh_list.Count; i++)
848 {
849 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
850 meshAsset.Data = mesh_list[i].AsBinary();
851 if (istest)
852 meshAsset.Local = true;
853 m_assetService.Store(meshAsset);
854 meshAssets.Add(meshAsset.FullID);
583 } 855 }
584 856
585 pbs.TextureEntry = textureEntry.GetBytes(); 857 int skipedMeshs = 0;
858 // build prims from instances
859 for (int i = 0; i < instance_list.Count; i++)
860 {
861 OSDMap inner_instance_list = (OSDMap)instance_list[i];
862
863 // skip prims that are 2 small
864 Vector3 scale = inner_instance_list["scale"].AsVector3();
865
866 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
867 {
868 skipedMeshs++;
869 continue;
870 }
871
872 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
873
874 Primitive.TextureEntry textureEntry
875 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
586 876
587 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, "");
588 meshAsset.Data = mesh_list[i].AsBinary();
589 m_assetService.Store(meshAsset);
590 877
591 pbs.SculptEntry = true; 878 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
592 pbs.SculptTexture = meshAsset.FullID; 879 for (uint face = 0; face < face_list.Count; face++)
593 pbs.SculptType = (byte)SculptType.Mesh; 880 {
594 pbs.SculptData = meshAsset.Data; 881 OSDMap faceMap = (OSDMap)face_list[(int)face];
882 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
883 if (faceMap.ContainsKey("fullbright"))
884 f.Fullbright = faceMap["fullbright"].AsBoolean();
885 if (faceMap.ContainsKey("diffuse_color"))
886 f.RGBA = faceMap["diffuse_color"].AsColor4();
887
888 int textureNum = faceMap["image"].AsInteger();
889 float imagerot = faceMap["imagerot"].AsInteger();
890 float offsets = (float)faceMap["offsets"].AsReal();
891 float offsett = (float)faceMap["offsett"].AsReal();
892 float scales = (float)faceMap["scales"].AsReal();
893 float scalet = (float)faceMap["scalet"].AsReal();
894
895 if (imagerot != 0)
896 f.Rotation = imagerot;
897
898 if (offsets != 0)
899 f.OffsetU = offsets;
900
901 if (offsett != 0)
902 f.OffsetV = offsett;
903
904 if (scales != 0)
905 f.RepeatU = scales;
906
907 if (scalet != 0)
908 f.RepeatV = scalet;
909
910 if (textures.Count > textureNum)
911 f.TextureID = textures[textureNum];
912 else
913 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
914
915 textureEntry.FaceTextures[face] = f;
916 }
917
918 pbs.TextureEntry = textureEntry.GetBytes();
919
920 bool hasmesh = false;
921 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
922 {
923 int meshindx = inner_instance_list["mesh"].AsInteger();
924 if (meshAssets.Count > meshindx)
925 {
926 pbs.SculptEntry = true;
927 pbs.SculptType = (byte)SculptType.Mesh;
928 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
929 // data will be requested from asset on rez (i hope)
930 hasmesh = true;
931 }
932 }
933
934 Vector3 position = inner_instance_list["position"].AsVector3();
935 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
595 936
596 Vector3 position = inner_instance_list["position"].AsVector3(); 937 // for now viwers do send fixed defaults
597 Vector3 scale = inner_instance_list["scale"].AsVector3(); 938 // but this may change
598 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 939// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
940 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
941 if(hasmesh)
942 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
943// int material = inner_instance_list["material"].AsInteger();
944 byte material = (byte)Material.Wood;
599 945
600// no longer used - begin ------------------------ 946// no longer used - begin ------------------------
601// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
602// int material = inner_instance_list["material"].AsInteger();
603// int mesh = inner_instance_list["mesh"].AsInteger(); 947// int mesh = inner_instance_list["mesh"].AsInteger();
604 948
605// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 949// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -614,24 +958,42 @@ namespace OpenSim.Region.ClientStack.Linden
614// UUID owner_id = permissions["owner_id"].AsUUID(); 958// UUID owner_id = permissions["owner_id"].AsUUID();
615// int owner_mask = permissions["owner_mask"].AsInteger(); 959// int owner_mask = permissions["owner_mask"].AsInteger();
616// no longer used - end ------------------------ 960// no longer used - end ------------------------
961
962
963 SceneObjectPart prim
964 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
965
966 prim.Scale = scale;
967 rotations.Add(rotation);
968 positions.Add(position);
969 prim.UUID = UUID.Random();
970 prim.CreatorID = creatorID;
971 prim.OwnerID = owner_id;
972 prim.GroupID = UUID.Zero;
973 prim.LastOwnerID = creatorID;
974 prim.CreationDate = Util.UnixTimeSinceEpoch();
975
976 if (grp == null)
977 prim.Name = assetName;
978 else
979 prim.Name = assetName + "#" + i.ToString();
617 980
618 UUID owner_id = m_HostCapsObj.AgentID; 981 if (restrictPerms)
982 {
983 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
984 prim.EveryoneMask = 0;
985 prim.GroupMask = 0;
986 prim.NextOwnerMask = 0;
987 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
988 }
619 989
620 SceneObjectPart prim 990 if(istest)
621 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 991 prim.Description = "For testing only. Other uses are prohibited";
992 else
993 prim.Description = "";
622 994
623 prim.Scale = scale; 995 prim.Material = material;
624 //prim.OffsetPosition = position; 996 prim.PhysicsShapeType = physicsShapeType;
625 rotations.Add(rotation);
626 positions.Add(position);
627 prim.UUID = UUID.Random();
628 prim.CreatorID = owner_id;
629 prim.OwnerID = owner_id;
630 prim.GroupID = UUID.Zero;
631 prim.LastOwnerID = prim.OwnerID;
632 prim.CreationDate = Util.UnixTimeSinceEpoch();
633 prim.Name = assetName;
634 prim.Description = "";
635 997
636// prim.BaseMask = (uint)base_mask; 998// prim.BaseMask = (uint)base_mask;
637// prim.EveryoneMask = (uint)everyone_mask; 999// prim.EveryoneMask = (uint)everyone_mask;
@@ -639,52 +1001,64 @@ namespace OpenSim.Region.ClientStack.Linden
639// prim.NextOwnerMask = (uint)next_owner_mask; 1001// prim.NextOwnerMask = (uint)next_owner_mask;
640// prim.OwnerMask = (uint)owner_mask; 1002// prim.OwnerMask = (uint)owner_mask;
641 1003
642 if (grp == null) 1004 if (grp == null)
643 grp = new SceneObjectGroup(prim); 1005 {
644 else 1006 grp = new SceneObjectGroup(prim);
645 grp.AddPart(prim); 1007 grp.LastOwnerID = creatorID;
646 } 1008 }
1009 else
1010 grp.AddPart(prim);
1011 }
647 1012
648 Vector3 rootPos = positions[0]; 1013 Vector3 rootPos = positions[0];
649 1014
650 if (grp.Parts.Length > 1) 1015 if (grp.Parts.Length > 1)
651 { 1016 {
652 // Fix first link number 1017 // Fix first link number
653 grp.RootPart.LinkNum++; 1018 grp.RootPart.LinkNum++;
654 1019
655 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1020 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
656 Quaternion tmprot; 1021 Quaternion tmprot;
657 Vector3 offset; 1022 Vector3 offset;
658 1023
659 // fix children rotations and positions 1024 // fix children rotations and positions
660 for (int i = 1; i < rotations.Count; i++) 1025 for (int i = 1; i < rotations.Count; i++)
661 { 1026 {
662 tmprot = rotations[i]; 1027 tmprot = rotations[i];
663 tmprot = rootRotConj * tmprot; 1028 tmprot = rootRotConj * tmprot;
664 1029
665 grp.Parts[i].RotationOffset = tmprot; 1030 grp.Parts[i].RotationOffset = tmprot;
666 1031
667 offset = positions[i] - rootPos; 1032 offset = positions[i] - rootPos;
1033
1034 offset *= rootRotConj;
1035 grp.Parts[i].OffsetPosition = offset;
1036 }
668 1037
669 offset *= rootRotConj; 1038 grp.AbsolutePosition = rootPos;
670 grp.Parts[i].OffsetPosition = offset; 1039 grp.UpdateGroupRotationR(rotations[0]);
1040 }
1041 else
1042 {
1043 grp.AbsolutePosition = rootPos;
1044 grp.UpdateGroupRotationR(rotations[0]);
671 } 1045 }
672 1046
673 grp.AbsolutePosition = rootPos; 1047 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
674 grp.UpdateGroupRotationR(rotations[0]);
675 } 1048 }
676 else 1049
1050 else // not a mesh model
677 { 1051 {
678 grp.AbsolutePosition = rootPos; 1052 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
679 grp.UpdateGroupRotationR(rotations[0]); 1053 return;
680 } 1054 }
681
682 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
683 } 1055 }
684 1056
685 AssetBase asset; 1057 AssetBase asset;
686 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1058 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
687 asset.Data = data; 1059 asset.Data = data;
1060 if (istest)
1061 asset.Local = true;
688 if (AddNewAsset != null) 1062 if (AddNewAsset != null)
689 AddNewAsset(asset); 1063 AddNewAsset(asset);
690 else if (m_assetService != null) 1064 else if (m_assetService != null)
@@ -692,11 +1066,17 @@ namespace OpenSim.Region.ClientStack.Linden
692 1066
693 InventoryItemBase item = new InventoryItemBase(); 1067 InventoryItemBase item = new InventoryItemBase();
694 item.Owner = m_HostCapsObj.AgentID; 1068 item.Owner = m_HostCapsObj.AgentID;
695 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1069 item.CreatorId = creatorIDstr;
696 item.CreatorData = String.Empty; 1070 item.CreatorData = String.Empty;
697 item.ID = inventoryItem; 1071 item.ID = inventoryItem;
698 item.AssetID = asset.FullID; 1072 item.AssetID = asset.FullID;
699 item.Description = assetDescription; 1073 if (istest)
1074 {
1075 item.Description = "For testing only. Other uses are prohibited";
1076 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1077 }
1078 else
1079 item.Description = assetDescription;
700 item.Name = assetName; 1080 item.Name = assetName;
701 item.AssetType = assType; 1081 item.AssetType = assType;
702 item.InvType = inType; 1082 item.InvType = inType;
@@ -704,18 +1084,60 @@ namespace OpenSim.Region.ClientStack.Linden
704 1084
705 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1085 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
706 // (owner) permissions. This becomes a problem if next permissions are changed. 1086 // (owner) permissions. This becomes a problem if next permissions are changed.
707 item.CurrentPermissions
708 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
709 1087
710 item.BasePermissions = (uint)PermissionMask.All; 1088 if (restrictPerms)
711 item.EveryOnePermissions = 0; 1089 {
712 item.NextPermissions = (uint)PermissionMask.All; 1090 item.CurrentPermissions
1091 = (uint)(PermissionMask.Move | PermissionMask.Modify);
1092
1093 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1094 item.EveryOnePermissions = 0;
1095 item.NextPermissions = 0;
1096 }
1097 else
1098 {
1099 item.CurrentPermissions
1100 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
1101
1102 item.BasePermissions = (uint)PermissionMask.All;
1103 item.EveryOnePermissions = 0;
1104 item.NextPermissions = (uint)PermissionMask.All;
1105 }
1106
713 item.CreationDate = Util.UnixTimeSinceEpoch(); 1107 item.CreationDate = Util.UnixTimeSinceEpoch();
714 1108
1109 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1110
715 if (AddNewInventoryItem != null) 1111 if (AddNewInventoryItem != null)
716 { 1112 {
717 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1113 if (istest)
1114 {
1115 m_Scene.AddInventoryItem(client, item);
1116/*
1117 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1118 if (client != null)
1119 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);
1120 */
1121 }
1122 else
1123 {
1124 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1125// if (client != null)
1126// {
1127// // let users see anything.. i don't so far
1128// string str;
1129// if (cost > 0)
1130// // dont remember where is money unit name to put here
1131// str = "Upload complete. charged " + cost.ToString() + "$";
1132// else
1133// str = "Upload complete";
1134// client.SendAgentAlertMessage(str, true);
1135// }
1136 }
718 } 1137 }
1138
1139 lock (m_ModelCost)
1140 m_FileAgentInventoryState = FileAgentInventoryState.idle;
719 } 1141 }
720 1142
721 /// <summary> 1143 /// <summary>
@@ -908,6 +1330,120 @@ namespace OpenSim.Region.ClientStack.Linden
908 return response; 1330 return response;
909 } 1331 }
910 1332
1333 public string GetObjectCost(string request, string path,
1334 string param, IOSHttpRequest httpRequest,
1335 IOSHttpResponse httpResponse)
1336 {
1337 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1338 OSDMap resp = new OSDMap();
1339
1340 OSDArray object_ids = (OSDArray)req["object_ids"];
1341
1342 for (int i = 0; i < object_ids.Count; i++)
1343 {
1344 UUID uuid = object_ids[i].AsUUID();
1345
1346 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1347
1348 if (part != null)
1349 {
1350 SceneObjectGroup grp = part.ParentGroup;
1351 if (grp != null)
1352 {
1353 float linksetCost;
1354 float linksetPhysCost;
1355 float partCost;
1356 float partPhysCost;
1357
1358 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1359
1360 OSDMap object_data = new OSDMap();
1361 object_data["linked_set_resource_cost"] = linksetCost;
1362 object_data["resource_cost"] = partCost;
1363 object_data["physics_cost"] = partPhysCost;
1364 object_data["linked_set_physics_cost"] = linksetPhysCost;
1365
1366 resp[uuid.ToString()] = object_data;
1367 }
1368 }
1369 }
1370
1371 string response = OSDParser.SerializeLLSDXmlString(resp);
1372 return response;
1373 }
1374
1375 public string ResourceCostSelected(string request, string path,
1376 string param, IOSHttpRequest httpRequest,
1377 IOSHttpResponse httpResponse)
1378 {
1379 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1380 OSDMap resp = new OSDMap();
1381
1382
1383 float phys=0;
1384 float stream=0;
1385 float simul=0;
1386
1387 if (req.ContainsKey("selected_roots"))
1388 {
1389 OSDArray object_ids = (OSDArray)req["selected_roots"];
1390
1391 // should go by SOG suming costs for all parts
1392 // ll v3 works ok with several objects select we get the list and adds ok
1393 // FS calls per object so results are wrong guess fs bug
1394 for (int i = 0; i < object_ids.Count; i++)
1395 {
1396 UUID uuid = object_ids[i].AsUUID();
1397 float Physc;
1398 float simulc;
1399 float streamc;
1400
1401 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1402 if (grp != null)
1403 {
1404 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1405 phys += Physc;
1406 stream += streamc;
1407 simul += simulc;
1408 }
1409 }
1410 }
1411 else if (req.ContainsKey("selected_prims"))
1412 {
1413 OSDArray object_ids = (OSDArray)req["selected_prims"];
1414
1415 // don't see in use in any of the 2 viewers
1416 // guess it should be for edit linked but... nothing
1417 // should go to SOP per part
1418 for (int i = 0; i < object_ids.Count; i++)
1419 {
1420 UUID uuid = object_ids[i].AsUUID();
1421
1422 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1423 if (part != null)
1424 {
1425 phys += part.PhysicsCost;
1426 stream += part.StreamingCost;
1427 simul += part.SimulationCost;
1428 }
1429 }
1430 }
1431
1432 if (simul != 0)
1433 {
1434 OSDMap object_data = new OSDMap();
1435
1436 object_data["physics"] = phys;
1437 object_data["streaming"] = stream;
1438 object_data["simulation"] = simul;
1439
1440 resp["selected"] = object_data;
1441 }
1442
1443 string response = OSDParser.SerializeLLSDXmlString(resp);
1444 return response;
1445 }
1446
911 public string UpdateAgentInformation(string request, string path, 1447 public string UpdateAgentInformation(string request, string path,
912 string param, IOSHttpRequest httpRequest, 1448 string param, IOSHttpRequest httpRequest,
913 IOSHttpResponse httpResponse) 1449 IOSHttpResponse httpResponse)
@@ -927,6 +1463,10 @@ namespace OpenSim.Region.ClientStack.Linden
927 1463
928 public class AssetUploader 1464 public class AssetUploader
929 { 1465 {
1466 private static readonly ILog m_log =
1467 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1468
1469
930 public event UpLoadedAsset OnUpLoad; 1470 public event UpLoadedAsset OnUpLoad;
931 private UpLoadedAsset handlerUpLoad = null; 1471 private UpLoadedAsset handlerUpLoad = null;
932 1472
@@ -941,10 +1481,21 @@ namespace OpenSim.Region.ClientStack.Linden
941 1481
942 private string m_invType = String.Empty; 1482 private string m_invType = String.Empty;
943 private string m_assetType = String.Empty; 1483 private string m_assetType = String.Empty;
1484 private int m_cost;
1485 private string m_error = String.Empty;
1486
1487 private Timer m_timeoutTimer = new Timer();
1488 private UUID m_texturesFolder;
1489 private int m_nreqtextures;
1490 private int m_nreqmeshs;
1491 private int m_nreqinstances;
1492 private bool m_IsAtestUpload;
944 1493
945 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1494 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
946 UUID parentFolderID, string invType, string assetType, string path, 1495 UUID parentFolderID, string invType, string assetType, string path,
947 IHttpServer httpServer, bool dumpAssetsToFile) 1496 IHttpServer httpServer, bool dumpAssetsToFile,
1497 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1498 bool IsAtestUpload)
948 { 1499 {
949 m_assetName = assetName; 1500 m_assetName = assetName;
950 m_assetDes = description; 1501 m_assetDes = description;
@@ -956,6 +1507,18 @@ namespace OpenSim.Region.ClientStack.Linden
956 m_assetType = assetType; 1507 m_assetType = assetType;
957 m_invType = invType; 1508 m_invType = invType;
958 m_dumpAssetsToFile = dumpAssetsToFile; 1509 m_dumpAssetsToFile = dumpAssetsToFile;
1510 m_cost = totalCost;
1511
1512 m_texturesFolder = texturesFolder;
1513 m_nreqtextures = nreqtextures;
1514 m_nreqmeshs = nreqmeshs;
1515 m_nreqinstances = nreqinstances;
1516 m_IsAtestUpload = IsAtestUpload;
1517
1518 m_timeoutTimer.Elapsed += TimedOut;
1519 m_timeoutTimer.Interval = 120000;
1520 m_timeoutTimer.AutoReset = false;
1521 m_timeoutTimer.Start();
959 } 1522 }
960 1523
961 /// <summary> 1524 /// <summary>
@@ -970,12 +1533,14 @@ namespace OpenSim.Region.ClientStack.Linden
970 UUID inv = inventoryItemID; 1533 UUID inv = inventoryItemID;
971 string res = String.Empty; 1534 string res = String.Empty;
972 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1535 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1536/*
973 uploadComplete.new_asset = newAssetID.ToString(); 1537 uploadComplete.new_asset = newAssetID.ToString();
974 uploadComplete.new_inventory_item = inv; 1538 uploadComplete.new_inventory_item = inv;
975 uploadComplete.state = "complete"; 1539 uploadComplete.state = "complete";
976 1540
977 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1541 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
978 1542*/
1543 m_timeoutTimer.Stop();
979 httpListener.RemoveStreamHandler("POST", uploaderPath); 1544 httpListener.RemoveStreamHandler("POST", uploaderPath);
980 1545
981 // TODO: probably make this a better set of extensions here 1546 // TODO: probably make this a better set of extensions here
@@ -992,12 +1557,49 @@ namespace OpenSim.Region.ClientStack.Linden
992 handlerUpLoad = OnUpLoad; 1557 handlerUpLoad = OnUpLoad;
993 if (handlerUpLoad != null) 1558 if (handlerUpLoad != null)
994 { 1559 {
995 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1560 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1561 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1562 }
1563 if (m_IsAtestUpload)
1564 {
1565 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1566 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1567 resperror.identifier = inv;
1568
1569 uploadComplete.error = resperror;
1570 uploadComplete.state = "Upload4Testing";
996 } 1571 }
1572 else
1573 {
1574 if (m_error == String.Empty)
1575 {
1576 uploadComplete.new_asset = newAssetID.ToString();
1577 uploadComplete.new_inventory_item = inv;
1578 // if (m_texturesFolder != UUID.Zero)
1579 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1580 uploadComplete.state = "complete";
1581 }
1582 else
1583 {
1584 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1585 resperror.message = m_error;
1586 resperror.identifier = inv;
997 1587
1588 uploadComplete.error = resperror;
1589 uploadComplete.state = "failed";
1590 }
1591 }
1592
1593 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
998 return res; 1594 return res;
999 } 1595 }
1000 1596
1597 private void TimedOut(object sender, ElapsedEventArgs args)
1598 {
1599 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1600 httpListener.RemoveStreamHandler("POST", uploaderPath);
1601 }
1602
1001 ///Left this in and commented in case there are unforseen issues 1603 ///Left this in and commented in case there are unforseen issues
1002 //private void SaveAssetToFile(string filename, byte[] data) 1604 //private void SaveAssetToFile(string filename, byte[] data)
1003 //{ 1605 //{
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}