📄 ddsloader.java
字号:
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* 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.jme.image.util;
import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import com.jme.image.Image;
import com.jme.image.Image.Format;
import com.jme.util.LittleEndien;
import com.jme.util.geom.BufferUtils;
import java.util.ArrayList;
import java.util.logging.Logger;
/**
*
* <code>DDSLoader</code> is an image loader that reads in a DirectX DDS file.
* Supports DXT1, DXT3, DXT5, RGB, RGBA, Grayscale, Alpha pixel formats.
* 2D images, mipmapped 2D images, and cubemaps.
*
* @author Gareth Jenkins-Jones
* @author Kirill Vainer
* @version $Id: DDSLoader.java,v 2.0 2008/8/15
*/
public final class DDSLoader {
private static final Logger logger = Logger.getLogger(DDSLoader.class.getName());
private DDSLoader() {
}
public static Image loadImage(InputStream fis) throws IOException {
return loadImage(fis, false);
}
public static Image loadImage(InputStream fis, boolean flip) throws IOException {
DDSReader reader = new DDSReader(fis);
reader.loadHeader();
ArrayList<ByteBuffer> data = reader.readData(flip);
return new Image(reader.pixelFormat_, reader.width_, reader.height_, 0, data, reader.sizes_);
}
/**
* DDS reader
*
* @author Gareth
*/
public static class DDSReader {
private static final int DDSD_MANDATORY = 0x1007;
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;
// used by compressonator to mark grayscale images, red channel mask is used for data and bitcount is 8
private static final int DDPF_GRAYSCALE = 0x20000;
// used by compressonator to mark alpha images, alpha channel mask is used for data and bitcount is 8
private static final int DDPF_ALPHA = 0x2;
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 double LOG2 = Math.log(2);
private int width_;
private int height_;
private int depth_; // currently unused
private int flags_;
private int pitchOrSize_;
private int mipMapCount_;
private int caps1_;
private int caps2_;
private boolean compressed_;
private boolean grayscaleOrAlpha_;
private Image.Format pixelFormat_;
private int bpp_;
private int[] sizes_;
private int redMask_, greenMask_, blueMask_, alphaMask_;
private DataInput in_;
public DDSReader(InputStream in) {
in_ = new LittleEndien(in);
}
/**
* Reads the header (first 128 bytes) of a DDS File
*/
public void loadHeader() throws IOException {
if (in_.readInt() != 0x20534444 || in_.readInt() != 124) {
throw new IOException("Not a DDS file");
}
flags_ = in_.readInt();
if (!is(flags_, DDSD_MANDATORY)) {
throw new IOException("Mandatory flags missing");
}
if (is(flags_, DDSD_DEPTH)) {
throw new IOException("Depth not supported");
}
height_ = in_.readInt();
width_ = in_.readInt();
pitchOrSize_ = in_.readInt();
depth_ = in_.readInt();
mipMapCount_ = in_.readInt();
in_.skipBytes(44);
readPixelFormat();
caps1_ = in_.readInt();
caps2_ = in_.readInt();
in_.skipBytes(12);
if (!is(caps1_, DDSCAPS_TEXTURE)) {
throw new IOException("File is not a texture");
}
if (is(caps2_, DDSCAPS2_VOLUME)) {
throw new IOException("Volume textures not supported");
}else{
depth_ = 0;
}
int expectedMipmaps = 1 + (int) Math.ceil(Math.log(Math.max(height_, width_)) / LOG2);
if (is(caps1_, DDSCAPS_MIPMAP)) {
if (!is(flags_, DDSD_MIPMAPCOUNT)) {
mipMapCount_ = expectedMipmaps;
} 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.warning("Got " + mipMapCount_ + "mipmaps, expected" + expectedMipmaps);
}
} else {
mipMapCount_ = 1;
}
loadSizes();
}
/**
* Reads the PixelFormat structure in a DDS file
*/
private void readPixelFormat() throws IOException {
int pfSize = in_.readInt();
if (pfSize != 32) {
throw new IOException("Pixel format size is " + pfSize
+ ", not 32");
}
int flags = in_.readInt();
if (is(flags, DDPF_FOURCC)) {
compressed_ = true;
int fourcc = in_.readInt();
in_.skipBytes(20);
switch (fourcc) {
case PF_DXT1:
bpp_ = 4;
if (is(flags, DDPF_ALPHAPIXELS)) {
pixelFormat_ = Image.Format.NativeDXT1A;
} else {
pixelFormat_ = Image.Format.NativeDXT1;
}
break;
case PF_DXT3:
bpp_ = 8;
pixelFormat_ = Image.Format.NativeDXT3;
break;
case PF_DXT5:
bpp_ = 8;
pixelFormat_ = Image.Format.NativeDXT5;
break;
default:
throw new IOException("Unknown fourcc: " + string(fourcc));
}
int size = ((width_ + 3) / 4) * ((height_ + 3) / 4) * bpp_ * 2;
if (is(flags_, DDSD_LINEARSIZE)) {
if (pitchOrSize_ == 0) {
logger.warning("Must use linear size with fourcc");
pitchOrSize_ = size;
} else if (pitchOrSize_ != size) {
logger.warning("Expected size = " + size + ", real = " + pitchOrSize_);
}
} else {
pitchOrSize_ = size;
}
} else {
compressed_ = false;
// skip fourCC
in_.readInt();
bpp_ = in_.readInt();
redMask_ = in_.readInt();
greenMask_ = in_.readInt();
blueMask_ = in_.readInt();
alphaMask_ = in_.readInt();
if (is(flags, DDPF_RGB)){
if (is(flags, DDPF_ALPHAPIXELS)){
pixelFormat_ = Format.RGBA8;
}else{
pixelFormat_ = Format.RGB8;
}
}else if (is(flags, DDPF_GRAYSCALE)){
switch (bpp_){
case 4: pixelFormat_ = Format.Luminance4; break;
case 8: pixelFormat_ = Format.Luminance8; break;
case 12: pixelFormat_ = Format.Luminance12; break;
case 16: pixelFormat_ = Format.Luminance16; break;
default: throw new IOException("Unsupported Grayscale BPP: "+bpp_);
}
grayscaleOrAlpha_ = true;
}else if (is(flags, DDPF_ALPHA)){
switch (bpp_){
case 4: pixelFormat_ = Format.Alpha4; break;
case 8: pixelFormat_ = Format.Alpha8; break;
case 12: pixelFormat_ = Format.Alpha12; break;
case 16: pixelFormat_ = Format.Alpha16; break;
default: throw new IOException("Unsupported Alpha BPP: "+bpp_);
}
grayscaleOrAlpha_ = true;
}else{
throw new IOException("Unknown PixelFormat in DDS file");
}
int size = (bpp_ / 8 * width_);
if (is(flags_, DDSD_LINEARSIZE)) {
if (pitchOrSize_ == 0) {
logger.warning("Linear size said to contain valid value but does not");
pitchOrSize_ = size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -