예제 #1
0
        private void UpdateTimer(object sender, EventArgs e)
        {
            if (Mode == AnimationMode.Spin)
            {
                if (MoveMultiplier < 1.0f)
                {
                    MoveMultiplier += _moveAcceleration;
                }
                else
                {
                    MoveMultiplier = 1.0f;
                }
            }
            else if (Mode != AnimationMode.Idle)
            {
                _autoMoveCurrent += _autoMoveStep;

                // Allow timer to overflow for 2 subsequent frames, so we
                // get finalizing 1.0 value at all times

                if (_autoMoveCurrent >= 1.0f + (_autoMoveStep * 2))
                {
                    Stop(true);
                }
                else
                {
                    var newMultiplier = MathC.SmoothStep(0.0, 1.0, _autoMoveCurrent);
                    MoveMultiplier = (float)MathC.Clamp(newMultiplier, 0.0, 1.0);
                }
            }
            else
            {
                Stop(true);
            }
        }
예제 #2
0
        private void ChangeColorByMouse(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Focus();
                _selectedColorCoord = new Point((int)MathC.Clamp((e.X / _paletteCellWidth), 0, PaletteSize.Width - 1),
                                                (int)MathC.Clamp((e.Y / _paletteCellHeight), 0, PaletteSize.Height - 1));

                if (_editor.SelectedObject is LightInstance)
                {
                    var light = _editor.SelectedObject as LightInstance;
                    if (!(_editor.Level.Settings.GameVersion.Legacy() <= TRVersion.Game.TR4 && light.Type == LightType.FogBulb))
                    {
                        light.Color = SelectedColor.ToFloat3Color() * 2.0f;
                        light.Room.RebuildLighting(_editor.Configuration.Rendering3D_HighQualityLightPreview);
                        _editor.ObjectChange(light, ObjectChangeType.Change);
                    }
                }
                else if (_editor.SelectedObject is StaticInstance)
                {
                    var instance = _editor.SelectedObject as StaticInstance;
                    instance.Color = SelectedColor.ToFloat3Color() * 2.0f;
                    _editor.ObjectChange(instance, ObjectChangeType.Change);
                }
                else if (_editor.Level.Settings.GameVersion == TRVersion.Game.TR5Main && _editor.SelectedObject is MoveableInstance)
                {
                    var instance = _editor.SelectedObject as MoveableInstance;
                    instance.Color = SelectedColor.ToFloat3Color() * 2.0f;
                    _editor.ObjectChange(instance, ObjectChangeType.Change);
                }

                _editor.LastUsedPaletteColourChange(SelectedColor);
                Invalidate();
            }
        }
예제 #3
0
        public UndoManager(int undoDepth)
        {
            undoDepth = MathC.Clamp(undoDepth, 1, MaxUndoDepth);

            _undoStack = new UndoRedoStack(undoDepth);
            _redoStack = new UndoRedoStack(undoDepth);
        }
예제 #4
0
        public SectorSelection?ClampToRoom(Room r, Direction?excludeBorderWallsDirection = Direction.None)
        {
            int[] c = new int[2] {
                0, 0
            };                             // How many blocks to cut from compared area zone perimeter
            bool excludeAll = !excludeBorderWallsDirection.HasValue;

            if (excludeAll || excludeBorderWallsDirection.Value == Direction.NegativeX || excludeBorderWallsDirection.Value == Direction.PositiveX)
            {
                if ((Start.Y == 0 || Start.Y == r.NumZSectors - 1) && Area.Size.Y == 0)
                {
                    return(null);
                }
                c[0] = 1;
            }
            if (excludeAll || excludeBorderWallsDirection.Value == Direction.NegativeZ || excludeBorderWallsDirection.Value == Direction.PositiveZ)
            {
                if ((Start.X == 0 || Start.X == r.NumXSectors - 1) && Area.Size.X == 0)
                {
                    return(null);
                }
                c[1] = 1;
            }

            return(new SectorSelection()
            {
                Start = new VectorInt2(MathC.Clamp(Start.X, c[1], r.NumXSectors - (1 + c[1])), MathC.Clamp(Start.Y, c[0], r.NumZSectors - (1 + c[0]))),
                End = new VectorInt2(MathC.Clamp(End.X, c[1], r.NumXSectors - (1 + c[1])), MathC.Clamp(End.Y, c[0], r.NumZSectors - (1 + c[0])))
            });
        }
예제 #5
0
 public static Color ToWinFormsColor(this Vector4 color, float?alpha = null)
 {
     return(Color.FromArgb(
                (int)Math.Max(0, Math.Min(255, Math.Round((alpha.HasValue ? MathC.Clamp(alpha.Value, 0.0, 1.0) : color.W) * 255.0f))),
                (int)Math.Max(0, Math.Min(255, Math.Round(color.X * 255.0f))),
                (int)Math.Max(0, Math.Min(255, Math.Round(color.Y * 255.0f))),
                (int)Math.Max(0, Math.Min(255, Math.Round(color.Z * 255.0f)))));
 }
예제 #6
0
        public void Emboss(int xStart, int yStart, int width, int height, int weight, int size)
        {
            size          = MathC.Clamp(size, 2, 8);
            int[,] kernel = new int[size, size];
            kernel[0, 0]  = -1;
            kernel[size - 1, size - 1] = 1;

            ApplyKernel(xStart, yStart, width, height, weight, kernel);
        }
예제 #7
0
 public void Resize(int newSize)
 {
     if (newSize == _undoStack.Count)
     {
         return;
     }
     newSize = MathC.Clamp(newSize, 1, MaxUndoDepth);
     _undoStack.Resize(newSize);
     _redoStack.Resize(newSize);
     UndoStackChanged?.Invoke(this, new EventArgs());
 }
예제 #8
0
        protected Vector4 ApplyColorTransform(Vector4 color)
        {
            // Clamp each value separately to prevent overflows which are possible because TE doesn't internally
            // clamp its vertex lighting to 2.0f.

            color.X = MathC.Clamp(color.X, 0.0f, 2.0f);
            color.Y = MathC.Clamp(color.Y, 0.0f, 2.0f);
            color.Z = MathC.Clamp(color.Z, 0.0f, 2.0f);
            color.W = MathC.Clamp(color.W, 0.0f, 1.0f);
            return(new Vector4(color.X / 2.0f, color.Y / 2.0f, color.Z / 2.0f, color.W));
        }
예제 #9
0
        public void ApplyKernel(int xStart, int yStart, int width, int height, int weight, int[,] kernel)
        {
            ImageC oldImage = new ImageC(width, height, new byte[width * height * 4]);

            oldImage.CopyFrom(0, 0, this, xStart, yStart, width, height);

            int kernel_width  = kernel.GetUpperBound(0) + 1;
            int kernel_height = kernel.GetUpperBound(1) + 1;

            for (int x = 0, xReal = xStart; x < width; x++, xReal++)
            {
                for (int y = 0, yReal = yStart; y < height; y++, yReal++)
                {
                    int r = 0, g = 0, b = 0;
                    for (int dx = 0; dx < kernel_width; dx++)
                    {
                        for (int dy = 0; dy < kernel_height; dy++)
                        {
                            int    sourceX = MathC.Clamp(x + dx, 0, width - 1);
                            int    sourceY = MathC.Clamp(y + dy, 0, height - 1);
                            ColorC clr     = oldImage.GetPixel(sourceX, sourceY);
                            r += (int)clr.R * kernel[dx, dy];
                            g += (int)clr.G * kernel[dx, dy];
                            b += (int)clr.B * kernel[dx, dy];
                        }
                    }
                    r = MathC.Clamp((int)(127 + r / weight), 0, 255);
                    g = MathC.Clamp((int)(127 + g / weight), 0, 255);
                    b = MathC.Clamp((int)(127 + b / weight), 0, 255);
                    SetPixel(xReal, yReal, new ColorC((byte)r, (byte)g, (byte)b));
                }
            }

            // Restore alpha
            for (int x = 0, xReal = xStart; x < width; x++, xReal++)
            {
                for (int y = 0, yReal = yStart; y < height; y++, yReal++)
                {
                    var alpha = oldImage.GetPixel(xReal, yReal).A;
                    var color = GetPixel(xReal, yReal);
                    color.A = alpha;
                    SetPixel(xReal, yReal, color);
                }
            }
        }
예제 #10
0
        void AddMessage(float?progress, string message, bool isWarning)
        {
            if (!(bool)Invoke((Func <bool>) delegate
            {
                if (progress.HasValue)
                {
                    pbStato.Value = (int)Math.Round(MathC.Clamp(progress.Value, 0, 100), 0);
                    TaskbarProgress.SetValue(Application.OpenForms[0].Handle, progress.Value, 100);
                }

                if (!string.IsNullOrEmpty(message))
                {
                    lstLog.SelectionBackColor = isWarning ? Color.Yellow.Multiply(Colors.Brightness) : Color.Empty;
                    lstLog.AppendText(message + "\n");
                    lstLog.ScrollToCaret();
                }

                return(!_threadShouldAbort);
            }))
            {
                throw new OperationCanceledException();
            }
        }
예제 #11
0
        private static byte[] PackTextureMap32To16BitDithered(byte[] textureData, int pageSize)
        {
            // Stucki dithering matrix, it produces better result than Floyd-Steinberg
            // with gradients
            var ditherMatrix = new byte[, ]
            {
                { 0, 0, 0, 8, 4 },
                { 2, 4, 8, 4, 2 },
                { 1, 2, 4, 2, 1 }
            };

            var seed       = new Random(31459);
            int pixelCount = textureData.Length / 4;
            var height     = pixelCount / pageSize;

            byte[] newTextureData = new byte[pixelCount * 2];

            for (int i = 0; i < pixelCount; i++)
            {
                int r1 = textureData[i * 4 + 2];
                int g1 = textureData[i * 4 + 1];
                int b1 = textureData[i * 4 + 0];
                int r2 = (byte)(r1 >> 3) << 3;
                int g2 = (byte)(g1 >> 3) << 3;
                int b2 = (byte)(b1 >> 3) << 3;
                int rE = r1 - r2;
                int bE = g1 - g2;
                int gE = b1 - b2;

                for (int row = 0; row < 3; row++)
                {
                    int offsetY = (i / pageSize) + row;

                    for (int col = 0; col < 5; col++)
                    {
                        int coefficient = ditherMatrix[row, col];
                        int offsetX     = (i % pageSize) + (col - 4);

                        if (coefficient != 0 && offsetX >= 0 && offsetX < pageSize && offsetY >= 0 && offsetY < height)
                        {
                            // Add some noise to coefficient to reduce banding
                            float finalCoeff = 42 - (seed.Next(0, 15));

                            int offsetIndex = (offsetY * pageSize + offsetX) * 4;
                            int newR        = (int)((rE * coefficient) / finalCoeff);
                            int newG        = (int)((gE * coefficient) / finalCoeff);
                            int newB        = (int)((bE * coefficient) / finalCoeff);

                            byte a = (byte)MathC.Clamp((textureData[offsetIndex + 3]), 0, 255);
                            byte r = (byte)MathC.Clamp((textureData[offsetIndex + 2] + newR), 0, 255);
                            byte g = (byte)MathC.Clamp((textureData[offsetIndex + 1] + newG), 0, 255);
                            byte b = (byte)MathC.Clamp((textureData[offsetIndex + 0] + newB), 0, 255);

                            if (r < 8 || a == 0)
                            {
                                r = 0;
                            }
                            if (g < 8 || a == 0)
                            {
                                g = 0;
                            }
                            if (b < 8 || a == 0)
                            {
                                b = 0;
                            }

                            if (a > 0 && a < 255)
                            {
                                // Convert true alpha to brightness with slight noise to prevent banding
                                a -= (byte)seed.Next(0, MathC.Clamp((255 - a) / 20, 0, a));
                                r  = (byte)(r * (a / 255.0f));
                                g  = (byte)(g * (a / 255.0f));
                                b  = (byte)(b * (a / 255.0f));
                            }

                            r /= 8;
                            g /= 8;
                            b /= 8;

                            ushort tmp = 0;

                            if (r == 255 && g == 255 && b == 255)
                            {
                                tmp = 0xffff;
                            }
                            else
                            {
                                tmp |= (ushort)(a == 0 ? 0 : 0x8000);
                                tmp |= (ushort)(r << 10);
                                tmp |= (ushort)(g << 5);
                                tmp |= (ushort)b;
                            }

                            newTextureData[offsetIndex / 2]     = (byte)((tmp & 0x00ff));
                            newTextureData[offsetIndex / 2 + 1] = (byte)((tmp & 0xff00) >> 8);
                        }
                    }
                }
            }
            return(newTextureData);
        }
예제 #12
0
        public static uint CompressColor(Vector3 color, float alpha = 1.0f, bool average = true)
        {
            float multiplier = average ? 128.0f : 255.0f;

            color = Vector3.Max(new Vector3(), Vector3.Min(new Vector3(255.0f), color * multiplier + new Vector3(0.5f)));
            return(((uint)color.X) | (((uint)color.Y) << 8) | (((uint)color.Z) << 16) | ((uint)(MathC.Clamp(alpha, 0, 1) * 255.0f) << 24));
        }
예제 #13
0
        private void WriteNgChunkAnimatedTextures(BinaryWriter writer)
        {
            var startOfChunk = writer.BaseStream.Position;

            writer.Write((ushort)0);
            writer.Write((ushort)0x8002);

            // Count number of textures with UVRotate
            writer.Write((byte)0x01);
            writer.Write(checked ((byte)_textureInfoManager.UvRotateCount));
            writer.Write((short)_textureInfoManager.AnimatedTextures.Count);

            // Array VetInfoRangeAnim
            for (var i = 0; i < 40; i++)
            {
                if (i >= _textureInfoManager.AnimatedTextures.Count)
                {
                    writer.Write((short)0);
                }
                else
                {
                    var param = (ushort)0;
                    var set   = _textureInfoManager.AnimatedTextures[i].Key;

                    switch (set.AnimationType)
                    {
                    case AnimatedTextureAnimationType.Frames:
                        param |= (ushort)MathC.Clamp(Math.Round(1000.0f / (set.Fps == 0 ? 16 : set.Fps)), 0, 0x1fff);
                        break;

                    case AnimatedTextureAnimationType.PFrames:
                        param = 0x4000;
                        break;

                    case AnimatedTextureAnimationType.UVRotate:
                        param  = 0x8000;
                        param |= (ushort)(set.Fps > 31 ? 0 : (int)MathC.Clamp(Math.Round(set.Fps), 0, 0x1F) << 8);     // 0 means 'MAX FPS'
                        param |= (ushort)(set.UvRotate & 0x00FF);
                        break;

                    case AnimatedTextureAnimationType.RiverRotate:
                        param  = 0xA000;
                        param |= (ushort)(set.Fps > 31 ? 0 : (int)MathC.Clamp(Math.Round(set.Fps), 0, 0x1F) << 8);     // 0 means 'MAX FPS'
                        param |= (ushort)(set.UvRotate & 0x00FF);
                        break;

                    case AnimatedTextureAnimationType.HalfRotate:
                        param  = 0xC000;
                        param |= (ushort)(set.Fps > 31 ? 0 : (int)MathC.Clamp(Math.Round(set.Fps), 0, 0x1F) << 8);     // 0 means 'MAX FPS'
                        param |= (ushort)(set.UvRotate & 0x00FF);
                        break;

                    default:
                        throw new NotSupportedException("Unsupported NG animation type encountered.");
                    }

                    writer.Write(param);
                }
            }

            // Array VetFromTex
            for (var i = 0; i < 40; i++)
            {
                if (i >= _textureInfoManager.AnimatedTextures.Count)
                {
                    writer.Write((short)0);
                }
                else
                {
                    var set = _textureInfoManager.AnimatedTextures[i];
                    writer.Write(_remappedTiles[set.Value.First()]);
                }
            }

            // Array VetToTex
            for (var i = 0; i < 40; i++)
            {
                if (i >= _textureInfoManager.AnimatedTextures.Count)
                {
                    writer.Write((short)0);
                }
                else
                {
                    var set = _textureInfoManager.AnimatedTextures[i];
                    writer.Write(_remappedTiles[set.Value.Last()]);
                }
            }

            var sizeDefault = (short)64;

            writer.Write(sizeDefault);

            var endOfChunk = writer.BaseStream.Position;
            var numWords   = (endOfChunk - startOfChunk) / 2;

            writer.Seek((int)startOfChunk, SeekOrigin.Begin);
            writer.Write((ushort)numWords);
            writer.Seek((int)endOfChunk, SeekOrigin.Begin);
        }