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 } 75 76 package this(sfShader* shader) 77 { 78 sfPtr = shader; 79 } 80 81 ~this() 82 { 83 import dsfml.system.config; 84 mixin(destructorOutput); 85 sfShader_destroy(sfPtr); 86 } 87 88 /** 89 * Load either the vertex or fragment shader from a file. 90 * 91 * 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. 92 * 93 * Params: 94 * filename = Path of the vertex or fragment shader file to load 95 * type = Type of shader (vertex or fragment) 96 * 97 * Returns: True if loading succeeded, false if it failed. 98 */ 99 bool loadFromFile(string filename, Type type) 100 { 101 import dsfml.system..string; 102 103 bool ret; 104 105 if(type == Type.Vertex) 106 { 107 ret = sfShader_loadFromFile(sfPtr, toStringz(filename) , null); 108 } 109 else 110 { 111 ret = sfShader_loadFromFile(sfPtr, null , toStringz(filename) ); 112 } 113 114 if(!ret) 115 { 116 err.write(toString(sfErr_getOutput())); 117 } 118 119 return ret; 120 } 121 122 /** 123 * Load both the vertex and fragment shaders from files. 124 * 125 * 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. 126 * 127 * Params: 128 * vertexShaderFilename = Path of the vertex shader file to load 129 * fragmentShaderFilename = Path of the fragment shader file to load 130 * 131 * Returns: True if loading succeeded, false if it failed. 132 */ 133 bool loadFromFile(string vertexShaderFilename, string fragmentShaderFilename) 134 { 135 import dsfml.system..string; 136 137 bool ret = sfShader_loadFromFile(sfPtr, toStringz(vertexShaderFilename) , toStringz(fragmentShaderFilename)); 138 if(!ret) 139 { 140 err.write(toString(sfErr_getOutput())); 141 } 142 143 return ret; 144 } 145 146 /** 147 * Load either the vertex or fragment shader from a source code in memory. 148 * 149 * 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. 150 * 151 * Params: 152 * shader = String containing the source code of the shader 153 * type = Type of shader (vertex or fragment) 154 * 155 * Returns: True if loading succeeded, false if it failed. 156 */ 157 bool loadFromMemory(string shader, Type type) 158 { 159 import dsfml.system..string; 160 161 bool ret; 162 163 if(type == Type.Vertex) 164 { 165 ret = sfShader_loadFromMemory(sfPtr, toStringz(shader) , null); 166 } 167 else 168 { 169 ret = sfShader_loadFromMemory(sfPtr, null , toStringz(shader) ); 170 } 171 if(!ret) 172 { 173 err.write(toString(sfErr_getOutput())); 174 } 175 return ret; 176 } 177 178 /** 179 * Load both the vertex and fragment shaders from source codes in memory. 180 * 181 * 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. 182 * 183 * Params: 184 * vertexShader = String containing the source code of the vertex shader 185 * fragmentShader = String containing the source code of the fragment shader 186 * 187 * Returns: True if loading succeeded, false if it failed. 188 */ 189 bool loadFromMemory(string vertexShader, string fragmentShader) 190 { 191 import dsfml.system..string; 192 193 bool ret = sfShader_loadFromMemory(sfPtr, toStringz(vertexShader) , toStringz(fragmentShader)); 194 if(!ret) 195 { 196 err.write(toString(sfErr_getOutput())); 197 } 198 199 return ret; 200 } 201 202 /** 203 * Load either the vertex or fragment shader from a custom stream. 204 * 205 * 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. 206 * 207 * Params: 208 * stream = Source stream to read from 209 * type = Type of shader (vertex or fragment) 210 * 211 * Returns: True if loading succeeded, false if it failed. 212 */ 213 bool loadFromStream(InputStream stream, Type type) 214 { 215 import dsfml.system..string; 216 217 bool ret; 218 219 if(type == Type.Vertex) 220 { 221 ret = sfShader_loadFromStream(sfPtr, new shaderStream(stream) , null); 222 } 223 else 224 { 225 ret = sfShader_loadFromStream(sfPtr, null , new shaderStream(stream)); 226 } 227 if(!ret) 228 { 229 err.write(toString(sfErr_getOutput())); 230 } 231 232 return ret; 233 } 234 235 /** 236 * Load both the vertex and fragment shaders from custom streams. 237 * 238 * 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. 239 * 240 * Params: 241 * vertexShaderStream = Source stream to read the vertex shader from 242 * fragmentShaderStream = Source stream to read the fragment shader from 243 * 244 * Returns: True if loading succeeded, false if it failed. 245 */ 246 bool loadFromStream(InputStream vertexShaderStream, InputStream fragmentShaderStream) 247 { 248 import dsfml.system..string; 249 250 bool ret = sfShader_loadFromStream(sfPtr, new shaderStream(vertexShaderStream), new shaderStream(fragmentShaderStream)); 251 if(!ret) 252 { 253 err.write(toString(sfErr_getOutput())); 254 } 255 return ret; 256 } 257 258 /** 259 * Change a float parameter of the shader. 260 * 261 * Params: 262 * name = The name of the variable to change in the shader. The corresponding parameter in the shader must be a float (float GLSL type). 263 * x = Value to assign 264 */ 265 void setParameter(string name, float x) 266 { 267 import dsfml.system..string; 268 sfShader_setFloatParameter(sfPtr, toStringz(name), x); 269 } 270 271 ///ditto 272 void opIndexAssign(float x, string name) 273 { 274 import dsfml.system..string; 275 sfShader_setFloatParameter(sfPtr, toStringz(name), x); 276 } 277 278 /** 279 * Change a 2-components vector parameter of the shader. 280 * 281 * Params: 282 * 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). 283 * x = First component of the value to assign 284 * y = Second component of the value to assign 285 */ 286 void setParameter(string name, float x, float y) 287 { 288 import dsfml.system..string; 289 sfShader_setFloat2Parameter(sfPtr, toStringz(name), x, y); 290 } 291 292 /** 293 * Change a 3-components vector parameter of the shader. 294 * 295 * Params: 296 * 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). 297 * x = First component of the value to assign 298 * y = Second component of the value to assign 299 * z = Third component of the value to assign 300 */ 301 void setParameter(string name, float x, float y, float z) 302 { 303 import dsfml.system..string; 304 sfShader_setFloat3Parameter(sfPtr, toStringz(name), x,y,z); 305 } 306 307 /** 308 * Change a 4-components vector parameter of the shader. 309 * 310 * Params: 311 * 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). 312 * x = First component of the value to assign 313 * y = Second component of the value to assign 314 * z = Third component of the value to assign 315 * w = Fourth component of the value to assign 316 */ 317 void setParameter(string name, float x, float y, float z, float w) 318 { 319 import dsfml.system..string; 320 sfShader_setFloat4Parameter(sfPtr, toStringz(name), x, y, z, w); 321 } 322 323 /** 324 * Change variable length vector parameter of the shader. The length of the set of floats must be between 1 and 4. 325 * 326 * Params: 327 * 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). 328 * val = The set of floats to assign. 329 */ 330 void opIndexAssign(float[] val, string name) 331 { 332 import dsfml.system..string; 333 //assert to make sure that val is of proper length at run time 334 assert((val.length >0) && (val.length <= 4)); 335 336 if(val.length == 1) 337 sfShader_setFloatParameter(sfPtr, toStringz(name), val[0]); 338 else if(val.length == 2) 339 sfShader_setFloat2Parameter(sfPtr, toStringz(name), val[0], val[1]); 340 else if(val.length == 3) 341 sfShader_setFloat3Parameter(sfPtr, toStringz(name), val[0], val[1], val[2]); 342 else if(val.length >= 4) 343 sfShader_setFloat4Parameter(sfPtr, toStringz(name), val[0], val[1], val[2], val[3]); 344 } 345 346 /** 347 * Change a 2-components vector parameter of the shader. 348 * 349 * Params: 350 * 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). 351 * vector = Vector to assign 352 */ 353 void setParameter(string name, Vector2f vector) 354 { 355 import dsfml.system..string; 356 sfShader_setFloat2Parameter(sfPtr, toStringz(name), vector.x, vector.y); 357 } 358 359 ///ditto 360 void opIndexAssign(Vector2f vector, string name) 361 { 362 import dsfml.system..string; 363 sfShader_setFloat2Parameter(sfPtr, toStringz(name), vector.x, vector.y); 364 } 365 366 /** 367 * Change a 3-components vector parameter of the shader. 368 * 369 * Params: 370 * 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). 371 * vector = Vector to assign 372 */ 373 void setParameter(string name, Vector3f vector) 374 { 375 import dsfml.system..string; 376 sfShader_setFloat3Parameter(sfPtr, toStringz(name), vector.x, vector.y, vector.z); 377 } 378 ///ditto 379 void opIndexAssign(Vector3f vector, string name) 380 { 381 import dsfml.system..string; 382 sfShader_setFloat3Parameter(sfPtr, toStringz(name), vector.x, vector.y, vector.z); 383 } 384 385 /** 386 * Change a color vector parameter of the shader. 387 * 388 * 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. 389 * 390 * Params: 391 * 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). 392 * color = Color to assign 393 */ 394 void setParameter(string name, Color color) 395 { 396 import dsfml.system..string; 397 sfShader_setColorParameter(sfPtr, toStringz(name), color.r, color.g, color.b, color.a); 398 } 399 ///ditto 400 void opIndexAssign(Color color, string name) 401 { 402 import dsfml.system..string; 403 sfShader_setColorParameter(sfPtr, toStringz(name), color.r, color.g, color.b, color.a); 404 } 405 406 /** 407 * Change a matrix parameter of the shader. 408 * 409 * Params: 410 * 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). 411 * transform = Transform to assign 412 */ 413 void setParameter(string name, Transform transform) 414 { 415 import dsfml.system..string; 416 sfShader_setTransformParameter(sfPtr, toStringz(name), transform.m_matrix.ptr); 417 } 418 ///ditto 419 void opIndexAssign(Transform transform, string name) 420 { 421 import dsfml.system..string; 422 sfShader_setTransformParameter(sfPtr, toStringz(name), transform.m_matrix.ptr); 423 } 424 425 /** 426 * Change a texture parameter of the shader. 427 * 428 * It is important to note that the texture parameter must remain alive as long as the shader uses it - no copoy is made internally. 429 * 430 * To use the texture of the object being draw, which cannot be known in advance, you can pass the special value Shader.CurrentTexture. 431 * 432 * Params: 433 * 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). 434 * texture = Texture to assign 435 */ 436 void setParameter(string name, const(Texture) texture) 437 { 438 import dsfml.system..string; 439 sfShader_setTextureParameter(sfPtr, toStringz(name), texture.sfPtr); 440 err.write(toString(sfErr_getOutput())); 441 } 442 ///ditto 443 void opIndexAssign(const(Texture) texture, string name) 444 { 445 import dsfml.system..string; 446 sfShader_setTextureParameter(sfPtr, toStringz(name), texture.sfPtr); 447 err.write(toString(sfErr_getOutput())); 448 } 449 450 451 /** 452 * Change a texture parameter of the shader. 453 * 454 * 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. 455 * 456 * Params: 457 * 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). 458 */ 459 void setParameter(string name, CurrentTextureType) 460 { 461 import dsfml.system..string; 462 sfShader_setCurrentTextureParameter(sfPtr, toStringz(name)); 463 } 464 465 /** 466 * Change a texture parameter of the shader. 467 * 468 * 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. 469 * 470 * Params: 471 * 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). 472 */ 473 void opIndexAssign(CurrentTextureType, string name) 474 { 475 import dsfml.system..string; 476 sfShader_setCurrentTextureParameter(sfPtr, toStringz(name)); 477 } 478 479 /** 480 * Bind a shader for rendering. 481 * 482 * 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. 483 * 484 * Params: 485 * shader = Shader to bind. Can be null to use no shader. 486 */ 487 static void bind(Shader shader) 488 { 489 (shader is null)?sfShader_bind(null):sfShader_bind(shader.sfPtr); 490 } 491 492 /** 493 * Tell whether or not the system supports shaders. 494 * 495 * This function should always be called before using the shader features. If it returns false, then any attempt to use DSFML Shader will fail. 496 * 497 * Returns: True if shaders are supported, false otherwise 498 */ 499 static bool isAvailable() 500 { 501 import dsfml.system..string; 502 bool toReturn = sfShader_isAvailable(); 503 err.write(toString(sfErr_getOutput())); 504 return toReturn; 505 } 506 } 507 508 unittest 509 { 510 //find some examples of interesting shaders and use them here 511 } 512 513 private extern(C++) interface sfmlInputStream 514 { 515 long read(void* data, long size); 516 517 long seek(long position); 518 519 long tell(); 520 521 long getSize(); 522 } 523 524 525 private class shaderStream:sfmlInputStream 526 { 527 private InputStream myStream; 528 529 this(InputStream stream) 530 { 531 myStream = stream; 532 } 533 534 extern(C++)long read(void* data, long size) 535 { 536 return myStream.read(data[0..cast(size_t)size]); 537 } 538 539 extern(C++)long seek(long position) 540 { 541 return myStream.seek(position); 542 } 543 544 extern(C++)long tell() 545 { 546 return myStream.tell(); 547 } 548 549 extern(C++)long getSize() 550 { 551 return myStream.getSize(); 552 } 553 } 554 555 package extern(C): 556 struct sfShader; 557 558 private extern(C): 559 560 //Construct a new shader 561 sfShader* sfShader_construct(); 562 563 //Load both the vertex and fragment shaders from files 564 bool sfShader_loadFromFile(sfShader* shader, const(char)* vertexShaderFilename, const char* fragmentShaderFilename); 565 566 //Load both the vertex and fragment shaders from source codes in memory 567 bool sfShader_loadFromMemory(sfShader* shader, const(char)* vertexShader, const char* fragmentShader); 568 569 //Load both the vertex and fragment shaders from custom streams 570 bool sfShader_loadFromStream(sfShader* shader, sfmlInputStream vertexShaderStream, sfmlInputStream fragmentShaderStream); 571 572 //Destroy an existing shader 573 void sfShader_destroy(sfShader* shader); 574 575 //Change a float parameter of a shader 576 void sfShader_setFloatParameter(sfShader* shader, const char* name, float x); 577 578 //Change a 2-components vector parameter of a shader 579 void sfShader_setFloat2Parameter(sfShader* shader, const char* name, float x, float y); 580 581 //Change a 3-components vector parameter of a shader 582 void sfShader_setFloat3Parameter(sfShader* shader, const char* name, float x, float y, float z); 583 584 //Change a 4-components vector parameter of a shader 585 void sfShader_setFloat4Parameter(sfShader* shader, const char* name, float x, float y, float z, float w); 586 587 //Change a color parameter of a shader 588 void sfShader_setColorParameter(sfShader* shader, const char* name, ubyte r, ubyte g, ubyte b, ubyte a); 589 590 //Change a matrix parameter of a shader 591 void sfShader_setTransformParameter(sfShader* shader, const char* name, float* transform); 592 593 //Change a texture parameter of a shader 594 void sfShader_setTextureParameter(sfShader* shader, const char* name, const sfTexture* texture); 595 596 //Change a texture parameter of a shader 597 void sfShader_setCurrentTextureParameter(sfShader* shader, const char* name); 598 599 //Bind a shader for rendering (activate it) 600 void sfShader_bind(const sfShader* shader); 601 602 //Tell whether or not the system supports shaders 603 bool sfShader_isAvailable(); 604 605 const(char)* sfErr_getOutput();