1 module glamour.sampler; 2 3 private { 4 import glamour.gl : GLuint, GLenum, 5 GL_TEXTURE_BORDER_COLOR, GL_TEXTURE0, 6 GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, 7 glGetSamplerParameterfv, glBindSampler, 8 glSamplerParameteri, glSamplerParameterf, 9 glGenSamplers, glDeleteSamplers, 10 glTexParameteri, glTexParameterf; 11 import glamour.texture : ITexture, Texture1D, Texture2D, Texture3D; 12 import glamour.util : checkgl; 13 14 debug import std.stdio : stderr; 15 } 16 17 18 /// 19 class ShaderException : Exception { 20 this(string msg) { 21 super(msg); 22 } 23 } 24 25 version(OSX) { 26 /// 27 alias EmulatedSampler Sampler; 28 } else { 29 /// 30 alias RealSampler Sampler; 31 } 32 33 interface ISampler { 34 void set_parameter(T)(GLenum name, T params) if(is(T : int) || is(T : float)); 35 float[] get_parameter(GLenum name); 36 void bind(ITexture tex); 37 void unbind(GLuint unit); 38 void unbind(ITexture tex); 39 void remove(); 40 } 41 42 /// Represents an OpenGL Sampler. 43 class RealSampler : ISampler { 44 /// The OpenGL sampler name. 45 GLuint sampler; 46 /// Alias this to sampler. 47 alias sampler this; 48 49 /// Creates the OpenGL sampler. 50 this() { 51 checkgl!glGenSamplers(1, &sampler); 52 } 53 54 ~this() { 55 debug if(sampler != 0) stderr.writefln("OpenGL: Sampler resources not released."); 56 } 57 58 /// Sets a sampler parameter. 59 void set_parameter(T)(GLenum name, T params) if(is(T : int) || is(T : float)) { 60 static if(is(T : int)) { 61 checkgl!glSamplerParameteri(sampler, name, params); 62 } else { 63 checkgl!glSamplerParameterf(sampler, name, params); 64 } 65 } 66 67 /// Queries a texture parameter from OpenGL. 68 float[] get_parameter(GLenum name) { 69 float[] ret; 70 71 if(name == GL_TEXTURE_BORDER_COLOR) { 72 ret.length = 4; 73 } else { 74 ret.length = 1; 75 } 76 77 checkgl!glGetSamplerParameterfv(sampler, name, ret.ptr); 78 return ret; 79 } 80 81 /// Binds the sampler. 82 void bind(GLuint unit) { 83 checkgl!glBindSampler(unit, sampler); 84 } 85 86 /// ditto 87 void bind(ITexture tex) { 88 checkgl!glBindSampler(tex.get_unit()-GL_TEXTURE0, sampler); 89 } 90 91 /// Unbinds the sampler. 92 void unbind(GLuint unit) { 93 checkgl!glBindSampler(unit, 0); 94 } 95 96 /// ditto 97 void unbind(ITexture tex) { 98 checkgl!glBindSampler(tex.get_unit(), 0); 99 } 100 101 /// Deletes the sampler. 102 void remove() { 103 checkgl!glDeleteSamplers(1, &sampler); 104 sampler = 0; 105 } 106 } 107 108 /// This emulates an OpenGL Sampler on platforms where no glGenSamplers is available (like OSX). 109 /// This only works with Texture1D, Texture2D and Texture3D so far. 110 class EmulatedSampler : ISampler { 111 protected Parameter[GLenum] parameters; 112 protected struct Parameter { 113 union { 114 int i; 115 float f; 116 } 117 bool is_float; 118 119 this(float f) { 120 this.is_float = true; 121 this.f = f; 122 } 123 124 this(int i) { 125 this.is_float = false; 126 this.i = i; 127 } 128 } 129 130 /// Sets a sampler parameter (and stores it internally). 131 void set_parameter(T)(GLenum name, T params) if(is(T : int) || is(T : float)) { 132 parameters[name] = Parameter(params); 133 } 134 135 /// Returns the stored parameter or [float.nan] if not internally stored. 136 float[] get_parameter(GLenum name) 137 in { assert(name != GL_TEXTURE_BORDER_COLOR); 138 assert(parameters[name].is_float); } 139 body { 140 if(auto param = name in parameters) { 141 return [param.f]; 142 } else { 143 return [float.nan]; 144 } 145 } 146 147 /// Stub, throws always ShaderException. 148 void bind(GLuint unit) { 149 throw new ShaderException("Unsupported bind operation for emulated sampler"); 150 } 151 152 /// Applies the parameters to the passed texture, must be one of Texture1D, Texture2D or Texture3D, 153 /// or throws ShaderException 154 void bind(ITexture tex) { 155 GLenum unit; 156 tex.bind(); 157 158 if(cast(Texture1D)tex) 159 unit = GL_TEXTURE_1D; 160 else if(cast(Texture2D)tex) 161 unit = GL_TEXTURE_2D; 162 else if(cast(Texture3D)tex) 163 unit = GL_TEXTURE_3D; 164 else 165 throw new ShaderException("Unsupported texture type"); 166 167 foreach(name, parameter; parameters) { 168 if(parameter.is_float) { 169 checkgl!glTexParameterf(unit, name, parameter.f); 170 } else { 171 checkgl!glTexParameteri(unit, name, parameter.i); 172 } 173 } 174 } 175 176 /// Stub. 177 void unbind(GLuint unit) {} 178 179 /// Stub. 180 void unbind(ITexture tex) {} 181 182 /// Stub. 183 void remove() {} 184 }