31 using System.Collections;
32 using System.Collections.Generic;
36 using OpenMetaverse.StructuredData;
38 using OpenSim.Framework;
39 using OpenSim.Region.Framework;
40 using OpenSim.Region.Framework.Scenes;
41 using OpenSim.Framework.Capabilities;
43 using ComponentAce.Compression.Libs.zlib;
48 namespace OpenSim.
Region.ClientStack.Linden
62 public float ModelMeshCostFactor = 0.0f;
63 public float ModelTextureCostFactor = 1.0f;
64 public float ModelMinCostFactor = 0.0f;
68 public float primCreationCost = 0.002f;
70 public float bytecost = 1e-5f;
78 const float medSizeWth = 1f;
79 const float lowSizeWth = 1.5f;
80 const float lowestSizeWth = 2f;
82 const float physMeshSizeWth = 6f;
83 const float physHullSizeWth = 8f;
87 const float highLodFactor = 17.36f;
88 const float midLodFactor = 277.78f;
89 const float lowLodFactor = 1111.11f;
95 const int bytesPerCoord = 6;
98 public float PrimScaleMin = 0.001f;
99 public float NonPhysicalPrimScaleMax = 256f;
100 public float PhysicalPrimScaleMax = 10f;
101 public int ObjectLinkedPartsMax = 512;
104 private class ameshCostParam
107 public int highLODSize;
108 public int medLODSize;
109 public int lowLODSize;
110 public int lowestLODSize;
112 public float costFee;
114 public float physicsCost;
129 error = string.Empty;
131 bool avatarSkeleton =
false;
133 if (resources == null ||
137 error =
"missing model information.";
141 int numberInstances = resources.instance_list.Array.Count;
143 if (ObjectLinkedPartsMax != 0 && numberInstances > ObjectLinkedPartsMax)
145 error =
"Model would have more than " + ObjectLinkedPartsMax.ToString() +
" linked prims";
149 meshcostdata.model_streaming_cost = 0.0;
150 meshcostdata.simulation_cost = 0.0;
151 meshcostdata.physics_cost = 0.0;
152 meshcostdata.resource_cost = 0.0;
154 meshcostdata.upload_price_breakdown.mesh_instance = 0;
155 meshcostdata.upload_price_breakdown.mesh_physics = 0;
156 meshcostdata.upload_price_breakdown.mesh_streaming = 0;
157 meshcostdata.upload_price_breakdown.model = 0;
165 textures_cost *= ModelTextureCostFactor;
167 itmp = (int)(textures_cost + 0.5f);
168 meshcostdata.upload_price_breakdown.texture = itmp;
175 bool haveMeshs =
false;
180 List<ameshCostParam> meshsCosts =
new List<ameshCostParam>();
184 numberMeshs = resources.mesh_list.Array.Count;
186 for (
int i = 0; i < numberMeshs; i++)
188 ameshCostParam curCost =
new ameshCostParam();
191 if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error))
200 error =
"model can only contain a avatar skeleton";
203 avatarSkeleton =
true;
205 meshsCosts.Add(curCost);
206 meshsfee += curCost.costFee;
216 for (
int i = 0; i < numberInstances; i++)
220 ArrayList ascale = (ArrayList)inst[
"scale"];
223 tmp = (double)ascale[0];
224 scale.X = (float)tmp;
225 tmp = (double)ascale[1];
226 scale.Y = (float)tmp;
227 tmp = (double)ascale[2];
228 scale.Z = (float)tmp;
230 if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin)
236 if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax)
238 error =
"Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() +
"m. Please ajust scale";
242 if (haveMeshs && inst.ContainsKey(
"mesh"))
244 mesh = (int)inst[
"mesh"];
246 if (mesh >= numberMeshs)
248 error =
"Incoerent model information.";
254 float sqdiam = scale.LengthSquared();
256 ameshCostParam curCost = meshsCosts[mesh];
257 float mesh_streaming = streamingCost(curCost, sqdiam);
259 meshcostdata.model_streaming_cost += mesh_streaming;
260 meshcostdata.physics_cost += curCost.physicsCost;
265 meshcostdata.model_streaming_cost += 0.5f;
266 meshcostdata.physics_cost += 1.0f;
270 meshcostdata.simulation_cost += 0.5f;
272 meshsfee += primCreationCost;
277 if (skipedSmall > numberInstances / 2)
279 error =
"Model contains too many prims smaller than " + PrimScaleMin.ToString() +
280 "m minimum allowed size. Please check scalling";
284 warning += skipedSmall.ToString() +
" of the requested " +numberInstances.ToString() +
285 " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() +
286 "m minimum allowed size. Please check scalling ";
290 meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
292 meshcostdata.resource_cost = meshcostdata.physics_cost;
295 meshcostdata.resource_cost = meshcostdata.simulation_cost;
299 meshsfee *= ModelMeshCostFactor;
301 if (meshsfee < ModelMinCostFactor)
302 meshsfee = ModelMinCostFactor;
305 meshsfee *= (float)basicCost;
309 totalcost += (int)meshsfee;
318 private bool MeshCost(byte[] data, ameshCostParam cost,out
bool skeleton, out
bool avatarPhys, out
string error)
320 cost.highLODSize = 0;
323 cost.lowestLODSize = 0;
324 cost.physicsCost = 0.0f;
327 error = string.Empty;
332 if (data == null || data.Length == 0)
334 error =
"Missing model information.";
341 error =
"Invalid model data";
343 using (MemoryStream ms =
new MemoryStream(data))
347 OSD osd = OSDParser.DeserializeLLSDBinary(ms);
357 start = (int)ms.Position;
363 int highlod_size = 0;
366 int lowestlod_size = 0;
371 int phys_hullsvertices = 0;
373 int physmesh_size = 0;
374 int phys_ntriangles = 0;
376 int submesh_offset = -1;
378 if (map.ContainsKey(
"skeleton"))
380 tmpmap = (
OSDMap)map[
"skeleton"];
381 if (tmpmap.ContainsKey(
"offset") && tmpmap.ContainsKey(
"size"))
383 int sksize = tmpmap[
"size"].AsInteger();
389 if (map.ContainsKey(
"physics_convex"))
391 tmpmap = (
OSDMap)map[
"physics_convex"];
392 if (tmpmap.ContainsKey(
"offset"))
393 submesh_offset = tmpmap[
"offset"].AsInteger() + start;
394 if (tmpmap.ContainsKey(
"size"))
395 hulls_size = tmpmap[
"size"].AsInteger();
398 if (submesh_offset < 0 || hulls_size == 0)
400 error =
"Missing physics_convex block";
404 if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
406 error =
"Bad physics_convex block";
414 if (map.ContainsKey(
"high_lod"))
416 tmpmap = (
OSDMap)map[
"high_lod"];
418 if (tmpmap.ContainsKey(
"offset"))
419 submesh_offset = tmpmap[
"offset"].AsInteger() + start;
420 if (tmpmap.ContainsKey(
"size"))
421 highlod_size = tmpmap[
"size"].AsInteger();
424 if (submesh_offset < 0 || highlod_size <= 0)
426 error =
"Missing high_lod block";
430 bool haveprev =
true;
432 if (map.ContainsKey(
"medium_lod"))
434 tmpmap = (
OSDMap)map[
"medium_lod"];
435 if (tmpmap.ContainsKey(
"size"))
436 medlod_size = tmpmap[
"size"].AsInteger();
441 if (haveprev && map.ContainsKey(
"low_lod"))
443 tmpmap = (
OSDMap)map[
"low_lod"];
444 if (tmpmap.ContainsKey(
"size"))
445 lowlod_size = tmpmap[
"size"].AsInteger();
450 if (haveprev && map.ContainsKey(
"lowest_lod"))
452 tmpmap = (
OSDMap)map[
"lowest_lod"];
453 if (tmpmap.ContainsKey(
"size"))
454 lowestlod_size = tmpmap[
"size"].AsInteger();
457 if (map.ContainsKey(
"skin"))
459 tmpmap = (
OSDMap)map[
"skin"];
460 if (tmpmap.ContainsKey(
"size"))
461 skin_size = tmpmap[
"size"].AsInteger();
464 cost.highLODSize = highlod_size;
465 cost.medLODSize = medlod_size;
466 cost.lowLODSize = lowlod_size;
467 cost.lowestLODSize = lowestlod_size;
472 if(map.ContainsKey(
"physics_mesh"))
473 tmpmap = (
OSDMap)map[
"physics_mesh"];
474 else if (map.ContainsKey(
"physics_shape"))
475 tmpmap = (
OSDMap)map[
"physics_shape"];
479 if (tmpmap.ContainsKey(
"offset"))
480 submesh_offset = tmpmap[
"offset"].AsInteger() + start;
481 if (tmpmap.ContainsKey(
"size"))
482 physmesh_size = tmpmap[
"size"].AsInteger();
484 if (submesh_offset >= 0 || physmesh_size > 0)
487 if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
489 error =
"Model data parsing error";
496 phys_hullsvertices++;
497 cost.physicsCost = 0.04f * phys_hullsvertices;
504 sfee += medSizeWth * medlod_size;
505 sfee += lowSizeWth * lowlod_size;
506 sfee += lowestSizeWth * lowlod_size;
510 if (physmesh_size != 0)
511 sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4);
513 sfee += physHullSizeWth * hulls_size;
523 private bool submesh(byte[] data,
int offset,
int size, out
int ntriangles)
527 OSD decodedMeshOsd =
new OSD();
528 byte[] meshBytes =
new byte[size];
529 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
532 using (MemoryStream inMs =
new MemoryStream(meshBytes))
534 using (MemoryStream outMs =
new MemoryStream())
536 using (ZOutputStream zOut =
new ZOutputStream(outMs))
538 byte[] readBuffer =
new byte[4096];
540 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
542 zOut.Write(readBuffer, 0, readLen);
545 outMs.Seek(0, SeekOrigin.Begin);
547 byte[] decompressedBuf = outMs.GetBuffer();
548 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
558 OSDArray decodedMeshOsdArray = null;
562 decodedMeshOsdArray = (
OSDArray)decodedMeshOsd;
563 foreach (
OSD subMeshOsd
in decodedMeshOsdArray)
567 OSDMap subtmpmap = (
OSDMap)subMeshOsd;
568 if (subtmpmap.ContainsKey(
"NoGeometry") && ((OSDBoolean)subtmpmap[
"NoGeometry"]))
571 if (!subtmpmap.ContainsKey(
"Position"))
574 if (subtmpmap.ContainsKey(
"TriangleList"))
576 dummy = subtmpmap[
"TriangleList"].AsBinary();
577 ntriangles += dummy.Length / bytesPerCoord;
588 private bool hulls(byte[] data,
int offset,
int size, out
int nvertices, out
int nhulls)
593 OSD decodedMeshOsd =
new OSD();
594 byte[] meshBytes =
new byte[size];
595 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
598 using (MemoryStream inMs =
new MemoryStream(meshBytes))
600 using (MemoryStream outMs =
new MemoryStream())
602 using (ZOutputStream zOut =
new ZOutputStream(outMs))
604 byte[] readBuffer =
new byte[4096];
606 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
608 zOut.Write(readBuffer, 0, readLen);
611 outMs.Seek(0, SeekOrigin.Begin);
613 byte[] decompressedBuf = outMs.GetBuffer();
614 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
624 OSDMap cmap = (
OSDMap)decodedMeshOsd;
631 if (cmap.ContainsKey(
"BoundingVerts"))
633 dummy = cmap[
"BoundingVerts"].AsBinary();
634 nvertices = dummy.Length / bytesPerCoord;
658 private float streamingCost(ameshCostParam curCost,
float sqdiam)
663 float mh = sqdiam * highLodFactor;
666 float mm = sqdiam * midLodFactor;
670 float ml = sqdiam * lowLodFactor;
689 ma = mlst + ml + mm + mh;
693 int lst = curCost.lowestLODSize - 384;
694 int l = curCost.lowLODSize - 384;
695 int m = curCost.medLODSize - 384;
696 int h = curCost.highLODSize - 384;
717 float cost = (float)lst * mlst + (
float)l * ml + (float)m * mm + (
float)h * mh;
OpenMetaverse.StructuredData.OSDMap OSDMap
bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost, LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
OpenMetaverse.StructuredData.OSD OSD
OpenMetaverse.StructuredData.OSDArray OSDArray
double model_streaming_cost