mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-10 16:00:46 +00:00
Implementation of sRGB image support. Overhauls the linearization setup to utilize the sRGB image types, as well as refactors the use of ColorF and ColorI to be properly internally consistent. ColorIs are used only for front-facing/editing/UI settings, and ColorFs, now renamed to LinearColorF to reduce confusion of purpose, are used for color info in the engine itself. This avoids confusing and expensive conversions back and forth between types and avoids botches with linearity. Majority work done by @rextimmy
This commit is contained in:
parent
8780f83262
commit
25686ed4be
294 changed files with 3894 additions and 2813 deletions
779
Engine/source/gfx/bitmap/ddsData.h
Normal file
779
Engine/source/gfx/bitmap/ddsData.h
Normal file
|
|
@ -0,0 +1,779 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// https://github.com/Microsoft/DirectXTex
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _DDSDATA_H_
|
||||
#define _DDSDATA_H_
|
||||
|
||||
#ifndef _TORQUE_TYPES_H_
|
||||
#include "platform/types.h"
|
||||
#endif
|
||||
|
||||
#include "core/util/fourcc.h"
|
||||
|
||||
#ifdef TORQUE_OS_WIN
|
||||
#include <dxgiformat.h>
|
||||
#endif
|
||||
|
||||
namespace dds
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// DXGI Formats //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef TORQUE_OS_WIN
|
||||
//From directx SDK
|
||||
typedef enum DXGI_FORMAT
|
||||
{
|
||||
DXGI_FORMAT_UNKNOWN = 0,
|
||||
DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
|
||||
DXGI_FORMAT_R32G32B32A32_UINT = 3,
|
||||
DXGI_FORMAT_R32G32B32A32_SINT = 4,
|
||||
DXGI_FORMAT_R32G32B32_TYPELESS = 5,
|
||||
DXGI_FORMAT_R32G32B32_FLOAT = 6,
|
||||
DXGI_FORMAT_R32G32B32_UINT = 7,
|
||||
DXGI_FORMAT_R32G32B32_SINT = 8,
|
||||
DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
|
||||
DXGI_FORMAT_R16G16B16A16_UNORM = 11,
|
||||
DXGI_FORMAT_R16G16B16A16_UINT = 12,
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM = 13,
|
||||
DXGI_FORMAT_R16G16B16A16_SINT = 14,
|
||||
DXGI_FORMAT_R32G32_TYPELESS = 15,
|
||||
DXGI_FORMAT_R32G32_FLOAT = 16,
|
||||
DXGI_FORMAT_R32G32_UINT = 17,
|
||||
DXGI_FORMAT_R32G32_SINT = 18,
|
||||
DXGI_FORMAT_R32G8X24_TYPELESS = 19,
|
||||
DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
|
||||
DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
|
||||
DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
|
||||
DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM = 24,
|
||||
DXGI_FORMAT_R10G10B10A2_UINT = 25,
|
||||
DXGI_FORMAT_R11G11B10_FLOAT = 26,
|
||||
DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM = 28,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
|
||||
DXGI_FORMAT_R8G8B8A8_UINT = 30,
|
||||
DXGI_FORMAT_R8G8B8A8_SNORM = 31,
|
||||
DXGI_FORMAT_R8G8B8A8_SINT = 32,
|
||||
DXGI_FORMAT_R16G16_TYPELESS = 33,
|
||||
DXGI_FORMAT_R16G16_FLOAT = 34,
|
||||
DXGI_FORMAT_R16G16_UNORM = 35,
|
||||
DXGI_FORMAT_R16G16_UINT = 36,
|
||||
DXGI_FORMAT_R16G16_SNORM = 37,
|
||||
DXGI_FORMAT_R16G16_SINT = 38,
|
||||
DXGI_FORMAT_R32_TYPELESS = 39,
|
||||
DXGI_FORMAT_D32_FLOAT = 40,
|
||||
DXGI_FORMAT_R32_FLOAT = 41,
|
||||
DXGI_FORMAT_R32_UINT = 42,
|
||||
DXGI_FORMAT_R32_SINT = 43,
|
||||
DXGI_FORMAT_R24G8_TYPELESS = 44,
|
||||
DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
|
||||
DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
|
||||
DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
|
||||
DXGI_FORMAT_R8G8_TYPELESS = 48,
|
||||
DXGI_FORMAT_R8G8_UNORM = 49,
|
||||
DXGI_FORMAT_R8G8_UINT = 50,
|
||||
DXGI_FORMAT_R8G8_SNORM = 51,
|
||||
DXGI_FORMAT_R8G8_SINT = 52,
|
||||
DXGI_FORMAT_R16_TYPELESS = 53,
|
||||
DXGI_FORMAT_R16_FLOAT = 54,
|
||||
DXGI_FORMAT_D16_UNORM = 55,
|
||||
DXGI_FORMAT_R16_UNORM = 56,
|
||||
DXGI_FORMAT_R16_UINT = 57,
|
||||
DXGI_FORMAT_R16_SNORM = 58,
|
||||
DXGI_FORMAT_R16_SINT = 59,
|
||||
DXGI_FORMAT_R8_TYPELESS = 60,
|
||||
DXGI_FORMAT_R8_UNORM = 61,
|
||||
DXGI_FORMAT_R8_UINT = 62,
|
||||
DXGI_FORMAT_R8_SNORM = 63,
|
||||
DXGI_FORMAT_R8_SINT = 64,
|
||||
DXGI_FORMAT_A8_UNORM = 65,
|
||||
DXGI_FORMAT_R1_UNORM = 66,
|
||||
DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
|
||||
DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
|
||||
DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
|
||||
DXGI_FORMAT_BC1_TYPELESS = 70,
|
||||
DXGI_FORMAT_BC1_UNORM = 71,
|
||||
DXGI_FORMAT_BC1_UNORM_SRGB = 72,
|
||||
DXGI_FORMAT_BC2_TYPELESS = 73,
|
||||
DXGI_FORMAT_BC2_UNORM = 74,
|
||||
DXGI_FORMAT_BC2_UNORM_SRGB = 75,
|
||||
DXGI_FORMAT_BC3_TYPELESS = 76,
|
||||
DXGI_FORMAT_BC3_UNORM = 77,
|
||||
DXGI_FORMAT_BC3_UNORM_SRGB = 78,
|
||||
DXGI_FORMAT_BC4_TYPELESS = 79,
|
||||
DXGI_FORMAT_BC4_UNORM = 80,
|
||||
DXGI_FORMAT_BC4_SNORM = 81,
|
||||
DXGI_FORMAT_BC5_TYPELESS = 82,
|
||||
DXGI_FORMAT_BC5_UNORM = 83,
|
||||
DXGI_FORMAT_BC5_SNORM = 84,
|
||||
DXGI_FORMAT_B5G6R5_UNORM = 85,
|
||||
DXGI_FORMAT_B5G5R5A1_UNORM = 86,
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM = 87,
|
||||
DXGI_FORMAT_B8G8R8X8_UNORM = 88,
|
||||
DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
|
||||
DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
|
||||
DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
|
||||
DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
|
||||
DXGI_FORMAT_BC6H_TYPELESS = 94,
|
||||
DXGI_FORMAT_BC6H_UF16 = 95,
|
||||
DXGI_FORMAT_BC6H_SF16 = 96,
|
||||
DXGI_FORMAT_BC7_TYPELESS = 97,
|
||||
DXGI_FORMAT_BC7_UNORM = 98,
|
||||
DXGI_FORMAT_BC7_UNORM_SRGB = 99,
|
||||
DXGI_FORMAT_AYUV = 100,
|
||||
DXGI_FORMAT_Y410 = 101,
|
||||
DXGI_FORMAT_Y416 = 102,
|
||||
DXGI_FORMAT_NV12 = 103,
|
||||
DXGI_FORMAT_P010 = 104,
|
||||
DXGI_FORMAT_P016 = 105,
|
||||
DXGI_FORMAT_420_OPAQUE = 106,
|
||||
DXGI_FORMAT_YUY2 = 107,
|
||||
DXGI_FORMAT_Y210 = 108,
|
||||
DXGI_FORMAT_Y216 = 109,
|
||||
DXGI_FORMAT_NV11 = 110,
|
||||
DXGI_FORMAT_AI44 = 111,
|
||||
DXGI_FORMAT_IA44 = 112,
|
||||
DXGI_FORMAT_P8 = 113,
|
||||
DXGI_FORMAT_A8P8 = 114,
|
||||
DXGI_FORMAT_B4G4R4A4_UNORM = 115,
|
||||
DXGI_FORMAT_FORCE_UINT = 0xffffffff
|
||||
} DXGI_FORMAT;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// D3DFMT Formats //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
enum D3DFMT
|
||||
{
|
||||
D3DFMT_UNKNOWN = 0,
|
||||
|
||||
D3DFMT_R8G8B8 = 20,
|
||||
D3DFMT_A8R8G8B8 = 21,
|
||||
D3DFMT_X8R8G8B8 = 22,
|
||||
D3DFMT_R5G6B5 = 23,
|
||||
D3DFMT_X1R5G5B5 = 24,
|
||||
D3DFMT_A1R5G5B5 = 25,
|
||||
D3DFMT_A4R4G4B4 = 26,
|
||||
D3DFMT_R3G3B2 = 27,
|
||||
D3DFMT_A8 = 28,
|
||||
D3DFMT_A8R3G3B2 = 29,
|
||||
D3DFMT_X4R4G4B4 = 30,
|
||||
D3DFMT_A2B10G10R10 = 31,
|
||||
D3DFMT_A8B8G8R8 = 32,
|
||||
D3DFMT_X8B8G8R8 = 33,
|
||||
D3DFMT_G16R16 = 34,
|
||||
D3DFMT_A2R10G10B10 = 35,
|
||||
D3DFMT_A16B16G16R16 = 36,
|
||||
|
||||
D3DFMT_A8P8 = 40,
|
||||
D3DFMT_P8 = 41,
|
||||
|
||||
D3DFMT_L8 = 50,
|
||||
D3DFMT_A8L8 = 51,
|
||||
D3DFMT_A4L4 = 52,
|
||||
|
||||
D3DFMT_V8U8 = 60,
|
||||
D3DFMT_L6V5U5 = 61,
|
||||
D3DFMT_X8L8V8U8 = 62,
|
||||
D3DFMT_Q8W8V8U8 = 63,
|
||||
D3DFMT_V16U16 = 64,
|
||||
D3DFMT_A2W10V10U10 = 67,
|
||||
|
||||
D3DFMT_UYVY = MakeFourCC('U', 'Y', 'V', 'Y'),
|
||||
D3DFMT_R8G8_B8G8 = MakeFourCC('R', 'G', 'B', 'G'),
|
||||
D3DFMT_YUY2 = MakeFourCC('Y', 'U', 'Y', '2'),
|
||||
D3DFMT_G8R8_G8B8 = MakeFourCC('G', 'R', 'G', 'B'),
|
||||
D3DFMT_DXT1 = MakeFourCC('D', 'X', 'T', '1'),
|
||||
D3DFMT_DXT2 = MakeFourCC('D', 'X', 'T', '2'),
|
||||
D3DFMT_DXT3 = MakeFourCC('D', 'X', 'T', '3'),
|
||||
D3DFMT_DXT4 = MakeFourCC('D', 'X', 'T', '4'),
|
||||
D3DFMT_DXT5 = MakeFourCC('D', 'X', 'T', '5'),
|
||||
|
||||
D3DFMT_ATI1 = MakeFourCC('A', 'T', 'I', '1'),
|
||||
D3DFMT_AT1N = MakeFourCC('A', 'T', '1', 'N'),
|
||||
D3DFMT_ATI2 = MakeFourCC('A', 'T', 'I', '2'),
|
||||
D3DFMT_AT2N = MakeFourCC('A', 'T', '2', 'N'),
|
||||
|
||||
D3DFMT_BC4U = MakeFourCC('B', 'C', '4', 'U'),
|
||||
D3DFMT_BC4S = MakeFourCC('B', 'C', '4', 'S'),
|
||||
D3DFMT_BC5U = MakeFourCC('B', 'C', '5', 'U'),
|
||||
D3DFMT_BC5S = MakeFourCC('B', 'C', '5', 'S'),
|
||||
|
||||
D3DFMT_ETC = MakeFourCC('E', 'T', 'C', ' '),
|
||||
D3DFMT_ETC1 = MakeFourCC('E', 'T', 'C', '1'),
|
||||
D3DFMT_ATC = MakeFourCC('A', 'T', 'C', ' '),
|
||||
D3DFMT_ATCA = MakeFourCC('A', 'T', 'C', 'A'),
|
||||
D3DFMT_ATCI = MakeFourCC('A', 'T', 'C', 'I'),
|
||||
|
||||
D3DFMT_POWERVR_2BPP = MakeFourCC('P', 'T', 'C', '2'),
|
||||
D3DFMT_POWERVR_4BPP = MakeFourCC('P', 'T', 'C', '4'),
|
||||
|
||||
D3DFMT_D16_LOCKABLE = 70,
|
||||
D3DFMT_D32 = 71,
|
||||
D3DFMT_D15S1 = 73,
|
||||
D3DFMT_D24S8 = 75,
|
||||
D3DFMT_D24X8 = 77,
|
||||
D3DFMT_D24X4S4 = 79,
|
||||
D3DFMT_D16 = 80,
|
||||
|
||||
D3DFMT_D32F_LOCKABLE = 82,
|
||||
D3DFMT_D24FS8 = 83,
|
||||
|
||||
D3DFMT_L16 = 81,
|
||||
|
||||
D3DFMT_VERTEXDATA = 100,
|
||||
D3DFMT_INDEX16 = 101,
|
||||
D3DFMT_INDEX32 = 102,
|
||||
|
||||
D3DFMT_Q16W16V16U16 = 110,
|
||||
|
||||
D3DFMT_MULTI2_ARGB8 = MakeFourCC('M', 'E', 'T', '1'),
|
||||
|
||||
D3DFMT_R16F = 111,
|
||||
D3DFMT_G16R16F = 112,
|
||||
D3DFMT_A16B16G16R16F = 113,
|
||||
|
||||
D3DFMT_R32F = 114,
|
||||
D3DFMT_G32R32F = 115,
|
||||
D3DFMT_A32B32G32R32F = 116,
|
||||
|
||||
D3DFMT_CxV8U8 = 117,
|
||||
|
||||
D3DFMT_DX10 = MakeFourCC('D', 'X', '1', '0'),
|
||||
|
||||
D3DFMT_FORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Defines //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma pack(push,1)
|
||||
|
||||
#define DDS_HEADER_SIZE 124
|
||||
#define DDS_HEADER_DX10_SIZE 20
|
||||
#define DDS_MAGIC 0x20534444 // "DDS "
|
||||
#define DDS_FOURCC 0x00000004 // DDPF_FOURCC
|
||||
#define DDS_RGB 0x00000040 // DDPF_RGB
|
||||
#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS
|
||||
#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE
|
||||
#define DDS_LUMINANCEA 0x00020001 // DDPF_LUMINANCE | DDPF_ALPHAPIXELS
|
||||
#define DDS_ALPHAPIXELS 0x00000001 // DDPF_ALPHAPIXELS
|
||||
#define DDS_ALPHA 0x00000002 // DDPF_ALPHA
|
||||
#define DDS_PAL8 0x00000020 // DDPF_PALETTEINDEXED8
|
||||
#define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV
|
||||
#define DDS_YUV 0x00000200 //DDPF_YUV
|
||||
|
||||
#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
|
||||
#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT
|
||||
#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH
|
||||
#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH
|
||||
#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE
|
||||
|
||||
#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT
|
||||
#define DDS_WIDTH 0x00000004 // DDSD_WIDTH
|
||||
|
||||
#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE
|
||||
#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
|
||||
#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX
|
||||
|
||||
#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP
|
||||
#define DDS_CUBEMAP_POSITIVEX 0x00000400 // DDSCAPS2_CUBEMAP_POSITIVEX
|
||||
#define DDS_CUBEMAP_NEGATIVEX 0x00000800 // DDSCAPS2_CUBEMAP_NEGATIVEX
|
||||
#define DDS_CUBEMAP_POSITIVEY 0x00001000 // DDSCAPS2_CUBEMAP_POSITIVEY
|
||||
#define DDS_CUBEMAP_NEGATIVEY 0x00002000 // DDSCAPS2_CUBEMAP_NEGATIVEY
|
||||
#define DDS_CUBEMAP_POSITIVEZ 0x00004000 // DDSCAPS2_CUBEMAP_POSITIVEZ
|
||||
#define DDS_CUBEMAP_NEGATIVEZ 0x00008000 // DDSCAPS2_CUBEMAP_NEGATIVEZ
|
||||
|
||||
#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP | DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\
|
||||
DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\
|
||||
DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )
|
||||
|
||||
#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Enums //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION
|
||||
enum DDS_RESOURCE_DIMENSION
|
||||
{
|
||||
DDS_DIMENSION_TEXTURE1D = 2,
|
||||
DDS_DIMENSION_TEXTURE2D = 3,
|
||||
DDS_DIMENSION_TEXTURE3D = 4,
|
||||
};
|
||||
|
||||
// Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG
|
||||
enum DDS_RESOURCE_MISC_FLAG
|
||||
{
|
||||
DDS_RESOURCE_MISC_TEXTURECUBE = 0x4L,
|
||||
};
|
||||
|
||||
enum DDS_MISC_FLAGS2
|
||||
{
|
||||
DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,
|
||||
};
|
||||
|
||||
enum DDS_ALPHA_MODE
|
||||
{
|
||||
DDS_ALPHA_MODE_UNKNOWN = 0,
|
||||
DDS_ALPHA_MODE_STRAIGHT = 1,
|
||||
DDS_ALPHA_MODE_PREMULTIPLIED = 2,
|
||||
DDS_ALPHA_MODE_OPAQUE = 3,
|
||||
DDS_ALPHA_MODE_CUSTOM = 4,
|
||||
};
|
||||
|
||||
enum D3D10_RESOURCE_DIMENSION
|
||||
{
|
||||
D3D10_RESOURCE_DIMENSION_UNKNOWN = 0,
|
||||
D3D10_RESOURCE_DIMENSION_BUFFER = 1,
|
||||
D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2,
|
||||
D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3,
|
||||
D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4
|
||||
};
|
||||
|
||||
enum D3D10_RESOURCE_MISC_FLAG
|
||||
{
|
||||
D3D10_RESOURCE_MISC_GENERATE_MIPS = 0x1L,
|
||||
D3D10_RESOURCE_MISC_SHARED = 0x2L,
|
||||
D3D10_RESOURCE_MISC_TEXTURECUBE = 0x4L,
|
||||
D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX = 0x10L,
|
||||
D3D10_RESOURCE_MISC_GDI_COMPATIBLE = 0x20L,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Structs //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct DDS_PIXELFORMAT
|
||||
{
|
||||
U32 size;
|
||||
U32 flags;
|
||||
U32 fourCC;
|
||||
U32 bpp;
|
||||
U32 RBitMask;
|
||||
U32 GBitMask;
|
||||
U32 BBitMask;
|
||||
U32 ABitMask;
|
||||
|
||||
bool operator==(const DDS_PIXELFORMAT& _test) const
|
||||
{
|
||||
return ( size == _test.size &&
|
||||
flags == _test.flags &&
|
||||
fourCC == _test.fourCC &&
|
||||
bpp == _test.bpp &&
|
||||
RBitMask == _test.RBitMask &&
|
||||
GBitMask == _test.GBitMask &&
|
||||
BBitMask == _test.BBitMask &&
|
||||
ABitMask == _test.ABitMask);
|
||||
}
|
||||
};
|
||||
|
||||
struct DDS_HEADER
|
||||
{
|
||||
U32 size;
|
||||
U32 flags;
|
||||
U32 height;
|
||||
U32 width;
|
||||
U32 pitchOrLinearSize;
|
||||
U32 depth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwFlags
|
||||
U32 mipMapCount;
|
||||
U32 reserved1[11];
|
||||
DDS_PIXELFORMAT ddspf;
|
||||
U32 surfaceFlags;
|
||||
U32 cubemapFlags;
|
||||
U32 reserved2[3];
|
||||
};
|
||||
|
||||
struct DDS_HEADER_DXT10
|
||||
{
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
U32 resourceDimension;
|
||||
U32 miscFlag; // see DDS_RESOURCE_MISC_FLAG
|
||||
U32 arraySize;
|
||||
U32 miscFlags2; // see DDS_MISC_FLAGS2
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Pixel Formats //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_DXT1 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_DXT1, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_DXT2 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_DXT2, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_DXT3 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_DXT3, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_DXT4 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_DXT4, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_DXT5 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_DXT5, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_BC4_UNORM =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_BC4U, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_BC4_SNORM =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_BC4S, 0, 0, 0, 0, 0 };
|
||||
|
||||
//todo check diff between this and ('B','C','5','U')
|
||||
const DDS_PIXELFORMAT DDSPF_ATI2 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_ATI2, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_ATI1 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_ATI1, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_BC5_UNORM =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_BC5U, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_BC5_SNORM =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_BC5S, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_R8G8_B8G8, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_G8R8_G8B8, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_YUY2 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_YUY2, 0, 0, 0, 0, 0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_A8R8G8B8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_X8R8G8B8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_A8B8G8R8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_X8B8G8R8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_G16R16 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_R5G6B5 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_A1R5G5B5 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_A4R4G4B4 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_R8G8B8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_L8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0x00, 0x00, 0x00 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_L16 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0x0000, 0x0000, 0x0000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_A8L8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0x0000, 0x0000, 0xff00 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_A4L4 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x0000000f, 0x0000, 0x0000, 0x000000f0 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_A8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_V8U8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0x0000, 0x0000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_Q8W8V8U8 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
|
||||
|
||||
const DDS_PIXELFORMAT DDSPF_V16U16 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };
|
||||
|
||||
// D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue
|
||||
|
||||
// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)
|
||||
const DDS_PIXELFORMAT DDSPF_DX10 =
|
||||
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, D3DFMT_DX10, 0, 0, 0, 0, 0 };
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//get DDS_PIXELFORMAT struct from GFXFormat - todo more formats
|
||||
const DDS_PIXELFORMAT getDDSFormat(const GFXFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GFXFormatA4L4: return DDSPF_A4L4;
|
||||
case GFXFormatL8: return DDSPF_L8;
|
||||
case GFXFormatA8: return DDSPF_A8;
|
||||
case GFXFormatA8L8: return DDSPF_A8L8;
|
||||
case GFXFormatL16: return DDSPF_L16;
|
||||
case GFXFormatR5G6B5: return DDSPF_R5G6B5;
|
||||
case GFXFormatR5G5B5A1: return DDSPF_A1R5G5B5;
|
||||
case GFXFormatR8G8B8: return DDSPF_R8G8B8;
|
||||
case GFXFormatR8G8B8A8: return DDSPF_A8R8G8B8;
|
||||
case GFXFormatR8G8B8X8: return DDSPF_X8R8G8B8;
|
||||
case GFXFormatB8G8R8A8: return DDSPF_A8B8G8R8;
|
||||
case GFXFormatR16G16B16A16F:
|
||||
case GFXFormatR32G32B32A32F: return DDSPF_DX10;
|
||||
//compressed
|
||||
case GFXFormatBC1: return DDSPF_DXT1;
|
||||
case GFXFormatBC2: return DDSPF_DXT3;
|
||||
case GFXFormatBC3: return DDSPF_DXT5;
|
||||
case GFXFormatBC4: return DDSPF_ATI1;
|
||||
case GFXFormatBC5: return DDSPF_ATI2;
|
||||
default:
|
||||
{
|
||||
Con::errorf("dds::getDDSFormat: unknown format");
|
||||
return DDSPF_A8R8G8B8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get DXGI_FORMAT from GFXFormat - todo more formats
|
||||
const DXGI_FORMAT getDXGIFormat(const GFXFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
//byte
|
||||
case GFXFormatR5G6B5: return DXGI_FORMAT_B5G6R5_UNORM;
|
||||
case GFXFormatR5G5B5A1: return DXGI_FORMAT_B5G5R5A1_UNORM;
|
||||
case GFXFormatB8G8R8A8: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GFXFormatR8G8B8A8: return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
case GFXFormatR8G8B8X8: return DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||
case GFXFormatR10G10B10A2: return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
//uint
|
||||
case GFXFormatR16G16: return DXGI_FORMAT_R16G16_UINT;
|
||||
case GFXFormatR16G16B16A16: return DXGI_FORMAT_R16G16B16A16_UINT;
|
||||
//float
|
||||
case GFXFormatR16F: return DXGI_FORMAT_R16_FLOAT;
|
||||
case GFXFormatR32F: return DXGI_FORMAT_R32_FLOAT;
|
||||
case GFXFormatR16G16B16A16F: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case GFXFormatR32G32B32A32F: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
//compressed
|
||||
case GFXFormatBC1: return DXGI_FORMAT_BC1_UNORM;
|
||||
case GFXFormatBC2: return DXGI_FORMAT_BC2_UNORM;
|
||||
case GFXFormatBC3: return DXGI_FORMAT_BC3_UNORM;
|
||||
case GFXFormatBC4: return DXGI_FORMAT_BC4_UNORM;
|
||||
case GFXFormatBC5: return DXGI_FORMAT_BC5_UNORM;
|
||||
default:
|
||||
{
|
||||
Con::errorf("dds::getDXGIFormat: unknown format");
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get GFXFormat from D3DFMT - todo more formats
|
||||
const GFXFormat getGFXFormat(const D3DFMT format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
//byte
|
||||
case D3DFMT_A4L4: return GFXFormatA4L4;
|
||||
case D3DFMT_L8: return GFXFormatL8;
|
||||
case D3DFMT_A8: return GFXFormatA8;
|
||||
case D3DFMT_A8L8: return GFXFormatA8L8;
|
||||
case D3DFMT_L16: return GFXFormatL16;
|
||||
case D3DFMT_R5G6B5: return GFXFormatR5G6B5;
|
||||
case D3DFMT_A1R5G5B5: return GFXFormatR5G5B5A1;
|
||||
case D3DFMT_R8G8B8: return GFXFormatR8G8B8;
|
||||
case D3DFMT_A8R8G8B8: return GFXFormatR8G8B8A8;
|
||||
case D3DFMT_X8R8G8B8: return GFXFormatR8G8B8A8;
|
||||
case D3DFMT_A8B8G8R8: return GFXFormatB8G8R8A8;
|
||||
case D3DFMT_X8B8G8R8: return GFXFormatB8G8R8A8;
|
||||
//uint
|
||||
case D3DFMT_G16R16: return GFXFormatR16G16;
|
||||
case D3DFMT_A16B16G16R16: return GFXFormatR16G16B16A16;
|
||||
//float
|
||||
case D3DFMT_R16F: return GFXFormatR16F;
|
||||
case D3DFMT_R32F: return GFXFormatR32F;
|
||||
case D3DFMT_A16B16G16R16F: return GFXFormatR16G16B16A16F;
|
||||
case D3DFMT_A32B32G32R32F: return GFXFormatR32G32B32A32F;
|
||||
//compressed
|
||||
case D3DFMT_DXT1: return GFXFormatBC1;
|
||||
case D3DFMT_DXT2:
|
||||
case D3DFMT_DXT3: return GFXFormatBC2;
|
||||
case D3DFMT_DXT4:
|
||||
case D3DFMT_DXT5: return GFXFormatBC3;
|
||||
case D3DFMT_ATI1: return GFXFormatBC4;
|
||||
case D3DFMT_ATI2: return GFXFormatBC5;
|
||||
default:
|
||||
{
|
||||
Con::errorf("dds::getGFXFormat: unknown format");
|
||||
return GFXFormat_FIRST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get GFXFormat from DXGI_FORMAT - todo more formats
|
||||
const GFXFormat getGFXFormat(const DXGI_FORMAT format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
//byte
|
||||
case DXGI_FORMAT_B5G6R5_UNORM: return GFXFormatR5G6B5;
|
||||
case DXGI_FORMAT_B5G5R5A1_UNORM: return GFXFormatR5G5B5A1;
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM: return GFXFormatB8G8R8A8;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM: return GFXFormatR8G8B8A8;
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM: return GFXFormatR8G8B8X8;
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM: return GFXFormatR10G10B10A2;
|
||||
//uint
|
||||
case DXGI_FORMAT_R16G16_UINT: return GFXFormatR16G16;
|
||||
case DXGI_FORMAT_R16G16B16A16_UINT: return GFXFormatR16G16B16A16;
|
||||
//float
|
||||
case DXGI_FORMAT_R16_FLOAT: return GFXFormatR16F;
|
||||
case DXGI_FORMAT_R32_FLOAT: return GFXFormatR32F;
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT: return GFXFormatR16G16B16A16F;
|
||||
case DXGI_FORMAT_R32G32B32A32_FLOAT: return GFXFormatR32G32B32A32F;
|
||||
//compressed
|
||||
case DXGI_FORMAT_BC1_UNORM: return GFXFormatBC1;
|
||||
case DXGI_FORMAT_BC2_UNORM: return GFXFormatBC2;
|
||||
case DXGI_FORMAT_BC3_UNORM: return GFXFormatBC3;
|
||||
case DXGI_FORMAT_BC4_UNORM: return GFXFormatBC4;
|
||||
case DXGI_FORMAT_BC5_UNORM: return GFXFormatBC5;
|
||||
default:
|
||||
{
|
||||
Con::errorf("dds::getGFXFormatDxgi: unknown format");
|
||||
return GFXFormat_FIRST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get GFXFormat from DDS_PIXELFORMAT struct - todo more formats
|
||||
const GFXFormat getGFXFormat(const DDS_PIXELFORMAT &format)
|
||||
{
|
||||
if (format == DDSPF_DXT1)
|
||||
return GFXFormatBC1;
|
||||
else if (format == DDSPF_DXT2)
|
||||
return GFXFormatBC2;
|
||||
else if (format == DDSPF_DXT3)
|
||||
return GFXFormatBC2;
|
||||
else if (format == DDSPF_DXT4)
|
||||
return GFXFormatBC3;
|
||||
else if (format == DDSPF_DXT5)
|
||||
return GFXFormatBC3;
|
||||
else if (format == DDSPF_ATI1)
|
||||
return GFXFormatBC4;
|
||||
else if (format == DDSPF_ATI2)
|
||||
return GFXFormatBC5;
|
||||
else if (format == DDSPF_A8R8G8B8)
|
||||
return GFXFormatR8G8B8A8;
|
||||
else if (format == DDSPF_X8R8G8B8)
|
||||
return GFXFormatR8G8B8A8;
|
||||
else if (format == DDSPF_A8B8G8R8)
|
||||
return GFXFormatB8G8R8A8;
|
||||
else if (format == DDSPF_X8B8G8R8)
|
||||
return GFXFormatB8G8R8A8;
|
||||
else if (format == DDSPF_R8G8B8)
|
||||
return GFXFormatR8G8B8;
|
||||
else if (format == DDSPF_A8L8)
|
||||
return GFXFormatA8L8;
|
||||
else if (format == DDSPF_A4L4)
|
||||
return GFXFormatA4L4;
|
||||
else if (format == DDSPF_A8)
|
||||
return GFXFormatA8;
|
||||
else if (format == DDSPF_L8)
|
||||
return GFXFormatL8;
|
||||
else if (format == DDSPF_R5G6B5)
|
||||
return GFXFormatR5G6B5;
|
||||
else if (format == DDSPF_A1R5G5B5)
|
||||
return GFXFormatR5G5B5A1;
|
||||
else
|
||||
{
|
||||
Con::errorf("dds::getGFXFormat: unknown format");
|
||||
return GFXFormat_FIRST;
|
||||
}
|
||||
}
|
||||
|
||||
//get GFXFormat from fourcc value - todo more formats
|
||||
const GFXFormat getGFXFormat(const U32 fourcc)
|
||||
{
|
||||
switch (fourcc)
|
||||
{
|
||||
case D3DFMT_DXT1: return GFXFormatBC1;
|
||||
case D3DFMT_DXT2:
|
||||
case D3DFMT_DXT3: return GFXFormatBC2;
|
||||
case D3DFMT_DXT4:
|
||||
case D3DFMT_DXT5: return GFXFormatBC3;
|
||||
case D3DFMT_ATI1: return GFXFormatBC4;
|
||||
case D3DFMT_ATI2: return GFXFormatBC5;
|
||||
case D3DFMT_A16B16G16R16F: return GFXFormatR16G16B16A16F;
|
||||
case D3DFMT_A32B32G32R32F: return GFXFormatR32G32B32A32F;
|
||||
default:
|
||||
{
|
||||
Con::errorf("dds::getGFXFormatFourcc: unknown format");
|
||||
return GFXFormat_FIRST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool validateHeader(const DDS_HEADER &header)
|
||||
{
|
||||
if (header.size != DDS_HEADER_SIZE)
|
||||
{
|
||||
Con::errorf("DDS_HEADER - incorrect header size. Expected 124 bytes.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(header.flags & DDS_HEADER_FLAGS_TEXTURE))
|
||||
{
|
||||
Con::errorf("DDS_HEADER - incorrect surface description flags.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((header.flags & (DDS_HEADER_FLAGS_LINEARSIZE | DDS_HEADER_FLAGS_PITCH)) == (DDS_HEADER_FLAGS_LINEARSIZE | DDS_HEADER_FLAGS_PITCH))
|
||||
{
|
||||
// Both are invalid!
|
||||
Con::errorf("DDS_HEADER - encountered both DDSD_LINEARSIZE and DDSD_PITCH!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool validateHeaderDx10(const DDS_HEADER_DXT10 &header)
|
||||
{
|
||||
if (sizeof(DDS_HEADER_DXT10) != DDS_HEADER_DX10_SIZE)
|
||||
{
|
||||
Con::errorf("DDS_HEADER_DXT10 - incorrect header size. Expected 20 bytes.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
#include "platform/platform.h"
|
||||
#include "gfx/bitmap/ddsFile.h"
|
||||
|
||||
#include "gfx/bitmap/ddsData.h"
|
||||
#include "gfx/bitmap/bitmapUtils.h"
|
||||
#include "gfx/bitmap/imageUtils.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "core/util/fourcc.h"
|
||||
#include "console/console.h"
|
||||
|
|
@ -31,56 +33,11 @@
|
|||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
|
||||
#include <squish.h>
|
||||
|
||||
S32 DDSFile::smActiveCopies = 0;
|
||||
U32 DDSFile::smDropMipCount = 0;
|
||||
|
||||
// These were copied from the DX9 docs. The names are changed
|
||||
// from the "real" defines since not all platforms have them.
|
||||
enum DDSSurfaceDescFlags
|
||||
{
|
||||
DDSDCaps = 0x00000001l,
|
||||
DDSDHeight = 0x00000002l,
|
||||
DDSDWidth = 0x00000004l,
|
||||
DDSDPitch = 0x00000008l,
|
||||
DDSDPixelFormat = 0x00001000l,
|
||||
DDSDMipMapCount = 0x00020000l,
|
||||
DDSDLinearSize = 0x00080000l,
|
||||
DDSDDepth = 0x00800000l,
|
||||
};
|
||||
|
||||
enum DDSPixelFormatFlags
|
||||
{
|
||||
DDPFAlphaPixels = 0x00000001,
|
||||
DDPFFourCC = 0x00000004,
|
||||
DDPFRGB = 0x00000040,
|
||||
DDPFLUMINANCE = 0x00020000
|
||||
};
|
||||
|
||||
|
||||
enum DDSCapFlags
|
||||
{
|
||||
DDSCAPSComplex = 0x00000008,
|
||||
DDSCAPSTexture = 0x00001000,
|
||||
DDSCAPSMipMap = 0x00400000,
|
||||
|
||||
DDSCAPS2Cubemap = 0x00000200,
|
||||
DDSCAPS2Cubemap_POSITIVEX = 0x00000400,
|
||||
DDSCAPS2Cubemap_NEGATIVEX = 0x00000800,
|
||||
DDSCAPS2Cubemap_POSITIVEY = 0x00001000,
|
||||
DDSCAPS2Cubemap_NEGATIVEY = 0x00002000,
|
||||
DDSCAPS2Cubemap_POSITIVEZ = 0x00004000,
|
||||
DDSCAPS2Cubemap_NEGATIVEZ = 0x00008000,
|
||||
DDSCAPS2Volume = 0x00200000,
|
||||
};
|
||||
|
||||
#define FOURCC_DXT1 (MakeFourCC('D','X','T','1'))
|
||||
#define FOURCC_DXT2 (MakeFourCC('D','X','T','2'))
|
||||
#define FOURCC_DXT3 (MakeFourCC('D','X','T','3'))
|
||||
#define FOURCC_DXT4 (MakeFourCC('D','X','T','4'))
|
||||
#define FOURCC_DXT5 (MakeFourCC('D','X','T','5'))
|
||||
|
||||
DDSFile::DDSFile( const DDSFile &dds )
|
||||
: mFlags( dds.mFlags ),
|
||||
mHeight( dds.mHeight ),
|
||||
|
|
@ -133,13 +90,13 @@ U32 DDSFile::getSurfacePitch( U32 mipLevel ) const
|
|||
|
||||
switch(mFormat)
|
||||
{
|
||||
case GFXFormatDXT1:
|
||||
case GFXFormatBC1:
|
||||
case GFXFormatBC4:
|
||||
sizeMultiple = 8;
|
||||
break;
|
||||
case GFXFormatDXT2:
|
||||
case GFXFormatDXT3:
|
||||
case GFXFormatDXT4:
|
||||
case GFXFormatDXT5:
|
||||
case GFXFormatBC2:
|
||||
case GFXFormatBC3:
|
||||
case GFXFormatBC5:
|
||||
sizeMultiple = 16;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -172,13 +129,13 @@ U32 DDSFile::getSurfaceSize( U32 height, U32 width, U32 mipLevel ) const
|
|||
|
||||
switch(mFormat)
|
||||
{
|
||||
case GFXFormatDXT1:
|
||||
case GFXFormatBC1:
|
||||
case GFXFormatBC4:
|
||||
sizeMultiple = 8;
|
||||
break;
|
||||
case GFXFormatDXT2:
|
||||
case GFXFormatDXT3:
|
||||
case GFXFormatDXT4:
|
||||
case GFXFormatDXT5:
|
||||
case GFXFormatBC2:
|
||||
case GFXFormatBC3:
|
||||
case GFXFormatBC5:
|
||||
sizeMultiple = 16;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -197,25 +154,34 @@ U32 DDSFile::getSurfaceSize( U32 height, U32 width, U32 mipLevel ) const
|
|||
U32 DDSFile::getSizeInBytes() const
|
||||
{
|
||||
// TODO: This doesn't take mDepth into account, so
|
||||
// it doesn't work right for volume or cubemap textures!
|
||||
// it doesn't work right for volume textures!
|
||||
|
||||
U32 bytes = 0;
|
||||
for ( U32 i=0; i < mMipMapCount; i++ )
|
||||
bytes += getSurfaceSize( mHeight, mWidth, i );
|
||||
if (mFlags.test(CubeMapFlag))
|
||||
{
|
||||
for(U32 cubeFace=0;cubeFace < Cubemap_Surface_Count;cubeFace++)
|
||||
for (U32 i = 0; i < mMipMapCount; i++)
|
||||
bytes += getSurfaceSize(mHeight, mWidth, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (U32 i = 0; i < mMipMapCount; i++)
|
||||
bytes += getSurfaceSize(mHeight, mWidth, i);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
U32 DDSFile::getSizeInBytes( GFXFormat format, U32 height, U32 width, U32 mipLevels )
|
||||
{
|
||||
AssertFatal( format >= GFXFormatDXT1 && format <= GFXFormatDXT5,
|
||||
"DDSFile::getSizeInBytes - Must be a DXT format!" );
|
||||
AssertFatal( ImageUtil::isCompressedFormat(format),
|
||||
"DDSFile::getSizeInBytes - Must be a Block Compression format!" );
|
||||
|
||||
// From the directX docs:
|
||||
// max(1, width ÷ 4) x max(1, height ÷ 4) x 8(DXT1) or 16(DXT2-5)
|
||||
|
||||
U32 sizeMultiple = 0;
|
||||
if ( format == GFXFormatDXT1 )
|
||||
if ( format == GFXFormatBC1 || format == GFXFormatBC1_SRGB || format == GFXFormatBC4)
|
||||
sizeMultiple = 8;
|
||||
else
|
||||
sizeMultiple = 16;
|
||||
|
|
@ -236,317 +202,146 @@ U32 DDSFile::getSizeInBytes( GFXFormat format, U32 height, U32 width, U32 mipLev
|
|||
|
||||
bool DDSFile::readHeader(Stream &s)
|
||||
{
|
||||
U32 tmp;
|
||||
|
||||
U32 fourcc;
|
||||
// Read the FOURCC
|
||||
s.read(&tmp);
|
||||
s.read(&fourcc);
|
||||
|
||||
if(tmp != MakeFourCC('D', 'D', 'S', ' '))
|
||||
if(fourcc != DDS_MAGIC)
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - unexpected magic number, wanted 'DDS '!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the size of the header.
|
||||
s.read(&tmp);
|
||||
//dds headers
|
||||
dds::DDS_HEADER header = {};
|
||||
dds::DDS_HEADER_DXT10 dx10header = {};
|
||||
//todo DX10 formats
|
||||
bool hasDx10Header = false;
|
||||
|
||||
if(tmp != 124)
|
||||
//read in header
|
||||
s.read(DDS_HEADER_SIZE, &header);
|
||||
//check for dx10 header support
|
||||
if ((header.ddspf.flags & DDS_FOURCC) && (header.ddspf.fourCC == dds::D3DFMT_DX10))
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - incorrect header size. Expected 124 bytes.");
|
||||
//read in dx10 header
|
||||
s.read(DDS_HEADER_DX10_SIZE, &dx10header);
|
||||
if (!dds::validateHeaderDx10(dx10header))
|
||||
return false;
|
||||
|
||||
hasDx10Header = true;
|
||||
}
|
||||
|
||||
//make sure our dds header is valid
|
||||
if (!dds::validateHeader(header))
|
||||
return false;
|
||||
|
||||
// store details
|
||||
mPitchOrLinearSize = header.pitchOrLinearSize;
|
||||
mMipMapCount = header.mipMapCount ? header.mipMapCount : 1;
|
||||
mHeight = header.height;
|
||||
mWidth = header.width;
|
||||
mDepth = header.depth;
|
||||
mFourCC = header.ddspf.fourCC;
|
||||
|
||||
//process dx10 header
|
||||
if (hasDx10Header)
|
||||
{
|
||||
if (dx10header.arraySize > 1)
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - DX10 arrays not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
mFormat = dds::getGFXFormat(dx10header.dxgiFormat);
|
||||
//make sure getGFXFormat gave us a valid format
|
||||
if (mFormat == GFXFormat_FIRST)
|
||||
return false;
|
||||
//cubemap
|
||||
if (dx10header.miscFlag & dds::D3D10_RESOURCE_MISC_TEXTURECUBE)
|
||||
{
|
||||
mFlags.set(CubeMap_All_Flags | ComplexFlag);
|
||||
}
|
||||
|
||||
mHasTransparency = ImageUtil::isAlphaFormat(mFormat);
|
||||
|
||||
//mip map flag
|
||||
if (mMipMapCount > 1)
|
||||
mFlags.set(MipMapsFlag | ComplexFlag);
|
||||
|
||||
if (ImageUtil::isCompressedFormat(mFormat))
|
||||
mFlags.set(CompressedData);
|
||||
else
|
||||
{
|
||||
mBytesPerPixel = header.ddspf.bpp / 8;
|
||||
mFlags.set(RGBData);
|
||||
}
|
||||
|
||||
// we finished now
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read some flags...
|
||||
U32 ddsdFlags;
|
||||
s.read(&ddsdFlags);
|
||||
//process regular header
|
||||
|
||||
// "Always include DDSD_CAPS, DDSD_PIXELFORMAT, DDSD_WIDTH, DDSD_HEIGHT."
|
||||
if(!(ddsdFlags & (DDSDCaps | DDSDPixelFormat | DDSDWidth | DDSDHeight)))
|
||||
//D3DFMT_DX10 is caught above, no need to check now
|
||||
if (header.ddspf.flags & DDS_FOURCC)
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - incorrect surface description flags.");
|
||||
return false;
|
||||
}
|
||||
mFormat = dds::getGFXFormat(mFourCC);
|
||||
//make sure getGFXFormat gave us a valid format
|
||||
if (mFormat == GFXFormat_FIRST)
|
||||
return false;
|
||||
|
||||
// Read height and width (always present)
|
||||
s.read(&mHeight);
|
||||
s.read(&mWidth);
|
||||
|
||||
// Read pitch or linear size.
|
||||
|
||||
// First make sure we have valid flags (either linear size or pitch).
|
||||
if((ddsdFlags & (DDSDLinearSize | DDSDPitch)) == (DDSDLinearSize | DDSDPitch))
|
||||
{
|
||||
// Both are invalid!
|
||||
Con::errorf("DDSFile::readHeader - encountered both DDSD_LINEARSIZE and DDSD_PITCH!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ok, some flags are set, so let's do some reading.
|
||||
s.read(&mPitchOrLinearSize);
|
||||
|
||||
if(ddsdFlags & DDSDLinearSize)
|
||||
{
|
||||
mFlags.set(LinearSizeFlag); // ( mHeight / 4 ) * ( mWidth / 4 ) * DDSSIZE
|
||||
}
|
||||
else if (ddsdFlags & DDSDPitch)
|
||||
{
|
||||
mFlags.set(PitchSizeFlag); // ( mWidth / 4 ) * DDSSIZE ???
|
||||
if (ImageUtil::isCompressedFormat(mFormat))
|
||||
mFlags.set(CompressedData);
|
||||
else
|
||||
{
|
||||
mBytesPerPixel = header.ddspf.bpp / 8;
|
||||
mFlags.set(RGBData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither set! This appears to be depressingly common.
|
||||
// Con::warnf("DDSFile::readHeader - encountered neither DDSD_LINEARSIZE nor DDSD_PITCH!");
|
||||
}
|
||||
mFormat = dds::getGFXFormat(header.ddspf);
|
||||
//make sure getGFXFormat gave us a valid format
|
||||
if (mFormat == GFXFormat_FIRST)
|
||||
return false;
|
||||
|
||||
// Do we need to read depth? If so, we are a volume texture!
|
||||
s.read(&mDepth);
|
||||
|
||||
if(ddsdFlags & DDSDDepth)
|
||||
{
|
||||
mFlags.set(VolumeFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wipe it if the flag wasn't set!
|
||||
mDepth = 0;
|
||||
}
|
||||
|
||||
// Deal with mips!
|
||||
s.read(&mMipMapCount);
|
||||
|
||||
if(ddsdFlags & DDSDMipMapCount)
|
||||
{
|
||||
mFlags.set(MipMapsFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wipe it if the flag wasn't set!
|
||||
mMipMapCount = 1;
|
||||
}
|
||||
|
||||
// Deal with 11 DWORDS of reserved space (this reserved space brought to
|
||||
// you by DirectDraw and the letters F and U).
|
||||
for(U32 i=0; i<11; i++)
|
||||
s.read(&tmp);
|
||||
|
||||
// Now we're onto the pixel format!
|
||||
s.read(&tmp);
|
||||
|
||||
if(tmp != 32)
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - pixel format chunk has unexpected size!");
|
||||
return false;
|
||||
}
|
||||
|
||||
U32 ddpfFlags;
|
||||
|
||||
s.read(&ddpfFlags);
|
||||
|
||||
// Read the next few values so we can deal with them all in one go.
|
||||
U32 pfFourCC, pfBitCount, pfRMask, pfGMask, pfBMask, pfAlphaMask;
|
||||
|
||||
s.read(&pfFourCC);
|
||||
s.read(&pfBitCount);
|
||||
s.read(&pfRMask);
|
||||
s.read(&pfGMask);
|
||||
s.read(&pfBMask);
|
||||
s.read(&pfAlphaMask);
|
||||
|
||||
// Sanity check flags...
|
||||
if(!(ddpfFlags & (DDPFRGB | DDPFFourCC | DDPFLUMINANCE)))
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - incoherent pixel flags, neither RGB, FourCC, or Luminance!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// For now let's just dump the header info.
|
||||
if(ddpfFlags & DDPFLUMINANCE)
|
||||
{
|
||||
mBytesPerPixel = header.ddspf.bpp / 8;
|
||||
mFlags.set(RGBData);
|
||||
|
||||
mBytesPerPixel = pfBitCount / 8;
|
||||
|
||||
bool hasAlpha = ddpfFlags & DDPFAlphaPixels;
|
||||
|
||||
mHasTransparency = hasAlpha;
|
||||
|
||||
// Try to match a format.
|
||||
if(hasAlpha)
|
||||
{
|
||||
// If it has alpha it is one of...
|
||||
// GFXFormatA8L8
|
||||
// GFXFormatA4L4
|
||||
|
||||
if(pfBitCount == 16)
|
||||
mFormat = GFXFormatA8L8;
|
||||
else if(pfBitCount == 8)
|
||||
mFormat = GFXFormatA4L4;
|
||||
else
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - unable to match alpha Luminance format!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise it is one of...
|
||||
// GFXFormatL16
|
||||
// GFXFormatL8
|
||||
|
||||
if(pfBitCount == 16)
|
||||
mFormat = GFXFormatL16;
|
||||
else if(pfBitCount == 8)
|
||||
mFormat = GFXFormatL8;
|
||||
else
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - unable to match non-alpha Luminance format!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ddpfFlags & DDPFRGB)
|
||||
{
|
||||
mFlags.set(RGBData);
|
||||
|
||||
//Con::printf("RGB Pixel format of DDS:");
|
||||
//Con::printf(" bitcount = %d (16, 24, 32)", pfBitCount);
|
||||
mBytesPerPixel = pfBitCount / 8;
|
||||
//Con::printf(" red mask = %x", pfRMask);
|
||||
//Con::printf(" green mask = %x", pfGMask);
|
||||
//Con::printf(" blue mask = %x", pfBMask);
|
||||
|
||||
bool hasAlpha = false;
|
||||
|
||||
if(ddpfFlags & DDPFAlphaPixels)
|
||||
{
|
||||
hasAlpha = true;
|
||||
//Con::printf(" alpha mask = %x", pfAlphaMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Con::printf(" no alpha.");
|
||||
}
|
||||
|
||||
mHasTransparency = hasAlpha;
|
||||
|
||||
// Try to match a format.
|
||||
if(hasAlpha)
|
||||
{
|
||||
// If it has alpha it is one of...
|
||||
// GFXFormatR8G8B8A8
|
||||
// GFXFormatR5G5B5A1
|
||||
// GFXFormatA8
|
||||
|
||||
if(pfBitCount == 32)
|
||||
mFormat = GFXFormatR8G8B8A8;
|
||||
else if(pfBitCount == 16)
|
||||
mFormat = GFXFormatR5G5B5A1;
|
||||
else if(pfBitCount == 8)
|
||||
mFormat = GFXFormatA8;
|
||||
else
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - unable to match alpha RGB format!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise it is one of...
|
||||
// GFXFormatR8G8B8
|
||||
// GFXFormatR8G8B8X8
|
||||
// GFXFormatR5G6B5
|
||||
// GFXFormatL8
|
||||
|
||||
if(pfBitCount == 24)
|
||||
mFormat = GFXFormatR8G8B8;
|
||||
else if(pfBitCount == 32)
|
||||
mFormat = GFXFormatR8G8B8X8;
|
||||
else if(pfBitCount == 16)
|
||||
mFormat = GFXFormatR5G6B5;
|
||||
else if(pfBitCount == 8)
|
||||
{
|
||||
// luminance
|
||||
mFormat = GFXFormatL8;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::errorf("DDSFile::readHeader - unable to match non-alpha RGB format!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sweet, all done.
|
||||
}
|
||||
else if (ddpfFlags & DDPFFourCC)
|
||||
{
|
||||
mHasTransparency = (ddpfFlags & DDPFAlphaPixels);
|
||||
mFlags.set(CompressedData);
|
||||
|
||||
/* Con::printf("FourCC Pixel format of DDS:");
|
||||
Con::printf(" fourcc = '%c%c%c%c'", ((U8*)&pfFourCC)[0], ((U8*)&pfFourCC)[1], ((U8*)&pfFourCC)[2], ((U8*)&pfFourCC)[3]); */
|
||||
|
||||
// Ok, make a format determination.
|
||||
switch(pfFourCC)
|
||||
{
|
||||
case FOURCC_DXT1:
|
||||
mFormat = GFXFormatDXT1;
|
||||
break;
|
||||
case FOURCC_DXT2:
|
||||
mFormat = GFXFormatDXT2;
|
||||
break;
|
||||
case FOURCC_DXT3:
|
||||
mFormat = GFXFormatDXT3;
|
||||
break;
|
||||
case FOURCC_DXT4:
|
||||
mFormat = GFXFormatDXT4;
|
||||
break;
|
||||
case FOURCC_DXT5:
|
||||
mFormat = GFXFormatDXT5;
|
||||
break;
|
||||
default:
|
||||
Con::errorf("DDSFile::readHeader - unknown fourcc = '%c%c%c%c'", ((U8*)&pfFourCC)[0], ((U8*)&pfFourCC)[1], ((U8*)&pfFourCC)[2], ((U8*)&pfFourCC)[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Deal with final caps bits... Is this really necessary?
|
||||
//mip map flag
|
||||
if (mMipMapCount > 1)
|
||||
mFlags.set(MipMapsFlag | ComplexFlag);
|
||||
|
||||
U32 caps1, caps2;
|
||||
s.read(&caps1);
|
||||
s.read(&caps2);
|
||||
s.read(&tmp);
|
||||
s.read(&tmp); // More icky reserved space.
|
||||
//set transparency flag
|
||||
mHasTransparency = (header.ddspf.flags & DDS_ALPHAPIXELS);
|
||||
|
||||
// Screw caps1.
|
||||
// if(!(caps1 & DDSCAPS_TEXTURE)))
|
||||
// {
|
||||
// }
|
||||
if (header.flags & DDS_HEADER_FLAGS_LINEARSIZE)
|
||||
mFlags.set(LinearSizeFlag);
|
||||
else if (header.flags & DDS_HEADER_FLAGS_PITCH)
|
||||
mFlags.set(PitchSizeFlag);
|
||||
|
||||
// Caps2 has cubemap/volume info. Care about that.
|
||||
if(caps2 & DDSCAPS2Cubemap)
|
||||
//set cubemap flags
|
||||
if (header.cubemapFlags & DDS_CUBEMAP)
|
||||
{
|
||||
mFlags.set(CubeMapFlag);
|
||||
|
||||
mFlags.set(CubeMapFlag | ComplexFlag);
|
||||
// Store the face flags too.
|
||||
if ( caps2 & DDSCAPS2Cubemap_POSITIVEX ) mFlags.set( CubeMap_PosX_Flag );
|
||||
if ( caps2 & DDSCAPS2Cubemap_NEGATIVEX ) mFlags.set( CubeMap_NegX_Flag );
|
||||
if ( caps2 & DDSCAPS2Cubemap_POSITIVEY ) mFlags.set( CubeMap_PosY_Flag );
|
||||
if ( caps2 & DDSCAPS2Cubemap_NEGATIVEY ) mFlags.set( CubeMap_NegY_Flag );
|
||||
if ( caps2 & DDSCAPS2Cubemap_POSITIVEZ ) mFlags.set( CubeMap_PosZ_Flag );
|
||||
if ( caps2 & DDSCAPS2Cubemap_NEGATIVEZ ) mFlags.set( CubeMap_NegZ_Flag );
|
||||
if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEX) mFlags.set(CubeMap_PosX_Flag);
|
||||
if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEX) mFlags.set(CubeMap_NegX_Flag);
|
||||
if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEY) mFlags.set(CubeMap_PosY_Flag);
|
||||
if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEY) mFlags.set(CubeMap_NegY_Flag);
|
||||
if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEZ) mFlags.set(CubeMap_PosZ_Flag);
|
||||
if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEZ) mFlags.set(CubeMap_NegZ_Flag);
|
||||
}
|
||||
|
||||
// MS has ANOTHER reserved word here. This one particularly sucks.
|
||||
s.read(&tmp);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DDSFile::read(Stream &s, U32 dropMipCount)
|
||||
{
|
||||
if( !readHeader(s) || mMipMapCount == 0 )
|
||||
if( !readHeader(s) )
|
||||
{
|
||||
Con::errorf("DDSFile::read - error reading header!");
|
||||
return false;
|
||||
|
|
@ -618,96 +413,82 @@ bool DDSFile::read(Stream &s, U32 dropMipCount)
|
|||
|
||||
bool DDSFile::writeHeader( Stream &s )
|
||||
{
|
||||
// Read the FOURCC
|
||||
s.write( 4, "DDS " );
|
||||
// write DDS magic
|
||||
U32 magic = DDS_MAGIC;
|
||||
s.write(magic);
|
||||
|
||||
U32 tmp = 0;
|
||||
dds::DDS_HEADER header = {};
|
||||
dds::DDS_HEADER_DXT10 dx10header = {};
|
||||
|
||||
// Read the size of the header.
|
||||
s.write( 124 );
|
||||
bool hasDx10Header = false;
|
||||
//flags
|
||||
U32 surfaceFlags = DDS_SURFACE_FLAGS_TEXTURE;
|
||||
U32 cubemapFlags = 0;
|
||||
U32 headerFlags = DDS_HEADER_FLAGS_TEXTURE;
|
||||
|
||||
// Read some flags...
|
||||
U32 ddsdFlags = DDSDCaps | DDSDPixelFormat | DDSDWidth | DDSDHeight;
|
||||
|
||||
if ( mFlags.test( CompressedData ) )
|
||||
ddsdFlags |= DDSDLinearSize;
|
||||
else
|
||||
ddsdFlags |= DDSDPitch;
|
||||
//pixel format
|
||||
const dds::DDS_PIXELFORMAT &format = dds::getDDSFormat(mFormat);
|
||||
|
||||
if ( mMipMapCount > 0 )
|
||||
ddsdFlags |= DDSDMipMapCount;
|
||||
|
||||
s.write( ddsdFlags );
|
||||
|
||||
// Read height and width (always present)
|
||||
s.write( mHeight );
|
||||
s.write( mWidth );
|
||||
|
||||
// Ok, some flags are set, so let's do some reading.
|
||||
s.write( mPitchOrLinearSize );
|
||||
|
||||
// Do we need to read depth? If so, we are a volume texture!
|
||||
s.write( mDepth );
|
||||
|
||||
// Deal with mips!
|
||||
s.write( mMipMapCount );
|
||||
|
||||
// Deal with 11 DWORDS of reserved space (this reserved space brought to
|
||||
// you by DirectDraw and the letters F and U).
|
||||
for(U32 i=0; i<11; i++)
|
||||
s.write( tmp ); // is this right?
|
||||
|
||||
// Now we're onto the pixel format!
|
||||
|
||||
// This is the size, in bits,
|
||||
// of the pixel format data.
|
||||
tmp = 32;
|
||||
s.write( tmp );
|
||||
|
||||
U32 ddpfFlags;
|
||||
|
||||
U32 fourCC = 0;
|
||||
|
||||
if ( mFlags.test( CompressedData ) )
|
||||
// todo better dx10 support
|
||||
if (format.fourCC == dds::D3DFMT_DX10)
|
||||
{
|
||||
ddpfFlags = DDPFFourCC;
|
||||
if (mFormat == GFXFormatDXT1)
|
||||
fourCC = FOURCC_DXT1;
|
||||
if (mFormat == GFXFormatDXT3)
|
||||
fourCC = FOURCC_DXT3;
|
||||
if (mFormat == GFXFormatDXT5)
|
||||
fourCC = FOURCC_DXT5;
|
||||
dx10header.dxgiFormat = dds::getDXGIFormat(mFormat);
|
||||
dx10header.arraySize = 1;
|
||||
dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
dx10header.miscFlag = 0;
|
||||
dx10header.miscFlags2 = 0;
|
||||
hasDx10Header = true;
|
||||
}
|
||||
|
||||
if (mFlags.test(CompressedData))
|
||||
headerFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
|
||||
else
|
||||
ddpfFlags = mBytesPerPixel == 4 ? DDPFRGB | DDPFAlphaPixels : DDPFRGB;
|
||||
headerFlags |= DDS_HEADER_FLAGS_PITCH;
|
||||
|
||||
s.write( ddpfFlags );
|
||||
if (mMipMapCount > 1)
|
||||
{
|
||||
surfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP;
|
||||
headerFlags |= DDS_HEADER_FLAGS_MIPMAP;
|
||||
}
|
||||
|
||||
// Read the next few values so we can deal with them all in one go.
|
||||
//U32 pfFourCC, pfBitCount, pfRMask, pfGMask, pfBMask, pfAlphaMask;
|
||||
//cubemap flags
|
||||
if (mFlags.test(CubeMapFlag))
|
||||
{
|
||||
surfaceFlags |= DDS_SURFACE_FLAGS_CUBEMAP;
|
||||
cubemapFlags |= DDS_CUBEMAP_ALLFACES;
|
||||
}
|
||||
|
||||
s.write( fourCC );
|
||||
s.write( mBytesPerPixel * 8 );
|
||||
s.write( 0x000000FF );
|
||||
s.write( 0x00FF0000 );
|
||||
s.write( 0x0000FF00 );
|
||||
s.write( 0xFF000000 );
|
||||
//volume texture
|
||||
if (mDepth > 0)
|
||||
{
|
||||
headerFlags |= DDS_HEADER_FLAGS_VOLUME;
|
||||
dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE3D;
|
||||
}
|
||||
|
||||
// Deal with final caps bits... Is this really necessary?
|
||||
|
||||
U32 caps1 = DDSCAPSTexture;
|
||||
if ( mMipMapCount > 0 )
|
||||
caps1 |= DDSCAPSComplex | DDSCAPSMipMap;
|
||||
//main dds header
|
||||
header.size = sizeof(dds::DDS_HEADER);
|
||||
header.flags = headerFlags;
|
||||
header.height = mHeight;
|
||||
header.width = mWidth;
|
||||
header.pitchOrLinearSize = mPitchOrLinearSize;
|
||||
header.depth = mDepth;
|
||||
header.ddspf = format;
|
||||
header.mipMapCount = mMipMapCount;
|
||||
header.surfaceFlags = surfaceFlags;
|
||||
header.cubemapFlags = cubemapFlags;
|
||||
memset(header.reserved1, 0, sizeof(header.reserved1));
|
||||
memset(header.reserved2, 0, sizeof(header.reserved2));
|
||||
|
||||
tmp = 0;
|
||||
//check our header is ok
|
||||
if (!dds::validateHeader(header))
|
||||
return false;
|
||||
|
||||
s.write( caps1 );
|
||||
s.write( tmp );
|
||||
s.write( tmp );
|
||||
s.write( tmp );// More icky reserved space.
|
||||
|
||||
// MS has ANOTHER reserved word here. This one particularly sucks.
|
||||
s.write( tmp );
|
||||
//Write out the header
|
||||
s.write(DDS_HEADER_SIZE, &header);
|
||||
|
||||
//Write out dx10 header
|
||||
if (hasDx10Header)
|
||||
s.write(DDS_HEADER_DX10_SIZE, &dx10header);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -720,13 +501,16 @@ bool DDSFile::write( Stream &s )
|
|||
return false;
|
||||
}
|
||||
|
||||
// At this point we know what sort of image we contain. So we should
|
||||
// allocate some buffers, and read it in.
|
||||
|
||||
// How many surfaces are we talking about?
|
||||
if(mFlags.test(CubeMapFlag))
|
||||
{
|
||||
// Do something with cubemaps.
|
||||
for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++)
|
||||
{
|
||||
// write the mips
|
||||
for (S32 i = 0; i < mMipMapCount; i++)
|
||||
mSurfaces[cubeFace]->writeNextMip(this, s, mHeight, mWidth, i);
|
||||
}
|
||||
}
|
||||
else if (mFlags.test(VolumeFlag))
|
||||
{
|
||||
|
|
@ -912,6 +696,82 @@ DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
|
|||
return ret;
|
||||
}
|
||||
|
||||
DDSFile *DDSFile::createDDSCubemapFileFromGBitmaps(GBitmap **gbmps)
|
||||
{
|
||||
if (gbmps == NULL)
|
||||
return NULL;
|
||||
|
||||
AssertFatal(gbmps[0], "createDDSCubemapFileFromGBitmaps bitmap 0 is null");
|
||||
AssertFatal(gbmps[1], "createDDSCubemapFileFromGBitmaps bitmap 1 is null");
|
||||
AssertFatal(gbmps[2], "createDDSCubemapFileFromGBitmaps bitmap 2 is null");
|
||||
AssertFatal(gbmps[3], "createDDSCubemapFileFromGBitmaps bitmap 3 is null");
|
||||
AssertFatal(gbmps[4], "createDDSCubemapFileFromGBitmaps bitmap 4 is null");
|
||||
AssertFatal(gbmps[5], "createDDSCubemapFileFromGBitmaps bitmap 5 is null");
|
||||
|
||||
DDSFile *ret = new DDSFile;
|
||||
//all cubemaps have the same dimensions and formats
|
||||
GBitmap *pBitmap = gbmps[0];
|
||||
|
||||
if (pBitmap->getFormat() != GFXFormatR8G8B8A8)
|
||||
{
|
||||
Con::errorf("createDDSCubemapFileFromGBitmaps: Only GFXFormatR8G8B8A8 supported for now");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set up the DDSFile properties that matter. Since this is a GBitmap, there
|
||||
// are assumptions that can be made
|
||||
ret->mHeight = pBitmap->getHeight();
|
||||
ret->mWidth = pBitmap->getWidth();
|
||||
ret->mDepth = 0;
|
||||
ret->mFormat = pBitmap->getFormat();
|
||||
ret->mFlags.set( RGBData | CubeMapFlag | CubeMap_PosX_Flag | CubeMap_NegX_Flag | CubeMap_PosY_Flag |
|
||||
CubeMap_NegY_Flag | CubeMap_PosZ_Flag | CubeMap_NegZ_Flag);
|
||||
ret->mBytesPerPixel = pBitmap->getBytesPerPixel();
|
||||
//todo implement mip mapping
|
||||
ret->mMipMapCount = pBitmap->getNumMipLevels();
|
||||
ret->mHasTransparency = pBitmap->getHasTransparency();
|
||||
|
||||
for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++)
|
||||
{
|
||||
ret->mSurfaces.push_back(new SurfaceData());
|
||||
// Load the mips
|
||||
for (S32 i = 0; i < ret->mMipMapCount; i++)
|
||||
{
|
||||
const U32 mipSz = ret->getSurfaceSize(i);
|
||||
ret->mSurfaces.last()->mMips.push_back(new U8[mipSz]);
|
||||
|
||||
U8 *mipMem = ret->mSurfaces.last()->mMips.last();
|
||||
//straight copy
|
||||
dMemcpy(mipMem, gbmps[cubeFace]->getBits(i), mipSz);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DDSFile::decompressToGBitmap(GBitmap *dest)
|
||||
{
|
||||
// TBD: do we support other formats?
|
||||
if (mFormat != GFXFormatBC1 && mFormat != GFXFormatBC2 && mFormat != GFXFormatBC3)
|
||||
return false;
|
||||
|
||||
dest->allocateBitmapWithMips(getWidth(), getHeight(), getMipLevels(), GFXFormatR8G8B8A8);
|
||||
|
||||
// Decompress and copy mips...
|
||||
|
||||
U32 numMips = getMipLevels();
|
||||
|
||||
for (U32 i = 0; i < numMips; i++)
|
||||
{
|
||||
U8 *addr = dest->getAddress(0, 0, i);
|
||||
const U8 *mipBuffer = mSurfaces[0]->mMips[i];
|
||||
ImageUtil::decompress(mipBuffer, addr, getWidth(i), getHeight(i), mFormat);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DefineEngineFunction( getActiveDDSFiles, S32, (),,
|
||||
"Returns the count of active DDSs files in memory.\n"
|
||||
"@ingroup Rendering\n" )
|
||||
|
|
@ -65,6 +65,7 @@ struct DDSFile
|
|||
CubeMap_NegY_Flag = BIT(11),
|
||||
CubeMap_PosZ_Flag = BIT(12),
|
||||
CubeMap_NegZ_Flag = BIT(13),
|
||||
CubeMap_All_Flags = CubeMapFlag|CubeMap_PosX_Flag | CubeMap_NegX_Flag | CubeMap_PosY_Flag | CubeMap_NegY_Flag | CubeMap_PosZ_Flag | CubeMap_NegZ_Flag,
|
||||
};
|
||||
|
||||
/// The index into mSurfaces for each
|
||||
|
|
@ -115,9 +116,6 @@ struct DDSFile
|
|||
|
||||
Vector<U8*> mMips;
|
||||
|
||||
// Helper function to read in a mipchain.
|
||||
bool readMipChain();
|
||||
|
||||
void dumpImage(DDSFile *dds, U32 mip, const char *file);
|
||||
|
||||
/// Helper for reading a mip level.
|
||||
|
|
@ -200,6 +198,9 @@ struct DDSFile
|
|||
}
|
||||
|
||||
static DDSFile *createDDSFileFromGBitmap( const GBitmap *gbmp );
|
||||
//Create a single cubemap texture from 6 GBitmap
|
||||
static DDSFile *createDDSCubemapFileFromGBitmaps(GBitmap **gbmps);
|
||||
bool decompressToGBitmap(GBitmap *dest);
|
||||
};
|
||||
|
||||
#endif // _DDSFILE_H_
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "squish/squish.h"
|
||||
#include "gfx/bitmap/ddsFile.h"
|
||||
#include "gfx/bitmap/ddsUtils.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// If false is returned, from this method, the source DDS is not modified
|
||||
bool DDSUtil::squishDDS( DDSFile *srcDDS, const GFXFormat dxtFormat )
|
||||
{
|
||||
// Sanity check
|
||||
if( srcDDS->mBytesPerPixel != 4 )
|
||||
{
|
||||
AssertFatal( false, "Squish wants 32-bit source data" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build flags, start with fast compress
|
||||
U32 squishFlags = squish::kColourRangeFit;
|
||||
|
||||
// Flag which format we are using
|
||||
switch( dxtFormat )
|
||||
{
|
||||
case GFXFormatDXT1:
|
||||
squishFlags |= squish::kDxt1;
|
||||
break;
|
||||
|
||||
case GFXFormatDXT2:
|
||||
case GFXFormatDXT3:
|
||||
squishFlags |= squish::kDxt3;
|
||||
break;
|
||||
|
||||
case GFXFormatDXT4:
|
||||
case GFXFormatDXT5:
|
||||
squishFlags |= squish::kDxt5;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal( false, "Assumption failed" );
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// We got this far, so assume we can finish (gosh I hope so)
|
||||
srcDDS->mFormat = dxtFormat;
|
||||
srcDDS->mFlags.set( DDSFile::CompressedData );
|
||||
|
||||
// If this has alpha, set the flag
|
||||
if( srcDDS->mFormat == GFXFormatR8G8B8A8 )
|
||||
squishFlags |= squish::kWeightColourByAlpha;
|
||||
|
||||
// The source surface is the original surface of the file
|
||||
DDSFile::SurfaceData *srcSurface = srcDDS->mSurfaces.last();
|
||||
|
||||
// Create a new surface, this will be the DXT compressed surface. Once we
|
||||
// are done, we can discard the old surface, and replace it with this one.
|
||||
DDSFile::SurfaceData *newSurface = new DDSFile::SurfaceData();
|
||||
|
||||
for( S32 i = 0; i < srcDDS->mMipMapCount; i++ )
|
||||
{
|
||||
const U8 *srcBits = srcSurface->mMips[i];
|
||||
|
||||
const U32 mipSz = srcDDS->getSurfaceSize(i);
|
||||
U8 *dstBits = new U8[mipSz];
|
||||
newSurface->mMips.push_back( dstBits );
|
||||
|
||||
PROFILE_START(SQUISH_DXT_COMPRESS);
|
||||
|
||||
// Compress with Squish
|
||||
squish::CompressImage( srcBits, srcDDS->getWidth(i), srcDDS->getHeight(i),
|
||||
dstBits, squishFlags );
|
||||
|
||||
PROFILE_END();
|
||||
}
|
||||
|
||||
// Now delete the source surface, and return.
|
||||
srcDDS->mSurfaces.pop_back();
|
||||
delete srcSurface;
|
||||
srcDDS->mSurfaces.push_back( newSurface );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void DDSUtil::swizzleDDS( DDSFile *srcDDS, const Swizzle<U8, 4> &swizzle )
|
||||
{
|
||||
for( S32 i = 0; i < srcDDS->mMipMapCount; i++ )
|
||||
{
|
||||
swizzle.InPlace( srcDDS->mSurfaces.last()->mMips[i], srcDDS->getSurfaceSize( i ) );
|
||||
}
|
||||
}
|
||||
|
|
@ -347,6 +347,77 @@ void GBitmap::allocateBitmap(const U32 in_width, const U32 in_height, const bool
|
|||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GBitmap::allocateBitmapWithMips(const U32 in_width, const U32 in_height, const U32 in_numMips, const GFXFormat in_format)
|
||||
{
|
||||
//-------------------------------------- Some debug checks...
|
||||
U32 svByteSize = mByteSize;
|
||||
U8 *svBits = mBits;
|
||||
|
||||
AssertFatal(in_width != 0 && in_height != 0, "GBitmap::allocateBitmap: width or height is 0");
|
||||
|
||||
mInternalFormat = in_format;
|
||||
mWidth = in_width;
|
||||
mHeight = in_height;
|
||||
|
||||
mBytesPerPixel = 1;
|
||||
switch (mInternalFormat)
|
||||
{
|
||||
case GFXFormatA8:
|
||||
case GFXFormatL8: mBytesPerPixel = 1;
|
||||
break;
|
||||
case GFXFormatR8G8B8: mBytesPerPixel = 3;
|
||||
break;
|
||||
case GFXFormatR8G8B8X8:
|
||||
case GFXFormatR8G8B8A8: mBytesPerPixel = 4;
|
||||
break;
|
||||
case GFXFormatR5G6B5:
|
||||
case GFXFormatR5G5B5A1: mBytesPerPixel = 2;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(false, "GBitmap::GBitmap: misunderstood format specifier");
|
||||
break;
|
||||
}
|
||||
|
||||
// Set up the mip levels, if necessary...
|
||||
mNumMipLevels = 1;
|
||||
U32 allocPixels = in_width * in_height * mBytesPerPixel;
|
||||
mMipLevelOffsets[0] = 0;
|
||||
|
||||
|
||||
if (in_numMips != 0)
|
||||
{
|
||||
U32 currWidth = in_width;
|
||||
U32 currHeight = in_height;
|
||||
|
||||
do
|
||||
{
|
||||
mMipLevelOffsets[mNumMipLevels] = mMipLevelOffsets[mNumMipLevels - 1] +
|
||||
(currWidth * currHeight * mBytesPerPixel);
|
||||
currWidth >>= 1;
|
||||
currHeight >>= 1;
|
||||
if (currWidth == 0) currWidth = 1;
|
||||
if (currHeight == 0) currHeight = 1;
|
||||
|
||||
mNumMipLevels++;
|
||||
allocPixels += currWidth * currHeight * mBytesPerPixel;
|
||||
} while (currWidth != 1 || currHeight != 1 && mNumMipLevels != in_numMips);
|
||||
}
|
||||
AssertFatal(mNumMipLevels <= c_maxMipLevels, "GBitmap::allocateBitmap: too many miplevels");
|
||||
|
||||
// Set up the memory...
|
||||
mByteSize = allocPixels;
|
||||
mBits = new U8[mByteSize];
|
||||
|
||||
dMemset(mBits, 0xFF, mByteSize);
|
||||
|
||||
if (svBits != NULL)
|
||||
{
|
||||
dMemcpy(mBits, svBits, getMin(mByteSize, svByteSize));
|
||||
delete[] svBits;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GBitmap::extrudeMipLevels(bool clearBorders)
|
||||
{
|
||||
|
|
@ -410,6 +481,38 @@ void GBitmap::extrudeMipLevels(bool clearBorders)
|
|||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GBitmap::chopTopMips(U32 mipsToChop)
|
||||
{
|
||||
U32 scalePower = getMin(mipsToChop, getNumMipLevels() - 1);
|
||||
U32 newMipCount = getNumMipLevels() - scalePower;
|
||||
|
||||
U32 realWidth = getMax((U32)1, getWidth() >> scalePower);
|
||||
U32 realHeight = getMax((U32)1, getHeight() >> scalePower);
|
||||
|
||||
U8 *destBits = mBits;
|
||||
|
||||
U32 destOffsets[c_maxMipLevels];
|
||||
|
||||
for (U32 i = scalePower; i<mNumMipLevels; i++)
|
||||
{
|
||||
// Copy to the new bitmap...
|
||||
dMemcpy(destBits,
|
||||
getWritableBits(i),
|
||||
getSurfaceSize(i));
|
||||
|
||||
destOffsets[i - scalePower] = destBits - mBits;
|
||||
destBits += getSurfaceSize(i);
|
||||
}
|
||||
|
||||
dMemcpy(mMipLevelOffsets, destOffsets, sizeof(destOffsets));
|
||||
|
||||
mWidth = realWidth;
|
||||
mHeight = realHeight;
|
||||
mByteSize = destBits - mBits;
|
||||
mNumMipLevels = newMipCount;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GBitmap::extrudeMipLevelsDetail()
|
||||
{
|
||||
|
|
@ -609,9 +712,9 @@ bool GBitmap::checkForTransparency()
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ColorF GBitmap::sampleTexel(F32 u, F32 v) const
|
||||
LinearColorF GBitmap::sampleTexel(F32 u, F32 v) const
|
||||
{
|
||||
ColorF col(0.5f, 0.5f, 0.5f);
|
||||
LinearColorF col(0.5f, 0.5f, 0.5f);
|
||||
// normally sampling wraps all the way around at 1.0,
|
||||
// but locking doesn't support this, and we seem to calc
|
||||
// the uv based on a clamped 0 - 1...
|
||||
|
|
@ -733,6 +836,20 @@ bool GBitmap::setColor(const U32 x, const U32 y, const ColorI& rColor)
|
|||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
U8 GBitmap::getChanelValueAt(U32 x, U32 y, U32 chan)
|
||||
{
|
||||
ColorI pixelColor = ColorI(255,255,255,255);
|
||||
getColor(x, y, pixelColor);
|
||||
|
||||
switch (chan) {
|
||||
case 0: return pixelColor.red;
|
||||
case 1: return pixelColor.green;
|
||||
case 2: return pixelColor.blue;
|
||||
default: return pixelColor.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool GBitmap::combine( const GBitmap *bitmapA, const GBitmap *bitmapB, const GFXTextureOp combineOp )
|
||||
|
|
@ -1175,6 +1292,41 @@ Resource<GBitmap> GBitmap::_search(const Torque::Path &path)
|
|||
return Resource< GBitmap >( NULL );
|
||||
}
|
||||
|
||||
U32 GBitmap::getSurfaceSize(const U32 mipLevel) const
|
||||
{
|
||||
// Bump by the mip level.
|
||||
U32 height = getMax(U32(1), mHeight >> mipLevel);
|
||||
U32 width = getMax(U32(1), mWidth >> mipLevel);
|
||||
|
||||
if (mInternalFormat >= GFXFormatBC1 && mInternalFormat <= GFXFormatBC3)
|
||||
{
|
||||
// From the directX docs:
|
||||
// max(1, width ÷ 4) x max(1, height ÷ 4) x 8(DXT1) or 16(DXT2-5)
|
||||
|
||||
U32 sizeMultiple = 0;
|
||||
|
||||
switch (mInternalFormat)
|
||||
{
|
||||
case GFXFormatBC1:
|
||||
sizeMultiple = 8;
|
||||
break;
|
||||
case GFXFormatBC2:
|
||||
case GFXFormatBC3:
|
||||
sizeMultiple = 16;
|
||||
break;
|
||||
default:
|
||||
AssertISV(false, "DDSFile::getSurfaceSize - invalid compressed texture format, we only support DXT1-5 right now.");
|
||||
break;
|
||||
}
|
||||
|
||||
return getMax(U32(1), width / 4) * getMax(U32(1), height / 4) * sizeMultiple;
|
||||
}
|
||||
else
|
||||
{
|
||||
return height * width* mBytesPerPixel;
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineFunction( getBitmapInfo, String, ( const char *filename ),,
|
||||
"Returns image info in the following format: width TAB height TAB bytesPerPixel. "
|
||||
"It will return an empty string if the file is not found.\n"
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class Stream;
|
|||
class RectI;
|
||||
class Point2I;
|
||||
class ColorI;
|
||||
class ColorF;
|
||||
class LinearColorF;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- GBitmap
|
||||
|
|
@ -151,7 +151,13 @@ public:
|
|||
const bool in_extrudeMipLevels = false,
|
||||
const GFXFormat in_format = GFXFormatR8G8B8 );
|
||||
|
||||
void allocateBitmapWithMips(const U32 in_width,
|
||||
const U32 in_height,
|
||||
const U32 in_numMips,
|
||||
const GFXFormat in_format = GFXFormatR8G8B8);
|
||||
|
||||
void extrudeMipLevels(bool clearBorders = false);
|
||||
void chopTopMips(U32 mipsToChop);
|
||||
void extrudeMipLevelsDetail();
|
||||
|
||||
U32 getNumMipLevels() const { return mNumMipLevels; }
|
||||
|
|
@ -182,6 +188,8 @@ public:
|
|||
U32 getByteSize() const { return mByteSize; }
|
||||
U32 getBytesPerPixel() const { return mBytesPerPixel; }
|
||||
|
||||
U32 getSurfaceSize(const U32 mipLevel) const;
|
||||
|
||||
/// Use these functions to set and get the mHasTransparency value
|
||||
/// This is used to indicate that this bitmap has pixels that have
|
||||
/// an alpha value less than 255 (used by the auto-Material mapper)
|
||||
|
|
@ -194,9 +202,10 @@ public:
|
|||
/// the bitmap bits and to check for alpha values less than 255
|
||||
bool checkForTransparency();
|
||||
|
||||
ColorF sampleTexel(F32 u, F32 v) const;
|
||||
LinearColorF sampleTexel(F32 u, F32 v) const;
|
||||
bool getColor(const U32 x, const U32 y, ColorI& rColor) const;
|
||||
bool setColor(const U32 x, const U32 y, const ColorI& rColor);
|
||||
U8 getChanelValueAt(U32 x, U32 y, U32 chan);
|
||||
|
||||
/// This method will combine bitmapA and bitmapB using the operation specified
|
||||
/// by combineOp. The result will be stored in the bitmap that this method is
|
||||
|
|
|
|||
304
Engine/source/gfx/bitmap/imageUtils.cpp
Normal file
304
Engine/source/gfx/bitmap/imageUtils.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gfx/bitmap/imageUtils.h"
|
||||
#include "gfx/bitmap/ddsFile.h"
|
||||
#include "platform/threads/threadPool.h"
|
||||
#include "squish/squish.h"
|
||||
|
||||
namespace ImageUtil
|
||||
{
|
||||
// get squish quality flag
|
||||
S32 _getSquishQuality(const CompressQuality quality)
|
||||
{
|
||||
switch (quality)
|
||||
{
|
||||
case LowQuality:
|
||||
return squish::kColourRangeFit;
|
||||
case MediumQuality:
|
||||
return squish::kColourClusterFit;
|
||||
case HighQuality:
|
||||
return squish::kColourIterativeClusterFit;
|
||||
default:
|
||||
return squish::kColourRangeFit;//default is low quality
|
||||
}
|
||||
}
|
||||
|
||||
// get squish compression flag
|
||||
S32 _getSquishFormat(const GFXFormat compressFormat)
|
||||
{
|
||||
switch (compressFormat)
|
||||
{
|
||||
case GFXFormatBC1:
|
||||
return squish::kDxt1;
|
||||
case GFXFormatBC2:
|
||||
return squish::kDxt3;
|
||||
case GFXFormatBC3:
|
||||
return squish::kDxt5;
|
||||
case GFXFormatBC4:
|
||||
return squish::kBc4;
|
||||
case GFXFormatBC5:
|
||||
return squish::kBc5;
|
||||
default:
|
||||
return squish::kDxt1;
|
||||
}
|
||||
}
|
||||
|
||||
//Thread work job for compression
|
||||
struct CompressJob : public ThreadPool::WorkItem
|
||||
{
|
||||
S32 width;
|
||||
S32 height;
|
||||
S32 flags;
|
||||
const U8 *pSrc;
|
||||
U8 *pDst;
|
||||
GFXFormat format;
|
||||
CompressQuality quality;
|
||||
|
||||
CompressJob(const U8 *srcRGBA, U8 *dst, const S32 w, const S32 h, const GFXFormat compressFormat, const CompressQuality compressQuality)
|
||||
: pSrc(srcRGBA),pDst(dst), width(w), height(h), format(compressFormat),quality(compressQuality) {}
|
||||
|
||||
protected:
|
||||
virtual void execute()
|
||||
{
|
||||
rawCompress(pSrc,pDst, width, height, format,quality);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// compress raw pixel data, expects rgba format
|
||||
bool rawCompress(const U8 *srcRGBA, U8 *dst, const S32 width, const S32 height, const GFXFormat compressFormat, const CompressQuality compressQuality)
|
||||
{
|
||||
if (!isCompressedFormat(compressFormat))
|
||||
return false;
|
||||
|
||||
S32 squishFlags = _getSquishQuality(compressQuality);
|
||||
S32 squishFormat = _getSquishFormat(compressFormat);
|
||||
|
||||
squishFlags |= squishFormat;
|
||||
|
||||
squish::CompressImage(srcRGBA, width,height,dst,squishFlags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// compress DDSFile
|
||||
bool ddsCompress(DDSFile *srcDDS, const GFXFormat compressFormat,const CompressQuality compressQuality)
|
||||
{
|
||||
if (srcDDS->mBytesPerPixel != 4)
|
||||
{
|
||||
Con::errorf("ImageCompress::ddsCompress: data must be 32bit");
|
||||
return false;
|
||||
}
|
||||
|
||||
//can't compress DDSFile if it is already compressed
|
||||
if (ImageUtil::isCompressedFormat(srcDDS->mFormat))
|
||||
{
|
||||
Con::errorf("ImageCompress::ddsCompress: file is already compressed");
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool cubemap = srcDDS->mFlags.test(DDSFile::CubeMapFlag);
|
||||
const U32 mipCount = srcDDS->mMipMapCount;
|
||||
// We got this far, so assume we can finish (gosh I hope so)
|
||||
srcDDS->mFormat = compressFormat;
|
||||
srcDDS->mFlags.set(DDSFile::CompressedData);
|
||||
|
||||
//grab global thread pool
|
||||
ThreadPool* pThreadPool = &ThreadPool::GLOBAL();
|
||||
|
||||
if (cubemap)
|
||||
{
|
||||
static U32 nCubeFaces = 6;
|
||||
Vector<U8*> dstDataStore;
|
||||
dstDataStore.setSize(nCubeFaces * mipCount);
|
||||
|
||||
for (S32 cubeFace = 0; cubeFace < nCubeFaces; cubeFace++)
|
||||
{
|
||||
DDSFile::SurfaceData *srcSurface = srcDDS->mSurfaces[cubeFace];
|
||||
for (U32 currentMip = 0; currentMip < mipCount; currentMip++)
|
||||
{
|
||||
const U32 dataIndex = cubeFace * mipCount + currentMip;
|
||||
const U8 *srcBits = srcSurface->mMips[currentMip];
|
||||
const U32 mipSz = srcDDS->getSurfaceSize(currentMip);
|
||||
U8 *dstBits = new U8[mipSz];
|
||||
dstDataStore[dataIndex] = dstBits;
|
||||
|
||||
ThreadSafeRef<CompressJob> item(new CompressJob(srcBits, dstBits, srcDDS->getWidth(currentMip), srcDDS->getHeight(currentMip), compressFormat, compressQuality));
|
||||
pThreadPool->queueWorkItem(item);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//wait for work items to finish
|
||||
pThreadPool->waitForAllItems();
|
||||
|
||||
for (S32 cubeFace = 0; cubeFace < nCubeFaces; cubeFace++)
|
||||
{
|
||||
DDSFile::SurfaceData *pSrcSurface = srcDDS->mSurfaces[cubeFace];
|
||||
for (U32 currentMip = 0; currentMip < mipCount; currentMip++)
|
||||
{
|
||||
const U32 dataIndex = cubeFace * mipCount + currentMip;
|
||||
delete[] pSrcSurface->mMips[currentMip];
|
||||
pSrcSurface->mMips[currentMip] = dstDataStore[dataIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The source surface is the original surface of the file
|
||||
DDSFile::SurfaceData *pSrcSurface = srcDDS->mSurfaces.last();
|
||||
|
||||
// Create a new surface, this will be the DXT compressed surface. Once we
|
||||
// are done, we can discard the old surface, and replace it with this one.
|
||||
DDSFile::SurfaceData *pNewSurface = new DDSFile::SurfaceData();
|
||||
//no point using threading if only 1 mip
|
||||
const bool useThreading = bool(mipCount > 1);
|
||||
for (U32 currentMip = 0; currentMip < mipCount; currentMip++)
|
||||
{
|
||||
const U8 *pSrcBits = pSrcSurface->mMips[currentMip];
|
||||
|
||||
const U32 mipSz = srcDDS->getSurfaceSize(currentMip);
|
||||
U8 *pDstBits = new U8[mipSz];
|
||||
pNewSurface->mMips.push_back(pDstBits);
|
||||
|
||||
if (useThreading)
|
||||
{
|
||||
// Create CompressJob item
|
||||
ThreadSafeRef<CompressJob> item(new CompressJob(pSrcBits, pDstBits, srcDDS->getWidth(currentMip), srcDDS->getHeight(currentMip), compressFormat, compressQuality));
|
||||
pThreadPool->queueWorkItem(item);
|
||||
}
|
||||
else
|
||||
rawCompress(pSrcBits, pDstBits, srcDDS->getWidth(currentMip), srcDDS->getHeight(currentMip), compressFormat, compressQuality);
|
||||
|
||||
}
|
||||
//block and wait for CompressJobs to finish
|
||||
if(useThreading)
|
||||
pThreadPool->waitForAllItems();
|
||||
|
||||
// Now delete the source surface and replace with new compressed surface
|
||||
srcDDS->mSurfaces.pop_back();
|
||||
delete pSrcSurface;
|
||||
srcDDS->mSurfaces.push_back(pNewSurface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool decompress(const U8 *src, U8 *dstRGBA,const S32 width,const S32 height, const GFXFormat srcFormat)
|
||||
{
|
||||
if (!isCompressedFormat(srcFormat))
|
||||
return false;
|
||||
|
||||
S32 squishFlag = _getSquishFormat(srcFormat);
|
||||
squish::DecompressImage(dstRGBA, width, height, src, squishFlag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void swizzleDDS(DDSFile *srcDDS, const Swizzle<U8, 4> &swizzle)
|
||||
{
|
||||
if (srcDDS->mFlags.test(DDSFile::CubeMapFlag))
|
||||
{
|
||||
for (S32 cubeFace = 0; cubeFace < DDSFile::Cubemap_Surface_Count; cubeFace++)
|
||||
{
|
||||
for (S32 i = 0; i < srcDDS->mMipMapCount; i++)
|
||||
{
|
||||
swizzle.InPlace(srcDDS->mSurfaces[cubeFace]->mMips[i], srcDDS->getSurfaceSize(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 i = 0; i < srcDDS->mMipMapCount; i++)
|
||||
{
|
||||
swizzle.InPlace(srcDDS->mSurfaces.last()->mMips[i], srcDDS->getSurfaceSize(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isCompressedFormat(const GFXFormat format)
|
||||
{
|
||||
if (format >= GFXFormatBC1 && format <= GFXFormatBC3_SRGB)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isAlphaFormat(const GFXFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GFXFormatA8:
|
||||
case GFXFormatA4L4:
|
||||
case GFXFormatA8L8:
|
||||
case GFXFormatR5G5B5A1:
|
||||
case GFXFormatR8G8B8A8:
|
||||
case GFXFormatB8G8R8A8:
|
||||
case GFXFormatR16G16B16A16F:
|
||||
case GFXFormatR32G32B32A32F:
|
||||
case GFXFormatR10G10B10A2:
|
||||
//case GFXFormatBC1://todo BC1 can store alpha
|
||||
case GFXFormatBC2:
|
||||
case GFXFormatBC3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isSRGBFormat(const GFXFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GFXFormatR8G8B8_SRGB:
|
||||
case GFXFormatR8G8B8A8_SRGB:
|
||||
case GFXFormatBC1_SRGB:
|
||||
case GFXFormatBC2_SRGB:
|
||||
case GFXFormatBC3_SRGB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
GFXFormat toSRGBFormat(const GFXFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GFXFormatR8G8B8:
|
||||
return GFXFormatR8G8B8_SRGB;
|
||||
case GFXFormatR8G8B8X8:
|
||||
case GFXFormatR8G8B8A8:
|
||||
return GFXFormatR8G8B8A8_SRGB;
|
||||
case GFXFormatBC1:
|
||||
return GFXFormatBC1_SRGB;
|
||||
case GFXFormatBC2:
|
||||
return GFXFormatBC2_SRGB;
|
||||
case GFXFormatBC3:
|
||||
return GFXFormatBC3_SRGB;
|
||||
default:
|
||||
return format;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
// Copyright (c) 2016 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
|
|
@ -20,15 +20,43 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _DDS_UTILS_H_
|
||||
#define _DDS_UTILS_H_
|
||||
#ifndef _IMAGE_UTILS_H_
|
||||
#define _IMAGE_UTILS_H_
|
||||
|
||||
#ifndef _SWIZZLE_H_
|
||||
#include "core/util/swizzle.h"
|
||||
#endif
|
||||
#ifndef _GFXENUMS_H_
|
||||
#include "gfx/gfxEnums.h"
|
||||
#endif
|
||||
|
||||
struct DDSFile;
|
||||
|
||||
namespace DDSUtil
|
||||
namespace ImageUtil
|
||||
{
|
||||
bool squishDDS( DDSFile *srcDDS, const GFXFormat dxtFormat );
|
||||
void swizzleDDS( DDSFile *srcDDS, const Swizzle<U8, 4> &swizzle );
|
||||
enum CompressQuality
|
||||
{
|
||||
LowQuality,
|
||||
MediumQuality,
|
||||
HighQuality
|
||||
};
|
||||
|
||||
// compress raw pixel data, expects rgba format
|
||||
bool rawCompress(const U8 *srcRGBA, U8 *dst, const S32 width, const S32 height, const GFXFormat compressFormat, const CompressQuality compressQuality = LowQuality);
|
||||
// compress DDSFile
|
||||
bool ddsCompress(DDSFile *srcDDS, const GFXFormat compressFormat, const CompressQuality compressQuality = LowQuality);
|
||||
// decompress compressed pixel data, dest data should be rgba format
|
||||
bool decompress(const U8 *src, U8 *dstRGBA, const S32 width, const S32 height, const GFXFormat srcFormat);
|
||||
//swizzle dds file
|
||||
void swizzleDDS(DDSFile *srcDDS, const Swizzle<U8, 4> &swizzle);
|
||||
//check if a GFXFormat is compressed
|
||||
bool isCompressedFormat(const GFXFormat format);
|
||||
bool isSRGBFormat(const GFXFormat format);
|
||||
//check if a GFXFormat has an alpha channel
|
||||
bool isAlphaFormat(const GFXFormat format);
|
||||
|
||||
//convert to sRGB format
|
||||
GFXFormat toSRGBFormat(const GFXFormat format);
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue