2009-10-08 10 views
7

Poszukuję sposobu na implementację funkcjonalności Swizzle znalezionej w języku HLSL w języku C# dla tych, którzy nie znają tego, co to jest - służy do łatwego dostępu do elementów wektorowych.HLSL Swizzle - w 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) 

Możliwe byłoby utworzenie DUŻYCH właściwości (po jednym dla każdej możliwej kombinacji). Mam wrażenie, że można to zrobić za pomocą Linq, ale nie mam zbyt dużego doświadczenia z nim.

Nie wiem, czy XNA ma coś podobnego do typu, ale nie chcę iść tą ścieżką, ponieważ jest to wszystko, czego bym używał, to znaczy, jeśli to ma.

Dzięki.

+0

Proszę zapoznać się zmienił na moją odpowiedź, podaję rzeczywisty roztwór roboczy do tego problemu, ale wymaga C# 4.0 –

Odpowiedz

8

W wersji C# 3.5 i wcześniejszych najlepiej jest po prostu użyć całej gamy właściwości.

W języku C# 4.0 można jednak używać pisania i podklasy dynamic, aby uzyskać pożądaną funkcjonalność. To może, ale nie musi być lepsza opcja, nie wiem wiele o tej funkcjonalności.

EDIT:

Byłem tak intryguje pytanie, że poszedłem i wdrożył C# 4.0 rozwiązanie tego. Kod jest następujący, ale możesz także download a full solution if that's more your thing [github]. Jak zawsze, możesz używać/przerwać/tworzyć ten kod, jak tylko chcesz, po prostu nie obwiniaj mnie, jeśli to usunie twój dysk twardy.

EDIT 3: Jest to ostatnia edycja Zrobię tutaj, ale prawdopodobnie będę grać z tym więcej i będę wersję umieszczonego na bieżąco dla każdego, kto przychodzi się tutaj później.

EDIT 2:

Zanim pozwolę ci dostać się do kodu, istnieją przykłady tego, co będzie i nie będzie działać w Program.Main() w samym kodzie.

A teraz do kodu.

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

Zawsze można uogólnić go dalej i uczynić go 'Wektor ', ale było po prostu szczęśliwe, że podstawki działają ładnie. To naprawdę wygląda na użyteczne, więc rekwizyty do jego wychowania. –

+0

Pozdrawiam, z pewnością będę się tym zajmować (nie miałem jeszcze nic wspólnego z dynamicznymi typami). Inną rzeczą, która jest możliwa za pomocą implementacji HLSL jest przypisywanie wektorów o różnych rozmiarach (vec2 = vec4.xy) itp. Wierzę, że przy odrobinie gry, która powinna być możliwa. –

+0

Mój kod zwraca klasę Vector będącą podzestawem oryginalnego wektora po uzyskaniu do niego dostępu. Będę edytować w kilku przykładach. –