001/**
002 * Copyright (c) 2008-2014 Ardor Labs, Inc.
003 *
004 * This file is part of Ardor3D.
005 *
006 * Ardor3D is free software: you can redistribute it and/or modify it 
007 * under the terms of its license which may be found in the accompanying
008 * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
009 */
010
011package com.ardor3d.image.util.dds;
012
013import static com.ardor3d.image.util.dds.DdsUtils.isSet;
014
015import java.io.IOException;
016import java.util.logging.Logger;
017
018import com.ardor3d.util.LittleEndianDataInput;
019
020class DdsHeader {
021    private static final Logger logger = Logger.getLogger(DdsHeader.class.getName());
022
023    // ---- VALUES USED IN dwFlags ----
024    // Required caps flag.
025    final static int DDSD_CAPS = 0x1;
026    // Required caps flag.
027    final static int DDSD_HEIGHT = 0x2;
028    // Required caps flag.
029    final static int DDSD_WIDTH = 0x4;
030    // Required when pitch is provided for an uncompressed texture.
031    final static int DDSD_PITCH = 0x8;
032    // Required caps flag.
033    final static int DDSD_PIXELFORMAT = 0x1000;
034    // Required in a mipmapped texture.
035    final static int DDSD_MIPMAPCOUNT = 0x20000;
036    // Required when pitch is provided for a compressed texture.
037    final static int DDSD_LINEARSIZE = 0x80000;
038    // Required in a depth texture.
039    final static int DDSD_DEPTH = 0x800000;
040    // ---- /end VALUES USED IN dwFlags ----
041
042    // ---- VALUES USED IN dwCaps ----
043    // Optional; must be used on any file that contains more than one surface (a mipmap, a cubic environment map, or
044    // volume texture).
045    final static int DDSCAPS_COMPLEX = 0x8;
046    // Optional; should be used for a mipmap.
047    final static int DDSCAPS_MIPMAP = 0x400000;
048    // Required caps flag.
049    final static int DDSCAPS_TEXTURE = 0x1000;
050    // ---- /end VALUES USED IN dwCaps ----
051
052    // ---- VALUES USED IN dwCaps2 ----
053    // Required for a cube map.
054    final static int DDSCAPS2_CUBEMAP = 0x200;
055    // Required when these surfaces are stored in a cube map.
056    final static int DDSCAPS2_CUBEMAP_POSITIVEX = 0x400;
057    // Required when these surfaces are stored in a cube map.
058    final static int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800;
059    // Required when these surfaces are stored in a cube map.
060    final static int DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000;
061    // Required when these surfaces are stored in a cube map.
062    final static int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000;
063    // Required when these surfaces are stored in a cube map.
064    final static int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000;
065    // Required when these surfaces are stored in a cube map.
066    final static int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000;
067    // Required for a volume texture.
068    final static int DDSCAPS2_VOLUME = 0x200000;
069    // ---- /end VALUES USED IN dwCaps2 ----
070
071    int dwSize;
072    int dwFlags;
073    int dwHeight;
074    int dwWidth;
075    int dwLinearSize;
076    int dwDepth;
077    int dwMipMapCount;
078    int dwAlphaBitDepth;
079    int[] dwReserved1 = new int[10];
080    DdsPixelFormat ddpf;
081    int dwCaps;
082    int dwCaps2;
083    int dwCaps3;
084    int dwCaps4;
085    int dwTextureStage;
086
087    static DdsHeader read(final LittleEndianDataInput in) throws IOException {
088        final DdsHeader header = new DdsHeader();
089        header.dwSize = in.readInt();
090        if (header.dwSize != 124) {
091            throw new Error("invalid dds header size: " + header.dwSize);
092        }
093        header.dwFlags = in.readInt();
094        header.dwHeight = in.readInt();
095        header.dwWidth = in.readInt();
096        header.dwLinearSize = in.readInt();
097        header.dwDepth = in.readInt();
098        header.dwMipMapCount = in.readInt();
099        header.dwAlphaBitDepth = in.readInt();
100        for (int i = 0; i < header.dwReserved1.length; i++) {
101            header.dwReserved1[i] = in.readInt();
102        }
103        header.ddpf = DdsPixelFormat.read(in);
104        header.dwCaps = in.readInt();
105        header.dwCaps2 = in.readInt();
106        header.dwCaps3 = in.readInt();
107        header.dwCaps4 = in.readInt();
108        header.dwTextureStage = in.readInt();
109
110        final int expectedMipmaps = 1 + (int) Math.ceil(Math.log(Math.max(header.dwHeight, header.dwWidth))
111                / Math.log(2));
112
113        if (isSet(header.dwCaps, DDSCAPS_MIPMAP)) {
114            if (!isSet(header.dwFlags, DDSD_MIPMAPCOUNT)) {
115                header.dwMipMapCount = expectedMipmaps;
116            } else if (header.dwMipMapCount != expectedMipmaps) {
117                logger.fine("Got " + header.dwMipMapCount + " mipmaps, expected " + expectedMipmaps);
118            }
119        } else {
120            header.dwMipMapCount = 1;
121        }
122
123        return header;
124    }
125}