Calendar
Mo | Tu | We | Th | Fr | Sa | Su |
---|
30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
Archive
- 2002
- 2003
- 2004
- 2005
- 2006
- 2007
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2019
- 2020
|
Website may be up and down over next few months. I'm currently doing a complete overhaul of everything.
Going back to simple individual .htm pages, new overall site theme, sanitizing and cleaning up html of all
pages and blog posts, attempting to implement a new tooling and publishing system etc etc.
Below is a code sample containing drawing methods for drawing check boxes or any control type in a grid based layout similar to the SelectionGrid.
using System;
using UnityEngine;
public class ControlGrid
{
/// <summary>
/// Draw a grid of check boxes similar to SelectionGrid.
/// </summary>
/// <param name="checkedValues">Specifies the checked values of the check boxes.</param>
/// <param name="text">The content for each individual check box.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each check box.</param>
/// <param name="options">Specifies layout options to be applied to each check box.</param>
/// <returns>Returns the checked state for each check box.</returns>
/// <remarks><p>Check boxes are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
public static bool[] DrawCheckBoxGrid(bool[] checkedValues, string[] text, int columns, GUIStyle style, params GUILayoutOption[] options)
{
// convert string content into gui content
var content = new GUIContent[text.Length];
for (var i = 0; i < content.Length; i++)
{
content[i] = new GUIContent(text[i]);
}
return DrawCheckBoxGrid(checkedValues, content, columns, style, options);
}
/// <summary>
/// Draw a grid of check boxes similar to SelectionGrid.
/// </summary>
/// <param name="checkedValues">Specifies the checked values of the check boxes.</param>
/// <param name="textures">The content for each individual check box.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each check box.</param>
/// <param name="options">Specifies layout options to be applied to each check box.</param>
/// <returns>Returns the checked state for each check box.</returns>
/// <remarks><p>Check boxes are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
public static bool[] DrawCheckBoxGrid(bool[] checkedValues, Texture2D[] textures, int columns, GUIStyle style, params GUILayoutOption[] options)
{
// convert texture content into gui content
var content = new GUIContent[textures.Length];
for (var i = 0; i < content.Length; i++)
{
content[i] = new GUIContent(string.Empty, textures[i]);
}
return DrawCheckBoxGrid(checkedValues, content, columns, style, options);
}
/// <summary>
/// Draw a grid of check boxes similar to SelectionGrid.
/// </summary>
/// <param name="checkedValues">Specifies the checked values of the check boxes.</param>
/// <param name="content">The content for each individual check box.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each check box.</param>
/// <param name="options">Specifies layout options to be applied to each check box.</param>
/// <returns>Returns the checked state for each check box.</returns>
/// <remarks><p>Check boxes are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
public static bool[] DrawCheckBoxGrid(bool[] checkedValues, GUIContent[] content, int columns, GUIStyle style, params GUILayoutOption[] options)
{
return DrawGenericGrid((e, i, s, o) => GUILayout.Toggle(e[i], content[i], style, options), checkedValues, content, columns, style, options);
}
/// <summary>
/// Draw a grid of controls using a draw callback similar to SelectionGrid.
/// </summary>
/// <param name="drawCallback">Specifies a draw callback that is responsible for performing the actual drawing.</param>
/// <param name="values">Specifies the values of the controls.</param>
/// <param name="content">The content for each individual control.</param>
/// <param name="columns">The number of columns in the grid.</param>
/// <param name="style">The style to be applied to each control.</param>
/// <param name="options">Specifies layout options to be applied to each control.</param>
/// <returns>Returns the value for each control.</returns>
/// <remarks><p>Controls are drawn top to bottom, left to right.</p> </remarks>
/// <exception cref="IndexOutOfRangeException">Can occur if the size of the array is too small.</exception>
/// <exception cref="ArgumentNullException">If the drawCallback is null.</exception>
public static T[] DrawGenericGrid<T>(Func<T[], int, GUIStyle, GUILayoutOption[], T> drawCallback, T[] values, GUIContent[] content, int columns, GUIStyle style, params GUILayoutOption[] options)
{
if (drawCallback == null)
{
throw new ArgumentNullException("drawCallback");
}
GUILayout.BeginVertical();
var rowIndex = 0;
var columnIndex = 0;
var index = rowIndex * columns + columnIndex;
GUILayout.BeginHorizontal();
while (index < values.Length)
{
// draw control
values[index] = drawCallback(values, index, style, options);
// move to next column
columnIndex++;
// if passed max columns move down to next row and set to first column
if (columnIndex > columns - 1)
{
columnIndex = 0;
rowIndex++;
// remember to start a new horizontal layout
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
}
// re-calculate the index
index = rowIndex * columns + columnIndex;
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
return values;
}
}
Here is a simple example of how to use the draw methods
var emptyContent = new[] { GUIContent.none, GUIContent.none, GUIContent.none,
GUIContent.none, GUIContent.none, GUIContent.none,
GUIContent.none, GUIContent.none, GUIContent.none };
GUILayout.BeginVertical(GUILayout.MinWidth(128));
rule.IgnoreUpper = GUILayout.Toggle(rule.IgnoreUpper, "Upper Neighbors");
rule.NeighborsUpper = ControlGrid.DrawCheckBoxGrid(rule.NeighborsUpper, emptyContent, 3, GUI.skin.button, GUILayout.MaxWidth(32), GUILayout.MaxHeight(32));
GUILayout.EndVertical();
b55e85cb-8172-4da5-8ad2-359b5ebb0ee3|0|.0
MEFHelpers provides a helper class that provides a static method to make MEF composition easier. /// <summary>
/// Provides a helper class for MEF composition.
/// </summary>
public sealed class MEFHelpers
{
/// <summary>
/// Composes MEF parts.
/// </summary>
/// <param name="parts">The composable object parts.</param>
public static void Compose(params object[] parts)
{
Compose(parts, new string[0]);
}
/// <summary>
/// Composes MEF parts.
/// </summary>
/// <param name="searchFolders">Provides a series of search folders to search for *.dll files.</param>
/// <param name="parts">The composable object parts.</param>
public static void Compose(IEnumerable<string> searchFolders, params object[] parts)
{
// setup composition container
var catalog = new AggregateCatalog();
// check if folders were specified
if (searchFolders != null)
{
// add search folders
foreach (var folder in searchFolders.Where(System.IO.Directory.Exists))
{
catalog.Catalogs.Add(new DirectoryCatalog(folder, "*.dll"));
}
}
// compose and create plug ins
var composer = new CompositionContainer(catalog);
composer.ComposeParts(parts);
}
}
A usage scenario is provided below
public class KissCSMEFComposer
{
[ImportMany(typeof(IProcessor))]
public List<Lazy<IProcessor>> StringProcessors;
[ImportMany(typeof(ICommandRepository))]
public List<Lazy<ICommandRepository>> CommandRepository;
}
var composer = new KissCSMEFComposer();
// try to connect with MEF types
try
{
MEFHelpers.Compose(this.SearchFolders, composer);
}
catch (Exception ex)
{
// ERR: handle error
}
// register string processors
foreach (var processor in composer.StringProcessors)
{
StringProcessorRepository.Instance.Register(processor.Value);
}
// etc ...
12475fb8-8d55-450f-8018-946f135dffa0|0|.0
You can set the mouse cursor for a UI control by using EditorGUIUtility.AddCursorRect and specifying a MouseCursor enum. if (GUILayout.Button("Add"))
{
}
// show the "Link" cursor when the mouse is hovering over this rectangle.
EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link);
0c70f968-230a-445f-adc2-dd4709ac5192|0|.0
The code below can be used to log performance of your code.
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
/// Provides a simple performance testing class that utilizes <see cref="Stopwatch"/>.
/// </summary>
/// <typeparam name="T">The type that will be used as the indexer.</typeparam>
public class PerformanceTesting<T>
{
/// <summary>
/// Provides a model that contains timer information.
/// </summary>
private class TimerModel
{
/// <summary>
/// Used to record performance timings.
/// </summary>
public readonly Stopwatch Timer;
/// <summary>
/// Used to record how many times the <see cref="Timer"/> has been started.
/// </summary>
public int Count;
/// <summary>
/// Used to store the enabled state.
/// </summary>
private bool enabled;
/// <summary>
/// Gets or sets a value whether or not this timer if enabled.
/// </summary>
/// <remarks>If <see cref="Timer"/> has been started and Enabled is set to false the timer will be stopped.</remarks>
public bool Enabled
{
get
{
return this.enabled;
}
set
{
this.enabled = value;
// be sure to stop the timer if disabled
if (!value && this.Timer.IsRunning)
{
this.Timer.Stop();
}
}
}
/// <summary>
/// Default constructor.
/// </summary>
public TimerModel()
{
this.Timer = new Stopwatch();
this.enabled = true;
}
}
/// <summary>
/// Holds a reference to a singleton instance.
/// </summary>
private static PerformanceTesting<T> singleton;
/// <summary>
/// Used to store various timer information.
/// </summary>
private readonly Dictionary<T, TimerModel> timers;
/// <summary>
/// Default constructor.
/// </summary>
public PerformanceTesting()
{
this.timers = new Dictionary<T, TimerModel>();
}
/// <summary>
/// Creates a new timer.
/// </summary>
/// <param name="key">The unique key for the timer.</param>
/// <remarks>It is best to create the timer at the start of the application getting it ready for use.</remarks>
public void Create(T key)
{
this.timers.Add(key, new TimerModel());
}
/// <summary>
/// Creates a new timer for each key.
/// </summary>
/// <param name="keys">The unique keys for the timers.</param>
/// <remarks>It is best to create the timer at the start of the application getting it ready for use.</remarks>
public void Create(T[] keys)
{
foreach (var key in keys)
{
this.timers.Add(key, new TimerModel());
}
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns a time value in ticks.</returns>
public long TotalTicks(T key)
{
var model = this.timers[key];
return model.Timer.ElapsedTicks;
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="keys">The keys to the timers information.</param>
/// <returns>Returns the sum of the time values in ticks.</returns>
public long TotalTicks(T[] keys)
{
long total = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedTicks;
}
return total;
}
/// <summary>
/// Gets the start count.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>The number of times the timer has started.</returns>
public int GetStartCount(T key)
{
var model = this.timers[key];
return model.Count;
}
/// <summary>
/// Gets the start count for specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <returns>The sum total of times all specified the timers have started.</returns>
public int GetStartCount(T[] keys)
{
int total = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Count;
}
return total;
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns a time value in milliseconds.</returns>
public long TotalMilliseconds(T key)
{
var model = this.timers[key];
return model.Timer.ElapsedMilliseconds;
}
/// <summary>
/// Returns the total ticks that this timer has observed.
/// </summary>
/// <param name="keys">The keys to the timers information.</param>
/// <returns>Returns the sum of the time values in milliseconds.</returns>
public long TotalMilliseconds(T[] keys)
{
long total = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedMilliseconds;
}
return total;
}
/// <summary>
/// Calculates the average time in ticks that elapsed while this timer was recording.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns the average time in ticks that elapsed between each start and stop.</returns>
public long AverageTicks(T key)
{
var model = this.timers[key];
return model.Timer.ElapsedTicks / model.Count;
}
/// <summary>
/// Calculates the total average time in ticks that elapsed while the specified timers were recording.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <returns>Returns the total average time in ticks that elapsed between each start and stop for all the specified timers.</returns>
public long AverageTicks(T[] keys)
{
long total = 0;
var count = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedTicks;
count += model.Count;
}
return total / count;
}
/// <summary>
/// Calculates the average time in milliseconds that elapsed while this timer was recording.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <returns>Returns the average time in milliseconds that elapsed between each start and stop.</returns>
public long AverageMilliseconds(T key)
{
var model = this.timers[key];
if (model.Count == 0)
{
return 0;
}
return model.Timer.ElapsedMilliseconds / model.Count;
}
/// <summary>
/// Calculates the total average time in milliseconds that elapsed while the specified timers were recording.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <returns>Returns the total average time in milliseconds that elapsed between each start and stop for all the specified timers.</returns>
public long AverageMilliseconds(T[] keys)
{
long total = 0;
var count = 0;
foreach (var key in keys)
{
var model = this.timers[key];
total += model.Timer.ElapsedMilliseconds;
count += model.Count;
}
if (count == 0)
{
return 0;
}
return total / count;
}
/// <summary>
/// Removes the specified timers.
/// </summary>
/// <param name="keys">The keys to the timers that will be removed.</param>
public void Remove(T[] keys)
{
foreach (var key in keys)
{
this.timers.Remove(key);
}
}
/// <summary>
/// Removes a timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void Remove(T key)
{
this.timers.Remove(key);
}
/// <summary>
/// Resets all the timers.
/// </summary>
public void ResetAll()
{
foreach (var pair in this.timers)
{
pair.Value.Timer.Reset();
}
}
/// <summary>
/// Resets all the timers.
/// </summary>
/// <param name="resetCounts">If true will set each timer start count to 0.</param>
public void ResetAll(bool resetCounts)
{
foreach (var pair in this.timers)
{
pair.Value.Timer.Reset();
if (resetCounts)
{
pair.Value.Count = 0;
}
}
}
/// <summary>
/// Gets an array of timer keys.
/// </summary>
/// <returns>Returns an array of timer keys.</returns>
public T[] GetKeys()
{
var keys = new T[this.timers.Count];
this.timers.Keys.CopyTo(keys, 0);
return keys;
}
/// <summary>
/// Sets the enabled state of the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <param name="enabled">If true the timer will be enabled. If false the timer will be stopped if it is running.</param>
public void SetEnabled(T key, bool enabled)
{
var model = this.timers[key];
model.Enabled = enabled;
}
/// <summary>
/// Sets the enabled state of the specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="enabled">If true the timers will be enabled. If false the timers will be stopped if they are running.</param>
public void SetEnabled(T[] keys, bool enabled)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Enabled = enabled;
}
}
/// <summary>
/// Gets the enabled state of the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public bool IsEnabled(T key)
{
var model = this.timers[key];
return model.Enabled;
}
/// <summary>
/// Gets the enabled state of the specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="enabled">Will contain the enabled state for each specified key.</param>
public void IsEnabled(T[] keys, out bool[] enabled)
{
var enabledStates = new bool[keys.Length];
for (int i = 0; i < keys.Length; i++)
{
var model = this.timers[keys[i]];
enabledStates[i] = model.Enabled;
}
enabled = enabledStates;
}
/// <summary>
/// Starts the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <remarks>Will not start if the enabled state is false.</remarks>
public void Start(T key)
{
var model = this.timers[key];
if (!model.Enabled)
{
return;
}
model.Count++;
model.Timer.Start();
}
/// <summary>
/// Starts the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <remarks>Will not start if the timers enabled state is false.</remarks>
public void Start(T[] keys)
{
foreach (var key in keys)
{
var model = this.timers[key];
if (!model.Enabled)
{
continue;
}
model.Count++;
model.Timer.Start();
}
}
/// <summary>
/// Stops the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void Stop(T key)
{
var model = this.timers[key];
if (!model.Enabled)
{
return;
}
model.Timer.Stop();
}
/// <summary>
/// Stops the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
public void Stop(T[] keys)
{
foreach (var key in keys)
{
var model = this.timers[key];
if (!model.Enabled)
{
continue;
}
model.Timer.Stop();
}
}
/// <summary>
/// Resets the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void Reset(T key)
{
this.Reset(key, false);
}
/// <summary>
/// Resets the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
public void Reset(T[] keys)
{
this.Reset(keys, false);
}
/// <summary>
/// Resets the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <param name="resetCount">If true the start count for the timer will be set to 0.</param>
public void Reset(T key, bool resetCount)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCount)
{
model.Count = 0;
}
}
/// <summary>
/// Resets the timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="resetCounts">If true the start count for the timers will be set to 0.</param>
public void Reset(T[] keys, bool resetCounts)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCounts)
{
model.Count = 0;
}
}
}
/// <summary>
/// Resets the timer start count to 0.
/// </summary>
/// <param name="key">The key to the timer information.</param>
public void ResetCount(T key)
{
var model = this.timers[key];
model.Count = 0;
}
/// <summary>
/// Resets each timer start count to 0.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
public void ResetCount(T[] keys)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Count = 0;
}
}
/// <summary>
/// Restarts the timer.
/// </summary>
/// <param name="key">The key to the timer information.</param>
/// <param name="resetCount">If true the start count for the timer will be set to 0.</param>
/// <remarks>The timer will be reset then started again.</remarks>
public void Restart(T key, bool resetCount)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCount)
{
model.Count = 0;
}
this.Start(key);
}
/// <summary>
/// Restarts the specified timers.
/// </summary>
/// <param name="keys">The keys to the timer information.</param>
/// <param name="resetCounts">If true the start count for the timers will be set to 0.</param>
/// <remarks>Each timer will be reset then started again.</remarks>
public void Restart(T[] keys, bool resetCounts)
{
foreach (var key in keys)
{
var model = this.timers[key];
model.Timer.Reset();
if (resetCounts)
{
model.Count = 0;
}
}
this.Start(keys);
}
/// <summary>
/// Gets a singleton instance of the <see cref="PerformanceTesting{T}"/> class.
/// </summary>
public static PerformanceTesting<T> Instance
{
get
{
return singleton ?? (singleton = new PerformanceTesting<T>());
}
}
}
Setting up a performance counter
#if PERFORMANCE
var perf = PerformanceTesting<string>.Instance;
perf.Create("ScanLines");
#endif
A sample usage
#if PERFORMANCE
var perf = PerformanceTesting<string>.Instance;
perf.Reset("ScanLines");
perf.Start("ScanLines");
#endif
this.scanner.Calculate(this.points);
#if PERFORMANCE
perf.Stop("ScanLines");
#endif
How to report the results
#if PERFORMANCE
public static void ReportPerformanceTimes()
{
var perf = PerformanceTesting<string>.Instance;
foreach (var value in perf.GetKeys())
{
Debug.Log(string.Format("{0} - Total: {1}ms Average: {2} Count: {3}", value, perf.TotalMilliseconds(value), perf.AverageMilliseconds(value), perf.GetStartCount(value)));
}
Debug.Log(string.Format("Total Performance Times - Total: {0}ms", perf.TotalMilliseconds("ScanLines")));
}
#endif
67b32830-abeb-4028-a84c-0f87c797909b|0|.0
Ever wonder how unity makes assets in the project window pop out when you select a link to them in the inspector? See the EditorGUIUtility.PingObject method. [MenuItem("Examples/Ping Selected")]
static void Ping()
{
if (!Selection.activeObject)
{
Debug.LogError("Select an object to ping");
return;
}
EditorGUIUtility.PingObject(Selection.activeObject);
}
16b3c3c4-4c78-442d-9d09-a74e59e0fa3a|0|.0
This code uses a Point type that contains X/Y as integers similar to System.Drawing.Point. This class is used to calculate vertical scan lines for a polygon. It has been tested with 3 points but beyond that I am unsure if it will work. using System;
/// <summary>
/// Helper class used to calculate scan lines of a triangle
/// </summary>
public class TriangleScanLineCalculator
{
/// <summary>
/// Provides a high low type for storing min & max values for scan lines.
/// </summary>
public struct HiLoTYPE
{
public int High;
public int Low;
}
/// <summary>
/// Holds scan line information.
/// </summary>
protected internal HiLoTYPE[] scanLines;
/// <summary>
/// Holds the calculated scan line count.
/// </summary>
protected internal int scanLineCount;
/// <summary>
/// Gets the right most side of the triangle.
/// </summary>
public int MaximumX { get; private set; }
/// <summary>
/// Gets the left most side of the triangle.
/// </summary>
public int MinimumX { get; private set; }
/// <summary>
/// Gets the number of scan lines.
/// </summary>
public int Count
{
get { return scanLineCount; }
}
/// <summary>
/// Calculates the min & max y values for each scan line.
/// </summary>
/// <param name="points">The points that make up the triangle</param>
public void Calculate(Point[] points)
{
var xMax = 0;
var xMin = 0;
float XDelta = 0;
float YDelta = 0;
// X/Y distance between 2 vertexes
float YPos = 0;
float YSlope = 0;
var VertIndex1 = 0;
var VertIndex2 = 0;
var tempIndex = 0;
// Step 1: Find the min and max 'X' dimensions of the polygon
xMax = int.MinValue;
xMin = int.MaxValue;
for (var i = 0; i <= points.Length - 1; i++)
{
if (xMax < points[i].X)
{
xMax = points[i].X;
}
if (xMin > points[i].X)
{
xMin = points[i].X;
}
}
this.MinimumX = xMin;
this.MaximumX = xMax;
this.scanLineCount = xMax - xMin;
// Step 2: Resize scan line array to hold all the high and low x values
if (this.scanLines == null || this.scanLines.Length < xMax - xMin)
{
// allocate
Array.Resize(ref this.scanLines, (xMax - xMin) + 100);
}
// Step3: Set the height value of all scan lines to there min or max value(s)
for (var i = 0; i <= this.scanLines.Length - 1; i++)
{
this.scanLines[i].High = int.MinValue;
this.scanLines[i].Low = int.MaxValue;
}
// Step 4: Set up the Y highs and lows for each X scan line between the min X and Max X points
for (var i = 0; i < points.Length; i++)
{
// Step4a: Determine witch sides of the polygon we will be setting up
VertIndex1 = i;
VertIndex2 = i + 1;
if (VertIndex2 == points.Length) VertIndex2 = 0;
// Step4b: check if the first vertex if farther right then the second vertex
// and if so swap vertex indexes
if (points[VertIndex1].X > points[VertIndex2].X)
{
tempIndex = VertIndex1;
VertIndex1 = VertIndex2;
VertIndex2 = tempIndex;
}
// Step4c: Find the X/Y dist between vert1 and vert2
XDelta = points[VertIndex2].X - points[VertIndex1].X;
YDelta = points[VertIndex2].Y - points[VertIndex1].Y;
// Step4d: Determine the Y slope to use.
// YSlope determines how much to move down for every move we make to the right
if (XDelta != 0)
{
YSlope = YDelta / XDelta;
}
else
{
YSlope = 0;
}
// Save the starting y position in YPos
YPos = points[VertIndex1].Y;
// Step4e: Process all of scan lines between vert1 and vert2
for (var idy = points[VertIndex1].X; idy < points[VertIndex2].X; idy++)
{
// If the scan lines higher value has already been set then set the lower value
// we use the formula 'idy - XMin' to determine what index into the scan line
// array to use. (ScanLineIndex = AnyPositionBetweenVert1AndVert2 - LeftMostPartOfPoly)
// Store the scan line index in the TmpIndex variable so we don't
// have the overhead of doing 5 subtractions
tempIndex = idy - xMin;
var item = this.scanLines[tempIndex];
// Check if Scan(TmpIndex).High has been set already
if (item.High == int.MinValue)
{
// High has not been set yet
item.High = (int)YPos;
}
else
{
// High has been set yet so we set the low point
item.Low = (int)YPos;
// Ensure that the High is actually a higher value then low
if (item.High < item.Low)
{
var tempValue = item.High;
item.High = item.Low;
item.Low = tempValue;
}
}
this.scanLines[tempIndex] = item;
// update the Y position
YPos += YSlope;
}
}
}
/// <summary>
/// Retrieves a scan line.
/// </summary>
/// <param name="index">The index of the scan line.</param>
/// <returns>Returns information about the scan line.</returns>
public HiLoTYPE ScanLine(int index)
{
return this.scanLines[index];
}
/// <summary>
/// Gets all the scan lines.
/// </summary>
/// <returns>Returns all the scan line information.</returns>
public HiLoTYPE[] GetScanLines()
{
// if there are no scan lines return null.
if (this.scanLineCount == 0)
{
return null;
}
// resize the array
Array.Resize(ref this.scanLines, this.scanLineCount);
return this.scanLines;
}
/// <summary>
/// Calculates the scan lines for a triangle.
/// </summary>
/// <param name="points">The triangle points.</param>
/// <param name="minXValue">Will return the minimum x value that the triangle starts at.</param>
/// <returns>Returns the min max y values of the scanline.</returns>
public static HiLoTYPE[] Calculate(Point[] points, out int minXValue)
{
// create scan line calculator and get values from it
var scanner = new TriangleScanLineCalculator();
scanner.Calculate(points);
var items = scanner.GetScanLines();
minXValue = scanner.MinimumX;
return items;
}
}
e850ed73-bcdb-4eff-88fc-5d7f2450dc0e|0|.0
If you are writing UI code and you want the controls you are drawing to appear as if they are labels until they are in focus you can use the EditorGUIUtility.LookLikeInspector & EditorGUIUtility.LookLikeControls methods. public class LookLikeControlsInspector : EditorWindow
{
private int integer1;
float float1 = 5.5f;
[MenuItem("Examples/Look Like Controls - Inspector")]
static void Init()
{
var window = GetWindow<LookLikeControlsInspector>();
window.Show();
}
void OnGUI()
{
EditorGUIUtility.LookLikeInspector();
EditorGUILayout.TextField("Text Field:", "Hello There");
EditorGUILayout.IntField("Int Field:", integer1);
EditorGUILayout.FloatField("Float Field:", float1);
EditorGUILayout.Space();
EditorGUIUtility.LookLikeControls();
EditorGUILayout.TextField("Text Field", "Hello There");
EditorGUILayout.IntField("Int Field:", integer1);
EditorGUILayout.FloatField("Float Field:", float1);
}
}
bc4ab79b-89dd-4bf6-abad-b34331bc7af1|0|.0
I recently came across a strange behavior while loading text resource assets. In particular the Resources.LoadAll method does not accept Path.DirectorySeparatorChar characters in a path. In fact it only accepts Path.AltDirectorySeparatorChar characters. This behavior is different then standard .net file/folder methods that accept either Path.AltDirectorySeparatorChar or Path.DirectorySeparatorChar without distinction. What this means is that you can’t directly use Path.Combine to build a path and pass it to the Resources.LoadAll method you first have to replace any Path.DirectorySeparatorChar characters with Path.AltDirectorySeparatorChar characters. The documentation for Resources.Load also does not mention this behavior. I have submitted a bug report here –> https://fogbugz.unity3d.com/default.asp?533268_jgvrk2lbu1qm398e using System.IO;
using UnityEditor;
using UnityEngine;
/// <summary>
/// Handles settings registration.
/// </summary>
[InitializeOnLoad]
public class EditorInitialization
{
/// <summary>
/// Holds a value indicating whether the RunCallbacks method has been called at least once before.
/// </summary>
private static bool ranOnce;
/// <summary>
/// Initializes static members of the <see cref="EditorInitialization"/> class.
/// </summary>
static EditorInitialization()
{
EditorApplication.update += RunCallbacks;
}
private static void RunCallbacks()
{
if (!ranOnce)
{
// try to load resource
var path = Path.Combine("Test/SubFolder", "testfile"); // result is Test/SubFolder\testfile
// var data = Resources.LoadAll("Test/SubFolder/testfile", typeof(TextAsset)); // this line is successful
var data = Resources.LoadAll(path, typeof(TextAsset)); // this line fails
if (data != null && data.Length != 0)
{
Debug.Log("found it");
}
else
{
Debug.Log("not found! " + path);
}
ranOnce = true;
return;
}
// do stuff
}
}
6f0918db-eed4-4814-be1c-b014f0ecec11|0|.0
Source - http://stackoverflow.com/questions/11518935/mvc-redirect-to-default-route/11520787#11520787 Redirect route handler public class RedirectRouteHandler : IRouteHandler
{
private string _redirectUrl;
public RedirectRouteHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
if (_redirectUrl.StartsWith("~/"))
{
string virtualPath = _redirectUrl.Substring(2);
Route route = new Route(virtualPath, null);
var vpd = route.GetVirtualPath(requestContext,
requestContext.RouteData.Values);
if (vpd != null)
{
_redirectUrl = "~/" + vpd.VirtualPath;
}
}
return new RedirectHandler(_redirectUrl, false);
}
}
Redirect http handler
public class RedirectHandler : IHttpHandler
{
private readonly string _redirectUrl;
public RedirectHandler(string redirectUrl, bool isReusable)
{
_redirectUrl = redirectUrl;
IsReusable = isReusable;
}
public bool IsReusable { get; private set; }
public void ProcessRequest(HttpContext context)
{
context.Response.Status = "301 Moved Permanently";
context.Response.StatusCode = 301;
context.Response.AddHeader("Location", _redirectUrl);
}
}
Extension methods
public static class RouteExtensions
{
public static void Redirect(this RouteCollection routes, string url, string redirectUrl)
{
routes.Add(new Route(url, new RedirectRouteHandler(redirectUrl)));
}
}
b1e3898b-54a1-4d4a-9d4f-5920a7330fed|0|.0
The code below allows you to copy a directory structure with or without sub folders including files. Also includes a callback that can be used to filter out files or folders and reports the copy progress. /// <summary>
/// Copies a directory structure to the destination.
/// </summary>
/// <param name="source">The directory structure to be copied.</param>
/// <param name="destination">The destination where the directory structure will be copied to.</param>
/// <param name="copySubDirectories">true to copy all subdirectories.</param>
/// <param name="overwriteFiles">true if the destination files can be overwritten; otherwise, false.</param>
/// <param name="callback">Provides a callback function for reporting progress. </param>
/// <remarks><p>The callback invoked just before a file copy occurs providing a way of being notified.</p>
/// <p>The callback parameter order is source file, destination file, progress.</p>
/// <p>If the callback is specified it should return true to allow the file copy to occur.</p>
/// <p>The progress parameter reports progress from 0 to 100. Values to the left of the decimal represent folder copy progress and values to the
/// right of the decimal from 0.000 to 0.99 represent the current file copy progress for the folder that is being copied.</p>
/// <p>To get the current file copy progress as a value from 0 to 100 use the formula fileProgress = progress - 100 * 100.</p></remarks>
public static void CopyDirectories(string source, string destination, bool copySubDirectories, bool overwriteFiles, Func<string, string, float, bool> callback)
{
// ensure source folder exists
if (!Directory.Exists(source))
{
throw new DirectoryNotFoundException("The path specified in source is invalid (for example, it is on an unmapped drive).");
}
// create destination folder
Directory.CreateDirectory(destination);
// get all files in source and copy them to destination folder
var files = Directory.GetFiles(source);
var progress = 0f; // used to report the progress from 0 to 100
// set up action to copy files
var fileProcessor = new Action<float, string[], string>((folderProgress, filesToCopy, folder) =>
{
// copy files
for (var i = 0; i < filesToCopy.Length; i++)
{
// get file
var file = filesToCopy[i];
// set default result
var result = true;
// build destination filename
var fileName = Path.GetFileName(file);
if (fileName == null) // should never happen
{
return;
}
fileName = Path.Combine(folder, fileName);
// check if callback specified
if (callback != null)
{
// store result from callback
result = callback(file, fileName, progress);
}
// if result is true we are allowed to copy the file
if (result)
{
File.Copy(file, fileName, overwriteFiles);
}
// (folder progress * 100) + file progress
progress = folderProgress + ((float)i / filesToCopy.Length);
}
});
// copy initial files
fileProcessor(0, files, destination);
// check to copy sub directories
if (!copySubDirectories)
{
return;
}
// get the folder tree for the source folder
var folders = Directory.GetDirectories(source, "*.*", SearchOption.AllDirectories);
// process each sub folder
for (var index = 0; index < folders.Length; index++)
{
// get folder and increment index
var folder = folders[index];
// get files
files = Directory.GetFiles(folder);
// crop source root from destination and build destination folder path
folder = folder.Remove(0, source.Length);
folder = Path.Combine(destination, folder);
// create destination folder
Directory.CreateDirectory(folder);
// process file copying
fileProcessor((index / folders.Length) * 100, files, folder);
}
}
4f1e1d71-ba07-4a45-b0e8-c3fff3afe535|0|.0
|
|