1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
extern crate dds;

use gl;
use gl::types::*;
use std::mem;
use std::borrow::Borrow;
use self::dds::DXGIFormat;

use features::traits::{Image, CubemapImage};

impl<S: Borrow<[u8]>> Image for dds::Dds<S> {
    type DataType = u8;

    // From https://raw.githubusercontent.com/openglredbook/examples/master/vermilion/vdds.cpp
    fn gl_internal_format_type(&self) -> Option<(GLenum, GLenum, GLenum)> {
        match self.format() {
            Ok(DXGIFormat::R32G32B32A32_FLOAT) => Some((gl::RGBA32F, gl::RGBA, gl::FLOAT)),
            Ok(DXGIFormat::R32G32B32A32_UINT) => Some((gl::RGBA32UI, gl::RGBA_INTEGER, gl::UNSIGNED_INT)),
            Ok(DXGIFormat::R32G32B32A32_SINT) => Some((gl::RGBA32I, gl::RGBA_INTEGER, gl::INT)),

            Ok(DXGIFormat::R32G32B32_FLOAT) => Some((gl::RGB32F, gl::RGB, gl::FLOAT)),
            Ok(DXGIFormat::R32G32B32_UINT) => Some((gl::RGB32UI, gl::RGB_INTEGER, gl::UNSIGNED_INT)),
            Ok(DXGIFormat::R32G32B32_SINT) => Some((gl::RGB32I, gl::RGB_INTEGER, gl::INT)),

            Ok(DXGIFormat::R16G16B16A16_FLOAT) => Some((gl::RGBA16F, gl::RGBA, gl::HALF_FLOAT)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::R16G16B16A16_UNORM) => Some((gl::RGBA16, gl::RGBA, gl::UNSIGNED_SHORT)),
            Ok(DXGIFormat::R16G16B16A16_UINT) => Some((gl::RGBA16UI, gl::RGBA_INTEGER, gl::UNSIGNED_SHORT)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::R16G16B16A16_SNORM) => Some((gl::RGBA16_SNORM, gl::RGBA, gl::SHORT)),
            Ok(DXGIFormat::R16G16B16A16_SINT) => Some((gl::RGBA16I, gl::RGBA_INTEGER, gl::SHORT)),

            Ok(DXGIFormat::R32G32_FLOAT) => Some((gl::RG32F, gl::RG, gl::FLOAT)),
            Ok(DXGIFormat::R32G32_UINT) => Some((gl::RG32UI, gl::RG_INTEGER, gl::UNSIGNED_INT)),
            Ok(DXGIFormat::R32G32_SINT) => Some((gl::RG32I, gl::RG_INTEGER, gl::INT)),

            Ok(DXGIFormat::D32_FLOAT_S8X24_UINT)  // This may not be right
                => Some((gl::DEPTH32F_STENCIL8, gl::DEPTH_STENCIL, gl::FLOAT_32_UNSIGNED_INT_24_8_REV)),


            Ok(DXGIFormat::R10G10B10A2_UNORM) => Some((gl::RGB10_A2, gl::RGBA, gl::UNSIGNED_INT)),
            Ok(DXGIFormat::R10G10B10A2_UINT) => Some((gl::RGB10_A2UI, gl::RGBA_INTEGER, gl::UNSIGNED_INT)),
            Ok(DXGIFormat::R11G11B10_FLOAT) => Some((gl::R11F_G11F_B10F, gl::RGB, gl::UNSIGNED_INT)),

            Ok(DXGIFormat::R8G8B8A8_UNORM) => Some((gl::RGBA8, gl::RGBA, gl::UNSIGNED_BYTE)),
            Ok(DXGIFormat::R8G8B8A8_UNORM_SRGB) => Some((gl::SRGB8_ALPHA8, gl::RGBA, gl::UNSIGNED_BYTE)),
            Ok(DXGIFormat::R8G8B8A8_UINT) => Some((gl::RGBA8UI, gl::RGBA_INTEGER, gl::UNSIGNED_BYTE)),
            Ok(DXGIFormat::R8G8B8A8_SNORM) => Some((gl::RGBA8_SNORM, gl::RGBA, gl::BYTE)),
            Ok(DXGIFormat::R8G8B8A8_SINT) => Some((gl::RGBA8I, gl::RGBA_INTEGER, gl::BYTE)),

            Ok(DXGIFormat::R16G16_FLOAT) => Some((gl::RG16F, gl::RG, gl::HALF_FLOAT)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::R16G16_UNORM) => Some((gl::RG16, gl::RG, gl::UNSIGNED_SHORT)),
            Ok(DXGIFormat::R16G16_UINT) => Some((gl::RG16UI, gl::RG_INTEGER, gl::UNSIGNED_SHORT)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::R16G16_SNORM) => Some((gl::RG16_SNORM, gl::RG, gl::SHORT)),
            Ok(DXGIFormat::R16G16_SINT) => Some((gl::RG16I, gl::RG_INTEGER, gl::SHORT)),

            Ok(DXGIFormat::D32_FLOAT) => Some((gl::DEPTH_COMPONENT32F, gl::DEPTH_COMPONENT, gl::FLOAT)),
            Ok(DXGIFormat::R32_FLOAT) => Some((gl::R32F, gl::RED, gl::FLOAT)),
            Ok(DXGIFormat::R32_UINT) => Some((gl::R32UI, gl::RED_INTEGER, gl::UNSIGNED_INT)),
            Ok(DXGIFormat::R32_SINT) => Some((gl::R32I, gl::RED_INTEGER, gl::INT)),

            Ok(DXGIFormat::D24_UNORM_S8_UINT)  // This may not be right
                => Some((gl::DEPTH24_STENCIL8, gl::DEPTH_STENCIL, gl::UNSIGNED_INT)),

            Ok(DXGIFormat::R8G8_UNORM) => Some((gl::RG8, gl::RG, gl::UNSIGNED_BYTE)),
            Ok(DXGIFormat::R8G8_UINT) => Some((gl::RG8UI, gl::RG_INTEGER, gl::UNSIGNED_BYTE)),
            Ok(DXGIFormat::R8G8_SNORM) => Some((gl::RG8_SNORM, gl::RG, gl::BYTE)),
            Ok(DXGIFormat::R8G8_SINT) => Some((gl::RG8I, gl::RG_INTEGER, gl::BYTE)),

            Ok(DXGIFormat::R16_FLOAT) => Some((gl::R16F, gl::RED, gl::HALF_FLOAT)),
            Ok(DXGIFormat::D16_UNORM) => Some((gl::DEPTH_COMPONENT16, gl::DEPTH_COMPONENT, gl::HALF_FLOAT)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::R16_UNORM) => Some((gl::R16, gl::RED, gl::UNSIGNED_SHORT)),
            Ok(DXGIFormat::R16_UINT) => Some((gl::R16UI, gl::RED_INTEGER, gl::UNSIGNED_SHORT)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::R16_SNORM) => Some((gl::R16_SNORM, gl::RED, gl::SHORT)),
            Ok(DXGIFormat::R16_SINT) => Some((gl::R16I, gl::RED_INTEGER, gl::SHORT)),

            Ok(DXGIFormat::R8_UNORM) | Ok(DXGIFormat::A8_UNORM)
                => Some((gl::R8, gl::RED, gl::UNSIGNED_BYTE)),
            Ok(DXGIFormat::R8_UINT) => Some((gl::R8UI, gl::RED_INTEGER, gl::UNSIGNED_BYTE)),
            Ok(DXGIFormat::R8_SNORM) => Some((gl::R8_SNORM, gl::RED, gl::BYTE)),
            Ok(DXGIFormat::R8_SINT) => Some((gl::R8I, gl::RED_INTEGER, gl::BYTE)),

            Ok(DXGIFormat::R9G9B9E5_SHAREDEXP) => Some((gl::RGB9_E5, gl::RGB, gl::UNSIGNED_SHORT)),

            Ok(DXGIFormat::BC1_UNORM)
                => Some((
                    gl::COMPRESSED_RGBA_S3TC_DXT1_EXT,
                    gl::COMPRESSED_RGBA_S3TC_DXT1_EXT,
                    gl::NONE)),
            Ok(DXGIFormat::BC2_UNORM)
                =>  Some((
                    gl::COMPRESSED_RGBA_S3TC_DXT3_EXT,
                    gl::COMPRESSED_RGBA_S3TC_DXT3_EXT,
                    gl::NONE)),
            Ok(DXGIFormat::BC3_UNORM)
                =>  Some((
                    gl::COMPRESSED_RGBA_S3TC_DXT5_EXT,
                    gl::COMPRESSED_RGBA_S3TC_DXT5_EXT,
                    gl::NONE)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::BC6H_UF16)
                =>  Some((
                    gl::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB,
                    gl::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB,
                    gl::NONE)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::BC6H_SF16)
                =>  Some((
                    gl::COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB,
                    gl::COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB,
                    gl::NONE)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::BC7_UNORM)
                =>  Some((
                    gl::COMPRESSED_RGBA_BPTC_UNORM_ARB,
                    gl::COMPRESSED_RGBA_BPTC_UNORM_ARB,
                    gl::NONE)),
            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::BC7_UNORM_SRGB)
                =>  Some((
                    gl::COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB,
                    gl::COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB,
                    gl::NONE)),

            #[cfg(any(feature="gles", feature="webgl"))]
            Ok(DXGIFormat::BC6H_UF16)
                =>  Some((
                    gl::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT,
                    gl::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT,
                    gl::NONE)),
            #[cfg(any(feature="gles", feature="webgl"))]
            Ok(DXGIFormat::BC6H_SF16)
                =>  Some((
                    gl::COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT,
                    gl::COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT,
                    gl::NONE)),
            #[cfg(any(feature="gles", feature="webgl"))]
            Ok(DXGIFormat::BC7_UNORM)
                =>  Some((
                    gl::COMPRESSED_RGBA_BPTC_UNORM_EXT,
                    gl::COMPRESSED_RGBA_BPTC_UNORM_EXT,
                    gl::NONE)),
            #[cfg(any(feature="gles", feature="webgl"))]
            Ok(DXGIFormat::BC7_UNORM_SRGB)
                =>  Some((
                    gl::COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT,
                    gl::COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT,
                    gl::NONE)),

            Ok(DXGIFormat::B5G5R5A1_UNORM) => Some((gl::RGB5_A1, gl::RGBA, gl::UNSIGNED_SHORT)),

            #[cfg(not(any(feature="gles", feature="webgl")))]
            Ok(DXGIFormat::B8G8R8A8_UNORM) | Ok(DXGIFormat::B8G8R8X8_UNORM)
                => Some((gl::RGBA8, gl::BGRA, gl::UNSIGNED_BYTE)),
            #[cfg(any(feature="gles", feature="webgl"))]
            Ok(DXGIFormat::B8G8R8A8_UNORM) | Ok(DXGIFormat::B8G8R8X8_UNORM)
                 => Some((gl::RGBA8, gl::BGRA_EXT, gl::UNSIGNED_BYTE)),


            Ok(_) => {
                error!("Unkown format {:?}", self.format());
                None
            }

            Err(err) => {
                error!("Error retrieving dds format {}", err);
                None
            }
        }
    }

    fn num_components(&self) -> usize{
        let four_cc = self.fourcc_str();
        if &four_cc == "DXT1" || &four_cc == "DXT3" || &four_cc == "DXT5" {
            4
        }else if &four_cc == "DX10" || self.fourcc() == 0{
            if self.a_bitmask() != 0{
                4
            }else{
                3
            }
        }else{
            unreachable!()
        }
    }

    fn width(&self, level: usize) -> usize{
        let mut level0_w = self.width() as usize;
        for _ in 0..level{
            level0_w /= 2;
        }
        level0_w
    }

    fn height(&self, level: usize) -> usize{
        let mut level0_h = self.height() as usize;
        for _ in 0..level{
            level0_h /= 2;
        }
        level0_h
    }

    fn pitch_bytes(&self, level: usize) -> usize{
        let mut level0_p = self.pitch() / self.bytes_per_pixel();
        for _ in 0..level{
            level0_p /= 2;
        }
        level0_p * self.bytes_per_pixel()
    }

    fn bytes_per_pixel(&self) -> usize{
        self.bpp().unwrap() / 8
    }

    fn pitch_components(&self, level: usize) -> usize{ // TODO: is this correct?
        let mut level0_p = self.pitch() / self.bytes_per_pixel();
        for _ in 0..level{
            level0_p /= 2;
        }
        level0_p
    }

    fn data(&self) -> &[u8]{
        self.data()
    }

    fn levels(&self) -> usize{
        self.mipmap_count()
    }

    fn mipmap(&self, level: usize) -> Option<&[u8]>{
        self.mipmap(level).map(|dds| unsafe{ mem::transmute(dds.data()) })
    }

    fn is_gpu_compressed(&self) -> bool{
        self.is_compressed()
    }
}

impl<S: Borrow<[u8]>> CubemapImage for dds::Dds<S>{
    fn mipmap_face(&self, level: usize, face: usize) -> Option<&[u8]>{
        self.mipmap_face(level, face).ok().map(|dds| unsafe{ mem::transmute(dds.data()) })
    }
}