mirror of
https://github.com/TechplexEngineer/plexview.git
synced 2026-07-28 15:17:05 +00:00
Initial commit
I wish I could figure out how to have PlexVie be out of the LibOMV tree but its just not working die to a DLL not found exception about libopenjpeg. (Yes the dll is in the bin folder) This will do for now
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,714 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2014, openmetaverse.org
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Neither the name of the openmetaverse.org nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Drawing;
|
||||
using System.Xml.Serialization;
|
||||
using OpenMetaverse.ImportExport.Collada14;
|
||||
using OpenMetaverse.Rendering;
|
||||
using OpenMetaverse.Imaging;
|
||||
|
||||
namespace OpenMetaverse.ImportExport
|
||||
{
|
||||
/// <summary>
|
||||
/// Parsing Collada model files into data structures
|
||||
/// </summary>
|
||||
public class ColladaLoader
|
||||
{
|
||||
COLLADA Model;
|
||||
static XmlSerializer Serializer = null;
|
||||
List<Node> Nodes;
|
||||
List<ModelMaterial> Materials;
|
||||
Dictionary<string, string> MatSymTarget;
|
||||
string FileName;
|
||||
|
||||
class Node
|
||||
{
|
||||
public Matrix4 Transform = Matrix4.Identity;
|
||||
public string Name;
|
||||
public string ID;
|
||||
public string MeshID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses Collada document
|
||||
/// </summary>
|
||||
/// <param name="filename">Load .dae model from this file</param>
|
||||
/// <param name="loadImages">Load and decode images for uploading with model</param>
|
||||
/// <returns>A list of mesh prims that were parsed from the collada file</returns>
|
||||
public List<ModelPrim> Load(string filename, bool loadImages)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an instance of the XmlSerializer specifying type and namespace.
|
||||
if (Serializer == null)
|
||||
{
|
||||
Serializer = new XmlSerializer(typeof(COLLADA));
|
||||
}
|
||||
|
||||
this.FileName = filename;
|
||||
|
||||
// A FileStream is needed to read the XML document.
|
||||
FileStream fs = new FileStream(filename, FileMode.Open);
|
||||
XmlReader reader = XmlReader.Create(fs);
|
||||
Model = (COLLADA)Serializer.Deserialize(reader);
|
||||
fs.Close();
|
||||
var prims = Parse();
|
||||
if (loadImages)
|
||||
{
|
||||
LoadImages(prims);
|
||||
}
|
||||
return prims;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log("Failed parsing collada file: " + ex.Message, Helpers.LogLevel.Error, ex);
|
||||
return new List<ModelPrim>();
|
||||
}
|
||||
}
|
||||
|
||||
void LoadImages(List<ModelPrim> prims)
|
||||
{
|
||||
foreach (var prim in prims)
|
||||
{
|
||||
foreach (var face in prim.Faces)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(face.Material.Texture))
|
||||
{
|
||||
LoadImage(face.Material);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoadImage(ModelMaterial material)
|
||||
{
|
||||
var fname = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(FileName), material.Texture);
|
||||
|
||||
try
|
||||
{
|
||||
string ext = System.IO.Path.GetExtension(material.Texture).ToLower();
|
||||
|
||||
Bitmap bitmap = null;
|
||||
|
||||
if (ext == ".jp2" || ext == ".j2c")
|
||||
{
|
||||
material.TextureData = File.ReadAllBytes(fname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ext == ".tga")
|
||||
{
|
||||
bitmap = LoadTGAClass.LoadTGA(fname);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap = (Bitmap)Image.FromFile(fname);
|
||||
}
|
||||
|
||||
int width = bitmap.Width;
|
||||
int height = bitmap.Height;
|
||||
|
||||
// Handle resizing to prevent excessively large images and irregular dimensions
|
||||
if (!IsPowerOfTwo((uint)width) || !IsPowerOfTwo((uint)height) || width > 1024 || height > 1024)
|
||||
{
|
||||
var origWidth = width;
|
||||
var origHieght = height;
|
||||
|
||||
width = ClosestPowerOwTwo(width);
|
||||
height = ClosestPowerOwTwo(height);
|
||||
|
||||
width = width > 1024 ? 1024 : width;
|
||||
height = height > 1024 ? 1024 : height;
|
||||
|
||||
Logger.Log("Image has irregular dimensions " + origWidth + "x" + origHieght + ". Resizing to " + width + "x" + height, Helpers.LogLevel.Info);
|
||||
|
||||
Bitmap resized = new Bitmap(width, height, bitmap.PixelFormat);
|
||||
Graphics graphics = Graphics.FromImage(resized);
|
||||
|
||||
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
||||
graphics.InterpolationMode =
|
||||
System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
|
||||
graphics.DrawImage(bitmap, 0, 0, width, height);
|
||||
|
||||
bitmap.Dispose();
|
||||
bitmap = resized;
|
||||
}
|
||||
|
||||
material.TextureData = OpenJPEG.EncodeFromImage(bitmap, false);
|
||||
|
||||
Logger.Log("Successfully encoded " + fname, Helpers.LogLevel.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log("Failed loading " + fname + ": " + ex.Message, Helpers.LogLevel.Warning);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsPowerOfTwo(uint n)
|
||||
{
|
||||
return (n & (n - 1)) == 0 && n != 0;
|
||||
}
|
||||
|
||||
int ClosestPowerOwTwo(int n)
|
||||
{
|
||||
int res = 1;
|
||||
|
||||
while (res < n)
|
||||
{
|
||||
res <<= 1;
|
||||
}
|
||||
|
||||
return res > 1 ? res / 2 : 1;
|
||||
}
|
||||
|
||||
ModelMaterial ExtractMaterial(object diffuse)
|
||||
{
|
||||
ModelMaterial ret = new ModelMaterial();
|
||||
if (diffuse is common_color_or_texture_typeColor)
|
||||
{
|
||||
var col = (common_color_or_texture_typeColor)diffuse;
|
||||
ret.DiffuseColor = new Color4((float)col.Values[0], (float)col.Values[1], (float)col.Values[2], (float)col.Values[3]);
|
||||
}
|
||||
else if (diffuse is common_color_or_texture_typeTexture)
|
||||
{
|
||||
var tex = (common_color_or_texture_typeTexture)diffuse;
|
||||
ret.Texture = tex.texcoord;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void ParseMaterials()
|
||||
{
|
||||
|
||||
if (Model == null) return;
|
||||
|
||||
Materials = new List<ModelMaterial>();
|
||||
|
||||
// Material -> effect mapping
|
||||
Dictionary<string, string> matEffect = new Dictionary<string, string>();
|
||||
List<ModelMaterial> tmpEffects = new List<ModelMaterial>();
|
||||
|
||||
// Image ID -> filename mapping
|
||||
Dictionary<string, string> imgMap = new Dictionary<string, string>();
|
||||
|
||||
foreach (var item in Model.Items)
|
||||
{
|
||||
if (item is library_images)
|
||||
{
|
||||
var images = (library_images)item;
|
||||
if (images.image != null)
|
||||
{
|
||||
foreach (var image in images.image)
|
||||
{
|
||||
var img = (image)image;
|
||||
string ID = img.id;
|
||||
if (img.Item is string)
|
||||
{
|
||||
imgMap[ID] = (string)img.Item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in Model.Items)
|
||||
{
|
||||
if (item is library_materials)
|
||||
{
|
||||
var materials = (library_materials)item;
|
||||
if (materials.material != null)
|
||||
{
|
||||
foreach (var material in materials.material)
|
||||
{
|
||||
var ID = material.id;
|
||||
if (material.instance_effect != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(material.instance_effect.url))
|
||||
{
|
||||
matEffect[material.instance_effect.url.Substring(1)] = ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in Model.Items)
|
||||
{
|
||||
if (item is library_effects)
|
||||
{
|
||||
var effects = (library_effects)item;
|
||||
if (effects.effect != null)
|
||||
{
|
||||
foreach (var effect in effects.effect)
|
||||
{
|
||||
string ID = effect.id;
|
||||
foreach (var effItem in effect.Items)
|
||||
{
|
||||
if (effItem is effectFx_profile_abstractProfile_COMMON)
|
||||
{
|
||||
var teq = ((effectFx_profile_abstractProfile_COMMON)effItem).technique;
|
||||
if (teq != null)
|
||||
{
|
||||
if (teq.Item is effectFx_profile_abstractProfile_COMMONTechniquePhong)
|
||||
{
|
||||
var shader = (effectFx_profile_abstractProfile_COMMONTechniquePhong)teq.Item;
|
||||
if (shader.diffuse != null)
|
||||
{
|
||||
var material = ExtractMaterial(shader.diffuse.Item);
|
||||
material.ID = ID;
|
||||
tmpEffects.Add(material);
|
||||
}
|
||||
}
|
||||
else if (teq.Item is effectFx_profile_abstractProfile_COMMONTechniqueLambert)
|
||||
{
|
||||
var shader = (effectFx_profile_abstractProfile_COMMONTechniqueLambert)teq.Item;
|
||||
if (shader.diffuse != null)
|
||||
{
|
||||
var material = ExtractMaterial(shader.diffuse.Item);
|
||||
material.ID = ID;
|
||||
tmpEffects.Add(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var effect in tmpEffects)
|
||||
{
|
||||
if (matEffect.ContainsKey(effect.ID))
|
||||
{
|
||||
effect.ID = matEffect[effect.ID];
|
||||
if (!string.IsNullOrEmpty(effect.Texture))
|
||||
{
|
||||
if (imgMap.ContainsKey(effect.Texture))
|
||||
{
|
||||
effect.Texture = imgMap[effect.Texture];
|
||||
}
|
||||
}
|
||||
Materials.Add(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessNode(node node)
|
||||
{
|
||||
Node n = new Node();
|
||||
n.ID = node.id;
|
||||
|
||||
if (node.Items != null)
|
||||
// Try finding matrix
|
||||
foreach (var i in node.Items)
|
||||
{
|
||||
if (i is matrix)
|
||||
{
|
||||
var m = (matrix)i;
|
||||
for (int a = 0; a < 4; a++)
|
||||
for (int b = 0; b < 4; b++)
|
||||
{
|
||||
n.Transform[b, a] = (float)m.Values[a * 4 + b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find geometry and material
|
||||
if (node.instance_geometry != null && node.instance_geometry.Length > 0)
|
||||
{
|
||||
var instGeom = node.instance_geometry[0];
|
||||
if (!string.IsNullOrEmpty(instGeom.url))
|
||||
{
|
||||
n.MeshID = instGeom.url.Substring(1);
|
||||
}
|
||||
if (instGeom.bind_material != null && instGeom.bind_material.technique_common != null)
|
||||
{
|
||||
foreach (var teq in instGeom.bind_material.technique_common)
|
||||
{
|
||||
var target = teq.target;
|
||||
if (!string.IsNullOrEmpty(target))
|
||||
{
|
||||
target = target.Substring(1);
|
||||
MatSymTarget[teq.symbol] = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.Items != null && node.instance_geometry != null && node.instance_geometry.Length > 0)
|
||||
Nodes.Add(n);
|
||||
|
||||
// Recurse if the scene is hierarchical
|
||||
if (node.node1 != null)
|
||||
foreach (node nd in node.node1)
|
||||
ProcessNode(nd);
|
||||
}
|
||||
|
||||
void ParseVisualScene()
|
||||
{
|
||||
Nodes = new List<Node>();
|
||||
if (Model == null) return;
|
||||
|
||||
MatSymTarget = new Dictionary<string, string>();
|
||||
|
||||
foreach (var item in Model.Items)
|
||||
{
|
||||
if (item is library_visual_scenes)
|
||||
{
|
||||
var scene = ((library_visual_scenes)item).visual_scene[0];
|
||||
foreach (var node in scene.node)
|
||||
{
|
||||
ProcessNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ModelPrim> Parse()
|
||||
{
|
||||
var Prims = new List<ModelPrim>();
|
||||
|
||||
float DEG_TO_RAD = 0.017453292519943295769236907684886f;
|
||||
|
||||
if (Model == null) return Prims;
|
||||
|
||||
Matrix4 transform = Matrix4.Identity;
|
||||
|
||||
UpAxisType upAxis = UpAxisType.Y_UP;
|
||||
|
||||
var asset = Model.asset;
|
||||
if (asset != null)
|
||||
{
|
||||
upAxis = asset.up_axis;
|
||||
if (asset.unit != null)
|
||||
{
|
||||
float meter = (float)asset.unit.meter;
|
||||
transform[0, 0] = meter;
|
||||
transform[1, 1] = meter;
|
||||
transform[2, 2] = meter;
|
||||
}
|
||||
}
|
||||
|
||||
Matrix4 rotation = Matrix4.Identity;
|
||||
|
||||
if (upAxis == UpAxisType.X_UP)
|
||||
{
|
||||
rotation = Matrix4.CreateFromEulers(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
|
||||
}
|
||||
else if (upAxis == UpAxisType.Y_UP)
|
||||
{
|
||||
rotation = Matrix4.CreateFromEulers(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
rotation = rotation * transform;
|
||||
transform = rotation;
|
||||
|
||||
ParseVisualScene();
|
||||
ParseMaterials();
|
||||
|
||||
foreach (var item in Model.Items)
|
||||
{
|
||||
if (item is library_geometries)
|
||||
{
|
||||
var geometries = (library_geometries)item;
|
||||
foreach (var geo in geometries.geometry)
|
||||
{
|
||||
var mesh = geo.Item as mesh;
|
||||
if (mesh == null) continue;
|
||||
|
||||
var nodes = Nodes.FindAll(n => n.MeshID == geo.id);
|
||||
if (nodes != null)
|
||||
{
|
||||
byte[] mesh_asset = null;
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
var prim = new ModelPrim();
|
||||
prim.ID = node.ID;
|
||||
Prims.Add(prim);
|
||||
Matrix4 primTransform = transform;
|
||||
primTransform = primTransform * node.Transform;
|
||||
|
||||
AddPositions(mesh, prim, primTransform);
|
||||
|
||||
foreach (var mitem in mesh.Items)
|
||||
{
|
||||
if (mitem is triangles)
|
||||
{
|
||||
AddFacesFromPolyList(Triangles2Polylist((triangles)mitem), mesh, prim, primTransform);
|
||||
}
|
||||
if (mitem is polylist)
|
||||
{
|
||||
AddFacesFromPolyList((polylist)mitem, mesh, prim, primTransform);
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh_asset == null)
|
||||
{
|
||||
prim.CreateAsset(UUID.Zero);
|
||||
mesh_asset = prim.Asset;
|
||||
}
|
||||
else
|
||||
prim.Asset = mesh_asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Prims;
|
||||
}
|
||||
|
||||
source FindSource(source[] sources, string id)
|
||||
{
|
||||
id = id.Substring(1);
|
||||
|
||||
foreach (var src in sources)
|
||||
{
|
||||
if (src.id == id)
|
||||
return src;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void AddPositions(mesh mesh, ModelPrim prim, Matrix4 transform)
|
||||
{
|
||||
prim.Positions = new List<Vector3>();
|
||||
source posSrc = FindSource(mesh.source, mesh.vertices.input[0].source);
|
||||
double[] posVals = ((float_array)posSrc.Item).Values;
|
||||
|
||||
for (int i = 0; i < posVals.Length / 3; i++)
|
||||
{
|
||||
Vector3 pos = new Vector3((float)posVals[i * 3], (float)posVals[i * 3 + 1], (float)posVals[i * 3 + 2]);
|
||||
pos = Vector3.Transform(pos, transform);
|
||||
prim.Positions.Add(pos);
|
||||
}
|
||||
|
||||
prim.BoundMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
|
||||
prim.BoundMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
|
||||
|
||||
foreach (var pos in prim.Positions)
|
||||
{
|
||||
if (pos.X > prim.BoundMax.X) prim.BoundMax.X = pos.X;
|
||||
if (pos.Y > prim.BoundMax.Y) prim.BoundMax.Y = pos.Y;
|
||||
if (pos.Z > prim.BoundMax.Z) prim.BoundMax.Z = pos.Z;
|
||||
|
||||
if (pos.X < prim.BoundMin.X) prim.BoundMin.X = pos.X;
|
||||
if (pos.Y < prim.BoundMin.Y) prim.BoundMin.Y = pos.Y;
|
||||
if (pos.Z < prim.BoundMin.Z) prim.BoundMin.Z = pos.Z;
|
||||
}
|
||||
|
||||
prim.Scale = prim.BoundMax - prim.BoundMin;
|
||||
prim.Position = prim.BoundMin + (prim.Scale / 2);
|
||||
|
||||
// Fit vertex positions into identity cube -0.5 .. 0.5
|
||||
for (int i = 0; i < prim.Positions.Count; i++)
|
||||
{
|
||||
Vector3 pos = prim.Positions[i];
|
||||
pos = new Vector3(
|
||||
prim.Scale.X == 0 ? 0 : ((pos.X - prim.BoundMin.X) / prim.Scale.X) - 0.5f,
|
||||
prim.Scale.Y == 0 ? 0 : ((pos.Y - prim.BoundMin.Y) / prim.Scale.Y) - 0.5f,
|
||||
prim.Scale.Z == 0 ? 0 : ((pos.Z - prim.BoundMin.Z) / prim.Scale.Z) - 0.5f
|
||||
);
|
||||
prim.Positions[i] = pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int[] StrToArray(string s)
|
||||
{
|
||||
string[] vals = Regex.Split(s.Trim(), @"\s+");
|
||||
int[] ret = new int[vals.Length];
|
||||
|
||||
for (int i = 0; i < ret.Length; i++)
|
||||
{
|
||||
int.TryParse(vals[i], out ret[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AddFacesFromPolyList(polylist list, mesh mesh, ModelPrim prim, Matrix4 transform)
|
||||
{
|
||||
string material = list.material;
|
||||
source posSrc = null;
|
||||
source normalSrc = null;
|
||||
source uvSrc = null;
|
||||
|
||||
ulong stride = 0;
|
||||
int posOffset = -1;
|
||||
int norOffset = -1;
|
||||
int uvOffset = -1;
|
||||
|
||||
foreach (var inp in list.input)
|
||||
{
|
||||
stride = Math.Max(stride, inp.offset);
|
||||
|
||||
if (inp.semantic == "VERTEX")
|
||||
{
|
||||
posSrc = FindSource(mesh.source, mesh.vertices.input[0].source);
|
||||
posOffset = (int)inp.offset;
|
||||
}
|
||||
else if (inp.semantic == "NORMAL")
|
||||
{
|
||||
normalSrc = FindSource(mesh.source, inp.source);
|
||||
norOffset = (int)inp.offset;
|
||||
}
|
||||
else if (inp.semantic == "TEXCOORD")
|
||||
{
|
||||
uvSrc = FindSource(mesh.source, inp.source);
|
||||
uvOffset = (int)inp.offset;
|
||||
}
|
||||
}
|
||||
|
||||
stride += 1;
|
||||
|
||||
if (posSrc == null) return;
|
||||
|
||||
var vcount = StrToArray(list.vcount);
|
||||
var idx = StrToArray(list.p);
|
||||
|
||||
Vector3[] normals = null;
|
||||
if (normalSrc != null)
|
||||
{
|
||||
var norVal = ((float_array)normalSrc.Item).Values;
|
||||
normals = new Vector3[norVal.Length / 3];
|
||||
|
||||
for (int i = 0; i < normals.Length; i++)
|
||||
{
|
||||
normals[i] = new Vector3((float)norVal[i * 3 + 0], (float)norVal[i * 3 + 1], (float)norVal[i * 3 + 2]);
|
||||
normals[i] = Vector3.TransformNormal(normals[i], transform);
|
||||
normals[i].Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
Vector2[] uvs = null;
|
||||
if (uvSrc != null)
|
||||
{
|
||||
var uvVal = ((float_array)uvSrc.Item).Values;
|
||||
uvs = new Vector2[uvVal.Length / 2];
|
||||
|
||||
for (int i = 0; i < uvs.Length; i++)
|
||||
{
|
||||
uvs[i] = new Vector2((float)uvVal[i * 2 + 0], (float)uvVal[i * 2 + 1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ModelFace face = new ModelFace();
|
||||
face.MaterialID = list.material;
|
||||
if (face.MaterialID != null)
|
||||
{
|
||||
if (MatSymTarget.ContainsKey(list.material))
|
||||
{
|
||||
ModelMaterial mat = Materials.Find(m => m.ID == MatSymTarget[list.material]);
|
||||
if (mat != null)
|
||||
{
|
||||
face.Material = mat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int curIdx = 0;
|
||||
|
||||
for (int i = 0; i < vcount.Length; i++)
|
||||
{
|
||||
var nvert = vcount[i];
|
||||
if (nvert < 3 || nvert > 4)
|
||||
{
|
||||
throw new InvalidDataException("Only triangles and quads supported");
|
||||
}
|
||||
|
||||
Vertex[] verts = new Vertex[nvert];
|
||||
for (int j = 0; j < nvert; j++)
|
||||
{
|
||||
verts[j].Position = prim.Positions[idx[curIdx + posOffset + (int)stride * j]];
|
||||
|
||||
if (normals != null)
|
||||
{
|
||||
verts[j].Normal = normals[idx[curIdx + norOffset + (int)stride * j]];
|
||||
}
|
||||
|
||||
if (uvs != null)
|
||||
{
|
||||
verts[j].TexCoord = uvs[idx[curIdx + uvOffset + (int)stride * j]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (nvert == 3) // add the triangle
|
||||
{
|
||||
face.AddVertex(verts[0]);
|
||||
face.AddVertex(verts[1]);
|
||||
face.AddVertex(verts[2]);
|
||||
}
|
||||
else if (nvert == 4) // quad, add two triangles
|
||||
{
|
||||
face.AddVertex(verts[0]);
|
||||
face.AddVertex(verts[1]);
|
||||
face.AddVertex(verts[2]);
|
||||
|
||||
face.AddVertex(verts[0]);
|
||||
face.AddVertex(verts[2]);
|
||||
face.AddVertex(verts[3]);
|
||||
}
|
||||
|
||||
curIdx += (int)stride * nvert;
|
||||
}
|
||||
|
||||
prim.Faces.Add(face);
|
||||
|
||||
|
||||
}
|
||||
|
||||
polylist Triangles2Polylist(triangles triangles)
|
||||
{
|
||||
polylist poly = new polylist();
|
||||
poly.count = triangles.count;
|
||||
poly.input = triangles.input;
|
||||
poly.material = triangles.material;
|
||||
poly.name = triangles.name;
|
||||
poly.p = triangles.p;
|
||||
|
||||
string str = "3 ";
|
||||
System.Text.StringBuilder builder = new System.Text.StringBuilder(str.Length * (int)poly.count);
|
||||
for (int i = 0; i < (int)poly.count; i++) builder.Append(str);
|
||||
poly.vcount = builder.ToString();
|
||||
|
||||
return poly;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2014, openmetaverse.org
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Neither the name of the openmetaverse.org nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenMetaverse.Rendering;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
namespace OpenMetaverse.ImportExport
|
||||
{
|
||||
|
||||
public class ModelMaterial
|
||||
{
|
||||
public string ID;
|
||||
public Color4 DiffuseColor = Color4.White;
|
||||
public string Texture;
|
||||
public byte[] TextureData;
|
||||
}
|
||||
|
||||
public class ModelFace
|
||||
{
|
||||
public List<Vertex> Vertices = new List<Vertex>();
|
||||
public List<uint> Indices = new List<uint>();
|
||||
public string MaterialID = string.Empty;
|
||||
public ModelMaterial Material = new ModelMaterial();
|
||||
|
||||
Dictionary<Vertex, int> LookUp = new Dictionary<Vertex, int>();
|
||||
|
||||
public void AddVertex(Vertex v)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (LookUp.ContainsKey(v))
|
||||
{
|
||||
index = LookUp[v];
|
||||
}
|
||||
else
|
||||
{
|
||||
index = Vertices.Count;
|
||||
Vertices.Add(v);
|
||||
LookUp[v] = index;
|
||||
}
|
||||
|
||||
Indices.Add((uint)index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ModelPrim
|
||||
{
|
||||
public List<Vector3> Positions;
|
||||
public Vector3 BoundMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
|
||||
public Vector3 BoundMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
|
||||
public Vector3 Position;
|
||||
public Vector3 Scale;
|
||||
public Quaternion Rotation = Quaternion.Identity;
|
||||
public List<ModelFace> Faces = new List<ModelFace>();
|
||||
public string ID;
|
||||
public byte[] Asset;
|
||||
|
||||
public void CreateAsset(UUID creator)
|
||||
{
|
||||
OSDMap header = new OSDMap();
|
||||
header["version"] = 1;
|
||||
header["creator"] = creator;
|
||||
header["date"] = DateTime.Now;
|
||||
|
||||
OSDArray faces = new OSDArray();
|
||||
foreach (var face in Faces)
|
||||
{
|
||||
OSDMap faceMap = new OSDMap();
|
||||
|
||||
// Find UV min/max
|
||||
Vector2 uvMin = new Vector2(float.MaxValue, float.MaxValue);
|
||||
Vector2 uvMax = new Vector2(float.MinValue, float.MinValue);
|
||||
foreach (var v in face.Vertices)
|
||||
{
|
||||
if (v.TexCoord.X < uvMin.X) uvMin.X = v.TexCoord.X;
|
||||
if (v.TexCoord.Y < uvMin.Y) uvMin.Y = v.TexCoord.Y;
|
||||
|
||||
if (v.TexCoord.X > uvMax.X) uvMax.X = v.TexCoord.X;
|
||||
if (v.TexCoord.Y > uvMax.Y) uvMax.Y = v.TexCoord.Y;
|
||||
}
|
||||
OSDMap uvDomain = new OSDMap();
|
||||
uvDomain["Min"] = uvMin;
|
||||
uvDomain["Max"] = uvMax;
|
||||
faceMap["TexCoord0Domain"] = uvDomain;
|
||||
|
||||
|
||||
OSDMap positionDomain = new OSDMap();
|
||||
positionDomain["Min"] = new Vector3(-0.5f, -0.5f, -0.5f);
|
||||
positionDomain["Max"] = new Vector3(0.5f, 0.5f, 0.5f);
|
||||
faceMap["PositionDomain"] = positionDomain;
|
||||
|
||||
List<byte> posBytes = new List<byte>(face.Vertices.Count * sizeof(UInt16) * 3);
|
||||
List<byte> norBytes = new List<byte>(face.Vertices.Count * sizeof(UInt16) * 3);
|
||||
List<byte> uvBytes = new List<byte>(face.Vertices.Count * sizeof(UInt16) * 2);
|
||||
|
||||
foreach (var v in face.Vertices)
|
||||
{
|
||||
posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.X, -0.5f, 0.5f)));
|
||||
posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.Y, -0.5f, 0.5f)));
|
||||
posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.Z, -0.5f, 0.5f)));
|
||||
|
||||
norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.X, -1f, 1f)));
|
||||
norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.Y, -1f, 1f)));
|
||||
norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.Z, -1f, 1f)));
|
||||
|
||||
uvBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.TexCoord.X, uvMin.X, uvMax.X)));
|
||||
uvBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.TexCoord.Y, uvMin.Y, uvMax.Y)));
|
||||
}
|
||||
|
||||
faceMap["Position"] = posBytes.ToArray();
|
||||
faceMap["Normal"] = norBytes.ToArray();
|
||||
faceMap["TexCoord0"] = uvBytes.ToArray();
|
||||
|
||||
List<byte> indexBytes = new List<byte>(face.Indices.Count * sizeof(UInt16));
|
||||
foreach (var t in face.Indices)
|
||||
{
|
||||
indexBytes.AddRange(Utils.UInt16ToBytes((ushort)t));
|
||||
}
|
||||
faceMap["TriangleList"] = indexBytes.ToArray();
|
||||
|
||||
faces.Add(faceMap);
|
||||
}
|
||||
|
||||
byte[] physicStubBytes = Helpers.ZCompressOSD(PhysicsStub());
|
||||
|
||||
byte[] meshBytes = Helpers.ZCompressOSD(faces);
|
||||
int n = 0;
|
||||
|
||||
OSDMap lodParms = new OSDMap();
|
||||
lodParms["offset"] = n;
|
||||
lodParms["size"] = meshBytes.Length;
|
||||
header["high_lod"] = lodParms;
|
||||
n += meshBytes.Length;
|
||||
|
||||
lodParms = new OSDMap();
|
||||
lodParms["offset"] = n;
|
||||
lodParms["size"] = physicStubBytes.Length;
|
||||
header["physics_convex"] = lodParms;
|
||||
n += physicStubBytes.Length;
|
||||
|
||||
byte[] headerBytes = OSDParser.SerializeLLSDBinary(header, false);
|
||||
n += headerBytes.Length;
|
||||
|
||||
Asset = new byte[n];
|
||||
|
||||
int offset = 0;
|
||||
Buffer.BlockCopy(headerBytes, 0, Asset, offset, headerBytes.Length);
|
||||
offset += headerBytes.Length;
|
||||
|
||||
Buffer.BlockCopy(meshBytes, 0, Asset, offset, meshBytes.Length);
|
||||
offset += meshBytes.Length;
|
||||
|
||||
Buffer.BlockCopy(physicStubBytes, 0, Asset, offset, physicStubBytes.Length);
|
||||
offset += physicStubBytes.Length;
|
||||
|
||||
}
|
||||
|
||||
public static OSD PhysicsStub()
|
||||
{
|
||||
OSDMap ret = new OSDMap();
|
||||
ret["Max"] = new Vector3(0.5f, 0.5f, 0.5f);
|
||||
ret["Min"] = new Vector3(-0.5f, -0.5f, -0.5f);
|
||||
ret["BoundingVerts"] = new byte[] { 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 255, 255, 255, 127, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 127, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255 };
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2014, openmetaverse.org
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Neither the name of the openmetaverse.org nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenMetaverse.Http;
|
||||
|
||||
namespace OpenMetaverse.ImportExport
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements mesh upload communications with the simulator
|
||||
/// </summary>
|
||||
public class ModelUploader
|
||||
{
|
||||
/// <summary>
|
||||
/// Inlcude stub convex hull physics, required for uploading to Second Life
|
||||
/// </summary>
|
||||
public bool IncludePhysicsStub;
|
||||
|
||||
/// <summary>
|
||||
/// Use the same mesh used for geometry as the physical mesh upload
|
||||
/// </summary>
|
||||
public bool UseModelAsPhysics;
|
||||
|
||||
GridClient Client;
|
||||
List<ModelPrim> Prims;
|
||||
|
||||
/// <summary>
|
||||
/// Callback for mesh upload operations
|
||||
/// </summary>
|
||||
/// <param name="result">null on failure, result from server on success</param>
|
||||
public delegate void ModelUploadCallback(OSD result);
|
||||
|
||||
|
||||
string InvName, InvDescription;
|
||||
|
||||
/// <summary>
|
||||
/// Creates instance of the mesh uploader
|
||||
/// </summary>
|
||||
/// <param name="client">GridClient instance to communicate with the simulator</param>
|
||||
/// <param name="prims">List of ModelPrimitive objects to upload as a linkset</param>
|
||||
/// <param name="newInvName">Inventory name for newly uploaded object</param>
|
||||
/// <param name="newInvDesc">Inventory description for newly upload object</param>
|
||||
public ModelUploader(GridClient client, List<ModelPrim> prims, string newInvName, string newInvDesc)
|
||||
{
|
||||
this.Client = client;
|
||||
this.Prims = prims;
|
||||
this.InvName = newInvName;
|
||||
this.InvDescription = newInvDesc;
|
||||
}
|
||||
|
||||
List<byte[]> Images;
|
||||
Dictionary<string, int> ImgIndex;
|
||||
|
||||
OSD AssetResources(bool upload)
|
||||
{
|
||||
OSDArray instanceList = new OSDArray();
|
||||
List<byte[]> meshes = new List<byte[]>();
|
||||
List<byte[]> textures = new List<byte[]>();
|
||||
|
||||
foreach (var prim in Prims)
|
||||
{
|
||||
OSDMap primMap = new OSDMap();
|
||||
|
||||
OSDArray faceList = new OSDArray();
|
||||
|
||||
foreach (var face in prim.Faces)
|
||||
{
|
||||
OSDMap faceMap = new OSDMap();
|
||||
|
||||
faceMap["diffuse_color"] = face.Material.DiffuseColor;
|
||||
faceMap["fullbright"] = false;
|
||||
|
||||
if (face.Material.TextureData != null)
|
||||
{
|
||||
int index;
|
||||
if (ImgIndex.ContainsKey(face.Material.Texture))
|
||||
{
|
||||
index = ImgIndex[face.Material.Texture];
|
||||
}
|
||||
else
|
||||
{
|
||||
index = Images.Count;
|
||||
ImgIndex[face.Material.Texture] = index;
|
||||
Images.Add(face.Material.TextureData);
|
||||
}
|
||||
faceMap["image"] = index;
|
||||
faceMap["scales"] = 1.0f;
|
||||
faceMap["scalet"] = 1.0f;
|
||||
faceMap["offsets"] = 0.0f;
|
||||
faceMap["offsett"] = 0.0f;
|
||||
faceMap["imagerot"] = 0.0f;
|
||||
}
|
||||
|
||||
faceList.Add(faceMap);
|
||||
}
|
||||
|
||||
primMap["face_list"] = faceList;
|
||||
|
||||
primMap["position"] = prim.Position;
|
||||
primMap["rotation"] = prim.Rotation;
|
||||
primMap["scale"] = prim.Scale;
|
||||
|
||||
primMap["material"] = 3; // always sent as "wood" material
|
||||
primMap["physics_shape_type"] = 2; // always sent as "convex hull";
|
||||
primMap["mesh"] = meshes.Count;
|
||||
meshes.Add(prim.Asset);
|
||||
|
||||
|
||||
instanceList.Add(primMap);
|
||||
}
|
||||
|
||||
OSDMap resources = new OSDMap();
|
||||
resources["instance_list"] = instanceList;
|
||||
|
||||
OSDArray meshList = new OSDArray();
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
meshList.Add(OSD.FromBinary(mesh));
|
||||
}
|
||||
resources["mesh_list"] = meshList;
|
||||
|
||||
OSDArray textureList = new OSDArray();
|
||||
for (int i = 0; i < Images.Count; i++)
|
||||
{
|
||||
if (upload)
|
||||
{
|
||||
textureList.Add(new OSDBinary(Images[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
textureList.Add(new OSDBinary(Utils.EmptyBytes));
|
||||
}
|
||||
}
|
||||
|
||||
resources["texture_list"] = textureList;
|
||||
|
||||
resources["metric"] = "MUT_Unspecified";
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs model upload in one go, without first checking for the price
|
||||
/// </summary>
|
||||
public void Upload()
|
||||
{
|
||||
Upload(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs model upload in one go, without first checking for the price
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback that will be invoke upon completion of the upload. Null is sent on request failure</param>
|
||||
public void Upload(ModelUploadCallback callback)
|
||||
{
|
||||
PrepareUpload((result =>
|
||||
{
|
||||
if (result == null && callback != null)
|
||||
{
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result is OSDMap)
|
||||
{
|
||||
var res = (OSDMap)result;
|
||||
Uri uploader = new Uri(res["uploader"]);
|
||||
PerformUpload(uploader, (contents =>
|
||||
{
|
||||
if (contents != null)
|
||||
{
|
||||
var reply = (OSDMap)contents;
|
||||
if (reply.ContainsKey("new_inventory_item") && reply.ContainsKey("new_asset"))
|
||||
{
|
||||
// Request full update on the item in order to update the local store
|
||||
Client.Inventory.RequestFetchInventory(reply["new_inventory_item"].AsUUID(), Client.Self.AgentID);
|
||||
}
|
||||
}
|
||||
if (callback != null) callback(contents);
|
||||
}));
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask server for details of cost and impact of the mesh upload
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback that will be invoke upon completion of the upload. Null is sent on request failure</param>
|
||||
public void PrepareUpload(ModelUploadCallback callback)
|
||||
{
|
||||
Uri url = null;
|
||||
if (Client.Network.CurrentSim == null ||
|
||||
Client.Network.CurrentSim.Caps == null ||
|
||||
null == (url = Client.Network.CurrentSim.Caps.CapabilityURI("NewFileAgentInventory")))
|
||||
{
|
||||
Logger.Log("Cannot upload mesh, no connection or NewFileAgentInventory not available", Helpers.LogLevel.Warning);
|
||||
if (callback != null) callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Images = new List<byte[]>();
|
||||
ImgIndex = new Dictionary<string, int>();
|
||||
|
||||
OSDMap req = new OSDMap();
|
||||
req["name"] = InvName;
|
||||
req["description"] = InvDescription;
|
||||
|
||||
req["asset_resources"] = AssetResources(false);
|
||||
req["asset_type"] = "mesh";
|
||||
req["inventory_type"] = "object";
|
||||
|
||||
req["folder_id"] = Client.Inventory.FindFolderForType(AssetType.Object);
|
||||
req["texture_folder_id"] = Client.Inventory.FindFolderForType(AssetType.Texture);
|
||||
|
||||
req["everyone_mask"] = (int)PermissionMask.All;
|
||||
req["group_mask"] = (int)PermissionMask.All; ;
|
||||
req["next_owner_mask"] = (int)PermissionMask.All;
|
||||
|
||||
CapsClient request = new CapsClient(url);
|
||||
request.OnComplete += (client, result, error) =>
|
||||
{
|
||||
if (error != null || result == null || result.Type != OSDType.Map)
|
||||
{
|
||||
Logger.Log("Mesh upload request failure", Helpers.LogLevel.Error);
|
||||
if (callback != null) callback(null);
|
||||
return;
|
||||
}
|
||||
OSDMap res = (OSDMap)result;
|
||||
|
||||
if (res["state"] != "upload")
|
||||
{
|
||||
Logger.Log("Mesh upload failure: " + res["message"], Helpers.LogLevel.Error);
|
||||
if (callback != null) callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Log("Response from mesh upload prepare:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug);
|
||||
if (callback != null) callback(result);
|
||||
};
|
||||
|
||||
request.BeginGetResponse(req, OSDFormat.Xml, 3 * 60 * 1000);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performas actual mesh and image upload
|
||||
/// </summary>
|
||||
/// <param name="uploader">Uri recieved in the upload prepare stage</param>
|
||||
/// <param name="callback">Callback that will be invoke upon completion of the upload. Null is sent on request failure</param>
|
||||
public void PerformUpload(Uri uploader, ModelUploadCallback callback)
|
||||
{
|
||||
CapsClient request = new CapsClient(uploader);
|
||||
request.OnComplete += (client, result, error) =>
|
||||
{
|
||||
if (error != null || result == null || result.Type != OSDType.Map)
|
||||
{
|
||||
Logger.Log("Mesh upload request failure", Helpers.LogLevel.Error);
|
||||
if (callback != null) callback(null);
|
||||
return;
|
||||
}
|
||||
OSDMap res = (OSDMap)result;
|
||||
Logger.Log("Response from mesh upload perform:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug);
|
||||
if (callback != null) callback(res);
|
||||
};
|
||||
|
||||
request.BeginGetResponse(AssetResources(true), OSDFormat.Xml, 60 * 1000);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user