/// <summary> /// Link image or buffer object to the texture. /// </summary> /// <param name="file"></param> /// <param name="line"></param> /// <param name="err"></param> private void Link(string file, int line, CompileException err) { // IN CASE THIS IS A TEXTURE OBJECT if (glImg != null) { glname = glImg.glname; // get internal format GL.GetTextureLevelParameter(glname, 0, GetTextureParameter.TextureInternalFormat, out int f); Format = (GpuFormat)f; } // IN CASE THIS IS A BUFFER OBJECT else if (glBuff != null) { if (Format == 0) { throw err.Add($"No texture buffer format defined for " + "buffer '{buff}' (e.g. format RGBA8).", file, line); } // CREATE OPENGL OBJECT glname = GL.GenTexture(); GL.BindTexture(TextureTarget.TextureBuffer, glname); GL.TexBuffer(TextureBufferTarget.TextureBuffer, (SizedInternalFormat)Format, glBuff.glname); GL.BindTexture(TextureTarget.TextureBuffer, 0); } }
/// <summary> /// Create OpenGL object specifying the texture /// format and referenced scene objects directly. /// </summary> /// <param name="name"></param> /// <param name="anno"></param> /// <param name="format"></param> /// <param name="glbuff"></param> /// <param name="glimg"></param> public GLTexture(string name, string anno, GpuFormat format, GLBuffer glbuff, GLImage glimg) : base(name, anno) { var err = new CompileException($"texture '{name}'"); // set name Format = format; glBuff = glbuff; glImg = glimg; // INCASE THIS IS A TEXTURE OBJECT Link("", -1, err); if (HasErrorOrGlError(err, "", -1)) throw err; }
/// <summary> /// Create OpenGL object specifying the texture /// format and referenced scene objects directly. /// </summary> /// <param name="name"></param> /// <param name="anno"></param> /// <param name="format"></param> /// <param name="glbuff"></param> /// <param name="glimg"></param> public GLTexture(string name, string anno, GpuFormat format, GLBuffer glbuff, GLImage glimg) : base(name, anno) { var err = new CompileException($"texture '{name}'"); // set name Format = format; glBuff = glbuff; glImg = glimg; // INCASE THIS IS A TEXTURE OBJECT Link("", -1, err); if (HasErrorOrGlError(err, "", -1)) { throw err; } }
/// <summary> /// Link GLBuffer to existing OpenGL image. Used /// to provide debug information in the debug view. /// </summary> /// <param name="name"></param> /// <param name="anno"></param> /// <param name="glname">OpenGL object to like to.</param> public GLImage(string name, string anno, int glname) : base(name, anno) { int f, t; this.glname = glname; this.Size = Enumerable.Repeat(1, 4).ToArray(); GL.GetTextureParameter(glname, TexParameter.TextureTarget, out t); GL.GetTextureLevelParameter(glname, 0, TexParameter.TextureInternalFormat, out f); GL.GetTextureLevelParameter(glname, 0, TexParameter.TextureWidth, out Size[0]); GL.GetTextureLevelParameter(glname, 0, TexParameter.TextureHeight, out Size[1]); GL.GetTextureLevelParameter(glname, 0, TexParameter.TextureDepth, out Size[2]); Type = (TexTarget)t; Format = (GpuFormat)f; if (Type != TexTarget.Texture3D) { Size[3] = Size[2]; Size[2] = 1; } }
/// <summary> /// Link image or buffer object to the texture. /// </summary> /// <param name="file"></param> /// <param name="line"></param> /// <param name="err"></param> private void Link(string file, int line, CompileException err) { // IN CASE THIS IS A TEXTURE OBJECT if (glImg != null) { glname = glImg.glname; // get internal format int f; GL.GetTextureLevelParameter(glname, 0, GetTextureParameter.TextureInternalFormat, out f); Format = (GpuFormat)f; } // IN CASE THIS IS A BUFFER OBJECT else if (glBuff != null) { if (Format == 0) throw err.Add($"No texture buffer format defined for " + "buffer '{buff}' (e.g. format RGBA8).", file, line); // CREATE OPENGL OBJECT glname = GL.GenTexture(); GL.BindTexture(TextureTarget.TextureBuffer, glname); GL.TexBuffer(TextureBufferTarget.TextureBuffer, (SizedInternalFormat)Format, glBuff.glname); GL.BindTexture(TextureTarget.TextureBuffer, 0); } }
/// <summary> /// Bind texture to compute-image unit. /// </summary> /// <param name="unit">Image unit.</param> /// <param name="tex">Texture object.</param> /// <param name="level">Texture mipmap level.</param> /// <param name="layer">Texture array index or texture depth.</param> /// <param name="access">How the texture will be accessed by the shader.</param> /// <param name="format">Pixel format of texture pixels.</param> public static void BindImg(int unit, GLTexture tex, int level = 0, int layer = 0, TextureAccess access = TextureAccess.ReadOnly, GpuFormat format = GpuFormat.Rgba8) => FxDebugger.BindImg(unit, level, tex?.glImg?.Length > 0, layer, access, format, tex?.glname ?? 0);
/// <summary> /// Load a list of image files and return them as a single byte array. /// </summary> /// <param name="dir">compilation directory</param> /// <param name="filepaths">file paths to the image files</param> /// <param name="w">width of the returned texture data</param> /// <param name="h">height of the returned texture data</param> /// <param name="d">number of texture layers</param> /// <param name="gpuformat"></param> /// <returns></returns> private static byte[] LoadImageFiles(string dir, string[] filepaths, int[] size, GpuFormat gpuformat) { // SET DEFAULT DATA FOR OUTPUTS byte[] data = null; bool isdepth = gpuformat.ToString().StartsWith("Depth"); // set default file format and pixel size var fileformat = CpuFormat.Format32bppArgb; var pixelsize = Image.GetPixelFormatSize(fileformat) / 8; // LOAD IMAGA DATA FROM FILES if (filepaths?.Length > 0 && !isdepth) { // pre-load all files to get information // like minimal width and height var bmps = new Bitmap[filepaths.Length]; int imgW = int.MaxValue; int imgH = int.MaxValue; int imgL = size[3] > 0 ? Math.Min(filepaths.Length, size[3]) : filepaths.Length; for (int i = 0; i < imgL; i++) { var path = filepaths[i]; bmps[i] = new Bitmap(Path.IsPathRooted(path) ? path : dir + path); imgW = Math.Min(bmps[i].Width, imgW); imgH = Math.Min(bmps[i].Height, imgH); } // if w, h and d where not set by the user, // use the minimal image size if (size.All(x => x == 1)) { size[0] = imgW; size[1] = imgH; size[2] = 1; size[3] = imgL; } else if (size[2] > 1 && size[3] > 1) size[2] = 1; // allocate texture memory data = new byte[pixelsize * size[0] * size[1] * size[2] * size[3]]; // copy data to texture memory for (int i = 0; i < imgL; i++) { bmps[i].RotateFlip(RotateFlipType.RotateNoneFlipY); var bits = bmps[i].LockBits( new Rectangle(0, 0, Math.Min(bmps[i].Width, size[0]), Math.Min(bmps[i].Height, size[1])), LockMode.ReadOnly, fileformat); Marshal.Copy(bits.Scan0, data, pixelsize * size[0] * size[1] * i, bits.Stride * bits.Height); bmps[i].UnlockBits(bits); } } return data; }
/// <summary> /// Bind image/texture to image load/store unit. /// </summary> /// <param name="unit">binding unit</param> /// <param name="level">level of the texture/image to be bound</param> /// <param name="layered">is the texture layered (e.g. like a cube map is)</param> /// <param name="layer">layer of the layered texture to be bound</param> /// <param name="access">how shaders can access the texture resource</param> /// <param name="format">texture format of the texture</param> /// <param name="glname">texture/image to be bound</param> public static void BindImg(int unit, int level, bool layered, int layer, TextureAccess access, GpuFormat format, int glname) { // bind image to image load/store unit if ((imgUnits[unit].glname = glname) > 0) { imgUnits[unit].access = access; imgUnits[unit].format = (SizedInternalFormat)format; } GL.BindImageTexture(unit, glname, level, layered, Math.Max(layer, 0), imgUnits[unit].access, imgUnits[unit].format); }
/// <summary> /// Bind texture to compute-image unit. /// </summary> /// <param name="unit">Image unit.</param> /// <param name="tex">Texture object.</param> /// <param name="level">Texture mipmap level.</param> /// <param name="layer">Texture array index or texture depth.</param> /// <param name="access">How the texture will be accessed by the shader.</param> /// <param name="format">Pixel format of texture pixels.</param> public static void BindImg(int unit, GLTexture tex, int level = 0, int layer = 0, TextureAccess access = TextureAccess.ReadOnly, GpuFormat format = GpuFormat.Rgba8) { GL.BindImageTexture(unit, tex?.glname ?? 0, level, tex?.glImg?.Length > 0, Math.Max(layer, 0), access, (SizedInternalFormat)format); }