missing file for suport of mesh upload cost
parent
bc85c1d084
commit
5bbc4fb2a5
|
@ -0,0 +1,596 @@
|
||||||
|
// Proprietary code of Avination Virtual Limited
|
||||||
|
// (c) 2012 Melanie Thielker, Leal Duarte
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Framework;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Framework.Capabilities;
|
||||||
|
|
||||||
|
using ComponentAce.Compression.Libs.zlib;
|
||||||
|
|
||||||
|
using OSDArray = OpenMetaverse.StructuredData.OSDArray;
|
||||||
|
using OSDMap = OpenMetaverse.StructuredData.OSDMap;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
{
|
||||||
|
public class ModelCost
|
||||||
|
{
|
||||||
|
float ModelMinCost = 5.0f; // try to favor small meshs versus sculpts
|
||||||
|
|
||||||
|
// scale prices relative to basic cost
|
||||||
|
const float ModelCostScale = 1.0f;
|
||||||
|
|
||||||
|
const float primCreationCost = 0.01f; // 256 prims cost extra 2.56
|
||||||
|
|
||||||
|
// weigthed size to money convertion
|
||||||
|
const float bytecost = 1e-4f;
|
||||||
|
|
||||||
|
// for mesh upload fees based on compressed data sizes
|
||||||
|
// not using streaming physics and server costs as SL apparently does ??
|
||||||
|
|
||||||
|
const float medSizeWth = 1f; // 2x
|
||||||
|
const float lowSizeWth = 1.5f; // 2.5x
|
||||||
|
const float lowestSizeWth = 2f; // 3x
|
||||||
|
// favor potencial optimized meshs versus automatic decomposition
|
||||||
|
const float physMeshSizeWth = 6f; // counts 7x
|
||||||
|
const float physHullSizeWth = 8f; // counts 9x
|
||||||
|
|
||||||
|
// price compression to promote complex meshs
|
||||||
|
const float feeCompressionBase = 50.0f; // transition from linear to log cost
|
||||||
|
const float feeCompressionScale = 250.0f; // 10000 scales to 1000
|
||||||
|
|
||||||
|
// stream cost size factors
|
||||||
|
const float highLodFactor = 17.36f;
|
||||||
|
const float midLodFactor = 277.78f;
|
||||||
|
const float lowLodFactor = 1111.11f;
|
||||||
|
|
||||||
|
const int bytesPerCoord = 6; // 3 coords, 2 bytes per each
|
||||||
|
|
||||||
|
private class ameshCostParam
|
||||||
|
{
|
||||||
|
public int highLODSize;
|
||||||
|
public int medLODSize;
|
||||||
|
public int lowLODSize;
|
||||||
|
public int lowestLODSize;
|
||||||
|
public float costFee;
|
||||||
|
public float physicsCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost, LLSDAssetUploadResponseData meshcostdata, out string error)
|
||||||
|
{
|
||||||
|
totalcost = 0;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
if (resources == null ||
|
||||||
|
resources.instance_list == null ||
|
||||||
|
resources.instance_list.Array.Count == 0)
|
||||||
|
{
|
||||||
|
error = "Unable to upload mesh model. missing information.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
meshcostdata.model_streaming_cost = 0.0;
|
||||||
|
meshcostdata.simulation_cost = 0.0;
|
||||||
|
meshcostdata.physics_cost = 0.0;
|
||||||
|
meshcostdata.resource_cost = 0.0;
|
||||||
|
|
||||||
|
meshcostdata.upload_price_breakdown.mesh_instance = 0;
|
||||||
|
meshcostdata.upload_price_breakdown.mesh_physics = 0;
|
||||||
|
meshcostdata.upload_price_breakdown.mesh_streaming = 0;
|
||||||
|
meshcostdata.upload_price_breakdown.model = 0;
|
||||||
|
|
||||||
|
int itmp;
|
||||||
|
|
||||||
|
// textures cost
|
||||||
|
if (resources.texture_list != null && resources.texture_list.Array.Count > 0)
|
||||||
|
{
|
||||||
|
int textures_cost = resources.texture_list.Array.Count;
|
||||||
|
textures_cost *= basicCost;
|
||||||
|
|
||||||
|
meshcostdata.upload_price_breakdown.texture = textures_cost;
|
||||||
|
totalcost += textures_cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
float meshsfee = 0;
|
||||||
|
|
||||||
|
// meshs assets cost
|
||||||
|
|
||||||
|
int numberMeshs = 0;
|
||||||
|
List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
|
||||||
|
// a model could have no mesh actually
|
||||||
|
if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
|
||||||
|
{
|
||||||
|
numberMeshs = resources.mesh_list.Array.Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < numberMeshs; i++)
|
||||||
|
{
|
||||||
|
ameshCostParam curCost = new ameshCostParam();
|
||||||
|
byte[] data = (byte[])resources.mesh_list.Array[i];
|
||||||
|
|
||||||
|
if (!MeshCost(data, curCost, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
meshsCosts.Add(curCost);
|
||||||
|
meshsfee += curCost.costFee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// instances (prims) cost
|
||||||
|
int numberInstances = resources.instance_list.Array.Count;
|
||||||
|
int mesh;
|
||||||
|
for (int i = 0; i < numberInstances; i++)
|
||||||
|
{
|
||||||
|
Hashtable inst = (Hashtable)resources.instance_list.Array[i];
|
||||||
|
|
||||||
|
// streamming cost
|
||||||
|
// assume all instances have a mesh
|
||||||
|
// but in general they can have normal prims
|
||||||
|
// but for now that seems not suported
|
||||||
|
// when they do, we will need to inspect pbs information
|
||||||
|
// and have cost funtions for all prims types
|
||||||
|
// don't check for shape type none, since
|
||||||
|
// that could be used to upload meshs with low cost
|
||||||
|
// changing later inworld
|
||||||
|
|
||||||
|
ArrayList ascale = (ArrayList)inst["scale"];
|
||||||
|
Vector3 scale;
|
||||||
|
double tmp;
|
||||||
|
tmp = (double)ascale[0];
|
||||||
|
scale.X = (float)tmp;
|
||||||
|
tmp = (double)ascale[1];
|
||||||
|
scale.Y = (float)tmp;
|
||||||
|
tmp = (double)ascale[2];
|
||||||
|
scale.Z = (float)tmp;
|
||||||
|
|
||||||
|
float sqdiam = scale.LengthSquared();
|
||||||
|
|
||||||
|
mesh = (int)inst["mesh"];
|
||||||
|
|
||||||
|
if(mesh >= numberMeshs)
|
||||||
|
{
|
||||||
|
error = "Unable to upload mesh model. incoerent information.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ameshCostParam curCost = meshsCosts[mesh];
|
||||||
|
float mesh_streaming = streamingCost(curCost, sqdiam);
|
||||||
|
|
||||||
|
meshcostdata.model_streaming_cost += mesh_streaming;
|
||||||
|
|
||||||
|
meshcostdata.physics_cost += curCost.physicsCost;
|
||||||
|
|
||||||
|
// unscripted and static prim server cost
|
||||||
|
meshcostdata.simulation_cost += 0.5f;
|
||||||
|
// charge for prims creation
|
||||||
|
meshsfee += primCreationCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost)
|
||||||
|
meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
|
||||||
|
else
|
||||||
|
meshcostdata.resource_cost = meshcostdata.physics_cost;
|
||||||
|
|
||||||
|
if (meshsfee < ModelMinCost)
|
||||||
|
meshsfee = ModelMinCost;
|
||||||
|
|
||||||
|
meshsfee *= ModelCostScale;
|
||||||
|
meshsfee += 0.5f; // rounding
|
||||||
|
|
||||||
|
totalcost += (int)meshsfee;
|
||||||
|
|
||||||
|
// breakdown prices
|
||||||
|
// don't seem to be in use so removed code for now
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MeshCost(byte[] data, ameshCostParam cost, out string error)
|
||||||
|
{
|
||||||
|
cost.highLODSize = 0;
|
||||||
|
cost.medLODSize = 0;
|
||||||
|
cost.lowLODSize = 0;
|
||||||
|
cost.lowestLODSize = 0;
|
||||||
|
cost.physicsCost = 0.0f;
|
||||||
|
cost.costFee = 0.0f;
|
||||||
|
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
if (data == null || data.Length == 0)
|
||||||
|
{
|
||||||
|
error = "Unable to upload mesh model. missing information.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSD meshOsd = null;
|
||||||
|
int start = 0;
|
||||||
|
|
||||||
|
error = "Unable to upload mesh model. Invalid data";
|
||||||
|
|
||||||
|
using (MemoryStream ms = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OSD osd = OSDParser.DeserializeLLSDBinary(ms);
|
||||||
|
if (osd is OSDMap)
|
||||||
|
meshOsd = (OSDMap)osd;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
start = (int)ms.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSDMap map = (OSDMap)meshOsd;
|
||||||
|
OSDMap tmpmap;
|
||||||
|
|
||||||
|
int highlod_size = 0;
|
||||||
|
int medlod_size = 0;
|
||||||
|
int lowlod_size = 0;
|
||||||
|
int lowestlod_size = 0;
|
||||||
|
int skin_size = 0;
|
||||||
|
|
||||||
|
int hulls_size = 0;
|
||||||
|
int phys_nhulls;
|
||||||
|
int phys_hullsvertices = 0;
|
||||||
|
|
||||||
|
int physmesh_size = 0;
|
||||||
|
int phys_ntriangles = 0;
|
||||||
|
|
||||||
|
int submesh_offset = -1;
|
||||||
|
|
||||||
|
if (map.ContainsKey("physics_convex"))
|
||||||
|
{
|
||||||
|
tmpmap = (OSDMap)map["physics_convex"];
|
||||||
|
if (tmpmap.ContainsKey("offset"))
|
||||||
|
submesh_offset = tmpmap["offset"].AsInteger() + start;
|
||||||
|
if (tmpmap.ContainsKey("size"))
|
||||||
|
hulls_size = tmpmap["size"].AsInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (submesh_offset < 0 || hulls_size == 0)
|
||||||
|
{
|
||||||
|
error = "Unable to upload mesh model. missing physics_convex block";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
|
||||||
|
{
|
||||||
|
error = "Unable to upload mesh model. bad physics_convex block";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
submesh_offset = -1;
|
||||||
|
|
||||||
|
// only look for LOD meshs sizes
|
||||||
|
|
||||||
|
if (map.ContainsKey("high_lod"))
|
||||||
|
{
|
||||||
|
tmpmap = (OSDMap)map["high_lod"];
|
||||||
|
// see at least if there is a offset for this one
|
||||||
|
if (tmpmap.ContainsKey("offset"))
|
||||||
|
submesh_offset = tmpmap["offset"].AsInteger() + start;
|
||||||
|
if (tmpmap.ContainsKey("size"))
|
||||||
|
highlod_size = tmpmap["size"].AsInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (submesh_offset < 0 || highlod_size <= 0)
|
||||||
|
{
|
||||||
|
error = "Unable to upload mesh model. missing high_lod";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool haveprev = true;
|
||||||
|
|
||||||
|
if (map.ContainsKey("medium_lod"))
|
||||||
|
{
|
||||||
|
tmpmap = (OSDMap)map["medium_lod"];
|
||||||
|
if (tmpmap.ContainsKey("size"))
|
||||||
|
medlod_size = tmpmap["size"].AsInteger();
|
||||||
|
else
|
||||||
|
haveprev = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (haveprev && map.ContainsKey("low_lod"))
|
||||||
|
{
|
||||||
|
tmpmap = (OSDMap)map["low_lod"];
|
||||||
|
if (tmpmap.ContainsKey("size"))
|
||||||
|
lowlod_size = tmpmap["size"].AsInteger();
|
||||||
|
else
|
||||||
|
haveprev = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (haveprev && map.ContainsKey("lowest_lod"))
|
||||||
|
{
|
||||||
|
tmpmap = (OSDMap)map["lowest_lod"];
|
||||||
|
if (tmpmap.ContainsKey("size"))
|
||||||
|
lowestlod_size = tmpmap["size"].AsInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.ContainsKey("skin"))
|
||||||
|
{
|
||||||
|
tmpmap = (OSDMap)map["skin"];
|
||||||
|
if (tmpmap.ContainsKey("size"))
|
||||||
|
skin_size = tmpmap["size"].AsInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
cost.highLODSize = highlod_size;
|
||||||
|
cost.medLODSize = medlod_size;
|
||||||
|
cost.lowLODSize = lowlod_size;
|
||||||
|
cost.lowestLODSize = lowestlod_size;
|
||||||
|
|
||||||
|
submesh_offset = -1;
|
||||||
|
|
||||||
|
if (map.ContainsKey("physics_mesh"))
|
||||||
|
{
|
||||||
|
tmpmap = (OSDMap)map["physics_mesh"];
|
||||||
|
if (tmpmap.ContainsKey("offset"))
|
||||||
|
submesh_offset = tmpmap["offset"].AsInteger() + start;
|
||||||
|
if (tmpmap.ContainsKey("size"))
|
||||||
|
physmesh_size = tmpmap["size"].AsInteger();
|
||||||
|
|
||||||
|
if (submesh_offset >= 0 || physmesh_size > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
|
||||||
|
{
|
||||||
|
error = "Unable to upload mesh model. parsing error";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// upload is done in convex shape type so only one hull
|
||||||
|
phys_hullsvertices++;
|
||||||
|
cost.physicsCost = 0.04f * phys_hullsvertices;
|
||||||
|
|
||||||
|
float sfee;
|
||||||
|
|
||||||
|
sfee = data.Length; // start with total compressed data size
|
||||||
|
|
||||||
|
// penalize lod meshs that should be more builder optimized
|
||||||
|
sfee += medSizeWth * medlod_size;
|
||||||
|
sfee += lowSizeWth * lowlod_size;
|
||||||
|
sfee += lowestSizeWth * lowlod_size;
|
||||||
|
|
||||||
|
// physics
|
||||||
|
// favor potencial optimized meshs versus automatic decomposition
|
||||||
|
if (physmesh_size != 0)
|
||||||
|
sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull
|
||||||
|
else
|
||||||
|
sfee += physHullSizeWth * hulls_size;
|
||||||
|
|
||||||
|
// bytes to money
|
||||||
|
sfee *= bytecost;
|
||||||
|
|
||||||
|
// fee compression
|
||||||
|
if (sfee > feeCompressionBase)
|
||||||
|
{
|
||||||
|
sfee -= feeCompressionBase;
|
||||||
|
sfee = feeCompressionScale * (float)Math.Log10((double)sfee);
|
||||||
|
sfee += feeCompressionBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cost.costFee = sfee;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool submesh(byte[] data, int offset, int size, out int ntriangles)
|
||||||
|
{
|
||||||
|
ntriangles = 0;
|
||||||
|
|
||||||
|
OSD decodedMeshOsd = new OSD();
|
||||||
|
byte[] meshBytes = new byte[size];
|
||||||
|
System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (MemoryStream inMs = new MemoryStream(meshBytes))
|
||||||
|
{
|
||||||
|
using (MemoryStream outMs = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (ZOutputStream zOut = new ZOutputStream(outMs))
|
||||||
|
{
|
||||||
|
byte[] readBuffer = new byte[4096];
|
||||||
|
int readLen = 0;
|
||||||
|
while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
|
||||||
|
{
|
||||||
|
zOut.Write(readBuffer, 0, readLen);
|
||||||
|
}
|
||||||
|
zOut.Flush();
|
||||||
|
outMs.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
byte[] decompressedBuf = outMs.GetBuffer();
|
||||||
|
decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSDArray decodedMeshOsdArray = null;
|
||||||
|
if ((!decodedMeshOsd is OSDArray))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
byte[] dummy;
|
||||||
|
|
||||||
|
decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
|
||||||
|
foreach (OSD subMeshOsd in decodedMeshOsdArray)
|
||||||
|
{
|
||||||
|
if (subMeshOsd is OSDMap)
|
||||||
|
{
|
||||||
|
OSDMap subtmpmap = (OSDMap)subMeshOsd;
|
||||||
|
if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!subtmpmap.ContainsKey("Position"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (subtmpmap.ContainsKey("TriangleList"))
|
||||||
|
{
|
||||||
|
dummy = subtmpmap["TriangleList"].AsBinary();
|
||||||
|
ntriangles += dummy.Length / bytesPerCoord;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls)
|
||||||
|
{
|
||||||
|
nvertices = 0;
|
||||||
|
nhulls = 1;
|
||||||
|
|
||||||
|
OSD decodedMeshOsd = new OSD();
|
||||||
|
byte[] meshBytes = new byte[size];
|
||||||
|
System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (MemoryStream inMs = new MemoryStream(meshBytes))
|
||||||
|
{
|
||||||
|
using (MemoryStream outMs = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (ZOutputStream zOut = new ZOutputStream(outMs))
|
||||||
|
{
|
||||||
|
byte[] readBuffer = new byte[4096];
|
||||||
|
int readLen = 0;
|
||||||
|
while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
|
||||||
|
{
|
||||||
|
zOut.Write(readBuffer, 0, readLen);
|
||||||
|
}
|
||||||
|
zOut.Flush();
|
||||||
|
outMs.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
byte[] decompressedBuf = outMs.GetBuffer();
|
||||||
|
decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSDMap cmap = (OSDMap)decodedMeshOsd;
|
||||||
|
if (cmap == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
byte[] dummy;
|
||||||
|
|
||||||
|
// must have one of this
|
||||||
|
if (cmap.ContainsKey("BoundingVerts"))
|
||||||
|
{
|
||||||
|
dummy = cmap["BoundingVerts"].AsBinary();
|
||||||
|
nvertices = dummy.Length / bytesPerCoord;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* upload is done with convex shape type
|
||||||
|
if (cmap.ContainsKey("HullList"))
|
||||||
|
{
|
||||||
|
dummy = cmap["HullList"].AsBinary();
|
||||||
|
nhulls += dummy.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (cmap.ContainsKey("Positions"))
|
||||||
|
{
|
||||||
|
dummy = cmap["Positions"].AsBinary();
|
||||||
|
nvertices = dummy.Length / bytesPerCoord;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float streamingCost(ameshCostParam curCost, float sqdiam)
|
||||||
|
{
|
||||||
|
// compute efective areas
|
||||||
|
float ma = 262144f;
|
||||||
|
|
||||||
|
float mh = sqdiam * highLodFactor;
|
||||||
|
if (mh > ma)
|
||||||
|
mh = ma;
|
||||||
|
float mm = sqdiam * midLodFactor;
|
||||||
|
if (mm > ma)
|
||||||
|
mm = ma;
|
||||||
|
|
||||||
|
float ml = sqdiam * lowLodFactor;
|
||||||
|
if (ml > ma)
|
||||||
|
ml = ma;
|
||||||
|
|
||||||
|
float mlst = ma;
|
||||||
|
|
||||||
|
mlst -= ml;
|
||||||
|
ml -= mm;
|
||||||
|
mm -= mh;
|
||||||
|
|
||||||
|
if (mlst < 1.0f)
|
||||||
|
mlst = 1.0f;
|
||||||
|
if (ml < 1.0f)
|
||||||
|
ml = 1.0f;
|
||||||
|
if (mm < 1.0f)
|
||||||
|
mm = 1.0f;
|
||||||
|
if (mh < 1.0f)
|
||||||
|
mh = 1.0f;
|
||||||
|
|
||||||
|
ma = mlst + ml + mm + mh;
|
||||||
|
|
||||||
|
// get LODs compressed sizes
|
||||||
|
// giving 384 bytes bonus
|
||||||
|
int lst = curCost.lowestLODSize - 384;
|
||||||
|
int l = curCost.lowLODSize - 384;
|
||||||
|
int m = curCost.medLODSize - 384;
|
||||||
|
int h = curCost.highLODSize - 384;
|
||||||
|
|
||||||
|
// use previus higher LOD size on missing ones
|
||||||
|
if (m <= 0)
|
||||||
|
m = h;
|
||||||
|
if (l <= 0)
|
||||||
|
l = m;
|
||||||
|
if (lst <= 0)
|
||||||
|
lst = l;
|
||||||
|
|
||||||
|
// force minumum sizes
|
||||||
|
if (lst < 16)
|
||||||
|
lst = 16;
|
||||||
|
if (l < 16)
|
||||||
|
l = 16;
|
||||||
|
if (m < 16)
|
||||||
|
m = 16;
|
||||||
|
if (h < 16)
|
||||||
|
h = 16;
|
||||||
|
|
||||||
|
// compute cost weighted by relative effective areas
|
||||||
|
|
||||||
|
float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh;
|
||||||
|
cost /= ma;
|
||||||
|
|
||||||
|
cost *= 0.004f; // overall tunning parameter
|
||||||
|
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue