Esempio n. 1
0
        public static void ScaleToFit(this OsbSprite sprite)
        {
            var bitmap = Bitmap.FromFile(sprite.GetTexturePathAt(sprite.CommandsStartTime));

            sprite.Scale(
                bitmap.Width / bitmap.Height > 480.0 / 854.0 ?
                480.0 / bitmap.Height
                : 854.0 / bitmap.Width
                );
        }
Esempio n. 2
0
        public bool GenerateCommands(OsbSprite sprite, Box2 bounds, Action <Action, OsbSprite> action = null, double?startTime = null, double?endTime = null, double timeOffset = 0, bool loopable = false)
        {
            var previousState = (State)null;
            var wasVisible    = false;
            var everVisible   = false;
            var stateAdded    = false;
            var imageSize     = Vector2.One;

            foreach (var state in states)
            {
                var time   = state.Time + timeOffset;
                var bitmap = StoryboardObjectGenerator.Current.GetMapsetBitmap(sprite.GetTexturePathAt(time));
                imageSize = new Vector2(bitmap.Width, bitmap.Height);

                PostProcess?.Invoke(state);
                var isVisible = state.IsVisible(bitmap.Width, bitmap.Height, sprite.Origin, bounds);

                if (isVisible)
                {
                    everVisible = true;
                }
                if (!wasVisible && isVisible)
                {
                    if (!stateAdded && previousState != null)
                    {
                        addKeyframes(previousState, time);
                    }
                    addKeyframes(state, time);
                    stateAdded = true;
                }
                else if (wasVisible && !isVisible)
                {
                    addKeyframes(state, time);
                    commitKeyframes(imageSize);
                    stateAdded = true;
                }
                else if (isVisible)
                {
                    addKeyframes(state, time);
                    stateAdded = true;
                }
                else
                {
                    stateAdded = false;
                }

                previousState = state;
                wasVisible    = isVisible;
            }

            if (wasVisible)
            {
                commitKeyframes(imageSize);
            }

            if (everVisible)
            {
                if (action != null)
                {
                    action(() => convertToCommands(sprite, startTime, endTime, timeOffset, loopable), sprite);
                }
                else
                {
                    convertToCommands(sprite, startTime, endTime, timeOffset, loopable);
                }
            }

            clearFinalKeyframes();
            return(everVisible);
        }
Esempio n. 3
0
        public override void GenerateStates(double time, CameraState cameraState, Object3dState object3dState)
        {
            var wvp         = object3dState.WorldTransform * cameraState.ViewProjection;
            var startVector = cameraState.ToScreen(wvp, StartPosition.ValueAt(time));
            var endVector   = cameraState.ToScreen(wvp, EndPosition.ValueAt(time));

            var delta  = endVector.Xy - startVector.Xy;
            var length = delta.Length;

            if (length == 0)
            {
                return;
            }

            var angle    = Math.Atan2(delta.Y, delta.X);
            var rotation = InterpolatingFunctions.DoubleAngle(GeneratorBody.EndState?.Rotation ?? 0, angle, 1);

            var thickness   = Thickness.ValueAt(time);
            var scaleFactor = object3dState.WorldTransform.ExtractScale().Y *(float)cameraState.ResolutionScale;
            var startScale  = scaleFactor * (float)(cameraState.FocusDistance / startVector.W) * thickness * StartThickness.ValueAt(time);
            var endScale    = scaleFactor * (float)(cameraState.FocusDistance / endVector.W) * thickness * EndThickness.ValueAt(time);

            var totalHeight = Math.Max(startScale, endScale);
            var bodyHeight  = Math.Min(startScale, endScale);
            var edgeHeight  = (totalHeight - bodyHeight) * 0.5f;
            var flip        = startScale < endScale;

            var ignoreEdges = edgeHeight < EdgeOverlap;

            if (ignoreEdges)
            {
                bodyHeight += edgeHeight * 2;
            }

            var opacity = startVector.W < 0 && endVector.W < 0 ? 0 : object3dState.Opacity;

            if (UseDistanceFade)
            {
                opacity *= Math.Max(cameraState.OpacityAt(startVector.W), cameraState.OpacityAt(endVector.W));
            }

            // Body

            var bitmapBody = StoryboardObjectGenerator.Current.GetMapsetBitmap(spriteBody.GetTexturePathAt(time));
            var bodyScale  = new Vector2(length / bitmapBody.Width, bodyHeight / bitmapBody.Height);

            var positionBody = startVector.Xy + delta * 0.5f;
            var bodyOpacity  = opacity;

            GeneratorBody.Add(new CommandGenerator.State()
            {
                Time     = time,
                Position = positionBody,
                Scale    = bodyScale,
                Rotation = rotation,
                Color    = object3dState.Color,
                Opacity  = bodyOpacity,
                Additive = Additive,
            });

            // Edges

            if (SpritePathEdge != null)
            {
                var bitmapEdge = StoryboardObjectGenerator.Current.GetMapsetBitmap(spriteTopEdge.GetTexturePathAt(time));
                var edgeScale  = new Vector2(length / bitmapEdge.Width, edgeHeight / bitmapEdge.Height);

                var edgeOffset     = new Vector2((float)Math.Cos(angle - Math.PI * 0.5), (float)Math.Sin(angle - Math.PI * 0.5)) * (bodyHeight * 0.5f - EdgeOverlap);
                var positionTop    = positionBody + edgeOffset;
                var positionBottom = positionBody - edgeOffset;

                var edgeOpacity = ignoreEdges ? 0 : opacity;

                GeneratorTopEdge.Add(new CommandGenerator.State()
                {
                    Time     = time,
                    Position = positionTop,
                    Scale    = edgeScale,
                    Rotation = rotation,
                    Color    = object3dState.Color,
                    Opacity  = edgeOpacity,
                    FlipH    = flip,
                    Additive = Additive,
                });
                GeneratorBottomEdge.Add(new CommandGenerator.State()
                {
                    Time     = time,
                    Position = positionBottom,
                    Scale    = edgeScale,
                    Rotation = rotation,
                    Color    = object3dState.Color,
                    Opacity  = edgeOpacity,
                    Additive = Additive,
                    FlipH    = flip,
                    FlipV    = true,
                });
            }

            // Caps

            if (SpritePathCap != null)
            {
                var bitmapCap     = StoryboardObjectGenerator.Current.GetMapsetBitmap(spriteStartCap.GetTexturePathAt(time));
                var startCapScale = new Vector2(startScale / bitmapCap.Width, startScale / bitmapCap.Height);
                var endCapScale   = new Vector2(endScale / bitmapCap.Width, endScale / bitmapCap.Height);

                var capOffset = OrientedCaps ? new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * CapOverlap : Vector2.Zero;

                if (OrientedCaps)
                {
                    startCapScale.X *= 0.5f;
                    endCapScale.X   *= 0.5f;
                }

                var startCapOpacity = startScale > 0.5f ? opacity : 0;
                var endCapOpacity   = endScale > 0.5f ? opacity : 0;

                GeneratorStartCap.Add(new CommandGenerator.State()
                {
                    Time     = time,
                    Position = startVector.Xy + capOffset,
                    Scale    = startCapScale,
                    Rotation = OrientedCaps ? rotation + Math.PI : 0,
                    Color    = object3dState.Color,
                    Opacity  = startCapOpacity,
                    Additive = Additive,
                });
                GeneratorEndCap.Add(new CommandGenerator.State()
                {
                    Time     = time,
                    Position = endVector.Xy - capOffset,
                    Scale    = endCapScale,
                    Rotation = OrientedCaps ? rotation + Math.PI : 0,
                    Color    = object3dState.Color,
                    Opacity  = endCapOpacity,
                    Additive = Additive,
                    FlipH    = OrientedCaps,
                });
            }
        }
Esempio n. 4
0
        public static void Draw(DrawContext drawContext, Camera camera, Box2 bounds, float opacity, Project project, FrameStats frameStats, OsbSprite sprite)
        {
            var time = project.DisplayTime * 1000;

            if (sprite.TexturePath == null || !sprite.IsActive(time))
            {
                return;
            }

            if (frameStats != null)
            {
                frameStats.SpriteCount++;
                frameStats.CommandCount         += sprite.CommandCost;
                frameStats.IncompatibleCommands |= sprite.HasIncompatibleCommands;
                frameStats.OverlappedCommands   |= sprite.HasOverlappedCommands;
            }

            var fade = sprite.OpacityAt(time);

            if (fade < 0.00001f)
            {
                return;
            }

            var scale = (Vector2)sprite.ScaleAt(time);

            if (scale.X == 0 || scale.Y == 0)
            {
                return;
            }
            if (sprite.FlipHAt(time))
            {
                scale.X = -scale.X;
            }
            if (sprite.FlipVAt(time))
            {
                scale.Y = -scale.Y;
            }

            Texture2dRegion texture  = null;
            var             fullPath = Path.Combine(project.MapsetPath, sprite.GetTexturePathAt(time));

            try
            {
                texture = project.TextureContainer.Get(fullPath);
                if (texture == null)
                {
                    fullPath = Path.Combine(project.ProjectAssetFolderPath, sprite.GetTexturePathAt(time));
                    texture  = project.TextureContainer.Get(fullPath);
                }
            }
            catch (IOException)
            {
                // Happens when another process is writing to the file, will try again later.
                return;
            }
            if (texture == null)
            {
                return;
            }

            var position   = sprite.PositionAt(time);
            var rotation   = sprite.RotationAt(time);
            var color      = sprite.ColorAt(time);
            var finalColor = ((Color4)color)
                             .LerpColor(Color4.Black, project.DimFactor)
                             .WithOpacity(opacity * fade);
            var additive = sprite.AdditiveAt(time);

            var origin = GetOriginVector(sprite.Origin, texture.Width, texture.Height);

            if (frameStats != null)
            {
                var size = texture.Size * scale;

                var spriteObb = new OrientedBoundingBox(position, origin * scale, size.X, size.Y, rotation);
                if (spriteObb.Intersects(OsuHitObject.WidescreenStoryboardBounds))
                {
                    frameStats.EffectiveCommandCount += sprite.CommandCost;

                    // Approximate how much of the sprite is on screen
                    var spriteAabb             = spriteObb.GetAABB();
                    var intersection           = spriteAabb.IntersectWith(OsuHitObject.WidescreenStoryboardBounds);
                    var aabbIntersectionFactor = (intersection.Width * intersection.Height) / (spriteAabb.Width * spriteAabb.Height);

                    var intersectionArea = size.X * size.Y * aabbIntersectionFactor;
                    frameStats.ScreenFill += Math.Min(OsuHitObject.WidescreenStoryboardArea, intersectionArea) / OsuHitObject.WidescreenStoryboardArea;
                }
            }

            var boundsScaling = bounds.Height / 480;

            DrawState.Prepare(drawContext.Get <QuadRenderer>(), camera, additive ? AdditiveStates : AlphaBlendStates)
            .Draw(texture, bounds.Left + bounds.Width * 0.5f + (position.X - 320) * boundsScaling, bounds.Top + position.Y * boundsScaling,
                  origin.X, origin.Y, scale.X * boundsScaling, scale.Y * boundsScaling, rotation, finalColor);
        }
Esempio n. 5
0
        public override void GenerateStates(double time, CameraState cameraState, Object3dState object3dState)
        {
            var wvp         = object3dState.WorldTransform * cameraState.ViewProjection;
            var startVector = cameraState.ToScreen(wvp, StartPosition.ValueAt(time));
            var endVector   = cameraState.ToScreen(wvp, EndPosition.ValueAt(time));

            var delta  = endVector.Xy - startVector.Xy;
            var length = delta.Length;

            if (length == 0)
            {
                return;
            }

            var angle    = Math.Atan2(delta.Y, delta.X);
            var rotation = InterpolatingFunctions.DoubleAngle(Generator.EndState?.Rotation ?? 0, angle, 1);

            var bitmap = StoryboardObjectGenerator.Current.GetMapsetBitmap(sprite.GetTexturePathAt(time));
            var scale  = new Vector2(length / bitmap.Width, Thickness.ValueAt(time));

            var opacity = startVector.W < 0 && endVector.W < 0 ? 0 : object3dState.Opacity;

            if (UseDistanceFade)
            {
                opacity *= Math.Max(cameraState.OpacityAt(startVector.W), cameraState.OpacityAt(endVector.W));
            }

            Vector2 position;

            switch (sprite.Origin)
            {
            default:
            case OsbOrigin.TopLeft:
            case OsbOrigin.CentreLeft:
            case OsbOrigin.BottomLeft:
                position = startVector.Xy;
                break;

            case OsbOrigin.TopCentre:
            case OsbOrigin.Centre:
            case OsbOrigin.BottomCentre:
                position = startVector.Xy + delta * 0.5f;
                break;

            case OsbOrigin.TopRight:
            case OsbOrigin.CentreRight:
            case OsbOrigin.BottomRight:
                position = endVector.Xy;
                break;
            }

            Generator.Add(new CommandGenerator.State()
            {
                Time     = time,
                Position = position,
                Scale    = scale,
                Rotation = rotation,
                Color    = object3dState.Color,
                Opacity  = opacity,
                Additive = Additive,
            });
        }
        public static void Draw(DrawContext drawContext, Camera camera, Box2 bounds, float opacity, Project project, OsbSprite sprite)
        {
            var time = project.DisplayTime * 1000;

            if (sprite.TexturePath == null || !sprite.IsActive(time))
            {
                return;
            }

            var fade = sprite.OpacityAt(time);

            if (fade < 0.00001f)
            {
                return;
            }

            var scale = (Vector2)sprite.ScaleAt(time);

            if (scale.X == 0 || scale.Y == 0)
            {
                return;
            }
            if (sprite.FlipHAt(time))
            {
                scale.X = -scale.X;
            }
            if (sprite.FlipVAt(time))
            {
                scale.Y = -scale.Y;
            }

            var       fullPath = Path.Combine(project.MapsetPath, sprite.GetTexturePathAt(time));
            Texture2d texture  = null;

            try
            {
                texture = project.TextureContainer.Get(fullPath);
            }
            catch (IOException)
            {
                // Happens when another process is writing to the file, will try again later.
                return;
            }
            if (texture == null)
            {
                return;
            }

            var position   = sprite.PositionAt(time);
            var rotation   = sprite.RotationAt(time);
            var color      = sprite.ColorAt(time);
            var finalColor = ((Color4)color).WithOpacity(opacity * fade);
            var additive   = sprite.AdditiveAt(time);

            Vector2 origin;

            switch (sprite.Origin)
            {
            default:
            case OsbOrigin.TopLeft: origin = new Vector2(0, 0); break;

            case OsbOrigin.TopCentre: origin = new Vector2(texture.Width * 0.5f, 0); break;

            case OsbOrigin.TopRight: origin = new Vector2(texture.Width, 0); break;

            case OsbOrigin.CentreLeft: origin = new Vector2(0, texture.Height * 0.5f); break;

            case OsbOrigin.Centre: origin = new Vector2(texture.Width * 0.5f, texture.Height * 0.5f); break;

            case OsbOrigin.CentreRight: origin = new Vector2(texture.Width, texture.Height * 0.5f); break;

            case OsbOrigin.BottomLeft: origin = new Vector2(0, texture.Height); break;

            case OsbOrigin.BottomCentre: origin = new Vector2(texture.Width * 0.5f, texture.Height); break;

            case OsbOrigin.BottomRight: origin = new Vector2(texture.Width, texture.Height); break;
            }

            var boundsScaling = bounds.Height / 480;

            DrawState.Prepare(drawContext.Get <SpriteRenderer>(), camera, additive ? AdditiveStates : AlphaBlendStates)
            .Draw(texture, bounds.Left + bounds.Width * 0.5f + (position.X - 320) * boundsScaling, bounds.Top + position.Y * boundsScaling,
                  origin.X, origin.Y, scale.X * boundsScaling, scale.Y * boundsScaling, rotation, finalColor);
        }
Esempio n. 7
0
        public override void GenerateStates(double time, CameraState cameraState, Object3dState object3dState)
        {
            var wvp = object3dState.WorldTransform * cameraState.ViewProjection;

            if (FixedEdge >= 0)
            {
                edgeIndex = FixedEdge;
            }

            Vector4 vector0, vector1, vector2;

            switch (edgeIndex)
            {
            case 0:
                vector0 = cameraState.ToScreen(wvp, Position0.ValueAt(time));
                vector1 = cameraState.ToScreen(wvp, Position1.ValueAt(time));
                vector2 = cameraState.ToScreen(wvp, Position2.ValueAt(time));
                break;

            case 1:
                vector2 = cameraState.ToScreen(wvp, Position0.ValueAt(time));
                vector0 = cameraState.ToScreen(wvp, Position1.ValueAt(time));
                vector1 = cameraState.ToScreen(wvp, Position2.ValueAt(time));
                break;

            case 2:
                vector1 = cameraState.ToScreen(wvp, Position0.ValueAt(time));
                vector2 = cameraState.ToScreen(wvp, Position1.ValueAt(time));
                vector0 = cameraState.ToScreen(wvp, Position2.ValueAt(time));
                break;

            default: throw new InvalidOperationException();
            }

            var cross = (vector2.X - vector0.X) * (vector1.Y - vector0.Y)
                        - (vector2.Y - vector0.Y) * (vector1.X - vector0.X);

            if (cross > 0)
            {
                if (Generator0.EndState != null)
                {
                    Generator0.EndState.Opacity = 0;
                }
                if (Generator1.EndState != null)
                {
                    Generator1.EndState.Opacity = 0;
                }
                return;
            }

            var bitmap = StoryboardObjectGenerator.Current.GetMapsetBitmap(sprite0.GetTexturePathAt(time));

            var switchedEdge = false;

            for (var i = 0; i < 3; i++)
            {
                var delta           = vector2.Xy - vector0.Xy;
                var deltaLength     = delta.Length;
                var normalizedDelta = delta / deltaLength;

                var delta2 = vector1.Xy - vector0.Xy;
                var dot    = Vector2.Dot(normalizedDelta, delta2);
                if (dot <= 0 || dot > deltaLength)
                {
                    if (FixedEdge >= 0)
                    {
                        if (Generator0.EndState != null)
                        {
                            Generator0.EndState.Opacity = 0;
                        }
                        if (Generator1.EndState != null)
                        {
                            Generator1.EndState.Opacity = 0;
                        }
                        break;
                    }

                    var temp = vector0;
                    vector0      = vector1;
                    vector1      = vector2;
                    vector2      = temp;
                    edgeIndex    = (edgeIndex + 1) % 3;
                    switchedEdge = true;
                    continue;
                }

                var position = project(vector0.Xy, vector2.Xy, vector1.Xy);
                var scale0   = new Vector2((vector2.Xy - position).Length / bitmap.Width, (vector1.Xy - position).Length / bitmap.Height);
                var scale1   = new Vector2((vector0.Xy - position).Length / bitmap.Width, scale0.Y);

                var angle    = Math.Atan2(delta.Y, delta.X);
                var rotation = InterpolatingFunctions.DoubleAngle(Generator0.EndState?.Rotation ?? 0, angle, 1);

                var opacity = vector0.W < 0 && vector1.W < 0 && vector2.W < 0 ? 0 : object3dState.Opacity;
                if (UseDistanceFade)
                {
                    opacity *= (cameraState.OpacityAt(vector0.W) + cameraState.OpacityAt(vector1.W) + cameraState.OpacityAt(vector2.W)) / 3;
                }

                if (switchedEdge)
                {
                    if (Generator0.EndState != null)
                    {
                        Generator0.EndState.Opacity = 0;
                    }
                    if (Generator1.EndState != null)
                    {
                        Generator1.EndState.Opacity = 0;
                    }
                }

                Generator0.Add(new CommandGenerator.State()
                {
                    Time     = time,
                    Position = position,
                    Scale    = scale0,
                    Rotation = rotation,
                    Color    = object3dState.Color,
                    Opacity  = switchedEdge ? 0 : opacity,
                    Additive = Additive,
                });
                Generator1.Add(new CommandGenerator.State()
                {
                    Time     = time,
                    Position = position,
                    Scale    = scale1,
                    Rotation = rotation,
                    Color    = object3dState.Color,
                    Opacity  = switchedEdge ? 0 : opacity,
                    Additive = Additive,
                    FlipH    = true,
                });
                break;
            }
        }