Changeset 190

Show
Ignore:
Timestamp:
06/27/10 14:17:58 (2 years ago)
Author:
JoeCoder
Message:

Added support for DXT1, DXT3, and DXT5 compressed DDS textures. DDS stores texture data in the same format that textures are compressed in video memory, reducing texture load times. Thanks go to Bill Baxter and his Luigi project on dsource.org for 95% of the DDS code.
Fixed a regression that broke tangent vector calculation and bump-mapping along with it.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/yage/resource/collada.d

    r189 r190  
    420420        // Enable blending if there's alpha. 
    421421        if (pass.blend==MaterialPass.Blend.NONE) 
    422             if (pass.diffuse.a < 255 || (pass.textures.length && pass.textures[0].texture.getImage().getChannels()==4)) 
     422            if (pass.diffuse.a < 255 || (pass.textures.length && pass.textures[0].texture.getImage() && pass.textures[0].texture.getImage().getChannels()==4)) 
    423423                pass.blend = MaterialPass.Blend.AVERAGE; 
    424424         
  • trunk/src/yage/resource/geometry.d

    r189 r190  
    1111import yage.core.format; 
    1212import yage.core.math.vector; 
     13import yage.core.object2; 
    1314import yage.resource.manager; 
    1415import yage.resource.material; 
     
    8687     * Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html */ 
    8788    public Vec3f[] createTangentVectors() 
    88     {        
    89         // TODO: Multiple meshes 
    90          
     89    {            
    9190        Vec3f[] vertices = cast(Vec3f[])getAttribute(Geometry.VERTICES); 
    9291        Vec3f[] normals = cast(Vec3f[])getAttribute(Geometry.NORMALS); 
     92         
    9393        float[] texCoords = cast(float[])getAttribute(Geometry.TEXCOORDS0); 
    9494        int texCoordCount = getVertexBuffer(Geometry.TEXCOORDS0).components;         
    9595        assert(texCoords.length/texCoordCount == vertices.length); 
    9696     
    97          
    9897        Vec3f[] tan1 = new Vec3f[vertices.length]; 
    99         Vec3f[] tan2 = new Vec3f[vertices.length]; 
    100          
     98        //Vec3f[] tan2 = new Vec3f[vertices.length];         
    10199        Vec3f[] tangents = new Vec3f[vertices.length]; 
    102100         
    103101        foreach (mesh; meshes) 
    104102            foreach (tri; mesh.getTriangles()) 
    105             { 
    106                  
     103            {                
    107104                Vec3f v1 = vertices[tri.x]; 
    108105                Vec3f v2 = vertices[tri.y]; 
    109106                Vec3f v3 = vertices[tri.z]; 
    110107                 
    111                 Vec2f w1 = Vec2f(texCoords[tri.x*texCoordCount..tri.x*texCoordCount+1]); 
    112                 Vec2f w2 = Vec2f(texCoords[tri.y*texCoordCount..tri.y*texCoordCount+1]); 
    113                 Vec2f w3 = Vec2f(texCoords[tri.z*texCoordCount..tri.z*texCoordCount+1]); 
     108                Vec2f w1, w2, w3; 
     109                if (texCoordCount==2) 
     110                {   w1 = (cast(Vec2f[])texCoords)[tri.x]; 
     111                    w2 = (cast(Vec2f[])texCoords)[tri.y]; 
     112                    w3 = (cast(Vec2f[])texCoords)[tri.z]; 
     113                } else if (texCoordCount==3) 
     114                {   w1 = Vec2f((cast(Vec3f[])texCoords)[tri.x].v); 
     115                    w2 = Vec2f((cast(Vec3f[])texCoords)[tri.y].v); 
     116                    w3 = Vec2f((cast(Vec3f[])texCoords)[tri.z].v); 
     117                } else 
     118                    throw new ResourceException("Texture coordinates must have 2 or 3 components to generate tangent vectors."); 
    114119                 
    115120                float x1 = v2.x - v1.x; 
     
    139144                tan1[tri.z] += sdir; 
    140145                 
    141                 tan2[tri.x] += tdir; 
    142                 tan2[tri.y] += tdir; 
    143                 tan2[tri.z] += tdir;           
     146                //tan2[tri.x] += tdir; 
     147                //tan2[tri.y] += tdir; 
     148                //tan2[tri.z] += tdir;             
    144149            } 
    145150         
     
    149154            Vec3f t = tan1[i]; 
    150155             
    151             tangents[i] = (t-n * n.dot(t)).normalize(); 
    152              
    153             //tangents[i].w = n.cross(t).dot(tan2[i]) < 0 ? -1 : 1; 
    154              
     156            tangents[i] = (t-n * n.dot(t)).normalize();          
     157            //tangents[i].w = n.cross(t).dot(tan2[i]) < 0 ? -1 : 1;          
    155158        } 
    156159        delete tan1; 
    157         delete tan2; 
     160        //delete tan2; 
    158161         
    159162        return tangents; 
  • trunk/src/yage/resource/texture.d

    r188 r190  
    1313import yage.core.math.vector; 
    1414import yage.core.object2; 
     15import yage.resource.dds; 
    1516import yage.resource.image; 
    1617import yage.resource.manager; 
     
    135136    protected char[] source;     
    136137    protected Image image; // if not null, the texture will be updated with this image the next time it is used. 
     138    //protected ubyte[] ddsImageData; 
     139    protected DDSImageData* ddsImageData; 
     140     
     141     
     142    public char[] ddsFile; 
     143     
     144    //public char[] ddsFile; // if not null, a dds texture will be loaded from this file the next time the texture is used. 
    137145    Vec2i padding;  // padding stores how many pixels of the original texture are unused. 
    138146                    // e.g. getWidth() returns the used texture + the padding.   
     
    154162        this.format = format; 
    155163        this.mipmap = mipmap; 
    156         setImage(new Image(source), format, mipmap, source); 
    157     } 
    158      
     164         
     165        if (filename[$-4..$]==".dds") 
     166        {   ddsFile = source; 
     167            ubyte[] contents = ResourceManager.getFile(filename); 
     168            ddsImageData = loadDDSTextureFile(contents); 
     169        } 
     170        else 
     171            setImage(new Image(source), format, mipmap, source); 
     172    } 
     173     
     174    /// 
    159175    this(Image image, Format format=Texture.Format.AUTO, bool mipmap=true, char[] source="", bool padding=false) 
    160176    {   this.format = format; 
     
    162178        setImage(image, format, mipmap, source, padding); 
    163179    } 
    164  
     180     
     181    /** 
     182     * If the texture is loaded from a dds file instead of an image, return the unparsed dds file contents. 
     183     * Otherwise an empty array is returned.  */ 
     184    DDSImageData* getDDSImageData() 
     185    {   return ddsImageData; 
     186    } 
     187     
    165188    /// Get / set the Image used by this texture. 
    166189    Image getImage() 
     
    173196    } 
    174197     
     198    /// 
    175199    void setImage(Image image) 
    176200    {   setImage(image, format, mipmap, source, padding.length2() != 0); 
    177     } 
    178      
     201    }   
     202    /// ditto 
    179203    void setImage(Image image, Format format, bool mipmap=true, char[] source="", bool pad=false) /// ditto 
    180204    {   assert(image !is null); 
    181         assert(image.getData() !is null);        
     205        assert(image.getData() !is null); 
     206        ddsImageData = null; 
     207         
    182208        this.image = image; 
    183209        this.format = format; 
  • trunk/src/yage/system/graphics/api/opengl.d

    r188 r190  
    2020import yage.gui.surface; 
    2121import yage.gui.style; 
     22import yage.resource.dds; 
    2223import yage.resource.geometry; 
    2324import yage.resource.image; 
     
    648649            {    
    649650                Timer timer = new Timer(true); 
     651                assert(gpuTexture.getImage() || gpuTexture.ddsFile.length); 
    650652                 
    651653                // Upload new image to graphics card memory 
    652654                Image image = gpuTexture.getImage(); 
    653                 assert(image); 
    654                              
    655                 // Convert auto format to a real format based on the image given. 
    656                 Texture.Format format; 
    657                 if (gpuTexture.getFormat() == Texture.Format.AUTO) 
    658                     switch(image.getChannels()) // This will support float formats when we switch to using Image2. 
    659                     {   case 1: format = Texture.Format.COMPRESSED_LUMINANCE; break; 
    660                         case 2: format = Texture.Format.COMPRESSED_LUMINANCE_ALPHA; break; 
    661                         case 3: format = Texture.Format.COMPRESSED_RGB; break;                   
    662                         case 4: format = Texture.Format.COMPRESSED_RGBA; break;                  
    663                         default: throw new ResourceException("Images with more than 4 channels are not supported."); 
     655                if (image) 
     656                { 
     657                    // Convert auto format to a real format based on the image given. 
     658                    Texture.Format format; 
     659                    if (gpuTexture.getFormat() == Texture.Format.AUTO) 
     660                        switch(image.getChannels()) // This will support float formats when we switch to using Image2. 
     661                        {   case 1: format = Texture.Format.COMPRESSED_LUMINANCE; break; 
     662                            case 2: format = Texture.Format.COMPRESSED_LUMINANCE_ALPHA; break; 
     663                            case 3: format = Texture.Format.COMPRESSED_RGB; break;                   
     664                            case 4: format = Texture.Format.COMPRESSED_RGBA; break;                  
     665                            default: throw new ResourceException("Images with more than 4 channels are not supported."); 
     666                        } 
     667                    else if (gpuTexture.getFormat() == Texture.Format.AUTO_UNCOMPRESSED) 
     668                        switch(image.getChannels()) // This will support float formats when we switch to using Image2. 
     669                        {   case 1: format = Texture.Format.LUMINANCE8; break; 
     670                            case 2: format = Texture.Format.LUMINANCE8_ALPHA8; break; 
     671                            case 3: format = Texture.Format.RGB8; break;                     
     672                            case 4: format = Texture.Format.RGBA8; break;                    
     673                            default: throw new ResourceException("Images with more than 4 channels are not supported."); 
     674                        } 
     675                     
     676                    // Convert from Texture.Format to OpenGL format constants. 
     677                    uint[Texture.Format] glFormatMap = [ 
     678                        Texture.Format.COMPRESSED_LUMINANCE : GL_LUMINANCE, 
     679                        Texture.Format.COMPRESSED_LUMINANCE_ALPHA : GL_LUMINANCE_ALPHA, 
     680                        Texture.Format.COMPRESSED_RGB : GL_RGB, 
     681                        Texture.Format.COMPRESSED_RGBA : GL_RGBA, 
     682                        Texture.Format.LUMINANCE8 : GL_LUMINANCE, 
     683                        Texture.Format.LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA, 
     684                        Texture.Format.RGB8 : GL_RGB, 
     685                        Texture.Format.RGBA8 : GL_RGBA,              
     686                    ]; 
     687                    uint[Texture.Format] glInternalFormatMap = [ 
     688                        Texture.Format.COMPRESSED_LUMINANCE : GL_COMPRESSED_LUMINANCE, 
     689                        Texture.Format.COMPRESSED_LUMINANCE_ALPHA : GL_COMPRESSED_LUMINANCE_ALPHA, 
     690                        Texture.Format.COMPRESSED_RGB : GL_COMPRESSED_RGB, 
     691                        Texture.Format.COMPRESSED_RGBA : GL_COMPRESSED_RGBA, 
     692                        Texture.Format.LUMINANCE8 : GL_LUMINANCE, 
     693                        Texture.Format.LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA, 
     694                        Texture.Format.RGB8 : GL_RGB, 
     695                        Texture.Format.RGBA8 : GL_RGBA,              
     696                    ];           
     697                    uint glFormat = glFormatMap[format]; 
     698                    uint glInternalFormat = glInternalFormatMap[format]; 
     699                     
     700     
     701                    gpuTexture.width = image.getWidth(); 
     702                    gpuTexture.height = image.getHeight(); 
     703                     
     704                    uint max = Probe.feature(Probe.Feature.MAX_TEXTURE_SIZE); 
     705                    uint new_width = image.getWidth(); 
     706                    uint new_height= image.getHeight(); 
     707                     
     708                    // Ensure power of two sized if required 
     709                    if (!Probe.feature(Probe.Feature.NON_2_TEXTURE)) 
     710                    { 
     711                        if (log2(new_height) != floor(log2(new_height))) 
     712                            new_height = nextPow2(new_height); 
     713                        if (log2(new_width) != floor(log2(new_width))) 
     714                            new_width = nextPow2(new_width); 
     715     
     716                        // Resize if necessary 
     717                        if (new_width != gpuTexture.width || new_height != gpuTexture.height) 
     718                            image = image.resize(min(new_width, max), min(new_height, max)); 
    664719                    } 
    665                 else if (gpuTexture.getFormat() == Texture.Format.AUTO_UNCOMPRESSED) 
    666                     switch(image.getChannels()) // This will support float formats when we switch to using Image2. 
    667                     {   case 1: format = Texture.Format.LUMINANCE8; break; 
    668                         case 2: format = Texture.Format.LUMINANCE8_ALPHA8; break; 
    669                         case 3: format = Texture.Format.RGB8; break;                     
    670                         case 4: format = Texture.Format.RGBA8; break;                    
    671                         default: throw new ResourceException("Images with more than 4 channels are not supported."); 
     720                         
     721                    // Build mipmaps (doing it ourself is several times faster than gluBuild2DMipmaps, 
     722                    int level = 0; 
     723                    while(true) { 
     724                        glTexImage2D(GL_TEXTURE_2D, level, glInternalFormat, image.getWidth(), image.getHeight(), 0, glFormat, GL_UNSIGNED_BYTE, image.getData().ptr); 
     725                        level++; 
     726                         
     727                        if (!gpuTexture.mipmap || image.getWidth() <= 4 || image.getHeight() <= 4) 
     728                            break; 
     729                         
     730                        image = image.resize(image.getWidth()/2, image.getHeight()/2); 
     731                                                     
    672732                    } 
    673                  
    674                 // Convert from Texture.Format to OpenGL format constants. 
    675                 uint[Texture.Format] glFormatMap = [ 
    676                     Texture.Format.COMPRESSED_LUMINANCE : GL_LUMINANCE, 
    677                     Texture.Format.COMPRESSED_LUMINANCE_ALPHA : GL_LUMINANCE_ALPHA, 
    678                     Texture.Format.COMPRESSED_RGB : GL_RGB, 
    679                     Texture.Format.COMPRESSED_RGBA : GL_RGBA, 
    680                     Texture.Format.LUMINANCE8 : GL_LUMINANCE, 
    681                     Texture.Format.LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA, 
    682                     Texture.Format.RGB8 : GL_RGB, 
    683                     Texture.Format.RGBA8 : GL_RGBA,              
    684                 ]; 
    685                 uint[Texture.Format] glInternalFormatMap = [ 
    686                     Texture.Format.COMPRESSED_LUMINANCE : GL_COMPRESSED_LUMINANCE, 
    687                     Texture.Format.COMPRESSED_LUMINANCE_ALPHA : GL_COMPRESSED_LUMINANCE_ALPHA, 
    688                     Texture.Format.COMPRESSED_RGB : GL_COMPRESSED_RGB, 
    689                     Texture.Format.COMPRESSED_RGBA : GL_COMPRESSED_RGBA, 
    690                     Texture.Format.LUMINANCE8 : GL_LUMINANCE, 
    691                     Texture.Format.LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA, 
    692                     Texture.Format.RGB8 : GL_RGB, 
    693                     Texture.Format.RGBA8 : GL_RGBA,              
    694                 ];           
    695                 uint glFormat = glFormatMap[format]; 
    696                 uint glInternalFormat = glInternalFormatMap[format]; 
    697                  
    698  
    699                 gpuTexture.width = image.getWidth(); 
    700                 gpuTexture.height = image.getHeight(); 
    701                  
    702                 uint max = Probe.feature(Probe.Feature.MAX_TEXTURE_SIZE); 
    703                 uint new_width = image.getWidth(); 
    704                 uint new_height= image.getHeight(); 
    705                  
    706                 // Ensure power of two sized if required 
    707                 if (!Probe.feature(Probe.Feature.NON_2_TEXTURE)) 
    708                 { 
    709                     if (log2(new_height) != floor(log2(new_height))) 
    710                         new_height = nextPow2(new_height); 
    711                     if (log2(new_width) != floor(log2(new_width))) 
    712                         new_width = nextPow2(new_width); 
    713  
    714                     // Resize if necessary 
    715                     if (new_width != gpuTexture.width || new_height != gpuTexture.height) 
    716                         image = image.resize(min(new_width, max), min(new_height, max)); 
    717                 } 
    718                      
    719                 // Build mipmaps (doing it ourself is several times faster than gluBuild2DMipmaps, 
    720                 int level = 0; 
    721                 while(true) { 
    722                     glTexImage2D(GL_TEXTURE_2D, level, glInternalFormat, image.getWidth(), image.getHeight(), 0, glFormat, GL_UNSIGNED_BYTE, image.getData().ptr); 
    723                     level++; 
    724                      
    725                     if (!gpuTexture.mipmap || image.getWidth() <= 4 || image.getHeight() <= 4) 
    726                         break; 
    727                      
    728                     image = image.resize(image.getWidth()/2, image.getHeight()/2); 
    729                                                  
    730                 } 
    731                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level-1); 
    732                  
     733                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level-1); 
     734                     
     735                } else if (gpuTexture.getDDSImageData() ){                   
     736                     
     737                    // This block is from Bill Baxter's DDS loader, See license in resource/dds.d 
     738                    DDSImageData* ddsData = gpuTexture.getDDSImageData(); 
     739                    if(ddsData) { 
     740                        int nHeight = ddsData.height; 
     741                        int nWidth = ddsData.width; 
     742                        int nNumMipMaps = ddsData.numMipMaps; 
     743                        int nBlockSize; 
     744                        if(ddsData.format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) 
     745                            nBlockSize = 8; 
     746                        else 
     747                            nBlockSize = 16; 
     748                        glGenTextures(1, &info.id); 
     749                        glBindTexture(GL_TEXTURE_2D, info.id); 
     750                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
     751                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
     752                        int nSize; 
     753                        int nOffset = 0; 
     754                        // Load the mip-map levels 
     755                        for(int k = 0; k < nNumMipMaps; ++k) { 
     756                            if(nWidth == 0) 
     757                                nWidth = 1; 
     758                            if(nHeight == 0) 
     759                                nHeight = 1; 
     760                            nSize = ((nWidth + 3) / 4) * ((nHeight + 3) / 4) * nBlockSize; 
     761                            glCompressedTexImage2DARB(GL_TEXTURE_2D, k, ddsData.format, nWidth, nHeight, 0, nSize, &ddsData.pixels[0] + nOffset); 
     762                            nOffset += nSize; 
     763                            // Half the image size for the next mip-map level... 
     764                            nWidth = (nWidth / 2); 
     765                            nHeight = (nHeight / 2); 
     766                        } 
     767                    } 
     768                    // end resource/dds.d license 
     769                } 
    733770                gpuTexture.dirty = false; 
    734771                gpuTexture.flipped = false; 
  • trunk/src/yage/system/graphics/probe.d

    r187 r190  
    2020{ 
    2121    private static char[] extensions; // return value from glGetString(GL_EXTENSIONS) 
    22     private static int fbo=-1, shader=-1, vbo=-1, mt=-1, np2=-1;  // so lookup only has to occur once. 
     22    private static int fbo=-1, shader=-1, vbo=-1, mt=-1, np2=-1, textureCompression=-1;   // so lookup only has to occur once. 
    2323     
    2424    /** 
     
    2727    {   MAX_LIGHTS,         /// Maximum number of lights that can be used at one time (isn't this always 8?) 
    2828        MAX_TEXTURE_SIZE,   /// Maximum allowed size for a texture 
    29         MAX_TEXTURE_UNITS,  /// Maximum number of textures that can be used in multitexturing 
     29        MAX_TEXTURE_UNITS,  /// Maximum number of textures that can be used in multitexturing       
    3030         
    3131        FBO,                /// Hardware support for rendering directly to a texture (Frame Buffer Object); first available in GeForce FX and Radeon 9x00 
    3232        MULTITEXTURE,       /// Hardware support for using multiple textures in a single rendering pass; first available on Voodoo2? 
     33        TEXTURE_COMPRESSION, 
    3334        NON_2_TEXTURE,      /// Hardware support for textures of arbitrary size; first available in GeForce FX and Radeon 9500 
    3435        SHADER,             /// Hardware support for openGl vertex and fragment shaders; first available in GeForce FX and Radeon 9x00 
     
    8283                    mt = cast(int)checkExtension("GL_ARB_multitexture"); 
    8384                return mt; 
     85            case Feature.TEXTURE_COMPRESSION: 
     86                if (textureCompression==-1) 
     87                    textureCompression = cast(int)checkExtension("GL_ARB_texture_compression"); 
     88                return textureCompression; 
    8489            case Feature.NON_2_TEXTURE: 
    8590                if (np2==-1) 
  • trunk/src/yage/system/window.d

    r187 r190  
    153153        SDL_EnableUNICODE(1); 
    154154        SDL_EnableKeyRepeat(1, 100); 
    155  
     155         
    156156        // Attempt to load multitexturing        
    157157        if (Probe.feature(Probe.Feature.MULTITEXTURE)) 
     
    159159                throw new YageException("GL_ARB_multitexture extension detected but it could not be loaded."); 
    160160            Log.info("GL_ARB_multitexture support enabled."); 
     161        }else 
     162            Log.info("GL_ARB_multitexture not supported.  This is ok, but graphical quality may be limited."); 
     163         
     164        // Texture Compression 
     165        if (Probe.feature(Probe.Feature.TEXTURE_COMPRESSION)) 
     166        {   if (!ARBTextureCompression.load("GL_ARB_texture_compression")) 
     167                throw new YageException("GL_ARB_texture_compression extension detected but it could not be loaded."); 
     168            Log.info("GL_ARB_texture_compression support enabled."); 
    161169        }else 
    162170            Log.info("GL_ARB_multitexture not supported.  This is ok, but graphical quality may be limited.");