Changeset 174
- Timestamp:
- 02/07/10 21:47:44 (2 years ago)
- Files:
-
- trunk/res/shader/diffuse-hdr.frag (modified) (1 diff)
- trunk/src/yage/resource/layer.d (modified) (2 diffs)
- trunk/src/yage/resource/material.d (modified) (2 diffs)
- trunk/src/yage/resource/shader.d (modified) (3 diffs)
- trunk/src/yage/system/graphics/api/opengl.d (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/res/shader/diffuse-hdr.frag
r28 r174 4 4 * 5 5 * Same as diffuse.frag except with max_brightness to allow materials to be 6 * brighter than 100 %. This probably requires floating point textures and a6 * brighter than 100 percent. This probably requires floating point textures and a 7 7 * few other tricks to be true HDR. 8 8 */ trunk/src/yage/resource/layer.d
r173 r174 9 9 import tango.math.Math; 10 10 import tango.io.Stdout; 11 import std.string;12 import std.stdio;13 11 14 import derelict.opengl.gl;15 import derelict.opengl.glext;16 12 import yage.core.all; 17 13 import yage.system.system; … … 121 117 } 122 118 123 124 /// Set a the value of a uniform variable (or array of uniform variables) in this Layer's Shader program.125 void setUniform(char[] name, float[] values ...)126 { setUniform(name, 1, values);127 }128 /// Ditto129 void setUniform(char[] name, Vec2f[] values ...)130 { setUniform(name, 2, cast(float[])values);131 }132 /// Ditto133 void setUniform(char[] name, Vec3f[] values ...)134 { setUniform(name, 3, cast(float[])values);135 }136 /// Ditto137 void setUniform(char[] name, Vec4f[] values ...)138 { setUniform(name, 4, cast(float[])values);139 }140 /// Ditto141 void setUniform(char[] name, Matrix[] values ...)142 { setUniform(name, 14, cast(float[])values);143 }144 145 /// Return a string of xml for this layer.146 char[] toString()147 { char[] result;148 result = "<layer" ~149 " ambient=\"" ~ ambient.hex ~ "\"" ~150 " diffuse=\"" ~ diffuse.hex ~ "\"" ~151 " specular=\"" ~ specular.hex ~ "\"" ~152 " emissive=\"" ~ emissive.hex ~ "\"" ~153 " specularity=\"" ~ .toString(specularity) ~ "\"" ~154 // " blend=\"" ~ .toString(blend) ~ "\"" ~155 // " cull=\"" ~ .toString(cull) ~ "\"" ~156 " draw=\"" ~ .toString(draw) ~ "\"" ~157 " width=\"" ~ .toString(width) ~ "\"" ~158 ">\n";159 160 //foreach (TextureInstance t; textures)161 // result~= t.toString();162 result~= "</layer>";163 return result;164 }165 166 // Helper function for the public setUniform() functions.167 protected void setUniform(char[] name, int width, float[] values)168 { if (!Probe.feature(Probe.Feature.SHADER))169 throw new ResourceException("Layer.setUniform() is only supported on hardware that supports shaders.");170 171 // Get the location of name172 if (program == 0)173 throw new ResourceException("Cannot set uniform variable for a layer with no shader program.");174 char[256] cname = 0;175 cname[0..name.length] = name;176 int location = glGetUniformLocationARB(program, cname.ptr);177 if (location == -1)178 throw new ResourceException("Unable to set uniform variable: " ~ name);179 180 // Send the uniform data181 switch (width)182 { case 1: glUniform1fvARB(location, values.length, values.ptr); break;183 case 2: glUniform2fvARB(location, values.length, values.ptr); break;184 case 3: glUniform3fvARB(location, values.length, values.ptr); break;185 case 4: glUniform4fvARB(location, values.length, values.ptr); break;186 case 16: glUniformMatrix4fvARB(location, values.length, false, values.ptr); break;187 default: break;188 }189 }190 119 } trunk/src/yage/resource/material.d
r173 r174 14 14 import std.stream; 15 15 import std.string; 16 import std.stdio;17 16 import yage.core.all; 18 17 import yage.core.object2; … … 259 258 } 260 259 261 /// Return a string of xml for this material along with all layers.262 char[] toString()263 { char[] result;264 result = Format.convert("<material maxlights={}>\n", max_lights);265 // Loop through layers266 foreach (Layer layer; layers)267 result ~= layer.toString();268 result~= "</material>\n";269 return result;270 }271 260 } 272 261 trunk/src/yage/resource/shader.d
r173 r174 7 7 module yage.resource.shader; 8 8 9 import std.file;10 import std.string;11 import derelict.opengl.gl;12 import derelict.opengl.glext;13 import yage.system.system;14 import yage.system.log;15 import yage.core.object2;;16 import yage.resource.manager;17 import yage.resource.resource;18 19 9 20 10 /** 21 * */ 11 * Shader stores vertex and fragment shader source code 12 * used by the graphics API to create a shader program. 13 * GraphicsApi.bindShader(Shader) binds the shader program, creating it if it doesn't exist.*/ 22 14 class Shader 23 15 { … … 25 17 enum Status 26 18 { NONE, /// 27 COMPILED, /// ditto 28 LINKED, /// ditto 29 EXECUTED, /// ditto 30 FAILED /// ditto 19 SUCCESS, /// ditto 20 FAIL /// ditto 31 21 } 32 22 Status status; /// ditto … … 36 26 protected char[] vertexSource; 37 27 protected char[] fragmentSource; 28 protected ShaderUniform[] uniforms; 38 29 39 /// 30 /** 31 * Params: 32 * vertexSource = Source code of a vertex shader. 33 * fragmentSource = Source code of a fragment shader. */ 40 34 this(char[] vertexSource, char[] fragmentSource) 41 { this.vertexSource = vertexSource ;42 this.fragmentSource = fragmentSource ;35 { this.vertexSource = vertexSource~"\0"; 36 this.fragmentSource = fragmentSource~"\0"; 43 37 } 44 38 45 39 /// 46 char[] getVertexSource() 47 { return vertexSource; 40 char[] getVertexSource(bool nullTerminated=false) 41 { if (nullTerminated) 42 return vertexSource; 43 return vertexSource[0..$-1]; 48 44 } 49 45 50 46 /// 51 char[] getFragmentSource() 52 { return fragmentSource; 47 char[] getFragmentSource(bool nullTerminated=false) 48 { if (nullTerminated) 49 return fragmentSource; 50 return fragmentSource[0..$-1]; 51 } 52 53 54 ShaderUniform[] getUniforms() 55 { 56 ShaderUniform[] result; 57 58 return result; 53 59 } 54 60 } 61 62 63 /** 64 * Used to pass variables to a shader */ 65 struct ShaderUniform 66 { 67 68 enum Type 69 { I1, I2, I3, I4, 70 F1, F2, F3, F4, 71 M2x2, M3x3, M4x4, 72 M2x3, M3x2, M2x4, M4x2, M4x3, M3x4 73 } 74 Type type; 75 char[] name; 76 void* values; 77 78 /// 79 static ShaderUniform opCall(char[] name, Type type, float[] values...) 80 { ShaderUniform result; 81 result.name = name; 82 result.values = values.ptr; 83 result.type = type; 84 return result; 85 } 86 static ShaderUniform opCall(char[] name, Type type, int[] values...) /// ditto 87 { ShaderUniform result; 88 result.name = name; 89 result.values = values.ptr; 90 result.type = type; 91 return result; 92 } 93 } trunk/src/yage/system/graphics/api/opengl.d
r173 r174 74 74 protected HashMap!(uint, ResourceInfo) shaders; 75 75 76 77 /** 78 * Free any resources from graphics memory are either: 79 * - haven't been used for longer than age, 80 * - are no longer referenced. 81 * If removed from graphics memory, they will be re-uploaded when needed again. 82 * Params: 83 * age = maximum age (in seconds) of objects to keep. Set to 0 to remove all items. Defaults to 3600. 84 */ 85 void cleanup(uint age=3600) 86 { 87 88 foreach (key, info; textures) 89 { if (info.resource is null || info.time <= time(null)-age) 90 { glDeleteTextures(1, &info.id); 91 textures.removeKey(key); 92 delete info; // nothing else references it at this point. 93 } } 94 foreach (key, info; vbos) 95 { if (info.resource is null || info.time <= time(null)-age) 96 { glDeleteBuffersARB(1, &info.id); 97 vbos.removeKey(key); 98 delete info; // nothing else references it at this point. 99 } } 100 } 101 76 77 /// 102 78 this() 103 79 { … … 114 90 } 115 91 92 /// 116 93 void bindCamera(CameraNode camera, int width, int height) 117 94 { current.camera = camera; … … 210 187 glDisable(GL_TEXTURE_2D); 211 188 212 // New189 213 190 if (layer.shader) 214 { bindShader(layer.shader, layer); 215 //layer.current_program = layer.program; 216 217 // Try to light and fog variables? 218 try { // bad for performance? 219 layer.setUniform("light_number", lights.length); 220 } catch{} 221 try { 222 layer.setUniform("fog_enabled", cast(float)current.camera.getScene().fogEnabled); 223 } catch{} 224 225 // Enable 191 { 192 ShaderUniform[3] uniforms; 193 uniforms[0] = ShaderUniform("light_number", ShaderUniform.Type.F1, cast(float)lights.length); 194 uniforms[1] = ShaderUniform("fog_enabled", ShaderUniform.Type.F1, cast(float)current.camera.getScene().fogEnabled); 195 196 197 198 // Bind Textures to UniformSampler2D 199 // TODO: Use glGetActiveUniform to get user defined uniforms that are sampler2D and automatically bind textures in order 200 // keep in mind 1d, 3d, cupe, and shadow textures 226 201 for (int i=0; i<layer.textures.length; i++) 227 { if (layer.textures[i].name.length) 202 { 203 if (layer.textures[i].name.length) 228 204 { char[256] cname = 0; 229 205 cname[0..layer.textures[i].name.length]= layer.textures[i].name; … … 234 210 glUniform1iARB(location, i); 235 211 } } 212 213 214 bindShader(layer.shader, layer, uniforms); 236 215 } 237 216 } else // unbind … … 285 264 286 265 bindShader(null, null); 287 //current.layer.current_program = 0;288 266 } 289 267 current.layer = layer; … … 446 424 447 425 /// TODO: Allow specifying uniform variable assignments. 448 void bindShader(Shader shader, Layer layer )426 void bindShader(Shader shader, Layer layer, ShaderUniform[] variables=null) 449 427 { 450 // Causes null pointer exception 428 if (!Probe.feature(Probe.Feature.SHADER)) 429 throw new GraphicsException("OpenGL.bindShader() is only supported on hardware that supports shaders."); 430 431 // Causes null pointer exception, but why? 451 432 //if (shader==current.shader) 452 433 // return; … … 455 436 { assert(shader.getVertexSource().length); 456 437 assert(shader.getFragmentSource().length); 457 458 // temporary 438 459 439 ResourceInfo info = ResourceInfo.getOrCreate(shader, shaders); 460 440 461 info.id = layer.program; 462 463 if (!layer.program) 464 { 465 char[] log; // accumulates all log entries 466 441 // Compile shader if not already compiled 442 if (shader.status == Shader.Status.NONE) 443 { assert(!info.id); 444 445 // Fail unless marked otherwise 446 shader.status = Shader.Status.FAIL; 447 shader.compileLog = ""; 448 uint vertexObj, fragmentObj; 449 450 // Cleanup on exit 451 scope(exit) 452 { if (vertexObj) // Mark shader objects for deletion 453 glDeleteObjectARB(vertexObj); // so they'll be deleted when the shader program is deleted. 454 if (fragmentObj) 455 glDeleteObjectARB(fragmentObj); 456 } 457 scope(failure) 458 if (info.id) 459 glDeleteObjectARB(info.id); 460 461 // Get OpenGL's log for a shader object. 467 462 char[] getLog(uint id) 468 463 { int len; char *log; … … 475 470 } 476 471 472 // Compile a shader into object code. 477 473 uint compile(char[] source, uint type) 478 474 { 479 // Compile this shader into a binary object 480 uint shaderObj; 481 { scope char** sourceZ = (new char*[1]).ptr; 482 shaderObj = glCreateShaderObjectARB(type); 483 sourceZ[0] = (source ~ "\0").ptr; 484 glShaderSourceARB(shaderObj, 1, sourceZ, null); 485 glCompileShaderARB(shaderObj); 486 delete sourceZ[0]; 487 } 475 // Compile this shader into a binary object 476 char* sourceZ = source.ptr; 477 uint shaderObj = glCreateShaderObjectARB(type); 478 glShaderSourceARB(shaderObj, 1, &sourceZ, null); 479 glCompileShaderARB(shaderObj); 488 480 489 481 // Get the compile log and check for errors 490 char[] objLog = getLog(shaderObj);491 log ~= objLog;482 char[] compileLog = getLog(shaderObj); 483 shader.compileLog ~= compileLog; 492 484 int status; 493 485 glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &status); 494 486 if (!status) 495 { try { 496 glDeleteObjectARB(shaderObj); 497 } finally { 498 throw new GraphicsException("Could not compile %s shader.\nReason: %s\nSource: %s", 499 type==GL_VERTEX_SHADER_ARB ? "vertex" : "fragment", objLog, source); 500 } } 487 throw new GraphicsException("Could not compile %s shader.\nReason: %s\nSource: %s", 488 type==GL_VERTEX_SHADER_ARB ? "vertex" : "fragment", compileLog, source); 501 489 502 490 return shaderObj; … … 504 492 505 493 // Compile 506 uint vertexObj = compile(shader.getVertexSource(), GL_VERTEX_SHADER_ARB);507 uint fragmentObj = compile(shader.getFragmentSource(), GL_FRAGMENT_SHADER_ARB);494 vertexObj = compile(shader.getVertexSource(true), GL_VERTEX_SHADER_ARB); 495 fragmentObj = compile(shader.getFragmentSource(true), GL_FRAGMENT_SHADER_ARB); 508 496 assert(vertexObj); 509 497 assert(fragmentObj); … … 515 503 glLinkProgramARB(info.id); // common failure point 516 504 505 // Check for errors 517 506 char[] linkLog = getLog(info.id); 518 log ~= linkLog; 519 520 // Check for errors 507 shader.compileLog ~= linkLog; 521 508 int status; 522 509 glGetObjectParameterivARB(info.id, GL_OBJECT_LINK_STATUS_ARB, &status); 523 if (!status) 510 if (!status) 524 511 throw new GraphicsException("Could not link the shaders.\nReason: %s", linkLog); 512 513 // Validate 525 514 glValidateProgramARB(info.id); 526 log ~= getLog(info.id); 515 char[] validateLog = getLog(info.id); 516 shader.compileLog ~= validateLog; 517 int isValid; 518 glGetObjectParameterivARB(info.id, GL_VALIDATE_STATUS, &isValid); 519 if (!isValid) 520 throw new GraphicsException("Shader failed validation.\nReason: %s", validateLog); 527 521 522 shader.status = Shader.Status.SUCCESS; 523 528 524 // Temporary 529 layer.program = info.id; 530 Log.info(log); 525 Log.info(shader.compileLog); 531 526 } 532 527 533 528 assert(info.id); 534 529 glUseProgramObjectARB(info.id); 530 531 // Bind uniform variables 532 foreach (uniform; variables) 533 { 534 // Get the location of name 535 char[256] cname = 0; // TODO: Fix potential buffer overflow 536 cname[0..uniform.name.length] = uniform.name; 537 int location = glGetUniformLocationARB(info.id, cname.ptr); 538 if (location == -1) 539 throw new GraphicsException("Unable to set OpenGL shader uniform variable: %s", uniform.name); 540 541 // Send the uniform data 542 switch (uniform.type) 543 { case ShaderUniform.Type.F1: glUniform1fvARB(location, 1, cast(float*)uniform.values); break; 544 case ShaderUniform.Type.F2: glUniform2fvARB(location, 2, cast(float*)uniform.values); break; 545 case ShaderUniform.Type.F3: glUniform3fvARB(location, 3, cast(float*)uniform.values); break; 546 case ShaderUniform.Type.F4: glUniform4fvARB(location, 4, cast(float*)uniform.values); break; 547 case ShaderUniform.Type.I1: glUniform1ivARB(location, 1, cast(int*)uniform.values); break; 548 case ShaderUniform.Type.I2: glUniform2ivARB(location, 2, cast(int*)uniform.values); break; 549 case ShaderUniform.Type.I3: glUniform3ivARB(location, 3, cast(int*)uniform.values); break; 550 case ShaderUniform.Type.I4: glUniform4ivARB(location, 4, cast(int*)uniform.values); break; 551 // TODO Other Matrix types 552 case ShaderUniform.Type.M2x2: glUniformMatrix2fvARB(location, 4, false, cast(float*)uniform.values); break; 553 case ShaderUniform.Type.M3x3: glUniformMatrix3fvARB(location, 9, false, cast(float*)uniform.values); break; 554 case ShaderUniform.Type.M4x4: glUniformMatrix4fvARB(location, 16, false, cast(float*)uniform.values); break; 555 default: break; 556 } 557 } 535 558 } else 536 559 glUseProgramObjectARB(0); // no shader … … 779 802 780 803 804 /** 805 * Free any resources from graphics memory are either: 806 * - haven't been used for longer than age, 807 * - are no longer referenced. 808 * If removed from graphics memory, they will be re-uploaded when needed again. 809 * Params: 810 * age = maximum age (in seconds) of objects to keep. Set to 0 to remove all items. Defaults to 3600. 811 */ 812 void cleanup(uint age=3600) 813 { 814 foreach (key, info; textures) 815 { if (info.resource is null || info.time <= time(null)-age) 816 { glDeleteTextures(1, &info.id); 817 textures.removeKey(key); 818 delete info; // nothing else references it at this point. 819 } } 820 foreach (key, info; vbos) 821 { if (info.resource is null || info.time <= time(null)-age) 822 { glDeleteBuffersARB(1, &info.id); 823 vbos.removeKey(key); 824 delete info; // nothing else references it at this point. 825 } } 826 foreach (key, info; shaders) 827 { if (info.resource is null || info.time <= time(null)-age) 828 { glDeleteBuffersARB(1, &info.id); 829 assert((cast(Shader)info.resource.ptr) !is null); 830 (cast(Shader)info.resource.ptr).status = Shader.Status.NONE; 831 shaders.removeKey(key); 832 delete info; // nothing else references it at this point. 833 } } 834 } 835 781 836 782 837 ///
