예제 #1
0
        public static void Set(this IAttachable attachable, int x, int y, PassBuffer passbuffer)
        {
            if (attachable == null || passbuffer == null || passbuffer.array == null)
            {
                return;
            }

            byte[] data      = passbuffer.ConvertTo(attachable.Format);
            byte[] dataStore = attachable.DataStore;
            int    width     = attachable.Width;
            int    height    = attachable.Height;
            int    singleElementByteLength = dataStore.Length / width / height;

            if (singleElementByteLength != data.Length)
            {
                for (int i = 0; i < singleElementByteLength && i < data.Length; i++)
                {
                    attachable.DataStore[(width * y + x) * singleElementByteLength + i] = data[i];
                }
            }
            else
            {
                for (int i = 0; i < singleElementByteLength; i++)
                {
                    attachable.DataStore[(width * y + x) * singleElementByteLength + i] = data[i];
                }
            }
        }
예제 #2
0
        private unsafe void ClipSpace2NormalDeviceSpace(PassBuffer passBuffer)
        {
            if (passBuffer.elementType != PassType.Vec4)
            {
                throw new Exception(String.Format("This pass-buffer must be of vec4 type!"));
            }

            var array  = (vec4 *)passBuffer.Mapbuffer();
            int length = passBuffer.Length();

            for (int i = 0; i < length; i++)
            {
                vec4  gl_Position = array[i];
                float w           = gl_Position.w;
                if (w != 0)
                {
                    gl_Position.x = gl_Position.x / w;
                    gl_Position.y = gl_Position.y / w;
                    gl_Position.z = gl_Position.z / w;
                    gl_Position.w = 1;
                }
                array[i] = gl_Position;
            }
            passBuffer.Unmapbuffer();
        }
예제 #3
0
        /// <summary>
        /// Convert data in bytes to data in specified <paramref name="internalFormat"/>.
        /// </summary>
        /// <param name="passbuffer">source data and its type.</param>
        /// <param name="internalFormat">type of target result.</param>
        /// <returns>target result.</returns>
        public static byte[] ConvertTo(this PassBuffer passbuffer, uint internalFormat)
        {
            GCHandle pin     = GCHandle.Alloc(passbuffer.array, GCHandleType.Pinned);
            IntPtr   address = Marshal.UnsafeAddrOfPinnedArrayElement(passbuffer.array, 0);

            byte[] result = ConvertTo(address, passbuffer.elementType, internalFormat);
            pin.Free();

            return(result);
        }
예제 #4
0
        private unsafe PassBuffer[] VertexShaderStage(int count, DrawElementsType type, IntPtr indices, VertexArrayObject vao, ShaderProgram program, GLBuffer indexBuffer)
        {
            PassBuffer[] passBuffers = null;
            VertexShader vs          = program.VertexShader; if (vs == null)

            {
                return(passBuffers);
            }

            // init pass-buffers to record output from vertex shader.
            FieldInfo[] outFieldInfos = (from item in vs.outVariableDict select item.Value.fieldInfo).ToArray();
            uint        vertexCount   = GetVertexCount(vao, indexBuffer, type);

            //int vertexSize = GetVertexSize(outFieldInfos);
            passBuffers = new PassBuffer[1 + outFieldInfos.Length];
            void *[] pointers = new void *[1 + outFieldInfos.Length];
            {
                // the first pass-buffer stores gl_Position.
                var passBuffer = new PassBuffer(PassType.Vec4, (int)vertexCount);
                pointers[0]    = (void *)passBuffer.Mapbuffer();
                passBuffers[0] = passBuffer;
            }
            for (int i = 1; i < passBuffers.Length; i++)
            {
                var      outField   = outFieldInfos[i - 1];
                PassType passType   = outField.FieldType.GetPassType();
                var      passBuffer = new PassBuffer(passType, (int)vertexCount);
                pointers[i]    = (void *)passBuffer.Mapbuffer();
                passBuffers[i] = passBuffer;
            }

            // execute vertex shader for each vertex.
            byte[]   indexData       = indexBuffer.Data;
            int      indexLength     = indexData.Length / ByteLength(type);
            GCHandle pin             = GCHandle.Alloc(indexData, GCHandleType.Pinned);
            IntPtr   pointer         = pin.AddrOfPinnedObject();
            var      gl_VertexIDList = new List <uint>();

            for (int indexID = indices.ToInt32() / ByteLength(type), c = 0; c < count && indexID < indexLength; indexID++, c++)
            {
                uint gl_VertexID = GetVertexID(pointer, type, indexID);
                if (gl_VertexIDList.Contains(gl_VertexID))
                {
                    continue;
                }
                else
                {
                    gl_VertexIDList.Add(gl_VertexID);
                }

                var instance = vs.CreateCodeInstance() as VertexCodeBase; // an executable vertex shader.
                instance.gl_VertexID = (int)gl_VertexID;                  // setup gl_VertexID.
                // setup "in SomeType varName;" vertex attributes.
                Dictionary <uint, VertexAttribDesc> locVertexAttribDict = vao.LocVertexAttribDict;
                foreach (InVariable inVar in vs.inVariableDict.Values) // Dictionary<string, InVariable>.Values
                {
                    VertexAttribDesc desc = null;
                    if (locVertexAttribDict.TryGetValue(inVar.location, out desc))
                    {
                        byte[]           dataStore        = desc.vbo.Data;
                        int              byteIndex        = desc.GetDataIndex(gl_VertexID);
                        VertexAttribType vertexAttribType = (VertexAttribType)desc.dataType;
                        object           value            = dataStore.ToStruct(inVar.fieldInfo.FieldType, byteIndex);
                        inVar.fieldInfo.SetValue(instance, value);
                    }
                }
                // setup "uniform SomeType varName;" in vertex shader.
                Dictionary <string, UniformValue> nameUniformDict = program.nameUniformDict;
                foreach (UniformVariable uniformVar in vs.UniformVariableDict.Values)
                {
                    string       name = uniformVar.fieldInfo.Name;
                    UniformValue obj  = null;
                    if (nameUniformDict.TryGetValue(name, out obj))
                    {
                        if (obj.value != null)
                        {
                            uniformVar.fieldInfo.SetValue(instance, obj.value);
                        }
                    }
                }

                instance.main(); // execute vertex shader code.

                // copy data to pass-buffer.
                {
                    PassBuffer passBuffer = passBuffers[0];
                    var        array      = (vec4 *)pointers[0];
                    array[gl_VertexID] = instance.gl_Position;
                }
                for (int i = 1; i < passBuffers.Length; i++)
                {
                    var outField = outFieldInfos[i - 1];
                    var obj      = outField.GetValue(instance);
                    switch (outField.FieldType.GetPassType())
                    {
                    case PassType.Float: { var array = (float *)pointers[i]; array[gl_VertexID] = (float)obj; } break;

                    case PassType.Vec2: { var array = (vec2 *)pointers[i]; array[gl_VertexID] = (vec2)obj; } break;

                    case PassType.Vec3: { var array = (vec3 *)pointers[i]; array[gl_VertexID] = (vec3)obj; } break;

                    case PassType.Vec4: { var array = (vec4 *)pointers[i]; array[gl_VertexID] = (vec4)obj; } break;

                    case PassType.Mat2: { var array = (mat2 *)pointers[i]; array[gl_VertexID] = (mat2)obj; } break;

                    case PassType.Mat3: { var array = (mat3 *)pointers[i]; array[gl_VertexID] = (mat3)obj; } break;

                    case PassType.Mat4: { var array = (mat4 *)pointers[i]; array[gl_VertexID] = (mat4)obj; } break;

                    default:
                        throw new NotImplementedException();
                    }
                    // a general way to do this:
                    //var obj = outField.GetValue(instance);
                    //byte[] bytes = obj.ToBytes();
                    //PassBuffer passBuffer = passBuffers[i];
                    //var array = (byte*)passBuffer.AddrOfPinnedObject();
                    //for (int t = 0; t < bytes.Length; t++)
                    //{
                    //    array[gl_VertexID * vertexSize + t] = bytes[t];
                    //}
                }
            }
            pin.Free();

            for (int i = 0; i < passBuffers.Length; i++)
            {
                passBuffers[i].Unmapbuffer();
            }

            return(passBuffers);
        }
예제 #5
0
        /// <summary>
        /// Find fragments in the specified triangle.
        /// </summary>
        /// <param name="fragCoord0"></param>
        /// <param name="fragCoord1"></param>
        /// <param name="fragCoord2"></param>
        /// <param name="pointers"></param>
        /// <param name="group"></param>
        /// <param name="passBuffers"></param>
        /// <param name="result"></param>
        unsafe private static void FindFragmentsInTriangle(vec3 fragCoord0, vec3 fragCoord1, vec3 fragCoord2, void *[] pointers, LinearInterpolationInfoGroup group, PassBuffer[] passBuffers, List <Fragment> result)
        {
            int attributeCount = passBuffers.Length - 1;
            var pixelList      = new List <vec3>();

            FindPixelsAtTriangle(fragCoord0, fragCoord1, fragCoord2, pixelList);
            //OnSamePlane(fragCoord0, fragCoord1, fragCoord2, pixelList);
            for (int i = 0; i < pixelList.Count; i++) // for each pixel at this line..
            {
                vec3  pixel = pixelList[i];
                var   fragment = new Fragment(pixel, attributeCount);
                float p0, p1, p2;
                LinearInterpolationTriangle(pixel, fragCoord0, fragCoord1, fragCoord2, out p0, out p1, out p2);
                for (int t = 0; t < attributeCount; t++) // new pass-buffer objects.
                {
                    PassType passType = passBuffers[t + 1].elementType;
                    fragment.attributes[t] = new PassBuffer(passType, 1);        // only one element.
                }
                for (int attrIndex = 0; attrIndex < attributeCount; attrIndex++) // fill data in pass-buffer.
                {
                    PassBuffer attribute         = fragment.attributes[attrIndex];
                    void *     fragmentAttribute = attribute.Mapbuffer().ToPointer();
                    switch (attribute.elementType)
                    {
                    case PassType.Float:
                    {
                        var fAttr = (float *)fragmentAttribute; var array = (float *)pointers[attrIndex];
                        fAttr[0] = array[group.array[0].gl_VertexID] * p0 + array[group.array[1].gl_VertexID] * p1 + array[group.array[2].gl_VertexID] * p2;
                    } break;

                    case PassType.Vec2:
                    {
                        var fAttr = (vec2 *)fragmentAttribute; var array = (vec2 *)pointers[attrIndex];
                        fAttr[0] = array[group.array[0].gl_VertexID] * p0 + array[group.array[1].gl_VertexID] * p1 + array[group.array[2].gl_VertexID] * p2;
                    } break;

                    case PassType.Vec3:
                    {
                        var fAttr = (vec3 *)fragmentAttribute; var array = (vec3 *)pointers[attrIndex];
                        fAttr[0] = array[group.array[0].gl_VertexID] * p0 + array[group.array[1].gl_VertexID] * p1 + array[group.array[2].gl_VertexID] * p2;
                    } break;

                    case PassType.Vec4:
                    {
                        var fAttr = (vec4 *)fragmentAttribute; var array = (vec4 *)pointers[attrIndex];
                        fAttr[0] = array[group.array[0].gl_VertexID] * p0 + array[group.array[1].gl_VertexID] * p1 + array[group.array[2].gl_VertexID] * p2;
                    } break;

                    case PassType.Mat2:
                    {
                        var fAttr = (mat2 *)fragmentAttribute; var array = (mat2 *)pointers[attrIndex];
                        fAttr[0] = array[group.array[0].gl_VertexID] * p0 + array[group.array[1].gl_VertexID] * p1 + array[group.array[2].gl_VertexID] * p2;
                    } break;

                    case PassType.Mat3:
                    {
                        var fAttr = (mat3 *)fragmentAttribute; var array = (mat3 *)pointers[attrIndex];
                        fAttr[0] = array[group.array[0].gl_VertexID] * p0 + array[group.array[1].gl_VertexID] * p1 + array[group.array[2].gl_VertexID] * p2;
                    } break;

                    case PassType.Mat4:
                    {
                        var fAttr = (mat4 *)fragmentAttribute; var array = (mat4 *)pointers[attrIndex];
                        fAttr[0] = array[group.array[0].gl_VertexID] * p0 + array[group.array[1].gl_VertexID] * p1 + array[group.array[2].gl_VertexID] * p2;
                    } break;

                    default:
                        throw new NotDealWithNewEnumItemException(typeof(PassType));
                    }
                    attribute.Unmapbuffer();
                }
                result.Add(fragment);
            }
        }
예제 #6
0
        private unsafe void FragmentShaderStage(ShaderProgram program, List <Fragment> fragmentList)
        {
            FragmentShader fs = program.FragmentShader; if (fs == null)

            {
                return;
            }

            foreach (var fragment in fragmentList)
            {
                var instance = fs.CreateCodeInstance() as FragmentCodeBase; // an executable fragment shader.
                instance.gl_FragCoord = fragment.gl_FragCoord;              // setup fragmen coordinatein window/screen space.
                // setup "in SomeType varName;" vertex attributes.
                InVariable[] inVariables = fs.inVariableDict.Values.ToArray();
                if (inVariables.Length != fragment.attributes.Length)
                {
                    throw new Exception("This should not happen!");
                }
                for (int index = 0; index < inVariables.Length; index++)
                {
                    InVariable inVar     = inVariables[index];
                    PassBuffer attribute = fragment.attributes[index];
                    var        pointer   = attribute.Mapbuffer().ToPointer();
                    switch (attribute.elementType)
                    {
                    case PassType.Float: inVar.fieldInfo.SetValue(instance, ((float *)pointer)[0]); break;

                    case PassType.Vec2: inVar.fieldInfo.SetValue(instance, ((vec2 *)pointer)[0]); break;

                    case PassType.Vec3: inVar.fieldInfo.SetValue(instance, ((vec3 *)pointer)[0]); break;

                    case PassType.Vec4: inVar.fieldInfo.SetValue(instance, ((vec4 *)pointer)[0]); break;

                    case PassType.Mat2: inVar.fieldInfo.SetValue(instance, ((mat2 *)pointer)[0]); break;

                    case PassType.Mat3: inVar.fieldInfo.SetValue(instance, ((mat3 *)pointer)[0]); break;

                    case PassType.Mat4: inVar.fieldInfo.SetValue(instance, ((mat4 *)pointer)[0]); break;

                    default: throw new NotDealWithNewEnumItemException(typeof(PassType));
                    }
                    attribute.Unmapbuffer();
                }
                // setup "uniform SomeType varName;" in fragment shader.
                Dictionary <string, UniformValue> nameUniformDict = program.nameUniformDict;
                foreach (UniformVariable uniformVar in fs.UniformVariableDict.Values)
                {
                    string       name = uniformVar.fieldInfo.Name;
                    UniformValue obj  = null;
                    if (nameUniformDict.TryGetValue(name, out obj))
                    {
                        if (obj.value != null)
                        {
                            uniformVar.fieldInfo.SetValue(instance, obj.value);
                        }
                    }
                }

                instance.main();       // execute fragment shader code.
                fragment.discard = instance.discard;
                if (!instance.discard) // if this fragment is not discarded.
                {
                    OutVariable[] outVariables = fs.outVariableDict.Values.ToArray();
                    var           outBuffers   = new PassBuffer[outVariables.Length];
                    for (int index = 0; index < outVariables.Length; index++)
                    {
                        OutVariable outVar    = outVariables[index];
                        var         outBuffer = new PassBuffer(outVar.fieldInfo.FieldType.GetPassType(), 1);
                        var         pointer   = outBuffer.Mapbuffer().ToPointer();
                        switch (outBuffer.elementType)
                        {
                        case PassType.Float: ((float *)pointer)[0] = (float)outVar.fieldInfo.GetValue(instance); break;

                        case PassType.Vec2: ((vec2 *)pointer)[0] = (vec2)outVar.fieldInfo.GetValue(instance); break;

                        case PassType.Vec3: ((vec3 *)pointer)[0] = (vec3)outVar.fieldInfo.GetValue(instance); break;

                        case PassType.Vec4: ((vec4 *)pointer)[0] = (vec4)outVar.fieldInfo.GetValue(instance); break;

                        case PassType.Mat2: ((mat2 *)pointer)[0] = (mat2)outVar.fieldInfo.GetValue(instance); break;

                        case PassType.Mat3: ((mat3 *)pointer)[0] = (mat3)outVar.fieldInfo.GetValue(instance); break;

                        case PassType.Mat4: ((mat4 *)pointer)[0] = (mat4)outVar.fieldInfo.GetValue(instance); break;

                        default: throw new NotDealWithNewEnumItemException(typeof(PassType));
                        }
                        outBuffer.Unmapbuffer();
                        outBuffers[index] = outBuffer;
                    }
                    fragment.outVariables = outBuffers;
                }
            }
        }
예제 #7
0
        private unsafe List <Fragment> LinearInterpolationPoints(int count, DrawElementsType type, IntPtr indices, VertexArrayObject vao, ShaderProgram program, GLBuffer indexBuffer, PassBuffer[] passBuffers)
        {
            var result           = new List <Fragment>();
            int attributeCount   = passBuffers.Length - 1;
            var gl_PositionArray = (vec4 *)passBuffers[0].Mapbuffer().ToPointer();
            var pointers         = new void *[passBuffers.Length - 1];

            for (int i = 0; i < pointers.Length; i++)
            {
                pointers[i] = passBuffers[i + 1].Mapbuffer().ToPointer();
            }
            byte[]   indexData       = indexBuffer.Data;
            int      indexLength     = indexData.Length / ByteLength(type);
            GCHandle pin             = GCHandle.Alloc(indexData, GCHandleType.Pinned);
            IntPtr   pointer         = pin.AddrOfPinnedObject();
            var      gl_VertexIDList = new List <uint>();
            ivec4    viewport        = this.viewport;

            for (int indexID = indices.ToInt32() / ByteLength(type), c = 0; c < count && indexID < indexLength; indexID++, c++)
            {
                uint gl_VertexID = GetVertexID(pointer, type, indexID);
                if (gl_VertexIDList.Contains(gl_VertexID))
                {
                    continue;
                }
                else
                {
                    gl_VertexIDList.Add(gl_VertexID);
                }

                vec3 fragCoord = new vec3((gl_PositionArray[gl_VertexID].x + 1) / 2.0f * viewport.z + viewport.x,
                                          (gl_PositionArray[gl_VertexID].y + 1) / 2.0f * viewport.w + viewport.y,
                                          (gl_PositionArray[gl_VertexID].z + 1) / 2.0f * (float)(this.depthRangeFar - this.depthRangeNear) + (float)this.depthRangeNear);
                var fragment = new Fragment(fragCoord, attributeCount);
                for (int i = 0; i < attributeCount; i++) // new pass-buffer objects.
                {
                    PassType passType = passBuffers[i].elementType;
                    fragment.attributes[i] = new PassBuffer(passType, 1);        // only one element.
                }
                for (int attrIndex = 0; attrIndex < attributeCount; attrIndex++) // fill data in pass-buffer.
                {
                    PassBuffer attribute         = fragment.attributes[attrIndex];
                    void *     fragmentAttribute = attribute.Mapbuffer().ToPointer();
                    switch (attribute.elementType)
                    {
                    case PassType.Float:
                    {
                        var fAttr = (float *)fragmentAttribute; var array = (float *)pointers[attrIndex];
                        fAttr[0] = array[gl_VertexID];
                    } break;

                    case PassType.Vec2:
                    {
                        var fAttr = (vec2 *)fragmentAttribute; var array = (vec2 *)pointers[attrIndex];
                        fAttr[0] = array[gl_VertexID];
                    } break;

                    case PassType.Vec3:
                    {
                        var fAttr = (vec3 *)fragmentAttribute; var array = (vec3 *)pointers[attrIndex];
                        fAttr[0] = array[gl_VertexID];
                    } break;

                    case PassType.Vec4:
                    {
                        var fAttr = (vec4 *)fragmentAttribute; var array = (vec4 *)pointers[attrIndex];
                        fAttr[0] = array[gl_VertexID];
                    } break;

                    case PassType.Mat2:
                    {
                        var fAttr = (mat2 *)fragmentAttribute; var array = (mat2 *)pointers[attrIndex];
                        fAttr[0] = array[gl_VertexID];
                    } break;

                    case PassType.Mat3:
                    {
                        var fAttr = (mat3 *)fragmentAttribute; var array = (mat3 *)pointers[attrIndex];
                        fAttr[0] = array[gl_VertexID];
                    } break;

                    case PassType.Mat4:
                    {
                        var fAttr = (mat4 *)fragmentAttribute; var array = (mat4 *)pointers[attrIndex];
                        fAttr[0] = array[gl_VertexID];
                    } break;

                    default:
                        throw new NotDealWithNewEnumItemException(typeof(PassType));
                    }
                    attribute.Unmapbuffer();
                }
                result.Add(fragment);
            }

            for (int i = 0; i < passBuffers.Length; i++)
            {
                passBuffers[i].Unmapbuffer();
            }

            return(result);
        }
예제 #8
0
        private void DrawElements(DrawTarget mode, int count, DrawElementsType type, IntPtr indices)
        {
            if (!Enum.IsDefined(typeof(DrawTarget), mode) || !Enum.IsDefined(typeof(DrawElementsType), type))
            {
                SetLastError(ErrorCode.InvalidEnum); return;
            }
            if (count < 0)
            {
                SetLastError(ErrorCode.InvalidValue); return;
            }
            // TODO: GL_INVALID_OPERATION is generated if a geometry shader is active and mode​ is incompatible with the input primitive type of the geometry shader in the currently installed program object.
            // TODO: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to an enabled array or the element array and the buffer object's data store is currently mapped.

            VertexArrayObject vao = this.currentVertexArrayObject; // data structure.

            if (vao == null)
            {
                return;
            }
            ShaderProgram program = this.currentShaderProgram; // algorithm.

            if (program == null)
            {
                return;
            }
            GLBuffer indexBuffer = this.currentBufferDict[BindBufferTarget.ElementArrayBuffer];

            if (indexBuffer == null)
            {
                return;
            }

            // execute vertex shader for each vertex!
            // This is a low effetient implementation.
            // passBuffers is input for the next stage: linear interpolation.
            // passBuffers[0] is gl_Position.
            // passBuffers[others] are attributes of vertexes.
            PassBuffer[] passBuffers = VertexShaderStage(count, type, indices, vao, program, indexBuffer);
            if (passBuffers == null)
            {
                return;
            }                                    // this stage failed.

            Framebuffer framebuffer = this.currentFramebuffer;

            if (framebuffer == null)
            {
                throw new Exception("This should not happen!");
            }

            ClipSpace2NormalDeviceSpace(passBuffers[0]);
            // linear interpolation.
            List <Fragment> fragmentList = LinearInterpolation(mode, count, type, indices, vao, program, indexBuffer, passBuffers);

            // execute fargment shader for each fragment!
            // This is a low effetient implementation.
            FragmentShaderStage(program, fragmentList);
            {
                int index = 0;
                while (index < fragmentList.Count)
                {
                    if (fragmentList[index].discard)
                    {
                        fragmentList.RemoveAt(index);
                    }
                    else
                    {
                        index++;
                    }
                }
            }
            // Scissor test

            // Multisampel fragment operations

            // Stencil test

            // Depth test
            DepthTest(fragmentList);

            //Blending

            // Dithering

            // Logical operations

            // write fragments to framebuffer's colorbuffer attachment(s).
            {
                uint[] drawBufferIndexes = framebuffer.DrawBuffers.ToArray();
                foreach (var fragment in fragmentList)
                {
                    if (fragment.depthTestFailed)
                    {
                        continue;
                    }

                    for (int i = 0; i < fragment.outVariables.Length && i < drawBufferIndexes.Length; i++)
                    {
                        PassBuffer  outVar     = fragment.outVariables[i];
                        IAttachable attachment = framebuffer.ColorbufferAttachments[drawBufferIndexes[i].ToIndex()];
                        attachment.Set((int)fragment.gl_FragCoord.x, (int)fragment.gl_FragCoord.y, outVar);
                    }
                }
            }
        }