| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- using System;
- using BansheeEngine;
- namespace BansheeEditor
- {
- /** @addtogroup AnimationEditor
- * @{
- */
- // TODO DOC
- public class GUITimeline
- {
- private const float LARGE_TICK_HEIGHT_PCT = 0.4f;
- private const float SMALL_TICK_HEIGHT_PCT = 0.2f;
- private const int PADDING = 30;
- private const int TEXT_PADDING = 2;
- private const int OPTIMAL_TICK_WIDTH = 15;
- private int maxTextWidth;
- private int largeTickHeight;
- private int smallTickHeight;
- private int drawableWidth;
- private float rangeLength = 60.0f;
- private int minWidth = 0;
- private GUICanvas canvas;
- private int width;
- private int height;
- private int fps = 1;
- public int MinWidth
- {
- get { return minWidth; }
- }
- public GUITimeline(GUILayout layout, int width, int height)
- {
- canvas = new GUICanvas();
- layout.AddElement(canvas);
- maxTextWidth = GUIUtility.CalculateTextBounds("99:999", EditorBuiltin.DefaultFont,
- EditorStyles.DefaultFontSize).x;
- SetSize(width, height);
- }
- public void SetSize(int width, int height)
- {
- this.width = width;
- this.height = height;
- canvas.SetWidth(width);
- canvas.SetHeight(height);
- largeTickHeight = (int)(height * LARGE_TICK_HEIGHT_PCT);
- smallTickHeight = (int)(height * SMALL_TICK_HEIGHT_PCT);
- drawableWidth = Math.Max(0, width - PADDING * 2);
- Rebuild();
- }
- public void SetRange(float length)
- {
- rangeLength = Math.Max(0.0f, length);
- Rebuild();
- }
- public void SetFPS(int fps)
- {
- this.fps = Math.Max(1, fps);
- Rebuild();
- }
-
- private void DrawTime(int xPos, float seconds, bool minutes)
- {
- TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
- string timeString;
- if (minutes)
- timeString = timeSpan.TotalMinutes.ToString("#0") + ":" + timeSpan.Seconds.ToString("D2");
- else
- timeString = timeSpan.TotalSeconds.ToString("#0.00");
- Vector2I textBounds = GUIUtility.CalculateTextBounds(timeString, EditorBuiltin.DefaultFont,
- EditorStyles.DefaultFontSize);
- Vector2I textPosition = new Vector2I();
- textPosition.x = xPos - textBounds.x / 2;
- textPosition.y = TEXT_PADDING;
- canvas.DrawText(timeString, textPosition, EditorBuiltin.DefaultFont, Color.LightGray,
- EditorStyles.DefaultFontSize);
- }
- private void DrawLargeTick(float t, bool drawText, bool displayAsMinutes)
- {
- int xPos = (int)((t / GetRange()) * drawableWidth) + PADDING;
- // Draw tick
- Vector2I start = new Vector2I(xPos, height - largeTickHeight);
- Vector2I end = new Vector2I(xPos, height);
- canvas.DrawLine(start, end, Color.LightGray);
- // Draw text if it fits
- if (drawText)
- DrawTime(xPos, t, displayAsMinutes);
- }
- private void DrawSmallTick(float t)
- {
- int xPos = (int)((t / GetRange()) * drawableWidth) + PADDING;
- // Draw tick
- Vector2I start = new Vector2I(xPos, height - smallTickHeight);
- Vector2I end = new Vector2I(xPos, height);
- canvas.DrawLine(start, end, Color.LightGray);
- }
- // Returns range rounded to the nearest multiple of FPS
- private float GetRange()
- {
- float spf = 1.0f/fps;
- return ((int)rangeLength/spf) * spf;
- }
- private void Rebuild()
- {
- const int TEXT_SPACING = 10;
- canvas.Clear();
- // TODO - Transition between interval sizes more lightly (dynamically change tick height?)
- // TODO - Calculate min width
- // TODO - When at optimal width it should display the entire range
- // TODO - Time values change as width changes, keep them constant?
- float range = GetRange();
- int numFrames = (int)range * fps;
- float frameWidth = drawableWidth / (float)numFrames;
-
- int tickInterval = (int)Math.Max(1.0f, OPTIMAL_TICK_WIDTH / frameWidth);
- int largeTickInterval = tickInterval * 5;
- float largeTickWidth = frameWidth * largeTickInterval;
- float timePerFrame = range / numFrames;
- float timePerTick = timePerFrame*tickInterval;
- bool displayAsMinutes = TimeSpan.FromSeconds(timePerTick).Minutes > 0;
- int textInterval = MathEx.CeilToInt((maxTextWidth + TEXT_SPACING) / largeTickWidth);
- // Draw extra frames to prevent the out-of-frame ticks from popping in and out as range changes
- float extraWidth = PADDING + maxTextWidth / 2;
- numFrames += (int)(extraWidth / frameWidth);
- float t = 0.0f;
- for (int i = 0; i < numFrames; i++)
- {
- if (i%largeTickInterval == 0)
- {
- int textIdx = i/largeTickInterval;
- bool drawText = textIdx % textInterval == 0;
- DrawLargeTick(t, drawText, displayAsMinutes);
- }
- else if (i%tickInterval == 0)
- DrawSmallTick(t);
- // Move to next tick
- t += timePerFrame;
- }
- }
- }
- /** @} */
- }
|