2009-10-08 4 views
7

CLS의 HLSL에서 발견 된 Swizzle 기능을 구현할 방법을 찾고 있습니다.이 기능은 익숙하지 않은 사람들을 위해 쉽게 벡터 요소 액세스에 사용됩니다.HLSL Swizzle - in C#

Vector4 v1, v2; 
// (t,x,y,z) or (alpha,r,g,b) 
v1 = new Vector4 (1,2,0,0); 
v2 = new Vector4 (0,0,3,4); 

// v1 (Green, Z) = v2 (Y, Blue) 
v1.gz = v2.yb; 
// Result : v1 = (1,2,3,4) 

많은 가능한 속성을 만들 수 있습니다 (가능한 조합마다 하나씩). 나는 그것이 Linq를 통해 가능할 수도 있다는 느낌이 있지만 나는 그것에 대해 많은 경험이 없다.

XNA에 유형과 같은 것이 있는지는 잘 모르겠지만이 경로를 사용하지 않으려 고합니다. 사용하고있는 모든 것, 즉 사용하고있는 경로입니다.

감사합니다.

+0

내 대답에 편집을 참조하십시오, 나는이 문제에 대한 실제 작업 솔루션을 포함 시켰습니다,하지만 당신은 항상 그것을 더 일반화하고 그것을'벡터 '만들 수있는 C# 4.0 –

답변

8

C# 3.5 및 이전 버전에서는 가장 좋은 방법은 단순히 전체 속성 집합을 사용하는 것입니다.

그러나 C# 4.0에서는 찾고자하는 기능을 얻기 위해 dynamic 입력하고 서브 클래스 DynamicObject을 사용할 수 있습니다. 이것은 더 나은 옵션이 될 수도 있고 그렇지 않을 수도 있습니다.이 기능에 대해 많이 알지 못합니다.

편집 : 나는 그래서 내가 가서이에 C# 4.0 솔루션을 구현하는 것이, 문제에 관심 된

. 코드는 다음과 같습니다. download a full solution if that's more your thing [github]도 가능합니다. 언제나 그렇듯이, 당신이 원하는대로이 코드를 사용/중단/만들 수 있습니다. 하드 드라이브를 지우면 저를 비난하지 마십시오.

편집 3 : 이 내가 여기 만들어 줄게 마지막 편집이지만, 나는 아마이 더 놀거야, 내가 나중에 여기로 오는 사람을위한 최신 링크 된 버전을하겠습니다.

편집 2 :

난 당신이 코드에 들어 가지 전에, 그리고 코드 자체에 Program.Main()에서 작동하지 않습니다 무슨의 사례가있다.

이제 코드를 참조하십시오.

namespace Swizzle 
{ 
    /// <summary> 
    /// This implements the Vector4 class as described in the question, based on our totally generic 
    /// Vector class. 
    /// </summary> 
    class Vector4 : Vector<int> 
    { 
     public Vector4(int val0, int val1, int val2, int val3) 
      : base(new Dictionary<char, int> { {'t', 0}, {'x', 1}, {'y', 2}, {'z', 3}, 
               {'a', 0}, {'r', 1}, {'g', 2}, {'b', 3}}, 
        new int[] { val0, val1, val2, val3 }) 
     { } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      dynamic v1, v2, v3; 

      v1 = new Vector4(1, 2, 3, 4); 

      v2 = v1.rgb; 
      // Prints: v2.r: 2 
      Console.WriteLine("v2.r: {0}", v2.r); 
      // Prints: red: 2 
      int red = v2.r; 
      Console.WriteLine("red: {0}", red); 
      // Prints: v2 has 3 elements. 
      Console.WriteLine("v2 has {0} elements.", v2.Length); 

      v3 = new Vector4(5, 6, 7, 8); 
      v3.ar = v2.gb; // yes, the names are preserved! v3 = (3, 4, 7, 8) 

      v2.r = 5; 
      //v2.a = 5; // fails: v2 has no 'a' element, only 'r', 'g', and 'b' 

      // Something fun that will also work 
      Console.WriteLine("v3.gr: {0}", v3.gr); 
      v3.rg = v3.gr; // switch green and red 
      Console.WriteLine("v3.gr: {0}", v3.gr); 

      Console.WriteLine("\r\nPress any key to continue."); 
      Console.ReadKey(true); 
     } 
    } 

    class Vector<T> : DynamicObject 
    { 
     private T[] m_values; 
     private Dictionary<char, int> m_positions; 

     public Vector(Dictionary<char, int> positions, params T[] values) 
     { 
      this.m_positions = positions; 
      this.m_values = values; 
     } 

     public T this[int index] { 
      get { return this.m_values[index]; } 
     } 

     public int Length 
     { 
      get { return this.m_values.Length; } 
     } 

     public override string ToString() 
     { 
      List<string> elements = new List<string>(this.Length); 

      for (int i = 0; i < this.Length; i++) 
      { 
       elements.Add(m_values[i].ToString()); 
      } 

      return string.Join(", ", elements.ToArray()); 
     } 

     public override bool TryGetMember(GetMemberBinder binder, out object result) 
     { 
      if (binder.Name == "Length") { 
       result = this.Length; 
       return true; 
      } 

      if (binder.Name.Length == 1 && this.m_positions.ContainsKey(binder.Name[0])) 
      { 
       result = m_values[this.m_positions[binder.Name[0]]]; 
       return true; 
      } 

      Dictionary<char, int> positions = new Dictionary<char, int>(binder.Name.Length); 
      List<T> values = new List<T>(binder.Name.Length); 
      int i = 0; 
      foreach (char c in binder.Name) 
      { 
       if (!this.m_positions.ContainsKey(c)) 
        return base.TryGetMember(binder, out result); 

       values.Add(m_values[m_positions[c]]); 
       positions.Add(c, i); 

       i++; 
      } 

      result = new Vector<T>(positions, values.ToArray()); 
      return true; 
     } 

     public override bool TrySetMember(SetMemberBinder binder, object value) 
     { 
      // sanity checking. 
      foreach (char c in binder.Name) 
      { 
       if (!this.m_positions.ContainsKey(c)) 
        return base.TrySetMember(binder, value); 
      } 

      Vector<T> vectorValue = value as Vector<T>; 

      if (vectorValue == null && binder.Name.Length == 1 && value is T) 
      { 
       m_values[m_positions[binder.Name[0]]] = (T)value; 
       return true; 
      } 
      else if (vectorValue == null) 
       throw new ArgumentException("You may only set properties of a Vector to another Vector of the same type."); 
      if (vectorValue.Length != binder.Name.Length) 
       throw new ArgumentOutOfRangeException("The length of the Vector given does not match the length of the Vector to assign it to."); 

      int i = 0; 
      foreach (char c in binder.Name) 
      { 
       m_values[m_positions[c]] = vectorValue[i]; 
       i++; 
      } 

      return true; 
     } 
    } 
} 
+0

을 필요로하지만 않습니다 기본 작업이 멋지게 잘되어있어서 기뻤습니다. 이것은 실제로 유용하게 보이기 때문에, 그것을 가져 오는 소품입니다. –

+0

건배, 나는 도전적으로 (나는 역동적 인 유형과 관련이 없다) 그걸 조사하고있을 것이다. HLSL 구현을 사용하여 가능한 다른 것은 다른 크기 (vec2 = vec4.xy) 등의 벡터를 할당하는 것입니다. 나는 그 또한 가능한 것이어야한다고 생각합니다. –

+0

내 코드는 액세스 할 때 원본 벡터의 하위 집합 인 Vector 클래스를 반환합니다. 몇 가지 예에서 편집하겠습니다. –