Пример #1
0
        public bool Raycast(FRay ray, out float closestDistance)
        {
            // Convert the ray to local space of this node since all of our raycasts are local.
            FRay localRay = WMath.TransformRay(ray, Transform.Position, Transform.LocalScale, Transform.Rotation.Inverted());
            bool bHit     = false;

            if (m_actorMesh != null)
            {
                bHit = m_actorMesh.Raycast(localRay, out closestDistance, true);
            }
            else
            {
                bHit = WMath.RayIntersectsAABB(localRay, m_objRender.GetAABB().Min, m_objRender.GetAABB().Max, out closestDistance);
            }

            if (bHit)
            {
                // Convert the hit point back to world space...
                Vector3 localHitPoint = localRay.Origin + (localRay.Direction * closestDistance);
                localHitPoint = Vector3.Transform(localHitPoint + Transform.Position, Transform.Rotation);

                // Now get the distance from the original ray origin and the new worldspace hit point.
                closestDistance = (localHitPoint - ray.Origin).Length;
            }

            return(bHit);
        }
Пример #2
0
        private void DoOrbitcamUpdate(float deltaTime)
        {
            float      orbitSensitivityScale = 0.02f; // Angle Axis expects rads, but we have... pixels, so we just move it way down by a factor.
            Quaternion deltaRot = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), -WInput.MouseDelta.Y * MouseSensitivity * deltaTime * orbitSensitivityScale) * Quaternion.FromAxisAngle(new Vector3(0, 1, 0), -WInput.MouseDelta.X * MouseSensitivity * deltaTime * orbitSensitivityScale);

            Transform.Rotation *= deltaRot;

            Vector3 moveDir = Vector3.Zero;

            if (WInput.GetKey(System.Windows.Input.Key.Q))
            {
                moveDir -= Vector3.UnitY;
            }
            if (WInput.GetKey(System.Windows.Input.Key.E))
            {
                moveDir += Vector3.UnitY;
            }

            if (moveDir.Length > 0)
            {
                moveDir.Normalize();
                m_orbitPivot += moveDir * (MoveSpeed / 2) * deltaTime;
            }

            m_orbitCameraDistance += -WInput.MouseScrollDelta * 50 * deltaTime;
            m_orbitCameraDistance  = WMath.Clamp(m_orbitCameraDistance, 100, 10000);

            Transform.Position = m_orbitPivot + Vector3.Transform(new Vector3(0, 0, m_orbitCameraDistance), Transform.Rotation);
        }
Пример #3
0
        private void DoFlycamUpdate(float deltaTime)
        {
            Vector3 moveDir = Vector3.Zero;

            if (WInput.GetKey(System.Windows.Input.Key.W))
            {
                moveDir -= Vector3.UnitZ;
            }
            if (WInput.GetKey(System.Windows.Input.Key.S))
            {
                moveDir += Vector3.UnitZ;
            }
            if (WInput.GetKey(System.Windows.Input.Key.D))
            {
                moveDir += Vector3.UnitX;
            }
            if (WInput.GetKey(System.Windows.Input.Key.A))
            {
                moveDir -= Vector3.UnitX;
            }

            // If they're holding down the shift key adjust their FOV when they scroll, otherwise adjust move speed.
            MoveSpeed += WInput.MouseScrollDelta * 100 * deltaTime;
            MoveSpeed  = WMath.Clamp(MoveSpeed, 100, 8000);

            if (WInput.GetMouseButton(1))
            {
                Rotate(deltaTime, WInput.MouseDelta.X, WInput.MouseDelta.Y);
            }

            float moveSpeed = WInput.GetKey(System.Windows.Input.Key.LeftShift) ? MoveSpeed * 3f : MoveSpeed;

            // Make it relative to the current rotation.
            moveDir = Vector3.Transform(moveDir, Transform.Rotation);

            // Do Q and E after we transform the moveDir so they're always in worldspace.
            if (WInput.GetKey(System.Windows.Input.Key.Q))
            {
                moveDir -= Vector3.UnitY;
            }
            if (WInput.GetKey(System.Windows.Input.Key.E))
            {
                moveDir += Vector3.UnitY;
            }

            // Normalize the move direction
            moveDir.NormalizeFast();

            // Early out if we're not moving this frame.
            if (moveDir.LengthFast < 0.1f)
            {
                return;
            }

            Transform.Position += Vector3.Multiply(moveDir, moveSpeed * deltaTime);
        }
Пример #4
0
        public bool Raycast(FRay ray, out float closestDistance)
        {
            // Convert the ray to local space of this node since all of our raycasts are local.
            FRay localRay;

            if (DisableRotationAndScaleForRaycasting)
            {
                localRay = WMath.TransformRay(ray, Transform.Position, Vector3.One, Quaternion.Identity);
            }
            else
            {
                localRay = WMath.TransformRay(ray, Transform.Position, VisualScale, Transform.Rotation.Inverted().ToSinglePrecision());
            }
            closestDistance = float.MaxValue;
            bool bHit = false;

            if (m_actorMeshes.Count > 0)
            {
                foreach (var actor_mesh in m_actorMeshes)
                {
                    bHit = actor_mesh.Raycast(localRay, out closestDistance, true);

                    if (bHit)
                    {
                        break;
                    }
                }
            }
            else if (m_objRender != null)
            {
                if (m_objRender.FaceCullingEnabled && m_objRender.GetAABB().Contains(localRay.Origin))
                {
                    // If the camera is inside an OBJ render that has backface culling on, the actor won't actually be visible, so don't select it.
                    return(false);
                }

                bHit = WMath.RayIntersectsAABB(localRay, m_objRender.GetAABB().Min, m_objRender.GetAABB().Max, out closestDistance);

                if (bHit)
                {
                    // Convert the hit point back to world space...
                    Vector3 localHitPoint  = localRay.Origin + (localRay.Direction * closestDistance);
                    Vector3 globalHitPoint = Transform.Position + Vector3.Transform(localHitPoint, Transform.Rotation.ToSinglePrecision());

                    // Now get the distance from the original ray origin and the new worldspace hit point.
                    closestDistance = (globalHitPoint - ray.Origin).Length;
                }
            }

            return(bHit);
        }
Пример #5
0
        void IRenderable.Draw(WSceneView view)
        {
            Vector3    scale       = Transform.LocalScale;
            Quaternion rotation    = Transform.Rotation;
            Vector3    translation = Transform.Position;

            if (RoomTransform != null)
            {
                rotation    = Quaternion.FromAxisAngle(Vector3.UnitY, WMath.DegreesToRadians(RoomTransform.YRotation));
                translation = new Vector3(RoomTransform.Translation.X, 0, RoomTransform.Translation.Y);
            }

            Matrix4 trs = Matrix4.CreateScale(scale) * Matrix4.CreateFromQuaternion(rotation) * Matrix4.CreateTranslation(translation);

            foreach (var mesh in m_roomModels)
            {
                mesh.Render(view.ViewMatrix, view.ProjMatrix, trs);
            }
        }
Пример #6
0
        public static float FindQuaternionTwist(this Quaternion quat, Vector3 axis)
        {
            axis.Normalize();

            // Get the plane the axis is a normal of
            Vector3 orthoNormal1, orthoNormal2;

            WMath.FindOrthoNormals(axis, out orthoNormal1, out orthoNormal2);
            Vector3 transformed = Vector3.Transform(orthoNormal1, quat);

            // Project transformed vector onto a plane
            Vector3 flattened = transformed - (Vector3.Dot(transformed, axis) * axis);

            flattened.Normalize();

            // Get the angle between the original vector and projected transform to get angle around normal
            float a = (float)Math.Acos((double)Vector3.Dot(orthoNormal1, flattened));

            return(WMath.RadiansToDegrees(a));
        }
Пример #7
0
        /// <summary>
        /// Create a Quaternion from Euler Angles. These should be in degrees in [-180, 180] space.
        /// </summary>
        public static Quaternion FromEulerAngles(this Quaternion quat, Vector3 eulerAngles)
        {
            eulerAngles.X = WMath.DegreesToRadians(eulerAngles.X);
            eulerAngles.Y = WMath.DegreesToRadians(eulerAngles.Y);
            eulerAngles.Z = WMath.DegreesToRadians(eulerAngles.Z);

            double c1   = Math.Cos(eulerAngles.Y / 2f);
            double s1   = Math.Sin(eulerAngles.Y / 2f);
            double c2   = Math.Cos(eulerAngles.X / 2f);
            double s2   = Math.Sin(eulerAngles.X / 2f);
            double c3   = Math.Cos(eulerAngles.Z / 2f);
            double s3   = Math.Sin(eulerAngles.Z / 2f);
            double c1c2 = c1 * c2;
            double s1s2 = s1 * s2;

            float w = (float)(c1c2 * c3 - s1s2 * s3);
            float x = (float)(c1c2 * s3 + s1s2 * c3);
            float y = (float)(s1 * c2 * c3 + c1 * s2 * s3);
            float z = (float)(c1 * s2 * c3 - s1 * c2 * s3);

            return(new Quaternion(x, y, z, w));
        }
Пример #8
0
        public LightingPalette Lerp(float t, bool presetA = true)
        {
            LightingPalette[] palette = presetA ? TimePresetA : TimePresetB;

            // Generate a new LightingPalette which is the interpolated values of things.
            t = WMath.Clamp(t, 0, 1);
            float scaledT    = t * (palette.Length - 1);
            int   lowerIndex = (int)scaledT;
            int   upperIndex = (int)(scaledT + 1f);
            float newT       = scaledT - (int)scaledT;

            //Console.WriteLine("t: {0} scaledT: {1} lIndex: {2} uIndex: {3} newT: {4}", t, scaledT, lowerIndex, upperIndex, newT);

            if (upperIndex == palette.Length)
            {
                upperIndex = lowerIndex;
            }

            LightingPalette interpPalette = new LightingPalette();

            interpPalette.Shadow        = WLinearColor.Lerp(palette[lowerIndex].Shadow, palette[upperIndex].Shadow, newT);
            interpPalette.ActorAmbient  = WLinearColor.Lerp(palette[lowerIndex].ActorAmbient, palette[upperIndex].ActorAmbient, newT);
            interpPalette.RoomLight     = WLinearColor.Lerp(palette[lowerIndex].RoomLight, palette[upperIndex].RoomLight, newT);
            interpPalette.RoomAmbient   = WLinearColor.Lerp(palette[lowerIndex].RoomAmbient, palette[upperIndex].RoomAmbient, newT);
            interpPalette.WaveColor     = WLinearColor.Lerp(palette[lowerIndex].WaveColor, palette[upperIndex].WaveColor, newT);
            interpPalette.OceanColor    = WLinearColor.Lerp(palette[lowerIndex].OceanColor, palette[upperIndex].OceanColor, newT);
            interpPalette.UnknownWhite1 = WLinearColor.Lerp(palette[lowerIndex].UnknownWhite1, palette[upperIndex].UnknownWhite1, newT);
            interpPalette.UnknownWhite2 = WLinearColor.Lerp(palette[lowerIndex].UnknownWhite2, palette[upperIndex].UnknownWhite2, newT);
            interpPalette.Doorway       = WLinearColor.Lerp(palette[lowerIndex].Doorway, palette[upperIndex].Doorway, newT);
            interpPalette.UnknownColor3 = WLinearColor.Lerp(palette[lowerIndex].UnknownColor3, palette[upperIndex].UnknownColor3, newT);
            interpPalette.Skybox        = LightingSkyboxColors.Lerp(palette[lowerIndex].Skybox, palette[upperIndex].Skybox, newT);
            interpPalette.Fog           = WLinearColor.Lerp(palette[lowerIndex].Fog, palette[upperIndex].Fog, newT);
            interpPalette.FogNearPlane  = WMath.Lerp(palette[lowerIndex].FogNearPlane, palette[upperIndex].FogNearPlane, newT);
            interpPalette.FogFarPlane   = WMath.Lerp(palette[lowerIndex].FogFarPlane, palette[upperIndex].FogFarPlane, newT);

            return(interpPalette);
        }
Пример #9
0
        public Vector3 GetCenter()
        {
            List <J3DNode> m_roomModelNodes = GetChildrenOfType <J3DNode>();

            Vector3 roomOffset = Vector3.Zero;

            if (m_roomModelNodes.Count > 0)
            {
                roomOffset += m_roomModelNodes[0].Model.BoundingSphere.Center;
            }

            if (RoomTransform != null)
            {
                roomOffset += new Vector3(RoomTransform.Translation.X, 0, RoomTransform.Translation.Y);

                float angle = WMath.DegreesToRadians(-RoomTransform.YRotation);
                float origX = roomOffset.X;
                float origZ = roomOffset.Z;
                roomOffset.X = (float)(origX * Math.Cos(angle) - origZ * Math.Sin(angle));
                roomOffset.Z = (float)(origX * Math.Sin(angle) + origZ * Math.Cos(angle));
            }

            return(roomOffset);
        }
Пример #10
0
        public static Quaternion FromEulerAnglesRobust(this Quaternion quat, Vector3 eulerAngles, string rotationOrder, bool usesX, bool usesY, bool usesZ)
        {
            quat = Quaternion.Identity;

            foreach (var axis in rotationOrder)
            {
                int axisIndex = "XYZ".IndexOf(axis);
                if (new[] { usesX, usesY, usesZ }[axisIndex])
                {
                    float      thisAxisRot    = new[] { eulerAngles.X, eulerAngles.Y, eulerAngles.Z }[axisIndex];
                    Vector3    axisUnitVector = new Vector3(axis == 'X' ? 1 : 0, axis == 'Y' ? 1 : 0, axis == 'Z' ? 1 : 0);
                    Quaternion thisAxisRotQ   = Quaternion.FromAxisAngle(axisUnitVector, WMath.DegreesToRadians(thisAxisRot));
                    quat *= thisAxisRotQ;
                }
                ;
            }

            return(quat);
        }
Пример #11
0
        public void ExportToStream(EndianBinaryWriter writer, WScene scene)
        {
            // Build a dictionary which lists unique FourCC's and a list of all relevant actors.
            var actorCategories = new Dictionary <FourCC, List <SerializableDOMNode> >();

            foreach (var child in scene)
            {
                var groupNode = child as WDOMGroupNode;
                if (groupNode == null)
                {
                    continue;
                }

                // If this is an ACTR, SCOB, or TRES group node, we have to dig into it to get the layers.
                if (groupNode.FourCC == FourCC.ACTR || groupNode.FourCC == FourCC.SCOB || groupNode.FourCC == FourCC.TRES)
                {
                    foreach (var layer in groupNode.Children)
                    {
                        foreach (var obj in layer.Children)
                        {
                            var actor = obj as SerializableDOMNode;

                            if (actor != null)
                            {
                                AddObjectToDictionary(actor, actorCategories);
                            }
                        }
                    }
                }
                else
                {
                    foreach (var obj in groupNode.Children)
                    {
                        var actor = obj as SerializableDOMNode;

                        if (actor != null)
                        {
                            AddObjectToDictionary(actor, actorCategories);
                        }
                    }
                }
            }

            // Create a chunk header for each one.
            var chunkHeaders = new List <ChunkHeader>();

            foreach (var kvp in actorCategories)
            {
                ChunkHeader header = new ChunkHeader();
                header.FourCC       = kvp.Key;
                header.ElementCount = kvp.Value.Count;

                chunkHeaders.Add(header);
            }

            long chunkStart = writer.BaseStream.Position;

            // Write the Header
            writer.Write(chunkHeaders.Count);
            for (int i = 0; i < chunkHeaders.Count; i++)
            {
                writer.Write((int)0); // Dummy Placeholder values for the Chunk Header.
                writer.Write((int)0);
                writer.Write((int)0);
            }

            // For each chunk, write the data for that chunk. Before writing the data, get the current offset and update the header.
            List <SerializableDOMNode>[] dictionaryData = new List <SerializableDOMNode> [actorCategories.Count];
            actorCategories.Values.CopyTo(dictionaryData, 0);

            for (int i = 0; i < chunkHeaders.Count; i++)
            {
                ChunkHeader header = chunkHeaders[i];
                chunkHeaders[i] = new ChunkHeader(header.FourCC, header.ElementCount, (int)(writer.BaseStream.Position - chunkStart));

                List <SerializableDOMNode> actors = dictionaryData[i];
                foreach (var actor in actors)
                {
                    MapActorDescriptor template = Globals.ActorDescriptors.Find(x => x.FourCC == actor.FourCC);
                    if (template == null)
                    {
                        Console.WriteLine("Unsupported FourCC (\"{0}\") for exporting!", actor.FourCC);
                        continue;
                    }

                    actor.PreSave();

                    actor.Save(writer);
                    //WriteActorToChunk(actor, template, writer);
                }
            }

            // Now that we've written every actor to file we can go back and re-write the headers now that we know their offsets.
            writer.BaseStream.Position = chunkStart + 0x4; // 0x4 is the offset to the Chunk Headers
            foreach (var header in chunkHeaders)
            {
                writer.WriteFixedString(FourCCConversion.GetStringFromEnum(header.FourCC), 4); // FourCC
                writer.Write(header.ElementCount);                                             // Number of Entries
                writer.Write(header.ChunkOffset);                                              // Offset from start of file.
            }

            // Seek to the end of the file, and then pad us to 32-byte alignment.
            writer.BaseStream.Seek(0, SeekOrigin.End);
            int delta = WMath.Pad32Delta(writer.BaseStream.Position);

            for (int i = 0; i < delta; i++)
            {
                writer.Write(0xFF);
            }
        }
Пример #12
0
        public List <WRoomTransform> GetRoomTransformTable()
        {
            List <WRoomTransform> roomTransforms = new List <WRoomTransform>();

            int multIndex = m_chunkList.FindIndex(x => x.FourCC == FourCC.MULT);

            if (multIndex >= 0)
            {
                ChunkHeader rtbl = m_chunkList[multIndex];
                m_reader.BaseStream.Position = rtbl.ChunkOffset;

                for (int i = 0; i < rtbl.ElementCount; i++)
                {
                    WRoomTransform roomTransform = new WRoomTransform(new Vector2(m_reader.ReadSingle(), m_reader.ReadSingle()), WMath.RotationShortToFloat(m_reader.ReadInt16()), m_reader.ReadByte(), m_reader.ReadByte());
                    roomTransforms.Add(roomTransform);
                }
            }

            return(roomTransforms);
        }
Пример #13
0
        public bool TransformFromInput(FRay ray, WSceneView view)
        {
            if (m_mode != FTransformMode.Translation)
            {
                WrapCursor();
            }

            // Store the cursor position in viewport coordinates.
            Vector2 screenDimensions = App.GetScreenGeometry();
            Vector2 cursorPos        = App.GetCursorPosition();
            Vector2 mouseCoords      = new Vector2(((2f * cursorPos.X) / screenDimensions.X) - 1f, (1f - ((2f * cursorPos.Y) / screenDimensions.Y))); //[-1,1] range

            bool shiftPressed = WInput.GetKey(Key.LeftShift) || WInput.GetKey(Key.RightShift);

            if (m_mode == FTransformMode.Translation)
            {
                // Create a Translation Plane
                Vector3 axisA, axisB;

                if (GetNumSelectedAxes() == 1)
                {
                    if (m_selectedAxes == FSelectedAxes.X)
                    {
                        axisB = Vector3.UnitX;
                    }
                    else if (m_selectedAxes == FSelectedAxes.Y)
                    {
                        axisB = Vector3.UnitY;
                    }
                    else
                    {
                        axisB = Vector3.UnitZ;
                    }

                    Vector3 dirToCamera = (m_position - view.GetCameraPos()).Normalized();
                    axisA = Vector3.Cross(axisB, dirToCamera);
                }
                else
                {
                    axisA = ContainsAxis(m_selectedAxes, FSelectedAxes.X) ? Vector3.UnitX : Vector3.UnitZ;
                    axisB = ContainsAxis(m_selectedAxes, FSelectedAxes.Y) ? Vector3.UnitY : Vector3.UnitZ;
                }

                Vector3 planeNormal = Vector3.Cross(axisA, axisB).Normalized();
                m_translationPlane = new FPlane(planeNormal, m_position);

                float intersectDist;
                if (m_translationPlane.RayIntersectsPlane(ray, out intersectDist))
                {
                    Vector3 hitPos     = ray.Origin + (ray.Direction * intersectDist);
                    Vector3 localDelta = Vector3.Transform(hitPos - m_position, m_rotation.Inverted());

                    // Calculate a new position
                    Vector3 newPos = m_position;
                    if (ContainsAxis(m_selectedAxes, FSelectedAxes.X))
                    {
                        newPos += Vector3.Transform(Vector3.UnitX, m_rotation) * localDelta.X;
                    }
                    if (ContainsAxis(m_selectedAxes, FSelectedAxes.Y))
                    {
                        newPos += Vector3.Transform(Vector3.UnitY, m_rotation) * localDelta.Y;
                    }
                    if (ContainsAxis(m_selectedAxes, FSelectedAxes.Z))
                    {
                        newPos += Vector3.Transform(Vector3.UnitZ, m_rotation) * localDelta.Z;
                    }

                    if (shiftPressed)
                    {
                        // Round to nearest 100 unit increment while shift is held down.
                        newPos.X = (float)Math.Round(newPos.X / 100f) * 100f;
                        newPos.Y = (float)Math.Round(newPos.Y / 100f) * 100f;
                        newPos.Z = (float)Math.Round(newPos.Z / 100f) * 100f;
                    }

                    // Check the new location to see if it's skyrocked off into the distance due to near-plane raytracing issues.
                    Vector3 newPosDirToCamera = (newPos - view.GetCameraPos()).Normalized();
                    float   dot = Math.Abs(Vector3.Dot(planeNormal, newPosDirToCamera));

                    //Console.WriteLine("hitPos: {0} localOffset: {1} newPos: {2}, dotResult: {3}", hitPos, localOffset, newPos, dot);
                    if (dot < 0.02f)
                    {
                        return(false);
                    }

                    // This is used to set the offset to the gizmo the mouse cursor is from the origin of the gizmo on the first frame
                    // that you click on the gizmo.
                    if (!m_hasSetMouseOffset)
                    {
                        m_translateOffset   = m_position - newPos;
                        m_deltaTranslation  = Vector3.Zero;
                        m_hasSetMouseOffset = true;
                        return(false);
                    }

                    // Apply Translation
                    m_deltaTranslation = Vector3.Transform(newPos - m_position + m_translateOffset, m_rotation.Inverted());

                    if (!ContainsAxis(m_selectedAxes, FSelectedAxes.X))
                    {
                        m_deltaTranslation.X = 0f;
                    }
                    if (!ContainsAxis(m_selectedAxes, FSelectedAxes.Y))
                    {
                        m_deltaTranslation.Y = 0f;
                    }
                    if (!ContainsAxis(m_selectedAxes, FSelectedAxes.Z))
                    {
                        m_deltaTranslation.Z = 0f;
                    }

                    m_totalTranslation += m_deltaTranslation;
                    m_position         += Vector3.Transform(m_deltaTranslation, m_rotation);

                    if (!m_hasTransformed && (m_deltaTranslation != Vector3.Zero))
                    {
                        m_hasTransformed = true;
                    }

                    return(m_hasTransformed);
                }
                else
                {
                    // Our raycast missed the plane
                    m_deltaTranslation = Vector3.Zero;
                    return(false);
                }
            }
            else if (m_mode == FTransformMode.Rotation)
            {
                Vector3 rotationAxis;
                if (m_selectedAxes == FSelectedAxes.X)
                {
                    rotationAxis = Vector3.UnitX;
                }
                else if (m_selectedAxes == FSelectedAxes.Y)
                {
                    rotationAxis = Vector3.UnitY;
                }
                else
                {
                    rotationAxis = Vector3.UnitZ;
                }

                // Convert these from [0-1] to [-1, 1] to match our mouse coords.
                Vector2 lineOrigin = (view.UnprojectWorldToViewport(m_hitPoint) * 2) - Vector2.One;
                Vector2 lineEnd    = (view.UnprojectWorldToViewport(m_hitPoint + m_moveDir) * 2) - Vector2.One;

                lineOrigin.Y = -lineOrigin.Y;
                lineEnd.Y    = -lineEnd.Y;

                Vector2 lineDir   = (lineEnd - lineOrigin).Normalized();
                float   rotAmount = Vector2.Dot(lineDir, mouseCoords + m_wrapOffset - lineOrigin) * 180f;

                if (float.IsNaN(rotAmount))
                {
                    Console.WriteLine("rotAmountNaN!");
                    return(false);
                }

                if (!m_hasSetMouseOffset)
                {
                    m_rotateOffset      = -rotAmount;
                    m_deltaRotation     = Quaternion.Identity;
                    m_hasSetMouseOffset = true;
                    return(false);
                }

                // Apply Rotation
                rotAmount += m_rotateOffset;
                if (shiftPressed)
                {
                    // Round to nearest 45 degree increment while shift is held down.
                    rotAmount = (float)Math.Round(rotAmount / 45f) * 45f;
                }
                Quaternion oldRot = m_currentRotation;
                m_currentRotation = Quaternion.FromAxisAngle(rotationAxis, WMath.DegreesToRadians(rotAmount));
                m_deltaRotation   = m_currentRotation * oldRot.Inverted();

                if (m_transformSpace == FTransformSpace.Local)
                {
                    m_rotation *= m_deltaRotation;
                }

                // Add to Total Rotation recorded for UI.
                if (m_selectedAxes == FSelectedAxes.X)
                {
                    m_totalRotation.X = rotAmount;
                }
                else if (m_selectedAxes == FSelectedAxes.Y)
                {
                    m_totalRotation.Y = rotAmount;
                }
                else
                {
                    m_totalRotation.Z = rotAmount;
                }

                if (!m_hasTransformed && rotAmount != 0f)
                {
                    m_hasTransformed = true;
                }

                return(m_hasTransformed);
            }
            else if (m_mode == FTransformMode.Scale)
            {
                // Create a line in screen space.
                // Convert these from [0-1] to [-1, 1] to match our mouse coords.
                Vector2 lineOrigin = (view.UnprojectWorldToViewport(m_position) * 2) - Vector2.One;
                lineOrigin.Y = -lineOrigin.Y;

                // Determine the appropriate world space directoin using the selected axes and then conver this for use with
                // screen-space controlls. This has to be done every frame because the axes can be flipped while the gizmo
                // is transforming, so we can't pre-calculate this.
                Vector3 dirX = Vector3.Transform(mFlipScaleX ? -Vector3.UnitX : Vector3.UnitX, m_rotation);
                Vector3 dirY = Vector3.Transform(mFlipScaleY ? -Vector3.UnitY : Vector3.UnitY, m_rotation);
                Vector3 dirZ = Vector3.Transform(mFlipScaleZ ? -Vector3.UnitZ : Vector3.UnitZ, m_rotation);
                Vector2 lineDir;

                // If there is only one axis, then the world space direction is the selected axis.
                if (GetNumSelectedAxes() == 1)
                {
                    Vector3 worldDir;
                    if (ContainsAxis(m_selectedAxes, FSelectedAxes.X))
                    {
                        worldDir = dirX;
                    }
                    if (ContainsAxis(m_selectedAxes, FSelectedAxes.Y))
                    {
                        worldDir = dirY;
                    }
                    else
                    {
                        worldDir = dirZ;
                    }

                    Vector2 worldPoint = (view.UnprojectWorldToViewport(m_position + worldDir) * 2) - Vector2.One;
                    worldPoint.Y = -lineOrigin.Y;

                    lineDir = (worldPoint - lineOrigin).Normalized();
                }
                // If there's two axii selected, then convert both to screen space and average them out to get the line direction.
                else if (GetNumSelectedAxes() == 2)
                {
                    Vector3 axisA = ContainsAxis(m_selectedAxes, FSelectedAxes.X) ? dirX : dirY;
                    Vector3 axisB = ContainsAxis(m_selectedAxes, FSelectedAxes.Z) ? dirZ : dirY;

                    Vector2 screenA = (view.UnprojectWorldToViewport(m_position + axisA) * 2) - Vector2.One;
                    screenA.Y = -screenA.Y;
                    Vector2 screenB = (view.UnprojectWorldToViewport(m_position + axisB) * 2) - Vector2.One;
                    screenB.Y = -screenB.Y;

                    screenA = (screenA - lineOrigin).Normalized();
                    screenB = (screenB - lineOrigin).Normalized();
                    lineDir = ((screenA + screenB) / 2f).Normalized();
                }
                // There's three axis, just use up.
                else
                {
                    lineDir = Vector2.UnitY;
                }

                float scaleAmount = Vector2.Dot(lineDir, mouseCoords + m_wrapOffset - lineOrigin) * 5f;

                if (shiftPressed)
                {
                    // Round to nearest whole number scale while shift is held down.
                    scaleAmount = (float)Math.Round(scaleAmount);
                }

                // Set their initial offset if we haven't already
                if (!m_hasSetMouseOffset)
                {
                    m_scaleOffset       = -scaleAmount;
                    m_deltaScale        = Vector3.One;
                    m_hasSetMouseOffset = true;
                    return(false);
                }

                // Apply the scale
                scaleAmount = scaleAmount + m_scaleOffset + 1f;

                // A multiplier is applied to the scale amount if it's less than one to prevent it dropping into the negatives.
                // ???
                if (scaleAmount < 1f)
                {
                    scaleAmount = 1f / (-(scaleAmount - 1f) + 1f);
                }

                Vector3 oldScale = m_totalScale;
                m_totalScale = Vector3.One;
                if (ContainsAxis(m_selectedAxes, FSelectedAxes.X))
                {
                    m_totalScale.X = scaleAmount;
                }
                if (ContainsAxis(m_selectedAxes, FSelectedAxes.Y))
                {
                    m_totalScale.Y = scaleAmount;
                }
                if (ContainsAxis(m_selectedAxes, FSelectedAxes.Z))
                {
                    m_totalScale.Z = scaleAmount;
                }

                m_deltaScale = new Vector3(m_totalScale.X / oldScale.X, m_totalScale.Y / oldScale.Y, m_totalScale.Z / oldScale.Z);

                if (!m_hasTransformed && (scaleAmount != 1f))
                {
                    m_hasTransformed = true;
                }

                return(m_hasTransformed);
            }

            return(false);
        }
Пример #14
0
        public bool CheckSelectedAxes(FRay ray)
        {
            // Convert the ray into local space so we can use axis-aligned checks, this solves the checking problem
            // when the gizmo is rotated due to being in Local mode.
            FRay localRay = new FRay();

            localRay.Direction = Vector3.Transform(ray.Direction, m_rotation.Inverted());
            localRay.Origin    = Vector3.Transform(ray.Origin - m_position, m_rotation.Inverted());

            //m_lineBatcher.DrawLine(localRay.Origin, localRay.Origin + (localRay.Direction * 10000), WLinearColor.White, 25, 5);
            List <AxisDistanceResult> results = new List <AxisDistanceResult>();

            if (m_mode == FTransformMode.Translation)
            {
                FAABox[] translationAABB = GetAABBBoundsForMode(FTransformMode.Translation);
                for (int i = 0; i < translationAABB.Length; i++)
                {
                    float intersectDist;
                    if (WMath.RayIntersectsAABB(localRay, translationAABB[i].Min, translationAABB[i].Max, out intersectDist))
                    {
                        results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist));
                    }
                }
            }
            else if (m_mode == FTransformMode.Rotation)
            {
                // We'll use a combination of AABB and Distance checks to give us the quarter-circles we need.
                FAABox[] rotationAABB = GetAABBBoundsForMode(FTransformMode.Rotation);

                float screenScale = 0f;
                for (int i = 0; i < 3; i++)
                {
                    screenScale += m_scale[i];
                }
                screenScale /= 3f;

                for (int i = 0; i < rotationAABB.Length; i++)
                {
                    float intersectDist;
                    if (WMath.RayIntersectsAABB(localRay, rotationAABB[i].Min, rotationAABB[i].Max, out intersectDist))
                    {
                        Vector3 intersectPoint = localRay.Origin + (localRay.Direction * intersectDist);
                        // Convert this aabb check into a radius check so we clip it by the semi-circles
                        // that the rotation tool actually is.
                        if (intersectPoint.Length > 105f * screenScale)
                        {
                            continue;
                        }

                        results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist));
                    }
                }
            }
            else if (m_mode == FTransformMode.Scale)
            {
                FAABox[] scaleAABB = GetAABBBoundsForMode(FTransformMode.Scale);
                for (int i = 0; i < scaleAABB.Length; i++)
                {
                    float intersectDist;
                    if (WMath.RayIntersectsAABB(localRay, scaleAABB[i].Min, scaleAABB[i].Max, out intersectDist))
                    {
                        // Special-case here to give the center scale point overriding priority. Because we intersected
                        // it, we can just override its distance to zero to make it clickable through the other bounding boxes.
                        if ((FSelectedAxes)i + 1 == FSelectedAxes.All)
                        {
                            intersectDist = 0f;
                        }

                        results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist));
                    }
                }
            }

            if (results.Count == 0)
            {
                m_selectedAxes = FSelectedAxes.None;
                return(false);
            }

            // If we get an intersection, sort them by the closest intersection distance.
            results.Sort((x, y) => x.Distance.CompareTo(y.Distance));
            m_selectedAxes = results[0].Axis;

            // Store where the mouse hit on the first frame in world space. This means converting the ray back to worldspace.
            Vector3 localHitPoint = localRay.Origin + (localRay.Direction * results[0].Distance);

            m_hitPoint = Vector3.Transform(localHitPoint, m_rotation) + m_position;
            return(true);
        }
Пример #15
0
        private void WriteActorToChunk(WActorNode actor, MapActorDescriptor template, EndianBinaryWriter writer)
        {
            // Just convert their rotation to Euler Angles now instead of doing it in parts later.
            Vector3 eulerRot = actor.Transform.Rotation.ToEulerAngles();

            foreach (var field in template.Fields)
            {
                IPropertyValue propValue = actor.Properties.Find(x => x.Name == field.FieldName);
                if (field.FieldName == "Position")
                {
                    propValue = new TVector3PropertyValue(actor.Transform.Position, "Position");
                }
                else if (field.FieldName == "X Rotation")
                {
                    short xRotShort = WMath.RotationFloatToShort(eulerRot.X);
                    propValue = new TShortPropertyValue(xRotShort, "X Rotation");
                }
                else if (field.FieldName == "Y Rotation")
                {
                    short yRotShort = WMath.RotationFloatToShort(eulerRot.Y);
                    propValue = new TShortPropertyValue(yRotShort, "Y Rotation");
                }
                else if (field.FieldName == "Z Rotation")
                {
                    short zRotShort = WMath.RotationFloatToShort(eulerRot.Z);
                    propValue = new TShortPropertyValue(zRotShort, "Z Rotation");
                }
                else if (field.FieldName == "X Scale")
                {
                    float xScale = actor.Transform.LocalScale.X;
                    propValue = new TBytePropertyValue((byte)(xScale * 10), "X Scale");
                }
                else if (field.FieldName == "Y Scale")
                {
                    float yScale = actor.Transform.LocalScale.Y;
                    propValue = new TBytePropertyValue((byte)(yScale * 10), "Y Scale");
                }
                else if (field.FieldName == "Z Scale")
                {
                    float zScale = actor.Transform.LocalScale.Z;
                    propValue = new TBytePropertyValue((byte)(zScale * 10), "Z Scale");
                }

                switch (field.FieldType)
                {
                case PropertyValueType.Byte:
                    writer.Write((byte)propValue.GetValue()); break;

                case PropertyValueType.Bool:
                    writer.Write((bool)propValue.GetValue()); break;

                case PropertyValueType.Short:
                    writer.Write((short)propValue.GetValue()); break;

                case PropertyValueType.Int:
                    writer.Write((int)propValue.GetValue()); break;

                case PropertyValueType.Float:
                    writer.Write((float)propValue.GetValue()); break;

                case PropertyValueType.String:
                    writer.Write(System.Text.Encoding.ASCII.GetBytes((string)propValue.GetValue())); break;

                case PropertyValueType.FixedLengthString:
                    string fixedLenStr = (string)propValue.GetValue();
                    for (int i = 0; i < field.Length; i++)
                    {
                        writer.Write(i < fixedLenStr.Length ? (byte)fixedLenStr[i] : (byte)0);
                    }
                    //writer.WriteFixedString((string)propValue.GetValue(), (int)field.Length); break;
                    break;

                case PropertyValueType.Vector2:
                    Vector2 vec2Val = (Vector2)propValue.GetValue();
                    writer.Write(vec2Val.X);
                    writer.Write(vec2Val.Y);
                    break;

                case PropertyValueType.Vector3:
                    Vector3 vec3Val = (Vector3)propValue.GetValue();
                    writer.Write(vec3Val.X);
                    writer.Write(vec3Val.Y);
                    writer.Write(vec3Val.Z);
                    break;

                case PropertyValueType.XRotation:
                case PropertyValueType.YRotation:
                case PropertyValueType.ZRotation:
                    writer.Write((short)propValue.GetValue()); break;

                case PropertyValueType.Color24:
                    WLinearColor color24 = (WLinearColor)propValue.GetValue();
                    writer.Write((byte)color24.R);
                    writer.Write((byte)color24.G);
                    writer.Write((byte)color24.B);
                    break;

                case PropertyValueType.Color32:
                    WLinearColor color32 = (WLinearColor)propValue.GetValue();
                    writer.Write((byte)color32.R);
                    writer.Write((byte)color32.G);
                    writer.Write((byte)color32.B);
                    writer.Write((byte)color32.A);
                    break;

                default:
                    Console.WriteLine("Unsupported PropertyValueType: {0}", field.FieldType);
                    break;
                }
            }
        }
Пример #16
0
        public void SetRoomTransform(WRoomTransform roomTransform)
        {
            List <J3DNode> m_roomModelNodes = GetChildrenOfType <J3DNode>();

            RoomTransform = roomTransform;
            foreach (J3DNode j3d_node in m_roomModelNodes)
            {
                j3d_node.Transform.Position      = new Vector3(RoomTransform.Translation.X, 0, RoomTransform.Translation.Y);
                j3d_node.Transform.LocalRotation = Quaterniond.FromAxisAngle(Vector3d.UnitY, WMath.DegreesToRadians(RoomTransform.YRotation));
            }
        }
        public EnvironmentLightingPalette Lerp(float t, bool presetA = true)
        {
            // Generate a new LightingPalette which is the interpolated values of things.
            t = WMath.Clamp(t, 0, 1);
            float scaledT    = t * (6 - 1);
            int   lowerIndex = (int)scaledT;
            int   upperIndex = (int)(scaledT + 1f);
            float newT       = scaledT - (int)scaledT;

            EnvironmentLightingPalette palette_a = null;
            EnvironmentLightingPalette palette_b = null;

            if (upperIndex == 6)
            {
                upperIndex = lowerIndex;
            }

            switch ((TimeOfDay)lowerIndex)
            {
            case TimeOfDay.Dawn:
                palette_a = Dawn;
                break;

            case TimeOfDay.Morning:
                palette_a = Morning;
                break;

            case TimeOfDay.Noon:
                palette_a = Noon;
                break;

            case TimeOfDay.Afternoon:
                palette_a = Afternoon;
                break;

            case TimeOfDay.Dusk:
                palette_a = Dusk;
                break;

            case TimeOfDay.Night:
                palette_a = Night;
                break;
            }

            switch ((TimeOfDay)upperIndex)
            {
            case TimeOfDay.Dawn:
                palette_b = Dawn;
                break;

            case TimeOfDay.Morning:
                palette_b = Morning;
                break;

            case TimeOfDay.Noon:
                palette_b = Noon;
                break;

            case TimeOfDay.Afternoon:
                palette_b = Afternoon;
                break;

            case TimeOfDay.Dusk:
                palette_b = Dusk;
                break;

            case TimeOfDay.Night:
                palette_b = Night;
                break;
            }

            //Console.WriteLine("t: {0} scaledT: {1} lIndex: {2} uIndex: {3} newT: {4}", t, scaledT, lowerIndex, upperIndex, newT);

            EnvironmentLightingPalette interpPalette = new EnvironmentLightingPalette();

            interpPalette.ShadowColor       = WLinearColor.Lerp(palette_a.ShadowColor, palette_b.ShadowColor, newT);
            interpPalette.ActorAmbientColor = WLinearColor.Lerp(palette_a.ActorAmbientColor, palette_b.ActorAmbientColor, newT);
            interpPalette.RoomLightColor    = WLinearColor.Lerp(palette_a.RoomLightColor, palette_b.RoomLightColor, newT);
            interpPalette.RoomAmbientColor  = WLinearColor.Lerp(palette_a.RoomAmbientColor, palette_b.RoomAmbientColor, newT);
            interpPalette.WaveColor         = WLinearColor.Lerp(palette_a.WaveColor, palette_b.WaveColor, newT);
            interpPalette.OceanColor        = WLinearColor.Lerp(palette_a.OceanColor, palette_b.OceanColor, newT);
            interpPalette.UnknownWhite1     = WLinearColor.Lerp(palette_a.UnknownWhite1, palette_b.UnknownWhite1, newT);
            interpPalette.UnknownWhite2     = WLinearColor.Lerp(palette_a.UnknownWhite2, palette_b.UnknownWhite2, newT);
            interpPalette.DoorBackfill      = WLinearColor.Lerp(palette_a.DoorBackfill, palette_b.DoorBackfill, newT);
            interpPalette.Unknown3          = WLinearColor.Lerp(palette_a.Unknown3, palette_b.Unknown3, newT);
            interpPalette.SkyboxPalette     = EnvironmentLightingSkyboxPalette.Lerp(palette_a.SkyboxPalette, palette_b.SkyboxPalette, newT);
            interpPalette.FogColor          = WLinearColor.Lerp(palette_a.FogColor, palette_b.FogColor, newT);
            interpPalette.FogNearPlane      = WMath.Lerp(palette_a.FogNearPlane, palette_b.FogNearPlane, newT);
            interpPalette.FogFarPlane       = WMath.Lerp(palette_a.FogFarPlane, palette_b.FogFarPlane, newT);

            return(interpPalette);
        }
 public static WLinearColor Lerp(WLinearColor a, WLinearColor b, float t)
 {
     t = WMath.Clamp(t, 0, 1);
     return(new WLinearColor((1 - t) * a.R + t * b.R, (1 - t) * a.G + t * b.G, (1 - t) * a.B + t * b.B, (1 - t) * a.A + t * b.A));
 }
Пример #19
0
        /// <summary>
        /// Convert a Quaternion to all possible ways it can be represented as Euler Angles.
        /// Returns the angles in [-180, 180] space in degrees.
        /// </summary>
        public static List <Vector3> ToEulerAnglesRobust(this Quaterniond quat, string rotationOrder)
        {
            var representations = new List <Vector3>();

            var qx = quat.X;
            var qy = quat.Y;
            var qz = quat.Z;
            var qw = quat.W;

            var mat = Matrix3d.CreateFromQuaternion(quat).Inverted();

            double x, y, z;

            switch (rotationOrder)
            {
            case "ZYX":
                y = Math.Asin(-Math.Min(1, Math.Max(-1, mat.M31)));
                if (Math.Abs(mat.M31) < 0.999999)
                {
                    x = Math.Atan2(mat.M32, mat.M33);
                    z = Math.Atan2(mat.M21, mat.M11);
                }
                else
                {
                    x = Math.Atan2(-mat.M12, mat.M22);
                    z = 0f;
                }
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));

                y = CopySign(Math.PI, y) - y;
                x = x - CopySign(Math.PI, x);
                z = z - CopySign(Math.PI, z);
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));
                break;

            case "YXZ":
                x = Math.Asin(-Math.Min(1, Math.Max(-1, mat.M23)));
                if (Math.Abs(mat.M23) < 0.999999)
                {
                    y = Math.Atan2(mat.M13, mat.M33);
                    z = Math.Atan2(mat.M21, mat.M22);
                }
                else
                {
                    y = Math.Atan2(-mat.M31, mat.M11);
                    z = 0f;
                }
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));

                x = CopySign(Math.PI, x) - x;
                y = y - CopySign(Math.PI, y);
                z = z - CopySign(Math.PI, z);
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));
                break;

            default:
                throw new NotImplementedException($"Quaternion to euler rotation conversion not implemented for rotation order: {rotationOrder}");
            }

            return(representations);
        }
Пример #20
0
        /// <summary>
        /// Convert a Quaternion to all possible ways it can be represented as Euler Angles.
        /// Returns the angles in [-180, 180] space in degrees.
        /// </summary>
        public static List <Vector3> ToEulerAnglesRobust(this Quaternion quat, string rotationOrder)
        {
            var representations = new List <Vector3>();

            var qx = quat.X;
            var qy = quat.Y;
            var qz = quat.Z;
            var qw = quat.W;

            // Convert the quaternion to a 3x3 matrix.
            // We don't use OpenTK's Matrix3 class because it stores the values as single-precision floats, which loses information.
            // By manually calculating the matrix elements as doubles, we can get the maximum amount of accuracy.
            double m11 = 1.0 - 2.0 * (qy * qy + qz * qz);
            double m12 = 2.0 * (qx * qy - qz * qw);
            double m13 = 2.0 * (qx * qz + qy * qw);
            double m21 = 2.0 * (qx * qy + qz * qw);
            double m22 = 1.0 - 2.0 * (qx * qx + qz * qz);
            double m23 = 2.0 * (qy * qz - qx * qw);
            double m31 = 2.0 * (qx * qz - qy * qw);
            double m32 = 2.0 * (qy * qz + qx * qw);
            double m33 = 1.0 - 2.0 * (qx * qx + qy * qy);

            double x, y, z;

            switch (rotationOrder)
            {
            case "ZYX":
                y = Math.Asin(-Math.Min(1, Math.Max(-1, m31)));
                if (Math.Abs(m31) < 0.999999)
                {
                    x = Math.Atan2(m32, m33);
                    z = Math.Atan2(m21, m11);
                }
                else
                {
                    x = Math.Atan2(-m12, m22);
                    z = 0f;
                }
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));

                y = CopySign(Math.PI, y) - y;
                x = x - CopySign(Math.PI, x);
                z = z - CopySign(Math.PI, z);
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));
                break;

            case "YXZ":
                x = Math.Asin(-Math.Min(1, Math.Max(-1, m23)));
                if (Math.Abs(m23) < 0.999999)
                {
                    y = Math.Atan2(m13, m33);
                    z = Math.Atan2(m21, m22);
                }
                else
                {
                    y = Math.Atan2(-m31, m11);
                    z = 0f;
                }
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));

                x = CopySign(Math.PI, x) - x;
                y = y - CopySign(Math.PI, y);
                z = z - CopySign(Math.PI, z);
                representations.Add(new Vector3(
                                        WMath.RadiansToDegrees((float)x),
                                        WMath.RadiansToDegrees((float)y),
                                        WMath.RadiansToDegrees((float)z)
                                        ));
                break;

            default:
                throw new NotImplementedException($"Quaternion to euler rotation conversion not implemented for rotation order: {rotationOrder}");
            }

            return(representations);
        }
Пример #21
0
        public void ExportToStream(EndianBinaryWriter writer, WScene scene)
        {
            // Build a dictionary which lists unique FourCC's and a list of all relevant actors.
            var actorCategories = new Dictionary <string, List <WActorNode> >();

            foreach (var child in scene)
            {
                WActorNode actor = child as WActorNode;
                if (actor != null)
                {
                    string fixedFourCC = ChunkHeader.LayerToFourCC(actor.FourCC, actor.Layer);

                    if (!actorCategories.ContainsKey(fixedFourCC))
                    {
                        actorCategories[fixedFourCC] = new List <WActorNode>();
                    }

                    actorCategories[fixedFourCC].Add(actor);
                }
            }

            // Create a chunk header for each one.
            var chunkHeaders = new List <ChunkHeader>();

            foreach (var kvp in actorCategories)
            {
                ChunkHeader header = new ChunkHeader();
                header.FourCC       = kvp.Key;
                header.ElementCount = kvp.Value.Count;

                chunkHeaders.Add(header);
            }

            long chunkStart = writer.BaseStream.Position;

            // Write the Header
            writer.Write(chunkHeaders.Count);
            for (int i = 0; i < chunkHeaders.Count; i++)
            {
                writer.Write((int)0); // Dummy Placeholder values for the Chunk Header.
                writer.Write((int)0);
                writer.Write((int)0);
            }

            // For each chunk, write the data for that chunk. Before writing the data, get the current offset and update the header.
            List <WActorNode>[] dictionaryData = new List <WActorNode> [actorCategories.Count];
            actorCategories.Values.CopyTo(dictionaryData, 0);

            for (int i = 0; i < chunkHeaders.Count; i++)
            {
                ChunkHeader header = chunkHeaders[i];
                chunkHeaders[i] = new ChunkHeader(header.FourCC, header.ElementCount, (int)(writer.BaseStream.Position - chunkStart));

                List <WActorNode> actors = dictionaryData[i];
                foreach (var actor in actors)
                {
                    MapActorDescriptor template = m_sActorDescriptors.Find(x => x.FourCC == actor.FourCC);
                    if (template == null)
                    {
                        Console.WriteLine("Unsupported FourCC (\"{0}\") for exporting!", actor.FourCC);
                        continue;
                    }

                    WriteActorToChunk(actor, template, writer);
                }
            }

            // Now that we've written every actor to file we can go back and re-write the headers now that we know their offsets.
            writer.BaseStream.Position = chunkStart + 0x4; // 0x4 is the offset to the Chunk Headers
            foreach (var header in chunkHeaders)
            {
                writer.WriteFixedString(header.FourCC, 4); // FourCC
                writer.Write(header.ElementCount);         // Number of Entries
                writer.Write(header.ChunkOffset);          // Offset from start of file.
            }

            // Seek to the end of the file, and then pad us to 32-byte alignment.
            writer.BaseStream.Seek(0, SeekOrigin.End);
            int delta = WMath.Pad32Delta(writer.BaseStream.Position);

            for (int i = 0; i < delta; i++)
            {
                writer.Write((byte)0xFF);
            }
        }
Пример #22
0
 /// <summary>
 /// Convert a Quaternion to Euler Angles. Returns the angles in [-180, 180] space in degrees.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="quat"></param>
 /// <returns></returns>
 public static Vector3 ToEulerAngles(this Quaternion quat)
 {
     return(new Vector3(WMath.RadiansToDegrees(PitchFromQuat(quat)), WMath.RadiansToDegrees(YawFromQuat(quat)), WMath.RadiansToDegrees(RollFromQuat(quat))));
 }
Пример #23
0
 public void DecrementSize()
 {
     m_gizmoSize = WMath.Clamp(m_gizmoSize - 0.05f, 0.05f, float.MaxValue);
 }
Пример #24
0
        public void Rotate(Vector3 axis, float angleInDegrees)
        {
            Quaterniond rotQuat = Quaterniond.FromAxisAngle((Vector3d)axis, WMath.DegreesToRadians(angleInDegrees));

            Rotation = rotQuat * Rotation;
        }
Пример #25
0
        private WActorNode LoadActorFromChunk(string fourCC, MapActorDescriptor template)
        {
            var newActor = new WActorNode(fourCC, m_world);
            List <IPropertyValue> actorProperties = new List <IPropertyValue>();

            foreach (var field in template.Fields)
            {
                IPropertyValue propValue = null;

                switch (field.FieldType)
                {
                case PropertyValueType.Byte:
                    propValue = new TBytePropertyValue(m_reader.ReadByte(), field.FieldName);
                    break;

                case PropertyValueType.Bool:
                    propValue = new TBoolPropertyValue(m_reader.ReadBoolean(), field.FieldName);
                    break;

                case PropertyValueType.Short:
                    propValue = new TShortPropertyValue(m_reader.ReadInt16(), field.FieldName);
                    break;

                case PropertyValueType.Int:
                    propValue = new TIntPropertyValue(m_reader.ReadInt32(), field.FieldName);
                    break;

                case PropertyValueType.Float:
                    propValue = new TFloatPropertyValue(m_reader.ReadSingle(), field.FieldName);
                    break;

                case PropertyValueType.FixedLengthString:
                case PropertyValueType.String:
                    string stringVal = (field.Length == 0) ? m_reader.ReadStringUntil('\0') : m_reader.ReadString(field.Length);
                    stringVal = stringVal.Trim(new[] { '\0' });
                    propValue = new TStringPropertyValue(stringVal, field.FieldName);
                    break;

                case PropertyValueType.Vector2:
                    propValue = new TVector2PropertyValue(new OpenTK.Vector2(m_reader.ReadSingle(), m_reader.ReadSingle()), field.FieldName);
                    break;

                case PropertyValueType.Vector3:
                    propValue = new TVector3PropertyValue(new OpenTK.Vector3(m_reader.ReadSingle(), m_reader.ReadSingle(), m_reader.ReadSingle()), field.FieldName);
                    break;

                case PropertyValueType.XRotation:
                case PropertyValueType.YRotation:
                case PropertyValueType.ZRotation:
                    propValue = new TShortPropertyValue(m_reader.ReadInt16(), field.FieldName);
                    break;

                case PropertyValueType.Color24:
                    propValue = new TLinearColorPropertyValue(new WLinearColor(m_reader.ReadByte() / 255f, m_reader.ReadByte() / 255f, m_reader.ReadByte() / 255f), field.FieldName);
                    break;

                case PropertyValueType.Color32:
                    propValue = new TLinearColorPropertyValue(new WLinearColor(m_reader.ReadByte() / 255f, m_reader.ReadByte() / 255f, m_reader.ReadByte() / 255f, m_reader.ReadByte() / 255f), field.FieldName);
                    break;

                default:
                    Console.WriteLine("Unsupported PropertyValueType: {0}", field.FieldType);
                    break;
                }

                propValue.SetUndoStack(m_world.UndoStack);
                actorProperties.Add(propValue);
            }

            // Now that we have loaded all properties out of it, we need to post-process them.
            IPropertyValue positionProperty = actorProperties.Find(x => x.Name == "Position");
            IPropertyValue xRotProperty     = actorProperties.Find(x => x.Name == "X Rotation");
            IPropertyValue yRotProperty     = actorProperties.Find(x => x.Name == "Y Rotation");
            IPropertyValue zRotProperty     = actorProperties.Find(x => x.Name == "Z Rotation");
            IPropertyValue xScaleProperty   = actorProperties.Find(x => x.Name == "X Scale");
            IPropertyValue yScaleProperty   = actorProperties.Find(x => x.Name == "Y Scale");
            IPropertyValue zScaleProperty   = actorProperties.Find(x => x.Name == "Z Scale");

            // Remove these properties from the actor so they don't get added to the UI.
            actorProperties.Remove(positionProperty);
            actorProperties.Remove(xRotProperty);
            actorProperties.Remove(yRotProperty);
            actorProperties.Remove(zRotProperty);
            actorProperties.Remove(xScaleProperty);
            actorProperties.Remove(yScaleProperty);
            actorProperties.Remove(zScaleProperty);

            if (positionProperty != null)
            {
                newActor.Transform.Position = (Vector3)positionProperty.GetValue();
            }

            float xRot = 0, yRot = 0, zRot = 0;

            if (xRotProperty != null)
            {
                xRot = WMath.RotationShortToFloat((short)xRotProperty.GetValue());
            }
            if (yRotProperty != null)
            {
                yRot = WMath.RotationShortToFloat((short)yRotProperty.GetValue());
            }
            if (zRotProperty != null)
            {
                zRot = WMath.RotationShortToFloat((short)zRotProperty.GetValue());
            }

            // Build rotation with ZYX order.
            Quaternion xRotQ = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), WMath.DegreesToRadians(xRot));
            Quaternion yRotQ = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), WMath.DegreesToRadians(yRot));
            Quaternion zRotQ = Quaternion.FromAxisAngle(new Vector3(0, 0, 1), WMath.DegreesToRadians(zRot));

            newActor.Transform.Rotation = zRotQ * yRotQ * xRotQ;

            float xScale = 1, yScale = 1, zScale = 1;

            if (xScaleProperty != null)
            {
                xScale = ((byte)xScaleProperty.GetValue()) / 10f;
            }
            if (yScaleProperty != null)
            {
                yScale = ((byte)yScaleProperty.GetValue()) / 10f;
            }
            if (zScaleProperty != null)
            {
                zScale = ((byte)zScaleProperty.GetValue()) / 10f;
            }

            newActor.Transform.LocalScale = new Vector3(xScale, yScale, zScale);

            newActor.Properties.AddRange(actorProperties);
            newActor.PostFinishedLoad();
            return(newActor);
        }