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]; } } }
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(); }
/// <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); }
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); }
/// <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); } }
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; } } }
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); }
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); } } } }