예제 #1
0
        private void VertexAttribLPointer(uint index, int size, VertexAttribLType type, int stride, IntPtr pointer)
        {
            // TODO: GL_INVALID_VALUE is generated if index​ is greater than or equal to GL_MAX_VERTEX_ATTRIBS.
            if (size != 1 && size != 2 && size != 3 && size != 4)
            {
                SetLastError(ErrorCode.InvalidValue); return;
            }
            if (!Enum.IsDefined(typeof(VertexAttribLType), type))
            {
                SetLastError(ErrorCode.InvalidEnum); return;
            }
            if (stride < 0)
            {
                SetLastError(ErrorCode.InvalidValue); return;
            }
            VertexArrayObject vao = this.currentVertexArrayObject;

            if (vao == null)
            {
                SetLastError(ErrorCode.InvalidOperation); return;
            }
            GLBuffer buffer = this.currentBufferDict[BindBufferTarget.ArrayBuffer];

            // GL_INVALID_OPERATION is generated if zero is bound to the GL_ARRAY_BUFFER buffer object binding point and the pointer​ argument is not NULL.
            // TODO: why only when "pointer​ argument is not NULL"?
            if (buffer == null)
            {
                SetLastError(ErrorCode.InvalidOperation); return;
            }
            VertexAttribDesc desc = null;

            if (!vao.LocVertexAttribDict.TryGetValue(index, out desc))
            {
                desc = new VertexAttribDesc();
                vao.LocVertexAttribDict.Add(index, desc);
            }
            desc.inLocation = index;
            desc.vbo        = buffer;
            desc.dataSize   = size;
            desc.dataType   = (uint)type;
            //desc.normalize = false; // not needed.
            desc.startPos = (uint)pointer.ToInt32();
            desc.stride   = (uint)stride;
        }
예제 #2
0
        private uint GetVertexCount(VertexArrayObject vao, GLBuffer indexBuffer, DrawElementsType type)
        {
            uint vertexCount = 0;

            VertexAttribDesc[] descs = vao.LocVertexAttribDict.Values.ToArray();
            if (descs.Length > 0)
            {
                int c = descs[0].GetVertexCount();
                if (c >= 0)
                {
                    vertexCount = (uint)c;
                }
            }
            else
            {
                uint maxvertexID   = GetMaxVertexID(indexBuffer.Data, type);
                uint vertexIDCount = GetVertexIDCount(indexBuffer.Data, type);
                vertexCount = Math.Min(maxvertexID, vertexIDCount);
            }

            return(vertexCount);
        }
예제 #3
0
        private void BufferData(BindBufferTarget target, int size, IntPtr data, Usage usage)
        {
            if (!Enum.IsDefined(typeof(BindBufferTarget), target))
            {
                SetLastError(ErrorCode.InvalidEnum); return;
            }
            if (!Enum.IsDefined(typeof(Usage), usage))
            {
                SetLastError(ErrorCode.InvalidEnum); return;
            }
            if (size < 0)
            {
                SetLastError(ErrorCode.InvalidValue); return;
            }
            GLBuffer buffer = this.currentBufferDict[target];

            if (buffer == null)
            {
                SetLastError(ErrorCode.InvalidOperation); return;
            }
            // TODO: GL_OUT_OF_MEMORY is generated if the GL is unable to create a data store with the specified size​.

            buffer.SetData(size, data, usage);
        }
예제 #4
0
        private unsafe List <Fragment> LinearInterpolationLineLoop(int count, DrawElementsType type, IntPtr indices, VertexArrayObject vao, ShaderProgram program, GLBuffer indexBuffer, PassBuffer[] passBuffers)
        {
            var result = new List <Fragment>();

            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      groupList   = new List <LinearInterpolationInfoGroup>();
            ivec4    viewport    = this.viewport; // ivec4(x, y, width, height)

            for (int indexID = indices.ToInt32() / ByteLength(type), c = 0; c < count && indexID < indexLength; indexID++, c++)
            {
                var group = new LinearInterpolationInfoGroup(2);
                for (int i = 0; i < 2; i++)
                {
                    uint gl_VertexID = GetVertexID(pointer, type, (indexID + i) % count);//TODO: line-loop vs indices & count.
                    vec4 gl_Position = gl_PositionArray[gl_VertexID];
                    vec3 fragCoord   = new vec3((gl_Position.x + 1) / 2.0f * viewport.z + viewport.x,
                                                (gl_Position.y + 1) / 2.0f * viewport.w + viewport.y,
                                                (gl_Position.z + 1) / 2.0f * (float)(this.depthRangeFar - this.depthRangeNear) + (float)this.depthRangeNear);
                    group.array[i] = new LinearInterpolationInfo(gl_VertexID, fragCoord);
                }

                if (groupList.Contains(group))
                {
                    continue;
                }                                            // discard the same line.
                else
                {
                    groupList.Add(group);
                }

                vec3 fragCoord0 = group.array[0].fragCoord, fragCoord1 = group.array[1].fragCoord;
                {
                    vec3 diff = (fragCoord0 - fragCoord1); // discard line that is too small.
                    if (Math.Abs(diff.x) < epsilon &&
                        Math.Abs(diff.y) < epsilon &&
                        Math.Abs(diff.z) < epsilon
                        )
                    {
                        continue;
                    }
                }

                FindFragmentsInLine(fragCoord0, fragCoord1, pointers, group, passBuffers, result);
            }

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

            return(result);
        }
예제 #5
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);
        }
예제 #6
0
        private unsafe List <Fragment> LinearInterpolationQuads(int count, DrawElementsType type, IntPtr indices, VertexArrayObject vao, ShaderProgram program, GLBuffer indexBuffer, PassBuffer[] passBuffers)
        {
            var result           = new List <Fragment>();
            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      groupList   = new List <LinearInterpolationInfoGroup>();
            ivec4    viewport    = this.viewport; // ivec4(x, y, width, height)

            count = (count - count % 4);
            for (int indexID = indices.ToInt32() / ByteLength(type), c = 0; c < count - 3 && indexID < indexLength - 3; indexID += 4, c += 4)
            {
                var group = new LinearInterpolationInfoGroup(4);
                for (int i = 0; i < 4; i++)
                {
                    uint gl_VertexID = GetVertexID(pointer, type, indexID + i);
                    vec4 gl_Position = gl_PositionArray[gl_VertexID];
                    vec3 fragCoord   = new vec3((gl_Position.x + 1) / 2.0f * viewport.z + viewport.x,
                                                (gl_Position.y + 1) / 2.0f * viewport.w + viewport.y,
                                                (gl_Position.z + 1) / 2.0f * (float)(this.depthRangeFar - this.depthRangeNear) + (float)this.depthRangeNear);
                    group.array[i] = new LinearInterpolationInfo(gl_VertexID, fragCoord);
                }

                if (groupList.Contains(group))
                {
                    continue;
                }                                            // discard the same line.
                else
                {
                    groupList.Add(group);
                }

                vec3 fragCoord0 = group.array[0].fragCoord;
                vec3 fragCoord1 = group.array[1].fragCoord;
                vec3 fragCoord2 = group.array[2].fragCoord;
                vec3 fragCoord3 = group.array[3].fragCoord;

                FindFragmentsInTriangle(fragCoord0, fragCoord1, fragCoord3, pointers, group, passBuffers, result);

                FindFragmentsInTriangle(fragCoord1, fragCoord2, fragCoord3, pointers, group, passBuffers, result);
            }

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

            return(result);
        }
예제 #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 List <Fragment> LinearInterpolationPatches(int count, DrawElementsType type, IntPtr indices, VertexArrayObject vao, ShaderProgram program, GLBuffer indexBuffer, PassBuffer[] passBuffers)
        {
            var            result = new List <Fragment>();
            FragmentShader fs     = program.FragmentShader;

            if (fs == null)
            {
                return(result);
            }

            return(result);
        }
예제 #9
0
        private List <Fragment> LinearInterpolation(DrawTarget mode, int count, DrawElementsType type, IntPtr indices, VertexArrayObject vao, ShaderProgram program, GLBuffer indexBuffer, PassBuffer[] passBuffers)
        {
            List <Fragment> result = null;

            switch (mode)
            {
            case DrawTarget.Points: result = LinearInterpolationPoints(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.Lines: result = LinearInterpolationLines(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.LineLoop: result = LinearInterpolationLineLoop(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.LineStrip: result = LinearInterpolationLineStrip(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.Triangles: result = LinearInterpolationTriangles(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.TriangleStrip: result = LinearInterpolationTriangleStrip(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.TriangleFan: result = LinearInterpolationTriangleFan(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.Quads: result = LinearInterpolationQuads(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.QuadStrip: result = LinearInterpolationQuadStrip(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.Polygon: result = LinearInterpolationPolygon(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.LinesAdjacency: result = LinearInterpolationLinesAdjacency(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.LineStripAdjacency: result = LinearInterpolationLineStripAdjacency(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.TrianglesAdjacency: result = LinearInterpolationTrianglesAdjacency(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.TriangleStripAdjacency: result = LinearInterpolationTriangleStripAdjacency(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            case DrawTarget.Patches: result = LinearInterpolationPatches(count, type, indices, vao, program, indexBuffer, passBuffers); break;

            default: throw new NotDealWithNewEnumItemException(typeof(DrawTarget));
            }

            return(result);
        }
예제 #10
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);
                    }
                }
            }
        }