Changeset 174

Show
Ignore:
Timestamp:
02/07/10 21:47:44 (2 years ago)
Author:
JoeCoder
Message:

Finished migrating OpenGL shader code out of resource.layer and into graphics.api.opengl.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/res/shader/diffuse-hdr.frag

    r28 r174  
    44 * 
    55 * Same as diffuse.frag except with max_brightness to allow materials to be 
    6  * brighter than 100%.  This probably requires floating point textures and a 
     6 * brighter than 100 percent.  This probably requires floating point textures and a 
    77 * few other tricks to be true HDR. 
    88 */ 
  • trunk/src/yage/resource/layer.d

    r173 r174  
    99import tango.math.Math; 
    1010import tango.io.Stdout; 
    11 import std.string; 
    12 import std.stdio; 
    1311 
    14 import derelict.opengl.gl; 
    15 import derelict.opengl.glext; 
    1612import yage.core.all; 
    1713import yage.system.system; 
     
    121117    } 
    122118 
    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     /// Ditto 
    129     void setUniform(char[] name, Vec2f[] values ...) 
    130     {   setUniform(name, 2, cast(float[])values); 
    131     } 
    132     /// Ditto 
    133     void setUniform(char[] name, Vec3f[] values ...) 
    134     {   setUniform(name, 3, cast(float[])values); 
    135     } 
    136     /// Ditto 
    137     void setUniform(char[] name, Vec4f[] values ...) 
    138     {   setUniform(name, 4, cast(float[])values); 
    139     } 
    140     /// Ditto 
    141     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 name 
    172         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 data 
    181         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     } 
    190119} 
  • trunk/src/yage/resource/material.d

    r173 r174  
    1414import std.stream; 
    1515import std.string; 
    16 import std.stdio; 
    1716import yage.core.all; 
    1817import yage.core.object2; 
     
    259258    } 
    260259 
    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 layers 
    266         foreach (Layer layer; layers) 
    267             result ~= layer.toString(); 
    268         result~= "</material>\n"; 
    269         return result; 
    270     } 
    271260} 
    272261 
  • trunk/src/yage/resource/shader.d

    r173 r174  
    77module yage.resource.shader; 
    88 
    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  
    199 
    2010/** 
    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.*/ 
    2214class Shader 
    2315{ 
     
    2517    enum Status 
    2618    {   NONE,       /// 
    27         COMPILED,   /// ditto 
    28         LINKED,     /// ditto 
    29         EXECUTED,   /// ditto 
    30         FAILED      /// ditto 
     19        SUCCESS,    /// ditto 
     20        FAIL        /// ditto 
    3121    }        
    3222    Status status;          /// ditto 
     
    3626    protected char[] vertexSource; 
    3727    protected char[] fragmentSource; 
     28    protected ShaderUniform[] uniforms; 
    3829     
    39     /// 
     30    /** 
     31     * Params: 
     32     *     vertexSource = Source code of a vertex shader. 
     33     *     fragmentSource = Source code of a fragment shader. */ 
    4034    this(char[] vertexSource, char[] fragmentSource) 
    41     {   this.vertexSource = vertexSource
    42         this.fragmentSource = fragmentSource
     35    {   this.vertexSource = vertexSource~"\0"
     36        this.fragmentSource = fragmentSource~"\0"
    4337    } 
    4438     
    4539    /// 
    46     char[] getVertexSource() 
    47     {   return vertexSource;         
     40    char[] getVertexSource(bool nullTerminated=false) 
     41    {   if (nullTerminated)      
     42            return vertexSource; 
     43        return vertexSource[0..$-1]; 
    4844    } 
    4945     
    5046    /// 
    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; 
    5359    } 
    5460} 
     61 
     62 
     63/** 
     64 * Used to pass variables to a shader */ 
     65struct 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  
    7474    protected HashMap!(uint, ResourceInfo) shaders; 
    7575     
    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    /// 
    10278    this() 
    10379    {    
     
    11490    } 
    11591     
     92    /// 
    11693    void bindCamera(CameraNode camera, int width, int height) 
    11794    {   current.camera = camera; 
     
    210187                glDisable(GL_TEXTURE_2D); 
    211188             
    212             // New 
     189             
    213190            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 
    226201                for (int i=0; i<layer.textures.length; i++) 
    227                 {   if (layer.textures[i].name.length) 
     202                {    
     203                    if (layer.textures[i].name.length) 
    228204                    {   char[256] cname = 0; 
    229205                        cname[0..layer.textures[i].name.length]= layer.textures[i].name; 
     
    234210                            glUniform1iARB(location, i); 
    235211                }   } 
     212                 
     213                 
     214                bindShader(layer.shader, layer, uniforms); 
    236215            } 
    237216        } else // unbind 
     
    285264             
    286265            bindShader(null, null); 
    287             //current.layer.current_program = 0; 
    288266        } 
    289267        current.layer = layer; 
     
    446424     
    447425    /// TODO: Allow specifying uniform variable assignments. 
    448     void bindShader(Shader shader, Layer layer
     426    void bindShader(Shader shader, Layer layer, ShaderUniform[] variables=null
    449427    {    
    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? 
    451432        //if (shader==current.shader) 
    452433        //  return; 
     
    455436        {   assert(shader.getVertexSource().length); 
    456437            assert(shader.getFragmentSource().length); 
    457              
    458             // temporary 
     438                         
    459439            ResourceInfo info = ResourceInfo.getOrCreate(shader, shaders); 
    460440             
    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. 
    467462                char[] getLog(uint id) 
    468463                {   int len;  char *log; 
     
    475470                } 
    476471                 
     472                // Compile a shader into object code. 
    477473                uint compile(char[] source, uint type) 
    478474                { 
    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); 
    488480                     
    489481                    // 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; 
    492484                    int status; 
    493485                    glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &status); 
    494486                    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); 
    501489                     
    502490                    return shaderObj; 
     
    504492                 
    505493                // 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); 
    508496                assert(vertexObj); 
    509497                assert(fragmentObj); 
     
    515503                glLinkProgramARB(info.id); // common failure point 
    516504                 
     505                // Check for errors 
    517506                char[] linkLog = getLog(info.id); 
    518                 log ~= linkLog; 
    519              
    520                 // Check for errors 
     507                shader.compileLog ~= linkLog; 
    521508                int status; 
    522509                glGetObjectParameterivARB(info.id, GL_OBJECT_LINK_STATUS_ARB, &status); 
    523                 if (!status) 
     510                if (!status)                    
    524511                    throw new GraphicsException("Could not link the shaders.\nReason:  %s", linkLog); 
     512                 
     513                // Validate 
    525514                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); 
    527521                     
     522                shader.status = Shader.Status.SUCCESS; 
     523                 
    528524                // Temporary 
    529                 layer.program = info.id; 
    530                 Log.info(log); 
     525                Log.info(shader.compileLog); 
    531526            } 
    532527             
    533528            assert(info.id); 
    534529            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            } 
    535558        } else 
    536559            glUseProgramObjectARB(0); // no shader 
     
    779802     
    780803     
     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     
    781836     
    782837    ///