@ -29,7 +29,6 @@
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
package com.jme3.texture.plugins ;
import com.jme3.asset.AssetInfo ;
@ -62,14 +61,11 @@ public class DDSLoader implements AssetLoader {
private static final Logger logger = Logger . getLogger ( DDSLoader . class . getName ( ) ) ;
private static final boolean forceRGBA = false ;
private static final int DDSD_MANDATORY = 0x1007 ;
private static final int DDSD_MANDATORY_DX10 = 0x6 ;
private static final int DDSD_MIPMAPCOUNT = 0x20000 ;
private static final int DDSD_LINEARSIZE = 0x80000 ;
private static final int DDSD_DEPTH = 0x800000 ;
private static final int DDPF_ALPHAPIXELS = 0x1 ;
private static final int DDPF_FOURCC = 0x4 ;
private static final int DDPF_RGB = 0x40 ;
@ -79,31 +75,24 @@ public class DDSLoader implements AssetLoader {
private static final int DDPF_ALPHA = 0x2 ;
// used by NVTextureTools to mark normal images.
private static final int DDPF_NORMAL = 0x80000000 ;
private static final int SWIZZLE_xGxR = 0x78477852 ;
private static final int DDSCAPS_COMPLEX = 0x8 ;
private static final int DDSCAPS_TEXTURE = 0x1000 ;
private static final int DDSCAPS_MIPMAP = 0x400000 ;
private static final int DDSCAPS2_CUBEMAP = 0x200 ;
private static final int DDSCAPS2_VOLUME = 0x200000 ;
private static final int PF_DXT1 = 0x31545844 ;
private static final int PF_DXT3 = 0x33545844 ;
private static final int PF_DXT5 = 0x35545844 ;
private static final int PF_ATI1 = 0x31495441 ;
private static final int PF_ATI2 = 0x32495441 ; // 0x41544932;
private static final int PF_DX10 = 0x30315844 ; // a DX10 format
private static final int DX10DIM_BUFFER = 0x1 ,
DX10DIM_TEXTURE1D = 0x2 ,
DX10DIM_TEXTURE2D = 0x3 ,
DX10DIM_TEXTURE3D = 0x4 ;
DX10DIM_TEXTURE1D = 0x2 ,
DX10DIM_TEXTURE2D = 0x3 ,
DX10DIM_TEXTURE3D = 0x4 ;
private static final int DX10MISC_GENERATE_MIPS = 0x1 ,
DX10MISC_TEXTURECUBE = 0x4 ;
DX10MISC_TEXTURECUBE = 0x4 ;
private static final double LOG2 = Math . log ( 2 ) ;
private int width ;
private int height ;
@ -115,60 +104,62 @@ public class DDSLoader implements AssetLoader {
private int caps2 ;
private boolean directx10 ;
private boolean compressed ;
private boolean texture3D ;
private boolean grayscaleOrAlpha ;
private boolean normal ;
private Format pixelFormat ;
private int bpp ;
private int [ ] sizes ;
private int redMask , greenMask , blueMask , alphaMask ;
private int redMask , greenMask , blueMask , alphaMask ;
private DataInput in ;
public DDSLoader ( ) {
}
public Object load ( AssetInfo info ) throws IOException {
if ( ! ( info . getKey ( ) instanceof TextureKey ) )
public Object load ( AssetInfo info ) throws IOException {
if ( ! ( info . getKey ( ) instanceof TextureKey ) ) {
throw new IllegalArgumentException ( "Texture assets must be loaded using a TextureKey" ) ;
}
InputStream stream = info . openStream ( ) ;
in = new LittleEndien ( stream ) ;
loadHeader ( ) ;
ArrayList < ByteBuffer > data = readData ( ( ( TextureKey ) info . getKey ( ) ) . isFlipY ( ) ) ;
stream . close ( ) ;
return new Image ( pixelFormat , width , height , 0 , data , sizes ) ;
ArrayList < ByteBuffer > data = readData ( ( ( TextureKey ) info . getKey ( ) ) . isFlipY ( ) ) ;
stream . close ( ) ;
return new Image ( pixelFormat , width , height , depth , data , sizes ) ;
}
public Image load ( InputStream stream ) throws IOException {
public Image load ( InputStream stream ) throws IOException {
in = new LittleEndien ( stream ) ;
loadHeader ( ) ;
ArrayList < ByteBuffer > data = readData ( false ) ;
return new Image ( pixelFormat , width , height , 0 , data , sizes ) ;
return new Image ( pixelFormat , width , height , depth , data , sizes ) ;
}
private void loadDX10Header ( ) throws IOException {
private void loadDX10Header ( ) throws IOException {
int dxgiFormat = in . readInt ( ) ;
if ( dxgiFormat ! = 83 ) {
throw new IOException ( "Only DXGI_FORMAT_BC5_UNORM " +
"is supported for DirectX10 DDS! Got: " + dxgiFormat ) ;
if ( dxgiFormat ! = 83 ) {
throw new IOException ( "Only DXGI_FORMAT_BC5_UNORM "
+ "is supported for DirectX10 DDS! Got: " + dxgiFormat ) ;
}
pixelFormat = Format . LATC ;
bpp = 8 ;
compressed = true ;
int resDim = in . readInt ( ) ;
if ( resDim = = DX10DIM_TEXTURE3D ) {
// mark texture as 3D
if ( resDim = = DX10DIM_TEXTURE3D ) {
texture3D = true ;
}
int miscFlag = in . readInt ( ) ;
int arraySize = in . readInt ( ) ;
if ( is ( miscFlag , DX10MISC_TEXTURECUBE ) ) {
if ( is ( miscFlag , DX10MISC_TEXTURECUBE ) ) {
// mark texture as cube
if ( arraySize ! = 6 ) {
if ( arraySize ! = 6 ) {
throw new IOException ( "Cubemaps should consist of 6 images!" ) ;
}
}
in . skipBytes ( 4 ) ; // skip reserved value
}
@ -185,7 +176,7 @@ public class DDSLoader implements AssetLoader {
if ( ! is ( flags , DDSD_MANDATORY ) & & ! is ( flags , DDSD_MANDATORY_DX10 ) ) {
throw new IOException ( "Mandatory flags missing" ) ;
}
height = in . readInt ( ) ;
width = in . readInt ( ) ;
pitchOrSize = in . readInt ( ) ;
@ -199,17 +190,23 @@ public class DDSLoader implements AssetLoader {
caps2 = in . readInt ( ) ;
in . skipBytes ( 12 ) ;
if ( ! directx10 ) {
if ( ! directx10 ) {
if ( ! is ( caps1 , DDSCAPS_TEXTURE ) ) {
throw new IOException ( "File is not a texture" ) ;
}
if ( depth < = 0 )
if ( depth < = 0 ) {
depth = 1 ;
}
if ( is ( caps2 , DDSCAPS2_CUBEMAP ) ) {
depth = 6 ; // somewhat of a hack, force loading 6 textures if a cubemap
}
if ( is ( caps2 , DDSCAPS2_VOLUME ) ) {
texture3D = true ;
}
}
int expectedMipmaps = 1 + ( int ) Math . ceil ( Math . log ( Math . max ( height , width ) ) / LOG2 ) ;
@ -220,14 +217,14 @@ public class DDSLoader implements AssetLoader {
} else if ( mipMapCount ! = expectedMipmaps ) {
// changed to warning- images often do not have the required amount,
// or specify that they have mipmaps but include only the top level..
logger . log ( Level . WARNING , "Got {0} mipmaps, expected {1}" ,
logger . log ( Level . WARNING , "Got {0} mipmaps, expected {1}" ,
new Object [ ] { mipMapCount , expectedMipmaps } ) ;
}
} else {
mipMapCount = 1 ;
}
if ( directx10 ) {
if ( directx10 ) {
loadDX10Header ( ) ;
}
@ -268,7 +265,7 @@ public class DDSLoader implements AssetLoader {
case PF_DXT5 :
bpp = 8 ;
pixelFormat = Image . Format . DXT5 ;
if ( swizzle = = SWIZZLE_xGxR ) {
if ( swizzle = = SWIZZLE_xGxR ) {
normal = true ;
}
break ;
@ -297,7 +294,7 @@ public class DDSLoader implements AssetLoader {
logger . warning ( "Must use linear size with fourcc" ) ;
pitchOrSize = size ;
} else if ( pitchOrSize ! = size ) {
logger . log ( Level . WARNING , "Expected size = {0}, real = {1}" ,
logger . log ( Level . WARNING , "Expected size = {0}, real = {1}" ,
new Object [ ] { size , pitchOrSize } ) ;
}
} else {
@ -321,7 +318,7 @@ public class DDSLoader implements AssetLoader {
} else {
pixelFormat = Format . RGB8 ;
}
} else if ( is ( pfFlags , DDPF_GRAYSCALE ) & & is ( pfFlags , DDPF_ALPHAPIXELS ) ) {
} else if ( is ( pfFlags , DDPF_GRAYSCALE ) & & is ( pfFlags , DDPF_ALPHAPIXELS ) ) {
switch ( bpp ) {
case 16 :
pixelFormat = Format . Luminance8Alpha8 ;
@ -368,7 +365,7 @@ public class DDSLoader implements AssetLoader {
logger . warning ( "Linear size said to contain valid value but does not" ) ;
pitchOrSize = size ;
} else if ( pitchOrSize ! = size ) {
logger . log ( Level . WARNING , "Expected size = {0}, real = {1}" ,
logger . log ( Level . WARNING , "Expected size = {0}, real = {1}" ,
new Object [ ] { size , pitchOrSize } ) ;
}
} else {
@ -464,9 +461,9 @@ public class DDSLoader implements AssetLoader {
* /
public ByteBuffer readRGB2D ( boolean flip , int totalSize ) throws IOException {
int redCount = count ( redMask ) ,
blueCount = count ( blueMask ) ,
greenCount = count ( greenMask ) ,
alphaCount = count ( alphaMask ) ;
blueCount = count ( blueMask ) ,
greenCount = count ( greenMask ) ,
alphaCount = count ( alphaMask ) ;
if ( redMask = = 0x00FF0000 & & greenMask = = 0x0000FF00 & & blueMask = = 0x000000FF ) {
if ( alphaMask = = 0xFF000000 & & bpp = = 32 ) {
@ -536,23 +533,20 @@ public class DDSLoader implements AssetLoader {
int mipWidth = width ;
int mipHeight = height ;
int offset = 0 ;
for ( int mip = 0 ; mip < mipMapCount ; mip + + ) {
if ( flip ) {
if ( flip ) {
byte [ ] data = new byte [ sizes [ mip ] ] ;
in . readFully ( data ) ;
ByteBuffer wrapped = ByteBuffer . wrap ( data ) ;
wrapped . rewind ( ) ;
ByteBuffer flipped = DXTFlipper . flipDXT ( wrapped , mipWidth , mipHeight , pixelFormat ) ;
buffer . put ( flipped ) ;
} else {
} else {
byte [ ] data = new byte [ sizes [ mip ] ] ;
in . readFully ( data ) ;
buffer . put ( data ) ;
}
offset + = sizes [ mip ] ;
mipWidth = Math . max ( mipWidth / 2 , 1 ) ;
mipHeight = Math . max ( mipHeight / 2 , 1 ) ;
}
@ -561,6 +555,153 @@ public class DDSLoader implements AssetLoader {
return buffer ;
}
/ * *
* Reads a grayscale image with mipmaps from the InputStream
* @param flip Flip the loaded image by Y axis
* @param totalSize Total size of the image in bytes including the mipmaps
* @return A ByteBuffer containing the grayscale image data with mips .
* @throws java . io . IOException If an error occured while reading from InputStream
* /
public ByteBuffer readGrayscale3D ( boolean flip , int totalSize ) throws IOException {
ByteBuffer buffer = BufferUtils . createByteBuffer ( totalSize * depth ) ;
if ( bpp = = 8 ) {
logger . finest ( "Source image format: R8" ) ;
}
assert bpp = = pixelFormat . getBitsPerPixel ( ) ;
for ( int i = 0 ; i < depth ; i + + ) {
int mipWidth = width ;
int mipHeight = height ;
for ( int mip = 0 ; mip < mipMapCount ; mip + + ) {
byte [ ] data = new byte [ sizes [ mip ] ] ;
in . readFully ( data ) ;
if ( flip ) {
data = flipData ( data , mipWidth * bpp / 8 , mipHeight ) ;
}
buffer . put ( data ) ;
mipWidth = Math . max ( mipWidth / 2 , 1 ) ;
mipHeight = Math . max ( mipHeight / 2 , 1 ) ;
}
}
buffer . rewind ( ) ;
return buffer ;
}
/ * *
* Reads an uncompressed RGB or RGBA image .
*
* @param flip Flip the image on the Y axis
* @param totalSize Size of the image in bytes including mipmaps
* @return ByteBuffer containing image data with mipmaps in the format specified by pixelFormat_
* @throws java . io . IOException If an error occured while reading from InputStream
* /
public ByteBuffer readRGB3D ( boolean flip , int totalSize ) throws IOException {
int redCount = count ( redMask ) ,
blueCount = count ( blueMask ) ,
greenCount = count ( greenMask ) ,
alphaCount = count ( alphaMask ) ;
if ( redMask = = 0x00FF0000 & & greenMask = = 0x0000FF00 & & blueMask = = 0x000000FF ) {
if ( alphaMask = = 0xFF000000 & & bpp = = 32 ) {
logger . finest ( "Data source format: BGRA8" ) ;
} else if ( bpp = = 24 ) {
logger . finest ( "Data source format: BGR8" ) ;
}
}
int sourcebytesPP = bpp / 8 ;
int targetBytesPP = pixelFormat . getBitsPerPixel ( ) / 8 ;
ByteBuffer dataBuffer = BufferUtils . createByteBuffer ( totalSize * depth ) ;
for ( int k = 0 ; k < depth ; k + + ) {
// ByteBuffer dataBuffer = BufferUtils.createByteBuffer(totalSize);
int mipWidth = width ;
int mipHeight = height ;
int offset = k * totalSize ;
byte [ ] b = new byte [ sourcebytesPP ] ;
for ( int mip = 0 ; mip < mipMapCount ; mip + + ) {
for ( int y = 0 ; y < mipHeight ; y + + ) {
for ( int x = 0 ; x < mipWidth ; x + + ) {
in . readFully ( b ) ;
int i = byte2int ( b ) ;
byte red = ( byte ) ( ( ( i & redMask ) > > redCount ) ) ;
byte green = ( byte ) ( ( ( i & greenMask ) > > greenCount ) ) ;
byte blue = ( byte ) ( ( ( i & blueMask ) > > blueCount ) ) ;
byte alpha = ( byte ) ( ( ( i & alphaMask ) > > alphaCount ) ) ;
if ( flip ) {
dataBuffer . position ( offset + ( ( mipHeight - y - 1 ) * mipWidth + x ) * targetBytesPP ) ;
}
//else
// dataBuffer.position(offset + (y * width + x) * targetBytesPP);
if ( alphaMask = = 0 ) {
dataBuffer . put ( red ) . put ( green ) . put ( blue ) ;
} else {
dataBuffer . put ( red ) . put ( green ) . put ( blue ) . put ( alpha ) ;
}
}
}
offset + = ( mipWidth * mipHeight * targetBytesPP ) ;
mipWidth = Math . max ( mipWidth / 2 , 1 ) ;
mipHeight = Math . max ( mipHeight / 2 , 1 ) ;
}
}
dataBuffer . rewind ( ) ;
return dataBuffer ;
}
/ * *
* Reads a DXT compressed image from the InputStream
*
* @param totalSize Total size of the image in bytes , including mipmaps
* @return ByteBuffer containing compressed DXT image in the format specified by pixelFormat_
* @throws java . io . IOException If an error occured while reading from InputStream
* /
public ByteBuffer readDXT3D ( boolean flip , int totalSize ) throws IOException {
logger . finest ( "Source image format: DXT" ) ;
ByteBuffer bufferAll = BufferUtils . createByteBuffer ( totalSize * depth ) ;
for ( int i = 0 ; i < depth ; i + + ) {
ByteBuffer buffer = BufferUtils . createByteBuffer ( totalSize ) ;
int mipWidth = width ;
int mipHeight = height ;
for ( int mip = 0 ; mip < mipMapCount ; mip + + ) {
if ( flip ) {
byte [ ] data = new byte [ sizes [ mip ] ] ;
in . readFully ( data ) ;
ByteBuffer wrapped = ByteBuffer . wrap ( data ) ;
wrapped . rewind ( ) ;
ByteBuffer flipped = DXTFlipper . flipDXT ( wrapped , mipWidth , mipHeight , pixelFormat ) ;
flipped . rewind ( ) ;
buffer . put ( flipped ) ;
} else {
byte [ ] data = new byte [ sizes [ mip ] ] ;
in . readFully ( data ) ;
buffer . put ( data ) ;
}
mipWidth = Math . max ( mipWidth / 2 , 1 ) ;
mipHeight = Math . max ( mipHeight / 2 , 1 ) ;
}
buffer . rewind ( ) ;
bufferAll . put ( buffer ) ;
}
return bufferAll ;
}
/ * *
* Reads the image data from the InputStream in the required format .
* If the file contains a cubemap image , it is loaded as 6 ByteBuffers
@ -583,19 +724,28 @@ public class DDSLoader implements AssetLoader {
}
ArrayList < ByteBuffer > allMaps = new ArrayList < ByteBuffer > ( ) ;
if ( depth > 1 ) {
for ( int i = 0 ; i < depth ; i + + ) {
if ( depth > 1 & & ! texture3D ) {
for ( int i = 0 ; i < depth ; i + + ) {
if ( compressed ) {
allMaps . add ( readDXT2D ( flip , totalSize ) ) ;
allMaps . add ( readDXT2D ( flip , totalSize ) ) ;
} else if ( grayscaleOrAlpha ) {
allMaps . add ( readGrayscale2D ( flip , totalSize ) ) ;
} else {
allMaps . add ( readRGB2D ( flip , totalSize ) ) ;
}
}
} else if ( texture3D ) {
if ( compressed ) {
allMaps . add ( readDXT3D ( flip , totalSize ) ) ;
} else if ( grayscaleOrAlpha ) {
allMaps . add ( readGrayscale3D ( flip , totalSize ) ) ;
} else {
allMaps . add ( readRGB3D ( flip , totalSize ) ) ;
}
} else {
if ( compressed ) {
allMaps . add ( readDXT2D ( flip , totalSize ) ) ;
allMaps . add ( readDXT2D ( flip , totalSize ) ) ;
} else if ( grayscaleOrAlpha ) {
allMaps . add ( readGrayscale2D ( flip , totalSize ) ) ;
} else {