Hello all
I have had need for a DDS-Reader, who can read a cubemap that resists in a single DDS-File. First a have created this with the NVidea-Texture-Tool (nvdxt). My tested cubemaps scenarios: # For a cubemap compressed and no mipmap (opengl can do that good) C:\NVideaTextureTool\nvdxt -nomipmap -dxt5 -cubeMap -list citymapfiles.lst -output citymap.dds C:\NVideaTextureTool\nvdxt -nomipmap -dxt3 -cubeMap -list citymapfiles.lst -output citymap.dds C:\NVideaTextureTool\nvdxt -nomipmap -dxt1 -cubeMap -list citymapfiles.lst -output citymap.dds # For a cubemap uncompressed and no mipmap (opengl can do that good) C:\NVideaTextureTool\nvdxt -nomipmap -u888 -cubeMap -list citymapfiles.lst -output citymap.dds C:\NVideaTextureTool\nvdxt -nomipmap -u8888 -cubeMap -list citymapfiles.lst -output citymap.dds The file citymapfiles.lst contains the 6 maps for a cube, eg. cties_negative_x.png cities_positive_x.png cities_negative_y.png cities_positive_y.png cities_negative_z.png cities_positive_z.png Now, for the next step i have must change the Class "DDSImage" from the package "com.sun.opengl.util.texture.spi" for correct readings. The return type are the same. My new Reader-class "DDsImages" now reads the dds files rgb,rgba und the 3 compressed dxt1,dxt3 and dxt5 with/without mipmaps, cubemap in the file. I habe all tested with that. The savings for maps are in the same order how in "citymapfiles.lst". It can be, that a name-change between the positive-X and negative-X ist required for correct display later in the cube. Now the java source for the reader (i hope it was useful): import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; public class DDsImages { private static int size = 0; private static int flags = 0; private static int width = 0; private static int height = 0; private static int pitchOrLinearSize = 0; private static int backBufferCountOrDepth = 0; private static int mipMapCountOrAux = 0; private static int alphaBitDepth = 0; private static int reserved1 = 0; private static int surface = 0; private static int colorSpaceLowValue = 0; private static int colorSpaceHighValue = 0; private static int destBltColorSpaceLowValue = 0; private static int destBltColorSpaceHighValue = 0; private static int srcOverlayColorSpaceLowValue = 0; private static int srcOverlayColorSpaceHighValue = 0; private static int srcBltColorSpaceLowValue = 0; private static int srcBltColorSpaceHighValue = 0; private static int pfSize = 0; private static int pfFlags = 0; private static int pfFourCC = 0; private static int pfRGBBitCount = 0; private static int pfRBitMask = 0; private static int pfGBitMask = 0; private static int pfBBitMask = 0; private static int pfABitMask = 0; private static int ddsCaps1 = 0; private static int ddsCaps2 = 0; private static int ddsCaps3 = 0; private static int ddsCaps4 = 0; private static int textureStage = 0; // // Selected bits in header flags // private static final int DDSD_CAPS = 0x00000001; // Capacities are valid private static final int DDSD_HEIGHT = 0x00000002; // Height is valid private static final int DDSD_WIDTH = 0x00000004; // Width is valid private static final int DDSD_PITCH = 0x00000008; // Pitch is valid private static final int DDSD_BACKBUFFERCOUNT = 0x00000020; // Back buffer count is valid private static final int DDSD_ZBUFFERBITDEPTH = 0x00000040; // Z-buffer bit depth is valid (shouldn't be used in DDSURFACEDESC2) private static final int DDSD_ALPHABITDEPTH = 0x00000080; // Alpha bit depth is valid private static final int DDSD_LPSURFACE = 0x00000800; // lpSurface is valid private static final int DDSD_PIXELFORMAT = 0x00001000; // ddpfPixelFormat is valid private static final int DDSD_MIPMAPCOUNT = 0x00020000; // Mip map count is valid private static final int DDSD_LINEARSIZE = 0x00080000; // dwLinearSize is valid private static final int DDSD_DEPTH = 0x00800000; // dwDepth is valid //Texture contains alpha data; dwRGBAlphaBitMask contains valid data. private static final int DDPF_ALPHAPIXELS = 0x00000001; // Alpha channel is present //Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data private static final int DDPF_ALPHA = 0x00000002; // Only contains alpha information //Texture contains compressed RGB data; dwFourCC contains valid data. //Four-character codes for specifying compressed or custom formats. Possible values include: DXT1, DXT2, DXT3, DXT4, or DXT5. // A FourCC of DX10 indicates the prescense of the DDS_HEADER_DXT10 extended header, and the dxgiFormat member of that structure indicates the true format. // When using a four-character code, dwFlags must include DDPF_FOURCC. private static final int DDPF_FOURCC = 0x00000004; // FourCC code is valid private static final int DDPF_PALETTEINDEXED4 = 0x00000008; // Surface is 4-bit color indexed private static final int DDPF_PALETTEINDEXEDTO8 = 0x00000010; // Surface is indexed into a palette which stores indices // into the destination surface's 8-bit palette private static final int DDPF_PALETTEINDEXED8 = 0x00000020; // Surface is 8-bit color indexed //Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks (dwRBitMask, dwRBitMask, dwRBitMask) contain valid data. private static final int DDPF_RGB = 0x00000040; // RGB data is present private static final int DDPF_COMPRESSED = 0x00000080; // Surface will accept pixel data in the format specified // and compress it during the write private static final int DDPF_RGBTOYUV = 0x00000100; // Surface will accept RGB data and translate it during // the write to YUV data. The format of the data to be written // will be contained in the pixel format structure. The DDPF_RGB // flag will be set. private static final int DDPF_YUV = 0x00000200; // Pixel format is YUV - YUV data in pixel format struct is valid private static final int DDPF_ZBUFFER = 0x00000400; // Pixel format is a z buffer only surface private static final int DDPF_PALETTEINDEXED1 = 0x00000800; // Surface is 1-bit color indexed private static final int DDPF_PALETTEINDEXED2 = 0x00001000; // Surface is 2-bit color indexed private static final int DDPF_ZPIXELS = 0x00002000; // Surface contains Z information in the pixels //Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count; // dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file. private static final int DDPF_LUMINANCE = 0x20000; // Selected bits in DDS capabilities flags private static final int DDSCAPS_TEXTURE = 0x00001000; // Can be used as a texture private static final int DDSCAPS_MIPMAP = 0x00400000; // Is one level of a mip-map private static final int DDSCAPS_COMPLEX = 0x00000008; // Selected bits in DDS extended capabilities flags private static final int DDSCAPS2_CUBEMAP = 0x00000200; private static final int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400; private static final int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800; private static final int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000; private static final int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000; private static final int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000; private static final int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000; // Known pixel formats private static final int D3DFMT_UNKNOWN = 0; public static final int D3DFMT_R8G8B8 = 20; public static final int D3DFMT_A8R8G8B8 = 21; public static final int D3DFMT_X8R8G8B8 = 22; // The following are also valid FourCC codes public static final int D3DFMT_DXT1 = 0x31545844; private static final int D3DFMT_DXT2 = 0x32545844; public static final int D3DFMT_DXT3 = 0x33545844; private static final int D3DFMT_DXT4 = 0x34545844; public static final int D3DFMT_DXT5 = 0x35545844; private static ByteBuffer buf = null; public static ImageInfo info[] = null; private DDsImages() { } public static final ImageInfo[] read( String filename ) throws Exception { final int MAGIC = 0x20534444; InputStream in = null; buf = null; info = null; String error = ""; try { // Normal InputStream from jar or filesystem in = DDsImages.class.getResourceAsStream(filename); // If not found in jar, then load from disk if ( in == null) in = new FileInputStream( filename ); if ( in instanceof FileInputStream ) { File file = new File(filename); int size = (int)file.length(); byte buffer[] = new byte[size]; ((FileInputStream)in).read( buffer, 0, size); buf = ByteBuffer.allocateDirect( size ).order(ByteOrder.nativeOrder()); buf.put(buffer).clear(); buffer = null; } else buf = ByteBuffer.allocateDirect( in.available() ).order(ByteOrder.nativeOrder()); if ( MAGIC!=buf.getInt() ) throw new Exception("No dds file format"); // size of the DDSURFACEDESC structure without magic, also -4 size = buf.getInt(); // determines what fields are valid flags = buf.getInt(); // height of surface to be created height = buf.getInt(); // width of surface to be created width = buf.getInt(); pitchOrLinearSize = buf.getInt(); backBufferCountOrDepth = buf.getInt(); // number of mip-map levels requested mipMapCountOrAux = buf.getInt(); // depth of alpha buffer requested alphaBitDepth = buf.getInt(); reserved1 = buf.getInt(); // pointer to the associated surface memory surface = buf.getInt(); // two entries are for color for empty cubemap faces colorSpaceLowValue = buf.getInt(); colorSpaceHighValue = buf.getInt(); destBltColorSpaceLowValue = buf.getInt(); destBltColorSpaceHighValue = buf.getInt(); srcOverlayColorSpaceLowValue = buf.getInt(); srcOverlayColorSpaceHighValue = buf.getInt(); srcBltColorSpaceLowValue = buf.getInt(); srcBltColorSpaceHighValue = buf.getInt(); // size of DDPIXELFORMAT structure pfSize = buf.getInt(); // pixel format flags pfFlags = buf.getInt(); // (FOURCC code) pfFourCC = buf.getInt(); // how many bits per pixel pfRGBBitCount = buf.getInt(); // mask for red bits pfRBitMask = buf.getInt(); // mask for green bits pfGBitMask = buf.getInt(); // mask for blue bits pfBBitMask = buf.getInt(); // mask for alpha channel pfABitMask = buf.getInt(); // Texture and mip-map flags ddsCaps1 = buf.getInt(); // Advanced capabilities ddsCaps2 = buf.getInt(); ddsCaps3 = buf.getInt(); ddsCaps4 = buf.getInt(); // stage in multitexture cascade textureStage = buf.getInt(); } catch( Exception e) { error = "Error -> "+e.getMessage(); } finally { if ( in!=null ) { try { in.close(); } catch (IOException e) { } } } if ( error.length()>0 ) throw new Exception(error); int maps = mipMapCountOrAux; int i; try { if ( isCubemap() ) { if ( maps==0 ) maps++; info = new ImageInfo[maps*6]; int j = 0; for ( i=0; i<maps; i++ ) info[i] = getCubeMipMaps( DDSCAPS2_CUBEMAP_NEGATIVEX, i ); j = i; for ( i=0; i<maps; i++ ) info[j+i] = getCubeMipMaps( DDSCAPS2_CUBEMAP_POSITIVEX, i ); j += i; for ( i=0; i<maps; i++ ) info[j+i] = getCubeMipMaps( DDSCAPS2_CUBEMAP_NEGATIVEY, i ); j += i; for ( i=0; i<maps; i++ ) info[j+i] = getCubeMipMaps( DDSCAPS2_CUBEMAP_POSITIVEY, i ); j += i; for ( i=0; i<maps; i++ ) info[j+i] = getCubeMipMaps( DDSCAPS2_CUBEMAP_NEGATIVEZ, i ); j += i; for ( i=0; i<maps; i++ ) info[j+i] = getCubeMipMaps( DDSCAPS2_CUBEMAP_POSITIVEZ, i ); } else { if ( maps==0 ) { info = new ImageInfo[1]; info[0] = getMipMap( ); } else { info = new ImageInfo[maps]; for ( i=0; i<maps; i++ ) info[i] = getMipMaps( i ); } } buf = null; return info; } catch( Exception e) { buf = null; throw new Exception("Error -> "+e.getMessage()); } } /** * Gets the ithe mipmap data (0..getNumMipMaps() - 1) * @param side Cubemap side or 0 for 2D texture * @param map Mipmap index * @return Image object */ private static ImageInfo getCubeMipMaps( int side, int map ) throws Exception { if ( !isCubemap() && ( side != 0 ) ) throw new Exception( "Illegal side for 2D texture: " + side ); if ( isCubemap() && !isCubemapSidePresent( side ) ) throw new Exception( "Illegal side, side not present: " + side ); if ( mipMapCountOrAux>0 && ( map<0 || map >=mipMapCountOrAux ) ) throw new Exception( "Illegal mipmap number " + map + " (0.." + ( mipMapCountOrAux - 1 ) + ")" ); int seek = 128; if ( isCubemap() ) seek += sideShiftInBytes( side ); for( int i = 0; i < map; i++ ) seek += mipMapSizeInBytes( i ); buf.limit( seek + mipMapSizeInBytes( map ) ); buf.position( seek ); ByteBuffer next = buf.slice(); if ( !isCompressed() ) { int bytesPerPixel = 3; if ( getPixelOrCompressionsFormat()==D3DFMT_A8R8G8B8 ) bytesPerPixel = 4; // colors are not in the right format for correct // display in opengl int k = next.capacity(); byte g,b; if ( bytesPerPixel==3 ) { for ( int i=0; i<k; i+=3 ) { g = next.get(i); b = next.get(i+2); next.put( i, b ); next.put(i+2, g); } } else { for ( int i=0; i<k; i+=4 ) { g = next.get(i); b = next.get(i+2); next.put( i, b ); next.put(i+2, g); } } next.clear(); } buf.position( 0 ); buf.limit( buf.capacity() ); return new ImageInfo( next, mipMapWidth( map ), mipMapHeight( map ), isCompressed(), getPixelOrCompressionsFormat() ); } /** * Gets the <i>ithe mipmap data (0..getNumMipMaps() - 1) * @param map Mipmap index * @return Image object */ private static ImageInfo getMipMaps( int map ) throws Exception { int seek = 128; for( int i = 0; i < map; i++ ) seek += mipMapSizeInBytes( i ); buf.limit( seek + mipMapSizeInBytes( map ) ); buf.position( seek ); ByteBuffer next = buf.slice(); if ( !isCompressed() ) { int bytesPerPixel = 3; if ( getPixelOrCompressionsFormat()==D3DFMT_A8R8G8B8 ) bytesPerPixel = 4; // colors are not in the right format for correct // display in opengl int k = next.capacity(); byte g,b; if ( bytesPerPixel==3 ) { for ( int i=0; i<k; i+=3 ) { g = next.get(i); b = next.get(i+2); next.put( i, b ); next.put(i+2, g); } } else { for ( int i=0; i<k; i+=4 ) { g = next.get(i); b = next.get(i+2); next.put( i, b ); next.put(i+2, g); } } next.clear(); } buf.position( 0 ); buf.limit( buf.capacity() ); return new ImageInfo( next, mipMapWidth( map ), mipMapHeight( map ), isCompressed(), getPixelOrCompressionsFormat() ); } private static ImageInfo getMipMap( ) throws Exception { int seek = 128; buf.position( seek ); ByteBuffer next = buf.slice(); if ( !isCompressed() ) { int bytesPerPixel = 3; if ( getPixelOrCompressionsFormat()==D3DFMT_A8R8G8B8 ) bytesPerPixel = 4; // colors are not in the right format for correct // display in opengl int k = next.capacity(); byte g,b; if ( bytesPerPixel==3 ) { for ( int i=0; i<k; i+=3 ) { g = next.get(i); b = next.get(i+2); next.put( i, b ); next.put(i+2, g); } } else { for ( int i=0; i<k; i+=4 ) { g = next.get(i); b = next.get(i+2); next.put( i, b ); next.put(i+2, g); } } next.clear(); } return new ImageInfo( next, width, height, isCompressed(), getPixelOrCompressionsFormat() ); } public static class ImageInfo { private ByteBuffer data; private int width; private int height; private boolean isCompressed; private int compressionFormat; private boolean cubemap = false; public ImageInfo( ByteBuffer _data, int _width, int _height, boolean _compressed, int _compressionFormat ) { data = _data; width = _width; height = _height; isCompressed = _compressed; compressionFormat = _compressionFormat; cubemap = isCubemap(); } public int getWidth() { return width; } public int getHeight() { return height; } public ByteBuffer getData() { return data; } public boolean isCubemap() { return cubemap; } public boolean isCompressed() { return isCompressed; } public int getCompressionFormat() { return compressionFormat; } } public static final boolean isCompressed() { return (( pfFlags & DDPF_FOURCC ) != 0 ); } /** * Width of the texture (or the top-most mipmap if mipmaps are * present) */ public static final int getWidth() { return width; } /** * Height of the texture (or the top-most mipmap if mipmaps are * present) */ public static final int getHeight() { return height; } /** * Total number of bits per pixel. Only valid if DDPF_RGB is * present. For A8R8G8B8, would be 32. */ public static final int getDepth() { return pfRGBBitCount; } /** * Number of mip maps in the texture */ public static final int getNumMipMaps() { return mipMapCountOrAux; } /** * Indicates whether this texture is cubemap * @return true if cubemap or false otherwise */ public static final boolean isCubemap() { return ( ( ddsCaps1 & DDSCAPS_COMPLEX ) != 0 ) && ( ( ddsCaps2 & DDSCAPS2_CUBEMAP ) != 0 ); } /** * Indicates whethe this cubemap side present * @param side Side to test * @return true if side present or false otherwise */ public static boolean isCubemapSidePresent( int side ) { return (isCubemap() && ( ddsCaps2 & side ) != 0); } public static final int getPixelOrCompressionsFormat() { if( ( pfFlags & DDPF_FOURCC ) != 0 ) return pfFourCC; else { if( ( pfFlags & DDPF_RGB ) != 0 ) { if( getDepth() == 32 && (pfRBitMask==0x00FF0000) && (pfGBitMask==0x0000FF00) && (pfBBitMask==0x000000FF) && (pfABitMask == 0xFF000000) ) return D3DFMT_A8R8G8B8; else { if( getDepth() == 24 && (pfRBitMask==0x00FF0000) && (pfGBitMask==0x0000FF00) && (pfBBitMask==0x000000FF) ) return D3DFMT_R8G8B8; else { if( getDepth() == 32 && (pfRBitMask==0x00FF0000) && (pfGBitMask==0x0000FF00) && (pfBBitMask == 0x000000FF) ) return D3DFMT_X8R8G8B8; } } } } return D3DFMT_UNKNOWN; } private static int mipMapWidth( int map ) { int width = getWidth(); for( int i = 0; i < map; i++ ) width >>= 1; if( width <= 0 ) return 1; return width; } private static int mipMapHeight( int map ) { int height = getHeight(); for( int i = 0; i < map; i++ ) height >>= 1; if( height <= 0 ) return 1; return height; } private static int mipMapSizeInBytes( int map ) { int width = mipMapWidth( map ); int height = mipMapHeight( map ); if( isCompressed() ) { int blockSize = ( getPixelOrCompressionsFormat() == D3DFMT_DXT1 ? 8 : 16 ); return ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize; } else return width * height * ( getDepth() / 8 ); } private static int sideSizeInBytes() { int numLevels = getNumMipMaps(); if( numLevels == 0 ) numLevels = 1; int size = 0; for( int i = 0; i < numLevels; i++ ) size += mipMapSizeInBytes( i ); return size; } private static int sideShiftInBytes( int side ) { int[] sides = { DDSCAPS2_CUBEMAP_POSITIVEX, DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY, DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ }; int shift = 0; int sideSize = sideSizeInBytes(); for ( int temp : sides ) { if ( ( temp & side ) != 0 ) return shift; shift += sideSize; } throw new RuntimeException( "Illegal side: " + side ); } } |
Sorry, i forgot something:
After the datas are read with DDsImages.ImageInfo[] info = DDsImages.read(filename); a change must be made to the right opengl pixelformat e.g. // all maps in a cube must have the same pixel or compressed format,so the // following call is correct for all maps int pixelOrCompressionsFormat = info[0].getCompressionFormat() switch(pixelOrCompressionsFormat) { case DDsImages.D3DFMT_DXT1:{ pixelOrCompressionsFormat = GL2.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; compressed = true; };break; case DDsImages.D3DFMT_DXT3:{ pixelOrCompressionsFormat = GL2.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; compressed = true; };break; case DDsImages.D3DFMT_DXT5:{ pixelOrCompressionsFormat = GL2.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; compressed = true; };break; case DDsImages.D3DFMT_A8R8G8B8: { pixelOrCompressionsFormat = GL2.GL_RGBA; compressed = false; };break; case DDsImages.D3DFMT_R8G8B8: case DDsImages.D3DFMT_X8R8G8B8:{ pixelOrCompressionsFormat = GL2.GL_RGB; compressed = false; };break; } |
In reply to this post by Melvin
Hello Melvin,
firstly, thank you for your contribution. However it would be great if you could provide it in form of a patch or even better just fork the git repository on githup and commit it into your own repository. This has several advantages, e.g. the authorship information won't be lost and you will be listed as commiter in the commit history... etc. http://help.github.com/forking/ http://help.github.com/git-email-settings/ + a small test would be nice but i don't want to ask to much :) best regards and thanks again, michael
|
Administrator
|
On Wednesday, May 26, 2010 17:34:16 Michael Bien [via jogamp] wrote:
> > Hello Melvin, > > firstly, thank you for your contribution. > > However it would be great if you could provide it in form of a patch or even > better just fork the git repository on githup and commit it into your own > repository. This has several advantages, e.g. the authorship information > won't be lost and you will be listed as commiter in the commit history... > etc. > > http://help.github.com/forking/ > http://help.github.com/git-email-settings/ > > + a small test would be nice but i don't want to ask to much :) + we need to talk about _where_ this should be submitted which repository, which package. ie could it become a TextureIO element cor com.jogamp.opengl.util.texture ? If not .. shall it be in jogl-utils, which is currently .. well, mostly unmaintained ? A junit test is currently sort of required, IMHO - features only with a junit test are guaranteed to be supported and working, of course. Last but not least, you are reliable that the code complies with our license. So .. the usual obstacles :) ~Sven > > best regards and thanks again, > > michael > > > Melvin wrote: > > > > Hello all > > > > I have had need for a DDS-Reader, who can read a cubemap that resists in a > > single DDS-File. > > ... > > > > > ______________________________________ > View message @ http://jogamp.762907.n3.nabble.com/Cubemap-in-a-single-DDS-File-tp843314p845166.html > To start a new topic under jogamp, email [hidden email] > To unsubscribe from jogamp, click http://jogamp.762907.n3.nabble.com/subscriptions/Unsubscribe.jtp?code=c2dvdGhlbEBqYXVzb2Z0LmNvbXw3NjI5MDd8MzkxNDI4MzU5 > -- health & wealth mailto:[hidden email] ; www : http://www.jausoft.com ; pgp: http://www.jausoft.com/gpg/ land : +49 (471) 4707742 ; cell: +49 (151) 28145941 Timezone CET: PST+9, EST+6, UTC+1 |
Hi Sven
This class is similar to jogls 2.0 "com.sun.opengl.util.texture.spi.DDSImage".I have it changed to make it possible to read cubemaps that are defined in a single .dds file, also i have corrected nasty color errors and errors with mipmaps, so it was now a good tested class. I have puted it in here,so that other can use it. I'm new here ,so that in the moment no git repository. I think the class is good in "com.jogamp.opengl.util.texture". (My english is not so good/perfect) |
Free forum by Nabble | Edit this page |