Radar's picture

GL.Uniform

Hi all,

i am trying to implement my own math in OpenTK.
But i have a problem with the GL.Uniform when i try to send a vector or a matrix.

I am not sure how to make that. I thought i did it right but GetError() returns Invalid Op.

I try to send my Matrix like this:

unsafe { GL.UniformMatrix4(this.uniLoc(uniformLocation), 1, false, (float*)mat44); }

I overloaded two operators of my Matrix44 struct (i adapted that from the Vector4.cs):

unsafe public static explicit operator float*(Matrix44 v)
        {
            fixed (float* first = v.fields) //fields is array
            return first;
        }
 
        unsafe public static explicit operator IntPtr(Matrix44 v)
        {
            fixed (float* first = v.fields)
                return (IntPtr)(first);
        }

And the struct starts like this:

[StructLayout(LayoutKind.Sequential)]
    public struct Matrix44
    {
        [MarshalAs(UnmanagedType.R4, SizeConst=16)]
        public float[] fields;  // = new float[16];
...
...

The matrix contains data. So it is not a problem of a uninitialized field-variable... well i guess.
I am still learning c# so if this is a noobish error i am sorry for that, but i don't understand why it does not work. I guess it must be my code.

Thank you very much in advance!!!


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
tksuoran's picture

I use this:

using System;
using System.Runtime.InteropServices;
 
using RenderStack.Math;
 
using OpenTK.Graphics.OpenGL;
 
namespace RenderStack.Graphics
{
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public abstract class Params<T> : IComparable where T : IEquatable<T>, IComparable<T>, IComparable
    {
        protected bool dirty = true; 
        public bool Dirty { get { return dirty; } set { dirty = value; } }
        public T[]  Value;
        public int  Elements;
        public int  Dimension;
        public T    X { get { return Value[0]; } set { if(!Value[0].Equals(value)){ Value[0] = value; dirty = true; } } }
        public T    Y { get { return Value[1]; } set { if(!Value[1].Equals(value)){ Value[1] = value; dirty = true; } } }
        public T    Z { get { return Value[2]; } set { if(!Value[2].Equals(value)){ Value[2] = value; dirty = true; } } }
        public T    W { get { return Value[3]; } set { if(!Value[3].Equals(value)){ Value[3] = value; dirty = true; } } }
 
        public T this[int index, int component]
        {
            get
            {
                return Value[index * Elements + component];
            }
            set
            {
                if(!Value[index * Elements + component].Equals(value))
                {
                    Value[index * Elements + component] = value;
                    dirty = true;
                }
            }
        }
        public T this[int index]
        {
            get 
            { 
                return Value[index]; 
            }
            set
            { 
                if(!Value[index].Equals(value))
                {
                    Value[index] = value;
                    dirty = true;
                }
            }
        }
 
        public Params()
        {
            Value = new T[1 * 1];
            Elements = 1;
            Dimension = 1;
        }
 
        public Params(int elements, int dimension)
        {
            Value = new T[dimension * elements];
            Elements = elements;
            Dimension = dimension;
        }
        public Params(T x)
        {
            Value = new T[1 * 1];
            Elements = 1;
            Dimension = 1;
            X = x;
        }
        public Params(T x, T y)
        {
            Value = new T[1 * 2];
            Elements = 2;
            Dimension = 1;
            X = x;
            Y = y;
        }
        public Params(T x, T y, T z)
        {
            Value = new T[1 * 3];
            Elements = 3;
            Dimension = 1;
            X = x;
            Y = y;
            Z = z;
        }
        public Params(T x, T y, T z, T w)
        {
            Value = new T[1 * 4];
            Elements = 4;
            Dimension = 1;
            X = x;
            Y = y;
            Z = z;
            W = w;
        }
 
        public void Set(T x)
        {
            X = x;
        }
        public void Set(T x, T y)
        {
            X = x;
            Y = y;
        }
        public void Set(T x, T y, T z)
        {
            X = x;
            Y = y;
            Z = z;
        }
        public void Set(T x, T y, T z, T w)
        {
            X = x;
            Y = y;
            Z = z;
            W = w;
        }
        public void Set(int index, T x)
        {
            Value[index * Elements + 0] = x;
        }
        public void Set(int index, T x, T y)
        {
            Value[index * Elements + 0] = x;
            Value[index * Elements + 1] = y;
        }
        public void Set(int index, T x, T y, T z)
        {
            Value[index * Elements + 0] = x;
            Value[index * Elements + 1] = y;
            Value[index * Elements + 2] = z;
        }
        public void Set(int index, T x, T y, T z, T w)
        {
            Value[index * Elements + 0] = x;
            Value[index * Elements + 1] = y;
            Value[index * Elements + 2] = z;
            Value[index * Elements + 3] = w;
        }
 
        public abstract void Apply(ref IUniformContext context);
 
        public int CompareTo(object o)
        {
            Params<T> other = (Params<T>)o;
            for(int i = 0; i < Value.Length; ++i)
            {
                if(Value[i].CompareTo(other.Value[i]) < 0)
                {
                    return -1;
                }
                if(Value[i].CompareTo(other.Value[i]) > 0)
                {
                    return 1;
                }
            }
            return 0;
        }
        public void CacheFrom(IUniformValue source)
        {
            Params<T> other = (Params<T>)source;
            for(int i = 0; i < Value.Length; ++i)
            {
                Value[i] = other.Value[i];
            }
        }
    }
 
    /// \brief A class which holds integers that can be fed to OpenGL uniforms.
    public class Ints : Params<int>, IUniformValue
    {
        public IUniformValue GetUninitialized()
        {
            Ints clone = new Ints(Elements, Dimension);
            for(int i = 0; i < Value.Length; ++i)
            {
                clone.Value[i] = int.MaxValue;
            }
            return clone;
        }
        public Ints():base(1,1){}
        public Ints(int elements, int dimension):base(elements, dimension){}
        public Ints(int x):base(x){}
        public override unsafe void Apply(ref IUniformContext context)
        {
            fixed(int* ptr = &Value[0])
            {
                switch(Elements)
                {
                    case  1: GL.Uniform1(context.Slot, Dimension, ptr); break;
                    case  2: GL.Uniform2(context.Slot, Dimension, ptr); break;
                    case  3: GL.Uniform3(context.Slot, Dimension, ptr); break;
                    case  4: GL.Uniform4(context.Slot, Dimension, ptr); break;
                }
            }
        }
    }
    /// \brief A class which holds unsigned integers that can be fed to OpenGL uniforms.
    public class UInts : Params<uint>, IUniformValue
    {
        public IUniformValue GetUninitialized()
        {
            UInts clone = new UInts(Elements, Dimension);
            for(int i = 0; i < Value.Length; ++i)
            {
                clone.Value[i] = uint.MaxValue;
            }
            return clone;
        }
        public UInts():base(1,1){}
        public UInts(int elements, int dimension):base(elements, dimension){}
        public UInts(uint x):base(x){}
        public override unsafe void Apply(ref IUniformContext context)
        {
            fixed(uint* ptr = &Value[0])
            {
                switch(Elements)
                {
                    case  1: GL.Uniform1(context.Slot, Dimension, ptr); break;
                    case  2: GL.Uniform2(context.Slot, Dimension, ptr); break;
                    case  3: GL.Uniform3(context.Slot, Dimension, ptr); break;
                    case  4: GL.Uniform4(context.Slot, Dimension, ptr); break;
                }
            }
        }
    }
    /// \brief A class which holds floats that can be fed to OpenGL uniforms.
    public class Floats : Params<float>, IUniformValue
    {
        public IUniformValue GetUninitialized()
        {
            Floats clone = new Floats(Elements, Dimension);
            for(int i = 0; i < Value.Length; ++i)
            {
                clone.Value[i] = float.MaxValue;
            }
            return clone;
        }
        public Floats():base(1,1){}
        public Floats(int elements, int dimension):base(elements, dimension){}
        public Floats(float x):base(x){}
        public Floats(float x, float y):base(x,y){}
        public Floats(float x, float y, float z):base(x,y,z){}
        public Floats(float x, float y, float z, float w):base(x,y,z,w){}
        public void Set(Vector2 v)
        {
            if(Elements != 2)
            {
                throw new ArgumentException();
            }
            X = v.X;
            Y = v.Y;
        }
        public void Set(Vector3 v)
        {
            if(Elements != 3)
            {
                throw new ArgumentException();
            }
            X = v.X;
            Y = v.Y;
            Z = v.Z;
        }
        public void Set(Vector4 v)
        {
            if(Elements != 4)
            {
                throw new ArgumentException();
            }
            X = v.X;
            Y = v.Y;
            Z = v.Z;
            W = v.W;
        }
        public void Set(int index, Vector2 v)
        {
            if(Elements != 2)
            {
                throw new ArgumentException();
            }
            if(!Value[index * Elements + 0].Equals(v.X)) { Value[index * Elements + 0] = v.X; dirty = true; }
            if(!Value[index * Elements + 1].Equals(v.Y)) { Value[index * Elements + 1] = v.Y; dirty = true; }
        }
        public void Set(int index, Vector3 v)
        {
            if(Elements != 3)
            {
                throw new ArgumentException();
            }
            if(!Value[index * Elements + 0].Equals(v.X)) { Value[index * Elements + 0] = v.X; dirty = true; }
            if(!Value[index * Elements + 1].Equals(v.Y)) { Value[index * Elements + 1] = v.Y; dirty = true; }
            if(!Value[index * Elements + 2].Equals(v.Z)) { Value[index * Elements + 2] = v.Z; dirty = true; }
        }
        public void Set(int index, Vector4 v)
        {
            if(Elements != 4)
            {
                throw new ArgumentException();
            }
            if(!Value[index * Elements + 0].Equals(v.X)) { Value[index * Elements + 0] = v.X; dirty = true; }
            if(!Value[index * Elements + 1].Equals(v.Y)) { Value[index * Elements + 1] = v.Y; dirty = true; }
            if(!Value[index * Elements + 2].Equals(v.Z)) { Value[index * Elements + 2] = v.Z; dirty = true; }
            if(!Value[index * Elements + 3].Equals(v.W)) { Value[index * Elements + 3] = v.W; dirty = true; }
        }
        public override unsafe void Apply(ref IUniformContext context)
        {
            fixed(float* ptr = &Value[0])
            {
                switch(Elements)
                {
                    case  1: GL.Uniform1        (context.Slot, Dimension, ptr); break;
                    case  2: GL.Uniform2        (context.Slot, Dimension, ptr); break;
                    case  3: GL.Uniform3        (context.Slot, Dimension, ptr); break;
                    case  4: GL.Uniform4        (context.Slot, Dimension, ptr); break;
                    case 16: GL.UniformMatrix4  (context.Slot, Dimension, false, ptr); break;
                }
            }
        }
        public void Set(Matrix4 m)
        {
            Set(0, m);
        }
        public void Set(int index, Matrix4 m)
        {
            if(Elements != 16)
            {
                throw new ArgumentException("Set(Matrix4) with Elements != 16");
            }
 
            if(!Value[index * Elements +  0].Equals(m._00)) { Value[index * Elements +  0] = m._00; dirty = true; }
            if(!Value[index * Elements +  1].Equals(m._10)) { Value[index * Elements +  1] = m._10; dirty = true; }
            if(!Value[index * Elements +  2].Equals(m._20)) { Value[index * Elements +  2] = m._20; dirty = true; }
            if(!Value[index * Elements +  3].Equals(m._30)) { Value[index * Elements +  3] = m._30; dirty = true; }
            if(!Value[index * Elements +  4].Equals(m._01)) { Value[index * Elements +  4] = m._01; dirty = true; }
            if(!Value[index * Elements +  5].Equals(m._11)) { Value[index * Elements +  5] = m._11; dirty = true; }
            if(!Value[index * Elements +  6].Equals(m._21)) { Value[index * Elements +  6] = m._21; dirty = true; }
            if(!Value[index * Elements +  7].Equals(m._31)) { Value[index * Elements +  7] = m._31; dirty = true; }
            if(!Value[index * Elements +  8].Equals(m._02)) { Value[index * Elements +  8] = m._02; dirty = true; }
            if(!Value[index * Elements +  9].Equals(m._12)) { Value[index * Elements +  9] = m._12; dirty = true; }
            if(!Value[index * Elements + 10].Equals(m._22)) { Value[index * Elements + 10] = m._22; dirty = true; }
            if(!Value[index * Elements + 11].Equals(m._32)) { Value[index * Elements + 11] = m._32; dirty = true; }
            if(!Value[index * Elements + 12].Equals(m._03)) { Value[index * Elements + 12] = m._03; dirty = true; }
            if(!Value[index * Elements + 13].Equals(m._13)) { Value[index * Elements + 13] = m._13; dirty = true; }
            if(!Value[index * Elements + 14].Equals(m._23)) { Value[index * Elements + 14] = m._23; dirty = true; }
            if(!Value[index * Elements + 15].Equals(m._33)) { Value[index * Elements + 15] = m._33; dirty = true; }
        }
    }
}