private void deleteShaders() { if (mProgramId != 0) { // this causes an exception EntryPointNotFound .. // GL.DeleteProgram (1, ref mProgramId ); mProgramId = 0; } if (mVertexShaderId != 0) { GL.DeleteShader(mVertexShaderId); GLUtils.CheckGLError(); mVertexShaderId = 0; } if (mFragmentShaderId != 0) { GL.DeleteShader(mFragmentShaderId); GLUtils.CheckGLError(); mFragmentShaderId = 0; } if (mMemUsage != 0) { mContext.statsDecrement(Context3D.Stats.Count_Program); mContext.statsSubtract(Context3D.Stats.Mem_Program, mMemUsage); mMemUsage = 0; } }
internal void SetPositionScale(float[] positionScale) { // update position scale if (mPositionScale != null) { GL.Uniform4(mPositionScale.Location, 1, positionScale); GLUtils.CheckGLError(); } }
public unsafe void uploadFromPointer(void *data, int dataLength, int startOffset, int count) { // swap to next buffer mBufferIndex++; if (mBufferIndex >= mIds.Length) { mBufferIndex = 0; } // get size of each index int elementSize = sizeof(ushort); int byteCount = count * elementSize; // bounds check if (byteCount > dataLength) { throw new ArgumentOutOfRangeException("data buffer is not big enough for upload"); } GL.BindBuffer(BufferTarget.ElementArrayBuffer, mIds[mBufferIndex]); GLUtils.CheckGLError(); if (startOffset == 0) { GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(byteCount), new IntPtr(data), mUsage); GLUtils.CheckGLError(); if (byteCount != mMemoryUsage) { // update stats for memory usage mContext.statsAdd(Context3D.Stats.Mem_IndexBuffer, byteCount - mMemoryUsage); mMemoryUsage = byteCount; } } else { // update range of index buffer GL.BufferSubData(BufferTarget.ElementArrayBuffer, new IntPtr(startOffset * elementSize), new IntPtr(byteCount), new IntPtr(data)); GLUtils.CheckGLError(); } }
public void uploadFromBitmapData(BitmapData source, uint miplevel = 0, bool generateMipmap = false) { int memUsage = (mWidth * mHeight) * 4; sMemoryUsedForTextures += memUsage; Console.WriteLine("Texture.uploadFromBitmapData() - " + mWidth + "x" + mHeight + " - Mem: " + (memUsage / 1024) + " KB - Total Mem: " + (sMemoryUsedForTextures / 1024) + " KB"); // Bind the texture GL.BindTexture(textureTarget, textureId); GLUtils.CheckGLError(); #if PLATFORM_MONOMAC if (generateMipmap) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1); } #endif #if PLATFORM_MONOMAC || PLATFORM_MONOTOUCH GL.TexImage2D(textureTarget, (int)miplevel, PixelInternalFormat.Rgba, mWidth, mHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, source.getRawData()); mAllocated = true; #elif PLATFORM_MONODROID GL.TexImage2D <uint>(textureTarget, (int)miplevel, (int)PixelInternalFormat.Rgba, mWidth, mHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, source.getRawData()); GLUtils.CheckGLError(); mAllocated = true; #endif #if PLATFORM_MONOTOUCH || PLATFORM_MONODROID if (generateMipmap) { GL.GenerateMipmap(textureTarget); GLUtils.CheckGLError(); } #endif // unbind texture and pixel buffer GL.BindTexture(textureTarget, 0); GLUtils.CheckGLError(); // Uhh... no! BEN // source.dispose(); // store memory usaged by texture trackMemoryUsage(memUsage); }
internal void Use() { // use program GL.UseProgram(mProgramId); GLUtils.CheckGLError(); // update texture units for all sampler uniforms foreach (var sampler in mSamplerUniforms) { if (sampler.RegCount == 1) { // single sampler GL.Uniform1(sampler.Location, sampler.RegIndex); GLUtils.CheckGLError(); } else { // sampler array? for (int i = 0; i < sampler.RegCount; i++) { GL.Uniform1(sampler.Location + i, sampler.RegIndex + i); GLUtils.CheckGLError(); } } } foreach (var sampler in mAlphaSamplerUniforms) { if (sampler.RegCount == 1) { // single sampler GL.Uniform1(sampler.Location, sampler.RegIndex); GLUtils.CheckGLError(); } else { // sampler array? for (int i = 0; i < sampler.RegCount; i++) { GL.Uniform1(sampler.Location + i, sampler.RegIndex + i); GLUtils.CheckGLError(); } } } }
// // Methods // #if OPENGL internal IndexBuffer3D(Context3D context3D, int numIndices, int multiBufferCount, bool isDynamic) { if (multiBufferCount < 1) { throw new ArgumentOutOfRangeException("multiBufferCount"); } mContext = context3D; mNumIndices = numIndices; mIds = new uint[multiBufferCount]; mElementType = DrawElementsType.UnsignedShort; GL.GenBuffers(multiBufferCount, mIds); GLUtils.CheckGLError(); mUsage = isDynamic ? BufferUsage.DynamicDraw : BufferUsage.StaticDraw; // update stats mContext.statsIncrement(Context3D.Stats.Count_IndexBuffer); }
public unsafe void uploadFromByteArray(ByteArray data, uint byteArrayOffset, uint miplevel = 0) { int memUsage = (mWidth * mHeight) * 4; sMemoryUsedForTextures += memUsage; Console.WriteLine("Texture.uploadFromByteArray() - " + mWidth + "x" + mHeight + " - Mem: " + (memUsage / 1024) + " KB - Total Mem: " + (sMemoryUsedForTextures / 1024) + " KB"); // Bind the texture GL.BindTexture(textureTarget, textureId); GLUtils.CheckGLError(); #if PLATFORM_MONOMAC || PLATFORM_MONOTOUCH // pin pointer to byte array data fixed(byte *bytePtr = data.getRawArray()) { IntPtr ptr = (IntPtr)bytePtr; GL.TexImage2D(textureTarget, (int)miplevel, PixelInternalFormat.Rgba, mWidth, mHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, ptr); } mAllocated = true; #elif PLATFORM_MONODROID fixed(byte *ptr = data.getRawArray()) { var address = new IntPtr(ptr + data.position); GL.TexImage2D(textureTarget, (int)miplevel, (int)PixelInternalFormat.Rgba, (int)mWidth, (int)mHeight, 0, PixelFormat.Rgba, PixelType.UnsignedByte, (IntPtr)address); } GLUtils.CheckGLError(); mAllocated = true; #endif // unbind texture and pixel buffer GL.BindTexture(textureTarget, 0); GLUtils.CheckGLError(); // store memory usaged by texture trackMemoryUsage(memUsage); }
private unsafe void uploadATFTextureFromByteArray(ByteArray data, uint byteArrayOffset) { data.position = byteArrayOffset; // read atf signature string signature = data.readUTFBytes(3); if (signature != "ATF") { throw new InvalidDataException("ATF signature not found"); } // read atf length uint length = readUInt24(data); if ((byteArrayOffset + length) > data.length) { throw new InvalidDataException("ATF length exceeds byte array length"); } // get format uint tdata = data.readUnsignedByte( ); AtfType type = (AtfType)(tdata >> 7); if (type != AtfType.NORMAL) { throw new NotImplementedException("ATF Cube maps are not supported"); } // Removing ATF format limitation to allow for multiple format support. // AtfFormat format = (AtfFormat)(tdata & 0x7f); // if (format != AtfFormat.Block) { // throw new NotImplementedException("Only ATF block compressed textures are supported"); // } // get dimensions int width = (1 << (int)data.readUnsignedByte()); int height = (1 << (int)data.readUnsignedByte()); if (width != mWidth || height != mHeight) { throw new InvalidDataException("ATF Width and height dont match"); } // get mipmap count int mipCount = (int)data.readUnsignedByte(); // read all mipmap levels for (int level = 0; level < mipCount; level++) { // read all gpu formats for (int gpuFormat = 0; gpuFormat < 3; gpuFormat++) { // read block length uint blockLength = readUInt24(data); if ((data.position + blockLength) > data.length) { throw new System.IO.InvalidDataException("Block length exceeds ATF file length"); } if (blockLength > 0) { // handle PVRTC on iOS if (gpuFormat == 1) { #if PLATFORM_MONOTOUCH OpenTK.Graphics.ES20.PixelInternalFormat pixelFormat = (OpenTK.Graphics.ES20.PixelInternalFormat) 0x8C02; fixed(byte *ptr = data.getRawArray()) { // upload from data position var address = new IntPtr(ptr + data.position); GL.CompressedTexImage2D(textureTarget, level, pixelFormat, width, height, 0, (int)blockLength, address); mAllocated = true; } trackCompressedMemoryUsage((int)blockLength); #endif } else if (gpuFormat == 2) { #if PLATFORM_MONODROID int textureLength = width * height / 2; fixed(byte *ptr = data.getRawArray()) { var address = new IntPtr(ptr + data.position); GL.CompressedTexImage2D(textureTarget, level, All.Etc1Rgb8Oes, width, height, 0, (int)textureLength, address); GLUtils.CheckGLError(); mAllocated = true; if (textureLength < blockLength) { mAlphaTexture = new Texture(mContext, width, height, mFormat, mOptimizeForRenderToTexture, mStreamingLevels); var alphaAddress = new IntPtr(ptr + data.position + textureLength); GL.BindTexture(mAlphaTexture.textureTarget, mAlphaTexture.textureId); GLUtils.CheckGLError(); GL.CompressedTexImage2D(mAlphaTexture.textureTarget, level, All.Etc1Rgb8Oes, width, height, 0, textureLength, alphaAddress); GLUtils.CheckGLError(); GL.BindTexture(mAlphaTexture.textureTarget, 0); GLUtils.CheckGLError(); mAllocated = true; } else { mAlphaTexture = new Texture(mContext, 1, 1, mFormat, mOptimizeForRenderToTexture, mStreamingLevels); var clearData = new BitmapData(width, height, true, 0xFFFFFFFF); GL.BindTexture(mAlphaTexture.textureTarget, mAlphaTexture.textureId); GLUtils.CheckGLError(); GL.TexImage2D(mAlphaTexture.textureTarget, level, (int)PixelInternalFormat.Rgba, 1, 1, 0, PixelFormat.Rgba, PixelType.UnsignedByte, clearData.getRawData()); GLUtils.CheckGLError(); GL.BindTexture(mAlphaTexture.textureTarget, 0); GLUtils.CheckGLError(); mAllocated = true; clearData.dispose(); } } trackCompressedMemoryUsage((int)blockLength); #endif } // TODO handle other formats/platforms } // next block data data.position += blockLength; } } }
public void uploadCompressedTextureFromByteArray(ByteArray data, uint byteArrayOffset, bool async = false) { #if PLATFORM_MONOMAC System.Console.WriteLine("NotImplementedWarning: Texture.uploadCompressedTextureFromByteArray()"); if (!mDidUpload) { var clearData = new BitmapData(32, 32, true, sColors[sColor % sColors.Length]); sColor++; uploadFromBitmapData(clearData); clearData.dispose(); mDidUpload = true; } #endif // see if this is an ATF container data.position = byteArrayOffset; string signature = data.readUTFBytes(3); data.position = byteArrayOffset; if (signature == "ATF") { // Bind the texture GL.BindTexture(textureTarget, textureId); GLUtils.CheckGLError(); uploadATFTextureFromByteArray(data, byteArrayOffset); GL.BindTexture(textureTarget, 0); GLUtils.CheckGLError(); } else { #if PLATFORM_MONOTOUCH || PLATFORM_MONODROID int memUsage = (mWidth * mHeight) / 2; sMemoryUsedForTextures += memUsage; Console.WriteLine("Texture.uploadCompressedTextureFromByteArray() - " + mWidth + "x" + mHeight + " - Mem: " + (memUsage / 1024) + " KB - Total Mem: " + (sMemoryUsedForTextures / 1024) + " KB"); // Bind the texture GL.BindTexture(textureTarget, textureId); GLUtils.CheckGLError(); if (byteArrayOffset != 0) { throw new NotSupportedException(); } #if PLATFORM_MONOTOUCH int dataLength = (int)(data.length - byteArrayOffset) - 4; // We remove the 4 bytes footer // TODO: Fix hardcoded value here OpenTK.Graphics.ES20.PixelInternalFormat pixelFormat = (OpenTK.Graphics.ES20.PixelInternalFormat) 0x8C02; GL.CompressedTexImage2D(textureTarget, 0, pixelFormat, mWidth, mHeight, 0, dataLength, data.getRawArray()); mAllocated = true; #elif PLATFORM_MONODROID data.position = 16; // skip the header int dataLength = ((int)data.length) - 16; GL.CompressedTexImage2D <byte>(textureTarget, 0, All.Etc1Rgb8Oes, mWidth, mHeight, 0, dataLength, data.getRawArray()); mAllocated = true; #endif trackCompressedMemoryUsage(dataLength); // unbind texture and pixel buffer GL.BindTexture(textureTarget, 0); GLUtils.CheckGLError(); #endif } if (async) { // load with a delay var timer = new flash.utils.Timer(1, 1); timer.addEventListener(TimerEvent.TIMER, (System.Action <Event>) this.OnTextureReady); timer.start(); } }
private void buildUniformList() { // clear internal lists mUniforms.Clear(); mVertexUniformLookup = new Uniform[MaxUniforms]; mFragmentUniformLookup = new Uniform[MaxUniforms]; mSamplerUniforms.Clear(); mAlphaSamplerUniforms.Clear(); mSamplerUsageMask = 0; int numActive = 0; GL.GetProgram(mProgramId, ProgramParameter.ActiveUniforms, out numActive); GLUtils.CheckGLError(); for (int i = 0; i < numActive; i++) { // create new uniform int size = 0; ActiveUniformType uniformType; var name = GL.GetActiveUniform(mProgramId, i, out size, out uniformType); GLUtils.CheckGLError(); var uniform = new Uniform(); uniform.Name = name.ToString(); uniform.Size = size; uniform.Type = uniformType; #if PLATFORM_MONOTOUCH || PLATFORM_MONOMAC uniform.Location = GL.GetUniformLocation(mProgramId, uniform.Name); GLUtils.CheckGLError(); #elif PLATFORM_MONODROID uniform.Location = GL.GetUniformLocation(mProgramId, new StringBuilder(uniform.Name, 0, uniform.Name.Length, uniform.Name.Length)); GLUtils.CheckGLError(); #endif // remove array [x] from names int indexBracket = uniform.Name.IndexOf('['); if (indexBracket >= 0) { uniform.Name = uniform.Name.Substring(0, indexBracket); } // determine register count for uniform switch (uniform.Type) { case ActiveUniformType.FloatMat2: uniform.RegCount = 2; break; case ActiveUniformType.FloatMat3: uniform.RegCount = 3; break; case ActiveUniformType.FloatMat4: uniform.RegCount = 4; break; default: uniform.RegCount = 1; // 1 by default break; } // multiple regcount by size uniform.RegCount *= uniform.Size; // add uniform to program list mUniforms.Add(uniform); if (uniform.Name == "vcPositionScale") { mPositionScale = uniform; } else if (uniform.Name.StartsWith("vc")) { // vertex uniform uniform.RegIndex = int.Parse(uniform.Name.Substring(2)); // store in vertex lookup table for (int reg = 0; reg < uniform.RegCount; reg++) { mVertexUniformLookup[uniform.RegIndex + reg] = uniform; } } else if (uniform.Name.StartsWith("fc")) { // fragment uniform uniform.RegIndex = int.Parse(uniform.Name.Substring(2)); // store in fragment lookup table for (int reg = 0; reg < uniform.RegCount; reg++) { mFragmentUniformLookup[uniform.RegIndex + reg] = uniform; } } else if (uniform.Name.StartsWith("sampler") && !uniform.Name.EndsWith("_alpha")) { // sampler uniform uniform.RegIndex = int.Parse(uniform.Name.Substring(7)); // add to list of sampler uniforms mSamplerUniforms.Add(uniform); // set sampler usage mask for this sampler uniform for (int reg = 0; reg < uniform.RegCount; reg++) { mSamplerUsageMask |= (1 << (uniform.RegIndex + reg)); } } else if (uniform.Name.StartsWith("sampler") && uniform.Name.EndsWith("_alpha")) { // sampler uniform int len = uniform.Name.IndexOf("_") - 7; uniform.RegIndex = int.Parse(uniform.Name.Substring(7, len)) + 4; // add to list of sampler uniforms mAlphaSamplerUniforms.Add(uniform); } if (Verbose) { Console.WriteLine("{0} name:{1} type:{2} size:{3} location:{4}", i, uniform.Name, uniform.Type, uniform.Size, uniform.Location); } } }
public void uploadFromGLSL(string vertexShaderSource, string fragmentShaderSource) { // delete existing shaders deleteShaders(); if (Verbose) { Console.WriteLine(vertexShaderSource); Console.WriteLine(fragmentShaderSource); } mVertexSource = vertexShaderSource; mFragmentSource = fragmentShaderSource; // compiler vertex shader mVertexShaderId = GL.CreateShader(ShaderType.VertexShader); GL.ShaderSource(mVertexShaderId, vertexShaderSource); GLUtils.CheckGLError(); GL.CompileShader(mVertexShaderId); GLUtils.CheckGLError(); int shaderCompiled = 0; GL.GetShader(mVertexShaderId, ShaderParameter.CompileStatus, out shaderCompiled); GLUtils.CheckGLError(); if (All.True != (All)shaderCompiled) { var vertexInfoLog = GL.GetShaderInfoLog(mVertexShaderId); if (!string.IsNullOrEmpty(vertexInfoLog)) { Console.Write("vertex: {0}", vertexInfoLog); } throw new Exception("Error compiling vertex shader: " + vertexInfoLog); } // compile fragment shader mFragmentShaderId = GL.CreateShader(ShaderType.FragmentShader); GL.ShaderSource(mFragmentShaderId, fragmentShaderSource); GLUtils.CheckGLError(); GL.CompileShader(mFragmentShaderId); GLUtils.CheckGLError(); int fragmentCompiled = 0; GL.GetShader(mFragmentShaderId, ShaderParameter.CompileStatus, out fragmentCompiled); if (All.True != (All)fragmentCompiled) { var fragmentInfoLog = GL.GetShaderInfoLog(mFragmentShaderId); if (!string.IsNullOrEmpty(fragmentInfoLog)) { Console.Write("fragment: {0}", fragmentInfoLog); } throw new Exception("Error compiling fragment shader: " + fragmentInfoLog); } // create program mProgramId = GL.CreateProgram(); GL.AttachShader(mProgramId, mVertexShaderId); GLUtils.CheckGLError(); GL.AttachShader(mProgramId, mFragmentShaderId); GLUtils.CheckGLError(); // bind all attribute locations for (int i = 0; i < Context3D.MaxAttributes; i++) { var name = "va" + i; if (vertexShaderSource.Contains(" " + name)) { GL.BindAttribLocation(mProgramId, i, name); } } // Link the program GL.LinkProgram(mProgramId); var infoLog = GL.GetProgramInfoLog(mProgramId); if (!string.IsNullOrEmpty(infoLog)) { Console.Write("program: {0}", infoLog); } // build uniform list buildUniformList(); // update stats for this program mMemUsage = 1; // TODO, figure out a way to get this mContext.statsIncrement(Context3D.Stats.Count_Program); mContext.statsAdd(Context3D.Stats.Mem_Program, mMemUsage); }