void CreatePrim (WarpRenderer renderer, ISceneChildEntity prim)
        {
            try {

                if ((PCode)prim.Shape.PCode != PCode.Prim)
                    return;
                if (prim.Scale.LengthSquared () < MIN_PRIM_SIZE * MIN_PRIM_SIZE)
                    return;

                Primitive omvPrim = prim.Shape.ToOmvPrimitive (prim.OffsetPosition, prim.GetRotationOffset ());
                FacetedMesh renderMesh = null;

                // Are we dealing with a sculptie or mesh?
                if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero) {
                    // Try fetching the asset
                    byte [] sculptAsset = m_scene.AssetService.GetData (omvPrim.Sculpt.SculptTexture.ToString ());
                    if (sculptAsset != null) {
                        // Is it a mesh?
                        if (omvPrim.Sculpt.Type == SculptType.Mesh) {
                            AssetMesh meshAsset = new AssetMesh (omvPrim.Sculpt.SculptTexture, sculptAsset);
                            FacetedMesh.TryDecodeFromAsset (omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
                            meshAsset = null;
                        } else // It's sculptie
                          {
                            Image sculpt = m_imgDecoder.DecodeToImage (sculptAsset);
                            if (sculpt != null) {
                                renderMesh = m_primMesher.GenerateFacetedSculptMesh (omvPrim, (Bitmap)sculpt,
                                                                                    DetailLevel.Medium);
                                sculpt.Dispose ();
                            }
                        }
                        sculptAsset = null;
                    } else {
                        // missing sculpt data... replace with something
                        renderMesh = m_primMesher.GenerateFacetedMesh (omvPrim, DetailLevel.Medium);
                    }

                } else // Prim
                  {
                    renderMesh = m_primMesher.GenerateFacetedMesh (omvPrim, DetailLevel.Medium);
                }

                if (renderMesh == null)
                    return;

                warp_Vector primPos = ConvertVector (prim.GetWorldPosition ());
                warp_Quaternion primRot = ConvertQuaternion (prim.GetRotationOffset ());

                warp_Matrix m = warp_Matrix.quaternionMatrix (primRot);

                if (prim.ParentID != 0) {
                    ISceneEntity group = m_scene.GetGroupByPrim (prim.LocalId);
                    if (group != null)
                        m.transform (warp_Matrix.quaternionMatrix (ConvertQuaternion (group.RootChild.GetRotationOffset ())));
                }

                warp_Vector primScale = ConvertVector (prim.Scale);

                string primID = prim.UUID.ToString ();

                // Create the prim faces
                for (int i = 0; i < renderMesh.Faces.Count; i++) {
                    Face renderFace = renderMesh.Faces [i];
                    string meshName = primID + "-Face-" + i;

                    warp_Object faceObj = new warp_Object (renderFace.Vertices.Count, renderFace.Indices.Count / 3);

                    foreach (Vertex v in renderFace.Vertices) {
                        warp_Vector pos = ConvertVector (v.Position);
                        warp_Vector norm = ConvertVector (v.Normal);

                        if (prim.Shape.SculptTexture == UUID.Zero)
                            norm = norm.reverse ();
                        warp_Vertex vert = new warp_Vertex (pos, norm, v.TexCoord.X, v.TexCoord.Y);

                        faceObj.addVertex (vert);
                    }

                    for (int j = 0; j < renderFace.Indices.Count;) {
                        faceObj.addTriangle (
                            renderFace.Indices [j++],
                            renderFace.Indices [j++],
                            renderFace.Indices [j++]);
                    }

                    Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace ((uint)i);
                    string materialName;
                    Color4 faceColor = GetFaceColor (teFace);

                    if (m_texturePrims && (prim.Scale.LengthSquared () > m_texturePrimSize)) {
                        materialName = GetOrCreateMaterial (renderer, faceColor, teFace.TextureID);
                    } else {
                        materialName = GetOrCreateMaterial (renderer, faceColor);
                    }

                    faceObj.transform (m);
                    faceObj.setPos (primPos);
                    faceObj.scaleSelf (primScale.x, primScale.y, primScale.z);

                    renderer.Scene.addObject (meshName, faceObj);

                    renderer.SetObjectMaterial (meshName, materialName);

                    faceObj = null;
                }
                renderMesh.Faces.Clear ();
                renderMesh = null;
            } catch (Exception ex) {
                MainConsole.Instance.Warn ("[Warp3D]: Exception creating prim, " + ex);
            }
        }
Пример #2
0
        private String PovMesh(Primitive prim)
        {
            string s;

            FacetedMesh renderMesh = null;

            if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero)
            {
                if (prim.Sculpt.Type == SculptType.Mesh)
                {
                    byte[] meshData = GetMesh(prim.Sculpt.SculptTexture);
                    if (meshData == null)
                        return string.Empty;

                    AssetMesh meshAsset = new AssetMesh(prim.Sculpt.SculptTexture, meshData);
                    FacetedMesh.TryDecodeFromAsset(prim, meshAsset, DetailLevel.Highest, out renderMesh);
                    meshAsset = null;
                }
                else // not a mesh, must be a sculptie
                {
                    Image sculpt = GetImage(Client, prim.Sculpt.SculptTexture);
                    if (sculpt == null)
                        return string.Empty;

                    renderMesh = m_primMesher.GenerateFacetedSculptMesh(prim, (Bitmap)sculpt, DetailLevel.Medium);
                    sculpt.Dispose();
                }
            }
            else
                renderMesh = m_primMesher.GenerateFacetedMesh(prim, DetailLevel.Highest);

            if (renderMesh == null)
                return string.Empty;

            Matrix4 mv = GetModelviewMatrix(prim);

            using (StringWriter sw = new StringWriter())
            {
                for (int i = 0; i < renderMesh.Faces.Count; i++)
                {
                    var face = renderMesh.Faces[i];
                    Primitive.TextureEntryFace tef = null;
                    try { tef = prim.Textures.GetFace((uint)i); }
                    catch (Exception) { continue; }

                    int numVerts = face.Vertices.Count;
                    int numIndices = face.Indices.Count;
                    if (numVerts == 0 || numIndices == 0 || tef == null)
                        continue;

                    sw.WriteLine("mesh2");
                    sw.WriteLine("{");

                    sw.WriteLine("vertex_vectors");
                    sw.WriteLine("{");

                    sw.WriteLine(numVerts.ToString());
                    for (int vi = 0; vi < numVerts; vi++)
                    {
                        Vector3 v = face.Vertices[vi].Position;
                        sw.WriteLine(PovVector3((v * mv) * 0.1f));
                    }
                    sw.WriteLine("}"); // vertex_vectors

                    sw.WriteLine("face_indices");
                    sw.WriteLine("{");

                    sw.WriteLine((numIndices / 3).ToString());

                    for (int ti = 0; ti < numIndices; ti += 3)
                        sw.WriteLine(string.Format("<{0},{1},{2}>", face.Indices[ti], face.Indices[ti + 1], face.Indices[ti + 2]));

                    sw.WriteLine("}"); // face_indices

                    // material

                    Color4 clr = tef.RGBA;
                    if (tef.TextureID != null && mKnownTextures.ContainsKey(tef.TextureID))
                    {
                        var texInfo = mKnownTextures[tef.TextureID];
                        if (texInfo != null)
                            clr *= texInfo.MeanColor;
                    }
                    sw.WriteLine("pigment {rgbf ");
                    sw.WriteLine(string.Format("<{0},{1},{2},{3}>", clr.R, clr.G, clr.B, 1.0f - clr.A));
                    sw.WriteLine("}");

                    //sw.WriteLine("pigment {rgb <1, 0.6, 0.6>}");

                    sw.WriteLine("}"); // mesh2
                }

                s = sw.ToString();
            }

            return s;
        }
Пример #3
0
        /// <summary>
        /// Full implementation of llGetBoundingBox according to SL 2015-04-15.
        /// http://wiki.secondlife.com/wiki/LlGetBoundingBox
        /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox
        /// Returns local bounding box of avatar without attachments
        /// if target is non-seated avatar or prim/mesh in avatar attachment.
        /// Returns local bounding box of object including seated avatars
        /// if target is seated avatar or prim/mesh in object.
        /// Uses meshing of prims for high accuracy
        /// or less accurate box models for speed.
        /// </summary>
        public LSL_List llGetBoundingBox(string obj)
        {
            m_host.AddScriptLPS(1);

            // Get target avatar if non-seated avatar or attachment, or prim and object
            UUID objID = UUID.Zero;
            UUID.TryParse(obj, out objID);
            ScenePresence agent = World.GetScenePresence(objID);
            if (agent != null)
            {
                if (agent.ParentPart != null)
                {
                    objID = agent.ParentPart.UUID;
                    agent = null;
                }
            }
            SceneObjectGroup group = null;
            SceneObjectPart target = World.GetSceneObjectPart(objID);
            if (target != null)
            {
                group = target.ParentGroup;
                if (group.IsAttachment) {
                    objID = group.AttachedAvatar;
                    agent = World.GetScenePresence(objID);
                    group = null;
                    target = null;
                }
            }

            // Initialize but break if no target
            LSL_List result = new LSL_List();
            int groupCount = 0;
            int partCount = 0;
            int vertexCount = 0;
            if (target == null && agent == null)
            {
                result.Add(new LSL_Vector());
                result.Add(new LSL_Vector());
                if (m_addStatsInGetBoundingBox)
                    result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount));
                return result;
            }
            Vector3 minPosition = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 maxPosition = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            // Try to get a mesher
            IRendering primMesher = null;
            List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
            if (renderers.Count > 0)
                primMesher = RenderingLoader.LoadRenderer(renderers[0]);

            // Get bounding box of just avatar, seated or not
            if (agent != null)
            {
                bool hasParent = false;
                Vector3 lower;
                Vector3 upper;
                BoundingBoxOfScenePresence(agent, out lower, out upper);
                Vector3 offset = Vector3.Zero;

                // Since local bounding box unrotated and untilted, keep it simple
                AddBoundingBoxOfSimpleBox(lower, upper, offset, agent.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                partCount++;
                groupCount++;

                // Return lower and upper bounding box corners
                result.Add(new LSL_Vector(minPosition));
                result.Add(new LSL_Vector(maxPosition));
                if (m_addStatsInGetBoundingBox)
                    result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount));
                return result;
            }
            // Get bounding box of object including seated avatars
            else if (group != null)
            {
                // Merge bounding boxes of all parts (prims and mesh)
                foreach (SceneObjectPart part in group.Parts)
                {
                    bool hasParent = (!part.IsRoot);
                    // When requested or if no mesher, keep it simple
                    if (m_useSimpleBoxesInGetBoundingBox || primMesher == null)
                    {
                        AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                    }
                    // Do the full mounty
                    else
                    {
                        Primitive omvPrim = part.Shape.ToOmvPrimitive(part.OffsetPosition, part.RotationOffset);
                        byte[] sculptAsset = null;
                        if (omvPrim.Sculpt != null)
                            sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());

                        // When part is mesh
                        // Quirk: Only imports as incompletely populated faceted mesh object, so needs an own handler.
                        if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null)
                        {
                            AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
                            FacetedMesh mesh = null;
                            FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh);
                            meshAsset = null;
                            if (mesh != null)
                            {
                                AddBoundingBoxOfFacetedMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                                mesh = null;
                            }
                        }

                        // When part is sculpt
                        // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt.
                        else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null)
                        {
                            IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>();
                            if (imgDecoder != null)
                            {
                                Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
                                if (sculpt != null)
                                {
                                    SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium);
                                    sculpt.Dispose();
                                    if (mesh != null)
                                    {
                                        AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                                        mesh = null;
                                    }
                                }
                            }
                        }

                        // When part is prim
                        else if (omvPrim.Sculpt == null)
                        {
                            SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium);
                            if (mesh != null)
                            {
                                AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                                mesh = null;
                            }
                        }

                        // When all else fails, try fallback to simple box
                        else
                        {
                            AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                        }
                    }
                    partCount++;
                }
            }

            // Merge bounding boxes of seated avatars
            foreach (ScenePresence sp in group.GetSittingAvatars())
            {
                Vector3 lower;
                Vector3 upper;
                BoundingBoxOfScenePresence(sp, out lower, out upper);
                Vector3 offset = sp.OffsetPosition;

                bool hasParent = true;
                // When requested or if no mesher, keep it simple
                if (m_useSimpleBoxesInGetBoundingBox || primMesher == null)
                {
                    AddBoundingBoxOfSimpleBox(lower, upper, offset, sp.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                }
                // Do the full mounty
                else
                {
                    // Prim shapes don't do center offsets, so add it here.
                    offset = offset + (lower + upper) * 0.5f * sp.Rotation;
                    Primitive omvPrim = MakeOpenMetaversePrim(upper - lower, offset, sp.Rotation, ScriptBaseClass.PRIM_TYPE_SPHERE);
                    SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium);
                    AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount);
                    mesh = null;
                }
                partCount++;
            }

            groupCount++;

            // Return lower and upper bounding box corners
            result.Add(new LSL_Vector(minPosition));
            result.Add(new LSL_Vector(maxPosition));
            if (m_addStatsInGetBoundingBox)
                result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount));

            primMesher = null;
            return result;
        }
Пример #4
0
        /// <summary>
        /// Implementation of llCastRay similar to SL 2015-04-21.
        /// http://wiki.secondlife.com/wiki/LlCastRay
        /// Uses pure geometry, bounding shapes, meshing and no physics
        /// for prims, sculpts, meshes, avatars and terrain.
        /// Implements all flags, reject types and data flags.
        /// Can handle both objects/groups and prims/parts, by config.
        /// May sometimes be inaccurate owing to calculation precision,
        /// meshing detail level and a bug in libopenmetaverse PrimMesher.
        /// </summary>
        public LSL_List llCastRayV3(LSL_Vector start, LSL_Vector end, LSL_List options)
        {
            m_host.AddScriptLPS(1);
            LSL_List result = new LSL_List();

            // Prepare throttle data
            int calledMs = Environment.TickCount;
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            UUID regionId = World.RegionInfo.RegionID;
            UUID userId = UUID.Zero;
            int msAvailable = 0;
            // Throttle per owner when attachment or "vehicle" (sat upon)
            if (m_host.ParentGroup.IsAttachment || m_host.ParentGroup.GetSittingAvatars().Count > 0)
            {
                userId = m_host.OwnerID;
                msAvailable = m_msPerAvatarInCastRay;
            }
            // Throttle per parcel when not attachment or vehicle
            else
            {
                LandData land = World.GetLandData(m_host.GetWorldPosition());
                if (land != null)
                    msAvailable = m_msPerRegionInCastRay * land.Area / 65536;
            }
            // Clamp for "oversized" parcels on varregions
            if (msAvailable > m_msMaxInCastRay)
                msAvailable = m_msMaxInCastRay;

            // Check throttle data
            int fromCalledMs = calledMs - m_msThrottleInCastRay;
            lock (m_castRayCalls)
            {
                for (int i = m_castRayCalls.Count - 1; i >= 0; i--)
                {
                    // Delete old calls from throttle data
                    if (m_castRayCalls[i].CalledMs < fromCalledMs)
                        m_castRayCalls.RemoveAt(i);
                    // Use current region (in multi-region sims)
                    else if (m_castRayCalls[i].RegionId == regionId)
                    {
                        // Reduce available time with recent calls
                        if (m_castRayCalls[i].UserId == userId)
                            msAvailable -= m_castRayCalls[i].UsedMs;
                    }
                }
            }

            // Return failure if not enough available time
            if (msAvailable < m_msMinInCastRay)
            {
                result.Add(new LSL_Integer(ScriptBaseClass.RCERR_CAST_TIME_EXCEEDED));
                return result;
            }

            // Initialize
            List<RayHit> rayHits = new List<RayHit>();
            float tol = m_floatToleranceInCastRay;
            Vector3 pos1Ray = start;
            Vector3 pos2Ray = end;

            // Get input options
            int rejectTypes = 0;
            int dataFlags = 0;
            int maxHits = 1;
            bool detectPhantom = false;
            for (int i = 0; i < options.Length; i += 2)
            {
                if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
                    rejectTypes = options.GetLSLIntegerItem(i + 1);
                else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
                    dataFlags = options.GetLSLIntegerItem(i + 1);
                else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
                    maxHits = options.GetLSLIntegerItem(i + 1);
                else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
                    detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0);
            }
            if (maxHits > m_maxHitsInCastRay)
                maxHits = m_maxHitsInCastRay;
            bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0);
            bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0);
            bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0);
            bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0);
            bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0);
            bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0);
            bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0);

            // Calculate some basic parameters
            Vector3 vecRay = pos2Ray - pos1Ray;
            float rayLength = vecRay.Length();

            // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits
            IRendering primMesher = null;
            List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
            if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1)
            {
                result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN));
                return result;
            }
            primMesher = RenderingLoader.LoadRenderer(renderers[0]);

            // Iterate over all objects/groups and prims/parts in region
            World.ForEachSOG(
                delegate(SceneObjectGroup group)
                {
                    // Check group filters unless part filters are configured
                    bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical);
                    bool isNonphysical = !isPhysical;
                    bool isPhantom = group.IsPhantom || group.IsVolumeDetect;
                    bool isAttachment = group.IsAttachment;
                    bool doGroup = true;
                    if (isPhysical && rejectPhysical)
                        doGroup = false;
                    if (isNonphysical && rejectNonphysical)
                        doGroup = false;
                    if (isPhantom && detectPhantom)
                        doGroup = true;
                    if (m_filterPartsInCastRay)
                        doGroup = true;
                    if (isAttachment && !m_doAttachmentsInCastRay)
                        doGroup = false;
                    // Parse object/group if passed filters
                    if (doGroup)
                    {
                        // Iterate over all prims/parts in object/group
                        foreach(SceneObjectPart part in group.Parts)
                        {
                            // Check part filters if configured
                            if (m_filterPartsInCastRay)
                            {
                                isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical);
                                isNonphysical = !isPhysical;
                                isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive);
                                bool doPart = true;
                                if (isPhysical && rejectPhysical)
                                    doPart = false;
                                if (isNonphysical && rejectNonphysical)
                                    doPart = false;
                                if (isPhantom && detectPhantom)
                                    doPart = true;
                                if (!doPart)
                                    continue;
                            }

                            // Parse prim/part and project ray if passed filters
                            Vector3 scalePart = part.Scale;
                            Vector3 posPart = part.GetWorldPosition();
                            Quaternion rotPart = part.GetWorldRotation();
                            Quaternion rotPartInv = Quaternion.Inverse(rotPart);
                            Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart;
                            Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart;

                            // Filter parts by shape bounding boxes
                            Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f);
                            if (!part.Shape.SculptEntry)
                                shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ));
                            shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol));
                            if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax))
                            {
                                // Prepare data needed to check for ray hits
                                RayTrans rayTrans = new RayTrans();
                                rayTrans.PartId = part.UUID;
                                rayTrans.GroupId = part.ParentGroup.UUID;
                                rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0;
                                rayTrans.ScalePart = scalePart;
                                rayTrans.PositionPart = posPart;
                                rayTrans.RotationPart = rotPart;
                                rayTrans.ShapeNeedsEnds = true;
                                rayTrans.Position1Ray = pos1Ray;
                                rayTrans.Position1RayProj = pos1RayProj;
                                rayTrans.VectorRayProj = pos2RayProj - pos1RayProj;

                                // Get detail level depending on type
                                int lod = 0;
                                // Mesh detail level
                                if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh)
                                    lod = (int)m_meshLodInCastRay;
                                // Sculpt detail level
                                else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh)
                                    lod = (int)m_sculptLodInCastRay;
                                // Shape detail level
                                else if (!part.Shape.SculptEntry)
                                    lod = (int)m_primLodInCastRay;

                                // Try to get cached mesh if configured
                                ulong meshKey = 0;
                                FacetedMesh mesh = null;
                                if (m_useMeshCacheInCastRay)
                                {
                                    meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod));
                                    lock (m_cachedMeshes)
                                    {
                                        m_cachedMeshes.TryGetValue(meshKey, out mesh);
                                    }
                                }

                                // Create mesh if no cached mesh
                                if (mesh == null)
                                {
                                    // Make an OMV prim to be able to mesh part
                                    Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart);
                                    byte[] sculptAsset = null;
                                    if (omvPrim.Sculpt != null)
                                        sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());

                                    // When part is mesh, get mesh
                                    if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null)
                                    {
                                        AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
                                        FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh);
                                        meshAsset = null;
                                    }

                                    // When part is sculpt, create mesh
                                    // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt.
                                    else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null)
                                    {
                                        IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>();
                                        if (imgDecoder != null)
                                        {
                                            Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
                                            if (sculpt != null)
                                            {
                                                mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay);
                                                sculpt.Dispose();
                                            }
                                        }
                                   }

                                    // When part is shape, create mesh
                                    else if (omvPrim.Sculpt == null)
                                    {
                                        if (
                                            omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 &&
                                            omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 &&
                                            omvPrim.PrimData.PathSkew == 0.0 &&
                                            omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0
                                        )
                                            rayTrans.ShapeNeedsEnds = false;
                                        mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay);
                                    }

                                    // Cache mesh if configured
                                    if (m_useMeshCacheInCastRay && mesh != null)
                                    {
                                        lock(m_cachedMeshes)
                                        {
                                            if (!m_cachedMeshes.ContainsKey(meshKey))
                                                m_cachedMeshes.Add(meshKey, mesh);
                                        }
                                    }
                                }
                                // Check mesh for ray hits
                                AddRayInFacetedMesh(mesh, rayTrans, ref rayHits);
                                mesh = null;
                            }
                        }
                    }
                }
            );

            // Check avatar filter
            if (!rejectAgents)
            {
                // Iterate over all avatars in region
                World.ForEachRootScenePresence(
                    delegate (ScenePresence sp)
                    {
                        // Get bounding box
                        Vector3 lower;
                        Vector3 upper;
                        BoundingBoxOfScenePresence(sp, out lower, out upper);
                        // Parse avatar
                        Vector3 scalePart = upper - lower;
                        Vector3 posPart = sp.AbsolutePosition;
                        Quaternion rotPart = sp.GetWorldRotation();
                        Quaternion rotPartInv = Quaternion.Inverse(rotPart);
                        posPart = posPart + (lower + upper) * 0.5f * rotPart;
                        // Project ray
                        Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart;
                        Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart;

                        // Filter avatars by shape bounding boxes
                        Vector3 shapeBoxMax = new Vector3(0.5f + tol, 0.5f + tol, 0.5f + tol);
                        if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax))
                        {
                            // Prepare data needed to check for ray hits
                            RayTrans rayTrans = new RayTrans();
                            rayTrans.PartId = sp.UUID;
                            rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID;
                            rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0;
                            rayTrans.ScalePart = scalePart;
                            rayTrans.PositionPart = posPart;
                            rayTrans.RotationPart = rotPart;
                            rayTrans.ShapeNeedsEnds = false;
                            rayTrans.Position1Ray = pos1Ray;
                            rayTrans.Position1RayProj = pos1RayProj;
                            rayTrans.VectorRayProj = pos2RayProj - pos1RayProj;

                            // Try to get cached mesh if configured
                            PrimitiveBaseShape prim = PrimitiveBaseShape.CreateSphere();
                            int lod = (int)m_avatarLodInCastRay;
                            ulong meshKey = prim.GetMeshKey(Vector3.One, (float)(4 << lod));
                            FacetedMesh mesh = null;
                            if (m_useMeshCacheInCastRay)
                            {
                                lock (m_cachedMeshes)
                                {
                                    m_cachedMeshes.TryGetValue(meshKey, out mesh);
                                }
                            }

                            // Create mesh if no cached mesh
                            if (mesh == null)
                            {
                                // Make OMV prim and create mesh
                                prim.Scale = scalePart;
                                Primitive omvPrim = prim.ToOmvPrimitive(posPart, rotPart);
                                mesh = primMesher.GenerateFacetedMesh(omvPrim, m_avatarLodInCastRay);

                                // Cache mesh if configured
                                if (m_useMeshCacheInCastRay && mesh != null)
                                {
                                    lock(m_cachedMeshes)
                                    {
                                        if (!m_cachedMeshes.ContainsKey(meshKey))
                                            m_cachedMeshes.Add(meshKey, mesh);
                                    }
                                }
                            }

                            // Check mesh for ray hits
                            AddRayInFacetedMesh(mesh, rayTrans, ref rayHits);
                            mesh = null;
                        }
                    }
                );
            }

            // Check terrain filter
            if (!rejectLand)
            {
                // Parse terrain

                // Mesh terrain and check bounding box
                Vector3 lower;
                Vector3 upper;
                List<Tri> triangles = TrisFromHeightmapUnderRay(pos1Ray, pos2Ray, out lower, out upper);
                lower.Z -= tol;
                upper.Z += tol;
                if ((pos1Ray.Z >= lower.Z || pos2Ray.Z >= lower.Z) && (pos1Ray.Z <= upper.Z || pos2Ray.Z <= upper.Z))
                {
                    // Prepare data needed to check for ray hits
                    RayTrans rayTrans = new RayTrans();
                    rayTrans.PartId = UUID.Zero;
                    rayTrans.GroupId = UUID.Zero;
                    rayTrans.Link = 0;
                    rayTrans.ScalePart = new Vector3 (1.0f, 1.0f, 1.0f);
                    rayTrans.PositionPart = Vector3.Zero;
                    rayTrans.RotationPart = Quaternion.Identity;
                    rayTrans.ShapeNeedsEnds = true;
                    rayTrans.Position1Ray = pos1Ray;
                    rayTrans.Position1RayProj = pos1Ray;
                    rayTrans.VectorRayProj = vecRay;

                    // Check mesh
                    AddRayInTris(triangles, rayTrans, ref rayHits);
                    triangles = null;
                }
            }

            // Sort hits by ascending distance
            rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance));

            // Check excess hits per part and group
            for (int t = 0; t < 2; t++)
            {
                int maxHitsPerType = 0;
                UUID id = UUID.Zero;
                if (t == 0)
                    maxHitsPerType = m_maxHitsPerPrimInCastRay;
                else
                    maxHitsPerType = m_maxHitsPerObjectInCastRay;

                // Handle excess hits only when needed
                if (maxHitsPerType < m_maxHitsInCastRay)
                {
                    // Find excess hits
                    Hashtable hits = new Hashtable();
                    for (int i = rayHits.Count - 1; i >= 0; i--)
                    {
                        if (t == 0)
                            id = rayHits[i].PartId;
                        else
                            id = rayHits[i].GroupId;
                        if (hits.ContainsKey(id))
                            hits[id] = (int)hits[id] + 1;
                        else
                            hits[id] = 1;
                    }

                    // Remove excess hits
                    for (int i = rayHits.Count - 1; i >= 0; i--)
                    {
                        if (t == 0)
                            id = rayHits[i].PartId;
                        else
                            id = rayHits[i].GroupId;
                        int hit = (int)hits[id];
                        if (hit > m_maxHitsPerPrimInCastRay)
                        {
                            rayHits.RemoveAt(i);
                            hit--;
                            hits[id] = hit;
                        }
                    }
                }
            }

            // Parse hits into result list according to data flags
            int hitCount = rayHits.Count;
            if (hitCount > maxHits)
                hitCount = maxHits;
            for (int i = 0; i < hitCount; i++)
            {
                RayHit rayHit = rayHits[i];
                if (getRootKey)
                    result.Add(new LSL_Key(rayHit.GroupId.ToString()));
                else
                    result.Add(new LSL_Key(rayHit.PartId.ToString()));
                result.Add(new LSL_Vector(rayHit.Position));
                if (getLinkNum)
                    result.Add(new LSL_Integer(rayHit.Link));
                if (getNormal)
                    result.Add(new LSL_Vector(rayHit.Normal));
            }
            result.Add(new LSL_Integer(hitCount));

            // Add to throttle data
            stopWatch.Stop();
            CastRayCall castRayCall = new CastRayCall();
            castRayCall.RegionId = regionId;
            castRayCall.UserId = userId;
            castRayCall.CalledMs = calledMs;
            castRayCall.UsedMs = (int)stopWatch.ElapsedMilliseconds;
            lock (m_castRayCalls)
            {
                m_castRayCalls.Add(castRayCall);
            }

            // Return hits
            return result;
        }
Пример #5
0
 private void Asset_MeshCallback(bool success, AssetMesh assetMesh)
 {
     lock (Manager.AssetsReceived)
         Manager.AssetsReceived[assetMesh.AssetID] = success;
 }
Пример #6
0
        /// <summary>
        /// Decodes mesh asset into FacetedMesh
        /// </summary>
        /// <param name="prim">Mesh primitive</param>
        /// <param name="meshAsset">Asset retrieved from the asset server</param>
        /// <param name="LOD">Level of detail</param>
        /// <param name="mesh">Resulting decoded FacetedMesh</param>
        /// <returns>True if mesh asset decoding was successful</returns>
        public static bool TryDecodeFromAsset(Primitive prim, AssetMesh meshAsset, DetailLevel LOD, out FacetedMesh mesh)
        {
            mesh = null;

            try
            {
                if (!meshAsset.Decode())
                {
                    return false;
                }

                OSDMap MeshData = meshAsset.MeshData;

                mesh = new FacetedMesh();

                mesh.Faces = new List<Face>();
                mesh.Prim = prim;
                mesh.Profile.Faces = new List<ProfileFace>();
                mesh.Profile.Positions = new List<Vector3>();
                mesh.Path.Points = new List<PathPoint>();

                OSD facesOSD = null;

                switch (LOD)
                {
                    default:
                    case DetailLevel.Highest:
                        facesOSD = MeshData["high_lod"];
                        break;

                    case DetailLevel.High:
                        facesOSD = MeshData["medium_lod"];
                        break;

                    case DetailLevel.Medium:
                        facesOSD = MeshData["low_lod"];
                        break;

                    case DetailLevel.Low:
                        facesOSD = MeshData["lowest_lod"];
                        break;
                }

                if (facesOSD == null || !(facesOSD is OSDArray))
                {
                    return false;
                }

                OSDArray decodedMeshOsdArray = (OSDArray)facesOSD;

                for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++)
                {
                    OSD subMeshOsd = decodedMeshOsdArray[faceNr];

                    // Decode each individual face
                    if (subMeshOsd is OSDMap)
                    {
                        Face oface = new Face();
                        oface.ID = faceNr;
                        oface.Vertices = new List<Vertex>();
                        oface.Indices = new List<ushort>();
                        oface.TextureFace = prim.Textures.GetFace((uint)faceNr);

                        OSDMap subMeshMap = (OSDMap)subMeshOsd;

                        Vector3 posMax;
                        Vector3 posMin;

                        // If PositionDomain is not specified, the default is from -0.5 to 0.5
                        if (subMeshMap.ContainsKey("PositionDomain"))
                        {
                            posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"];
                            posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"];
                        }
                        else
                        {
                            posMax = new Vector3(0.5f, 0.5f, 0.5f);
                            posMin = new Vector3(-0.5f, -0.5f, -0.5f);
                        }

                        // Vertex positions
                        byte[] posBytes = subMeshMap["Position"];

                        // Normals
                        byte[] norBytes = null;
                        if (subMeshMap.ContainsKey("Normal"))
                        {
                            norBytes = subMeshMap["Normal"];
                        }

                        // UV texture map
                        Vector2 texPosMax = Vector2.Zero;
                        Vector2 texPosMin = Vector2.Zero;
                        byte[] texBytes = null;
                        if (subMeshMap.ContainsKey("TexCoord0"))
                        {
                            texBytes = subMeshMap["TexCoord0"];
                            texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"];
                            texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"];
                        }

                        // Extract the vertex position data
                        // If present normals and texture coordinates too
                        for (int i = 0; i < posBytes.Length; i += 6)
                        {
                            ushort uX = Utils.BytesToUInt16(posBytes, i);
                            ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
                            ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);

                            Vertex vx = new Vertex();

                            vx.Position = new Vector3(
                                Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
                                Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
                                Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));

                            if (norBytes != null && norBytes.Length >= i + 4)
                            {
                                ushort nX = Utils.BytesToUInt16(norBytes, i);
                                ushort nY = Utils.BytesToUInt16(norBytes, i + 2);
                                ushort nZ = Utils.BytesToUInt16(norBytes, i + 4);

                                vx.Normal = new Vector3(
                                    Utils.UInt16ToFloat(nX, posMin.X, posMax.X),
                                    Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y),
                                    Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z));
                            }

                            var vertexIndexOffset = oface.Vertices.Count * 4;

                            if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4)
                            {
                                ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset);
                                ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2);

                                vx.TexCoord = new Vector2(
                                    Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X),
                                    Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y));
                            }

                            oface.Vertices.Add(vx);
                        }

                        byte[] triangleBytes = subMeshMap["TriangleList"];
                        for (int i = 0; i < triangleBytes.Length; i += 6)
                        {
                            ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i));
                            oface.Indices.Add(v1);
                            ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2));
                            oface.Indices.Add(v2);
                            ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4));
                            oface.Indices.Add(v3);
                        }

                        mesh.Faces.Add(oface);
                    }
                }

            }
            catch (Exception ex)
            {
                Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning);
                return false;
            }

            return true;
        }
Пример #7
0
        private void CreatePrim(WarpRenderer renderer, SceneObjectPart prim,
                bool useTextures)
        {
            const float MIN_SIZE = 2f;

            if ((PCode)prim.Shape.PCode != PCode.Prim)
                return;
            if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE)
                return;

            FacetedMesh renderMesh = null;
            Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset);

            if (m_renderMeshes)
            {
                if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero)
                {
                    // Try fetchinng the asset
                    byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
                    if (sculptAsset != null)
                    {
                        // Is it a mesh?
                        if (omvPrim.Sculpt.Type == SculptType.Mesh)
                        {
                            AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
                            FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
                            meshAsset = null;
                        }
                        else // It's sculptie
                        {
                            IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
                            if (imgDecoder != null)
                            {
                                Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
                                if (sculpt != null)
                                {
                                    renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt,
                                                                                        DetailLevel.Medium);
                                    sculpt.Dispose();
                                }
                            }
                        }
                    }
                }
            }

            // If not a mesh or sculptie, try the regular mesher
            if (renderMesh == null)
            {
                renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
            }

            if (renderMesh == null)
                return;

            warp_Vector primPos = ConvertVector(prim.GetWorldPosition());
            warp_Quaternion primRot = ConvertQuaternion(prim.RotationOffset);

            warp_Matrix m = warp_Matrix.quaternionMatrix(primRot);

            if (prim.ParentID != 0)
            {
                SceneObjectGroup group = m_scene.SceneGraph.GetGroupByPrim(prim.LocalId);
                if (group != null)
                    m.transform(warp_Matrix.quaternionMatrix(ConvertQuaternion(group.RootPart.RotationOffset)));
            }

            warp_Vector primScale = ConvertVector(prim.Scale);

            string primID = prim.UUID.ToString();

            // Create the prim faces
            // TODO: Implement the useTextures flag behavior
            for (int i = 0; i < renderMesh.Faces.Count; i++)
            {
                Face face = renderMesh.Faces[i];
                string meshName = primID + "-Face-" + i.ToString();

                // Avoid adding duplicate meshes to the scene
                if (renderer.Scene.objectData.ContainsKey(meshName))
                {
                    continue;
                }

                warp_Object faceObj = new warp_Object(face.Vertices.Count, face.Indices.Count / 3);

                for (int j = 0; j < face.Vertices.Count; j++)
                {
                    Vertex v = face.Vertices[j];

                    warp_Vector pos = ConvertVector(v.Position);
                    warp_Vector norm = ConvertVector(v.Normal);
                    
                    if (prim.Shape.SculptTexture == UUID.Zero)
                        norm = norm.reverse();
                    warp_Vertex vert = new warp_Vertex(pos, norm, v.TexCoord.X, v.TexCoord.Y);

                    faceObj.addVertex(vert);
                }

                for (int j = 0; j < face.Indices.Count; j += 3)
                {
                    faceObj.addTriangle(
                        face.Indices[j + 0],
                        face.Indices[j + 1],
                        face.Indices[j + 2]);
                }

                Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
                Color4 faceColor = GetFaceColor(teFace);
                string materialName = String.Empty;
                if (m_texturePrims && prim.Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize)
                    materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID);
                else
                    materialName = GetOrCreateMaterial(renderer, faceColor);

                faceObj.transform(m);
                faceObj.setPos(primPos);
                faceObj.scaleSelf(primScale.x, primScale.y, primScale.z);

                renderer.Scene.addObject(meshName, faceObj);

                renderer.SetObjectMaterial(meshName, materialName);
            }
        }