1 /* 2 DSFML - The Simple and Fast Multimedia Library for D 3 4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 6 This software is provided 'as-is', without any express or implied warranty. 7 In no event will the authors be held liable for any damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, including commercial applications, 10 and to alter it and redistribute it freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 14 15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 16 17 3. This notice may not be removed or altered from any source distribution 18 */ 19 20 module dsfml.graphics.shader; 21 22 import dsfml.graphics.texture; 23 import dsfml.graphics.transform; 24 import dsfml.graphics.color; 25 26 import dsfml.system.inputstream; 27 import dsfml.system.vector2; 28 import dsfml.system.vector3; 29 import dsfml.system.err; 30 31 32 /++ 33 + Shader class (vertex and fragment). 34 + 35 + Shaders are programs written using a specific language, executed directly by the graphics card and allowing one to apply real-time operations to the rendered entities. 36 + 37 + There are two kinds of shaders: 38 + - Vertex shaders, that process vertices 39 + - Fragment (pixel) shaders, that process pixels 40 + 41 + A DSFML Shader can be composed of either a vertex shader alone, a fragment shader alone, or both combined (see the variants of the load functions). 42 + 43 + Shaders are written in GLSL, which is a C-like language dedicated to OpenGL shaders. You'll probably need to learn its basics before writing your own shaders for SFML. 44 + 45 + Like any D/C/C++ program, a shader has its own variables that you can set from your D application. DSFML's Shader handles 5 different types of variables: 46 + - floats 47 + - vectors (2, 3, or 4 components) 48 + - colors 49 + - textures 50 + - transforms (matrices) 51 + 52 + Authors: Laurent Gomila, Jeremy DeHaan 53 + See_Also: http://www.sfml-dev.org/documentation/2.0/classsf_1_1Shader.php#details 54 +/ 55 class Shader 56 { 57 /// Types of shaders. 58 enum Type 59 { 60 Vertex, /// Vertex shader 61 Fragment /// Fragment (pixel) shader. 62 } 63 64 package sfShader* sfPtr; 65 66 /// Special type/value that can be passed to setParameter, and that represents the texture of the object being drawn. 67 struct CurrentTextureType {}; 68 static CurrentTextureType CurrentTexture; 69 70 71 this() 72 { 73 //creates an empty shader 74 sfPtr=sfShader_construct(); 75 } 76 77 package this(sfShader* shader) 78 { 79 sfPtr = shader; 80 } 81 82 ~this() 83 { 84 import dsfml.system.config; 85 mixin(destructorOutput); 86 sfShader_destroy(sfPtr); 87 } 88 89 /** 90 * Load either the vertex or fragment shader from a file. 91 * 92 * This function loads a single shader, either vertex or fragment, identified by the second argument. The source must be a text file containing a valid shader in GLSL language. GLSL is a C-like language dedicated to OpenGL shaders; you'll probably need to read a good documentation for it before writing your own shaders. 93 * 94 * Params: 95 * filename = Path of the vertex or fragment shader file to load 96 * type = Type of shader (vertex or fragment) 97 * 98 * Returns: True if loading succeeded, false if it failed. 99 */ 100 bool loadFromFile(string filename, Type type) 101 { 102 import dsfml.system..string; 103 104 bool ret; 105 106 if(type == Type.Vertex) 107 { 108 ret = sfShader_loadFromFile(sfPtr, toStringz(filename) , null); 109 } 110 else 111 { 112 ret = sfShader_loadFromFile(sfPtr, null , toStringz(filename) ); 113 } 114 115 if(!ret) 116 { 117 err.write(dsfml.system..string.toString(sfErr_getOutput())); 118 } 119 120 return ret; 121 } 122 123 /** 124 * Load both the vertex and fragment shaders from files. 125 * 126 * This function loads both the vertex and the fragment shaders. If one of them fails to load, the shader is left empty (the valid shader is unloaded). The sources must be text files containing valid shaders in GLSL language. GLSL is a C-like language dedicated to OpenGL shaders; you'll probably need to read a good documentation for it before writing your own shaders. 127 * 128 * Params: 129 * vertexShaderFilename = Path of the vertex shader file to load 130 * fragmentShaderFilename = Path of the fragment shader file to load 131 * 132 * Returns: True if loading succeeded, false if it failed. 133 */ 134 bool loadFromFile(string vertexShaderFilename, string fragmentShaderFilename) 135 { 136 import dsfml.system..string; 137 138 bool ret = sfShader_loadFromFile(sfPtr, toStringz(vertexShaderFilename) , toStringz(fragmentShaderFilename)); 139 if(!ret) 140 { 141 err.write(dsfml.system..string.toString(sfErr_getOutput())); 142 } 143 144 return ret; 145 } 146 147 /** 148 * Load either the vertex or fragment shader from a source code in memory. 149 * 150 * This function loads a single shader, either vertex or fragment, identified by the second argument. The source code must be a valid shader in GLSL language. GLSL is a C-like language dedicated to OpenGL shaders; you'll probably need to read a good documentation for it before writing your own shaders. 151 * 152 * Params: 153 * shader = String containing the source code of the shader 154 * type = Type of shader (vertex or fragment) 155 * 156 * Returns: True if loading succeeded, false if it failed. 157 */ 158 bool loadFromMemory(string shader, Type type) 159 { 160 import dsfml.system..string; 161 162 bool ret; 163 164 if(type == Type.Vertex) 165 { 166 ret = sfShader_loadFromMemory(sfPtr, toStringz(shader) , null); 167 } 168 else 169 { 170 ret = sfShader_loadFromMemory(sfPtr, null , toStringz(shader) ); 171 } 172 if(!ret) 173 { 174 err.write(dsfml.system..string.toString(sfErr_getOutput())); 175 } 176 return ret; 177 } 178 179 /** 180 * Load both the vertex and fragment shaders from source codes in memory. 181 * 182 * This function loads both the vertex and the fragment shaders. If one of them fails to load, the shader is left empty (the valid shader is unloaded). The sources must be valid shaders in GLSL language. GLSL is a C-like language dedicated to OpenGL shaders; you'll probably need to read a good documentation for it before writing your own shaders. 183 * 184 * Params: 185 * vertexShader = String containing the source code of the vertex shader 186 * fragmentShader = String containing the source code of the fragment shader 187 * 188 * Returns: True if loading succeeded, false if it failed. 189 */ 190 bool loadFromMemory(string vertexShader, string fragmentShader) 191 { 192 import dsfml.system..string; 193 194 bool ret = sfShader_loadFromMemory(sfPtr, toStringz(vertexShader) , toStringz(fragmentShader)); 195 if(!ret) 196 { 197 err.write(dsfml.system..string.toString(sfErr_getOutput())); 198 } 199 200 return ret; 201 } 202 203 /** 204 * Load either the vertex or fragment shader from a custom stream. 205 * 206 * This function loads a single shader, either vertex or fragment, identified by the second argument. The source code must be a valid shader in GLSL language. GLSL is a C-like language dedicated to OpenGL shaders; you'll probably need to read a good documentation for it before writing your own shaders. 207 * 208 * Params: 209 * stream = Source stream to read from 210 * type = Type of shader (vertex or fragment) 211 * 212 * Returns: True if loading succeeded, false if it failed. 213 */ 214 bool loadFromStream(InputStream stream, Type type) 215 { 216 import dsfml.system..string; 217 218 bool ret; 219 220 if(type == Type.Vertex) 221 { 222 ret = sfShader_loadFromStream(sfPtr, new shaderStream(stream) , null); 223 } 224 else 225 { 226 ret = sfShader_loadFromStream(sfPtr, null , new shaderStream(stream)); 227 } 228 if(!ret) 229 { 230 err.write(dsfml.system..string.toString(sfErr_getOutput())); 231 } 232 233 return ret; 234 } 235 236 /** 237 * Load both the vertex and fragment shaders from custom streams. 238 * 239 * This function loads a single shader, either vertex or fragment, identified by the second argument. The source code must be a valid shader in GLSL language. GLSL is a C-like language dedicated to OpenGL shaders; you'll probably need to read a good documentation for it before writing your own shaders. 240 * 241 * Params: 242 * vertexShaderStream = Source stream to read the vertex shader from 243 * fragmentShaderStream = Source stream to read the fragment shader from 244 * 245 * Returns: True if loading succeeded, false if it failed. 246 */ 247 bool loadFromStream(InputStream vertexShaderStream, InputStream fragmentShaderStream) 248 { 249 import dsfml.system..string; 250 251 bool ret = sfShader_loadFromStream(sfPtr, new shaderStream(vertexShaderStream), new shaderStream(fragmentShaderStream)); 252 if(!ret) 253 { 254 err.write(dsfml.system..string.toString(sfErr_getOutput())); 255 } 256 return ret; 257 } 258 259 /** 260 * Change a float parameter of the shader. 261 * 262 * Params: 263 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a float (float GLSL type). 264 * x = Value to assign 265 */ 266 void setParameter(string name, float x) 267 { 268 import dsfml.system..string; 269 sfShader_setFloatParameter(sfPtr, toStringz(name), x); 270 } 271 272 ///ditto 273 void opIndexAssign(float x, string name) 274 { 275 import dsfml.system..string; 276 sfShader_setFloatParameter(sfPtr, toStringz(name), x); 277 } 278 279 /** 280 * Change a 2-components vector parameter of the shader. 281 * 282 * Params: 283 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 2x1 vector (vec2 GLSL type). 284 * x = First component of the value to assign 285 * y = Second component of the value to assign 286 */ 287 void setParameter(string name, float x, float y) 288 { 289 import dsfml.system..string; 290 sfShader_setFloat2Parameter(sfPtr, toStringz(name), x, y); 291 } 292 293 /** 294 * Change a 3-components vector parameter of the shader. 295 * 296 * Params: 297 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 3x1 vector (vec3 GLSL type). 298 * x = First component of the value to assign 299 * y = Second component of the value to assign 300 * z = Third component of the value to assign 301 */ 302 void setParameter(string name, float x, float y, float z) 303 { 304 import dsfml.system..string; 305 sfShader_setFloat3Parameter(sfPtr, toStringz(name), x,y,z); 306 } 307 308 /** 309 * Change a 4-components vector parameter of the shader. 310 * 311 * Params: 312 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 4x1 vector (vec4 GLSL type). 313 * x = First component of the value to assign 314 * y = Second component of the value to assign 315 * z = Third component of the value to assign 316 * w = Fourth component of the value to assign 317 */ 318 void setParameter(string name, float x, float y, float z, float w) 319 { 320 import dsfml.system..string; 321 sfShader_setFloat4Parameter(sfPtr, toStringz(name), x, y, z, w); 322 } 323 324 /** 325 * Change variable length vector parameter of the shader. The length of the set of floats must be between 1 and 4. 326 * 327 * Params: 328 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 4x1 vector (vec4 GLSL type). 329 * val = The set of floats to assign. 330 */ 331 void opIndexAssign(float[] val, string name) 332 { 333 import dsfml.system..string; 334 //assert to make sure that val is of proper length at run time 335 assert((val.length >0) && (val.length <= 4)); 336 337 if(val.length == 1) 338 sfShader_setFloatParameter(sfPtr, toStringz(name), val[0]); 339 else if(val.length == 2) 340 sfShader_setFloat2Parameter(sfPtr, toStringz(name), val[0], val[1]); 341 else if(val.length == 3) 342 sfShader_setFloat3Parameter(sfPtr, toStringz(name), val[0], val[1], val[2]); 343 else if(val.length >= 4) 344 sfShader_setFloat4Parameter(sfPtr, toStringz(name), val[0], val[1], val[2], val[3]); 345 } 346 347 /** 348 * Change a 2-components vector parameter of the shader. 349 * 350 * Params: 351 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 2x1 vector (vec2 GLSL type). 352 * vector = Vector to assign 353 */ 354 void setParameter(string name, Vector2f vector) 355 { 356 import dsfml.system..string; 357 sfShader_setFloat2Parameter(sfPtr, toStringz(name), vector.x, vector.y); 358 } 359 360 ///ditto 361 void opIndexAssign(Vector2f vector, string name) 362 { 363 import dsfml.system..string; 364 sfShader_setFloat2Parameter(sfPtr, toStringz(name), vector.x, vector.y); 365 } 366 367 /** 368 * Change a 3-components vector parameter of the shader. 369 * 370 * Params: 371 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 3x1 vector (vec3 GLSL type). 372 * vector = Vector to assign 373 */ 374 void setParameter(string name, Vector3f vector) 375 { 376 import dsfml.system..string; 377 sfShader_setFloat3Parameter(sfPtr, toStringz(name), vector.x, vector.y, vector.z); 378 } 379 ///ditto 380 void opIndexAssign(Vector3f vector, string name) 381 { 382 import dsfml.system..string; 383 sfShader_setFloat3Parameter(sfPtr, toStringz(name), vector.x, vector.y, vector.z); 384 } 385 386 /** 387 * Change a color vector parameter of the shader. 388 * 389 * It is important to note that the components of the color are normalized before being passed to the shader. Therefore, they are converted from range [0 .. 255] to range [0 .. 1]. For example, a Color(255, 125, 0, 255) will be transformed to a vec4(1.0, 0.5, 0.0, 1.0) in the shader. 390 * 391 * Params: 392 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 4x1 vector (vec4 GLSL type). 393 * color = Color to assign 394 */ 395 void setParameter(string name, Color color) 396 { 397 import dsfml.system..string; 398 sfShader_setColorParameter(sfPtr, toStringz(name), color.r, color.g, color.b, color.a); 399 } 400 ///ditto 401 void opIndexAssign(Color color, string name) 402 { 403 import dsfml.system..string; 404 sfShader_setColorParameter(sfPtr, toStringz(name), color.r, color.g, color.b, color.a); 405 } 406 407 /** 408 * Change a matrix parameter of the shader. 409 * 410 * Params: 411 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 4x4 matrix (mat4 GLSL type). 412 * transform = Transform to assign 413 */ 414 void setParameter(string name, Transform transform) 415 { 416 import dsfml.system..string; 417 sfShader_setTransformParameter(sfPtr, toStringz(name), transform.m_matrix.ptr); 418 } 419 ///ditto 420 void opIndexAssign(Transform transform, string name) 421 { 422 import dsfml.system..string; 423 sfShader_setTransformParameter(sfPtr, toStringz(name), transform.m_matrix.ptr); 424 } 425 426 /** 427 * Change a texture parameter of the shader. 428 * 429 * It is important to note that the texture parameter must remain alive as long as the shader uses it - no copoy is made internally. 430 * 431 * To use the texture of the object being draw, which cannot be known in advance, you can pass the special value Shader.CurrentTexture. 432 * 433 * Params: 434 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 2D texture (sampler2D GLSL type). 435 * texture = Texture to assign 436 */ 437 void setParameter(string name, const(Texture) texture) 438 { 439 import dsfml.system..string; 440 sfShader_setTextureParameter(sfPtr, toStringz(name), texture.sfPtr); 441 err.write(dsfml.system..string.toString(sfErr_getOutput())); 442 } 443 ///ditto 444 void opIndexAssign(const(Texture) texture, string name) 445 { 446 import dsfml.system..string; 447 sfShader_setTextureParameter(sfPtr, toStringz(name), texture.sfPtr); 448 err.write(dsfml.system..string.toString(sfErr_getOutput())); 449 } 450 451 452 /** 453 * Change a texture parameter of the shader. 454 * 455 * This overload maps a shader texture variable to the texture of the object being drawn, which cannot be known in advance. The second argument must be Shader.CurrentTexture. 456 * 457 * Params: 458 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 2D texture (sampler2D GLSL type). 459 */ 460 void setParameter(string name, CurrentTextureType) 461 { 462 import dsfml.system..string; 463 sfShader_setCurrentTextureParameter(sfPtr, toStringz(name)); 464 } 465 466 /** 467 * Change a texture parameter of the shader. 468 * 469 * This overload maps a shader texture variable to the texture of the object being drawn, which cannot be known in advance. The value given must be Shader.CurrentTexture. 470 * 471 * Params: 472 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a 2D texture (sampler2D GLSL type). 473 */ 474 void opIndexAssign(CurrentTextureType, string name) 475 { 476 import dsfml.system..string; 477 sfShader_setCurrentTextureParameter(sfPtr, toStringz(name)); 478 } 479 480 /** 481 * Bind a shader for rendering. 482 * 483 * This function is not part of the graphics API, it mustn't be used when drawing SFML entities. It must be used only if you mix Shader with OpenGL code. 484 * 485 * Params: 486 * shader = Shader to bind. Can be null to use no shader. 487 */ 488 static void bind(Shader shader) 489 { 490 (shader is null)?sfShader_bind(null):sfShader_bind(shader.sfPtr); 491 } 492 493 /** 494 * Tell whether or not the system supports shaders. 495 * 496 * This function should always be called before using the shader features. If it returns false, then any attempt to use DSFML Shader will fail. 497 * 498 * Returns: True if shaders are supported, false otherwise 499 */ 500 static bool isAvailable() 501 { 502 import dsfml.system..string; 503 bool toReturn = sfShader_isAvailable(); 504 err.write(dsfml.system..string.toString(sfErr_getOutput())); 505 return toReturn; 506 } 507 } 508 509 unittest 510 { 511 //find some examples of interesting shaders and use them here 512 } 513 514 private extern(C++) interface shaderInputStream 515 { 516 long read(void* data, long size); 517 518 long seek(long position); 519 520 long tell(); 521 522 long getSize(); 523 } 524 525 526 private class shaderStream:shaderInputStream 527 { 528 private InputStream myStream; 529 530 this(InputStream stream) 531 { 532 myStream = stream; 533 } 534 535 extern(C++)long read(void* data, long size) 536 { 537 return myStream.read(data[0..cast(size_t)size]); 538 } 539 540 extern(C++)long seek(long position) 541 { 542 return myStream.seek(position); 543 } 544 545 extern(C++)long tell() 546 { 547 return myStream.tell(); 548 } 549 550 extern(C++)long getSize() 551 { 552 return myStream.getSize(); 553 } 554 } 555 556 package extern(C): 557 struct sfShader; 558 559 private extern(C): 560 561 //Construct a new shader 562 sfShader* sfShader_construct(); 563 564 //Load both the vertex and fragment shaders from files 565 bool sfShader_loadFromFile(sfShader* shader, const(char)* vertexShaderFilename, const char* fragmentShaderFilename); 566 567 //Load both the vertex and fragment shaders from source codes in memory 568 bool sfShader_loadFromMemory(sfShader* shader, const(char)* vertexShader, const char* fragmentShader); 569 570 //Load both the vertex and fragment shaders from custom streams 571 bool sfShader_loadFromStream(sfShader* shader, shaderInputStream vertexShaderStream, shaderInputStream fragmentShaderStream); 572 573 //Destroy an existing shader 574 void sfShader_destroy(sfShader* shader); 575 576 //Change a float parameter of a shader 577 void sfShader_setFloatParameter(sfShader* shader, const char* name, float x); 578 579 //Change a 2-components vector parameter of a shader 580 void sfShader_setFloat2Parameter(sfShader* shader, const char* name, float x, float y); 581 582 //Change a 3-components vector parameter of a shader 583 void sfShader_setFloat3Parameter(sfShader* shader, const char* name, float x, float y, float z); 584 585 //Change a 4-components vector parameter of a shader 586 void sfShader_setFloat4Parameter(sfShader* shader, const char* name, float x, float y, float z, float w); 587 588 //Change a color parameter of a shader 589 void sfShader_setColorParameter(sfShader* shader, const char* name, ubyte r, ubyte g, ubyte b, ubyte a); 590 591 //Change a matrix parameter of a shader 592 void sfShader_setTransformParameter(sfShader* shader, const char* name, float* transform); 593 594 //Change a texture parameter of a shader 595 void sfShader_setTextureParameter(sfShader* shader, const char* name, const sfTexture* texture); 596 597 //Change a texture parameter of a shader 598 void sfShader_setCurrentTextureParameter(sfShader* shader, const char* name); 599 600 //Bind a shader for rendering (activate it) 601 void sfShader_bind(const sfShader* shader); 602 603 //Tell whether or not the system supports shaders 604 bool sfShader_isAvailable(); 605 606 const(char)* sfErr_getOutput();