Cleanup: remove unused "dds" directory

Missing from [0] which duplicates some code into format_dds.cc.

[0]: aa3bdfd76a
This commit is contained in:
Campbell Barton
2023-05-10 12:26:27 +10:00
parent 46479f41e1
commit 0168c4b893
18 changed files with 0 additions and 4312 deletions

View File

@@ -1,621 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* 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 <BLI_sys_types.h> /* For `uint`. */
#include <BlockDXT.h>
#include <ColorBlock.h>
#include <Common.h>
#include <Stream.h>
/* ---------------------------------------------------------------------------
* BlockDXT1
* --------------------------------------------------------------------------*/
uint BlockDXT1::evaluatePalette(Color32 color_array[4]) const
{
/* Does bit expansion before interpolation. */
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (col0.r << 3) | (col0.r >> 2);
color_array[0].a = 0xFF;
/* @@ Same as above, but faster?
* Color32 c;
* c.u = ((col0.u << 3) & 0xf8) | ((col0.u << 5) & 0xfc00) | ((col0.u << 8) & 0xf80000);
* c.u |= (c.u >> 5) & 0x070007;
* c.u |= (c.u >> 6) & 0x000300;
* color_array[0].u = c.u; */
color_array[1].r = (col1.r << 3) | (col1.r >> 2);
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (col1.b << 3) | (col1.b >> 2);
color_array[1].a = 0xFF;
/* @@ Same as above, but faster?
* c.u = ((col1.u << 3) & 0xf8) | ((col1.u << 5) & 0xfc00) | ((col1.u << 8) & 0xf80000);
* c.u |= (c.u >> 5) & 0x070007;
* c.u |= (c.u >> 6) & 0x000300;
* color_array[1].u = c.u; */
if (col0.u > col1.u) {
/* Four-color block: derive the other two colors. */
color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
color_array[2].a = 0xFF;
color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
color_array[3].a = 0xFF;
return 4;
}
/* Three-color block: derive the other color. */
color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
color_array[2].a = 0xFF;
/* Set all components to 0 to match DXT specs. */
color_array[3].r = 0x00; /* color_array[2].r; */
color_array[3].g = 0x00; /* color_array[2].g; */
color_array[3].b = 0x00; /* color_array[2].b; */
color_array[3].a = 0x00;
return 3;
}
uint BlockDXT1::evaluatePaletteNV5x(Color32 color_array[4]) const
{
/* Does bit expansion before interpolation. */
color_array[0].b = (3 * col0.b * 22) / 8;
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (3 * col0.r * 22) / 8;
color_array[0].a = 0xFF;
color_array[1].r = (3 * col1.r * 22) / 8;
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (3 * col1.b * 22) / 8;
color_array[1].a = 0xFF;
int gdiff = color_array[1].g - color_array[0].g;
if (col0.u > col1.u) {
/* Four-color block: derive the other two colors. */
color_array[2].r = ((2 * col0.r + col1.r) * 22) / 8;
color_array[2].g = (256 * color_array[0].g + gdiff / 4 + 128 + gdiff * 80) / 256;
color_array[2].b = ((2 * col0.b + col1.b) * 22) / 8;
color_array[2].a = 0xFF;
color_array[3].r = ((2 * col1.r + col0.r) * 22) / 8;
color_array[3].g = (256 * color_array[1].g - gdiff / 4 + 128 - gdiff * 80) / 256;
color_array[3].b = ((2 * col1.b + col0.b) * 22) / 8;
color_array[3].a = 0xFF;
return 4;
}
/* Three-color block: derive the other color. */
color_array[2].r = ((col0.r + col1.r) * 33) / 8;
color_array[2].g = (256 * color_array[0].g + gdiff / 4 + 128 + gdiff * 128) / 256;
color_array[2].b = ((col0.b + col1.b) * 33) / 8;
color_array[2].a = 0xFF;
/* Set all components to 0 to match DXT specs. */
color_array[3].r = 0x00; /* color_array[2].r; */
color_array[3].g = 0x00; /* color_array[2].g; */
color_array[3].b = 0x00; /* color_array[2].b; */
color_array[3].a = 0x00;
return 3;
}
void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (col0.r << 3) | (col0.r >> 2);
color_array[0].a = 0xFF;
color_array[1].r = (col1.r << 3) | (col1.r >> 2);
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (col1.b << 3) | (col1.b >> 2);
color_array[1].a = 0xFF;
/* Three-color block: derive the other color. */
color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
color_array[2].a = 0xFF;
/* Set all components to 0 to match DXT specs. */
color_array[3].r = 0x00; /* color_array[2].r; */
color_array[3].g = 0x00; /* color_array[2].g; */
color_array[3].b = 0x00; /* color_array[2].b; */
color_array[3].a = 0x00;
}
void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (col0.r << 3) | (col0.r >> 2);
color_array[0].a = 0xFF;
color_array[1].r = (col1.r << 3) | (col1.r >> 2);
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (col1.b << 3) | (col1.b >> 2);
color_array[1].a = 0xFF;
/* Four-color block: derive the other two colors. */
color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
color_array[2].a = 0xFF;
color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
color_array[3].a = 0xFF;
}
void BlockDXT1::decodeBlock(ColorBlock *block) const
{
/* Decode color block. */
Color32 color_array[4];
evaluatePalette(color_array);
/* Write color block. */
for (uint j = 0; j < 4; j++) {
for (uint i = 0; i < 4; i++) {
uint idx = (row[j] >> (2 * i)) & 3;
block->color(i, j) = color_array[idx];
}
}
}
void BlockDXT1::decodeBlockNV5x(ColorBlock *block) const
{
/* Decode color block. */
Color32 color_array[4];
evaluatePaletteNV5x(color_array);
/* Write color block. */
for (uint j = 0; j < 4; j++) {
for (uint i = 0; i < 4; i++) {
uint idx = (row[j] >> (2 * i)) & 3;
block->color(i, j) = color_array[idx];
}
}
}
void BlockDXT1::setIndices(const int *idx)
{
indices = 0;
for (uint i = 0; i < 16; i++) {
indices |= (idx[i] & 3) << (2 * i);
}
}
inline void BlockDXT1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
inline void BlockDXT1::flip2()
{
swap(row[0], row[1]);
}
/* ---------------------------------------------------------------------------
* BlockDXT3
* ---------------------------------------------------------------------------*/
void BlockDXT3::decodeBlock(ColorBlock *block) const
{
/* Decode color. */
color.decodeBlock(block);
/* Decode alpha. */
alpha.decodeBlock(block);
}
void BlockDXT3::decodeBlockNV5x(ColorBlock *block) const
{
color.decodeBlockNV5x(block);
alpha.decodeBlock(block);
}
void AlphaBlockDXT3::decodeBlock(ColorBlock *block) const
{
block->color(0x0).a = (alpha0 << 4) | alpha0;
block->color(0x1).a = (alpha1 << 4) | alpha1;
block->color(0x2).a = (alpha2 << 4) | alpha2;
block->color(0x3).a = (alpha3 << 4) | alpha3;
block->color(0x4).a = (alpha4 << 4) | alpha4;
block->color(0x5).a = (alpha5 << 4) | alpha5;
block->color(0x6).a = (alpha6 << 4) | alpha6;
block->color(0x7).a = (alpha7 << 4) | alpha7;
block->color(0x8).a = (alpha8 << 4) | alpha8;
block->color(0x9).a = (alpha9 << 4) | alpha9;
block->color(0xA).a = (alphaA << 4) | alphaA;
block->color(0xB).a = (alphaB << 4) | alphaB;
block->color(0xC).a = (alphaC << 4) | alphaC;
block->color(0xD).a = (alphaD << 4) | alphaD;
block->color(0xE).a = (alphaE << 4) | alphaE;
block->color(0xF).a = (alphaF << 4) | alphaF;
}
void AlphaBlockDXT3::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
void AlphaBlockDXT3::flip2()
{
swap(row[0], row[1]);
}
void BlockDXT3::flip4()
{
alpha.flip4();
color.flip4();
}
void BlockDXT3::flip2()
{
alpha.flip2();
color.flip2();
}
/* ---------------------------------------------------------------------------
* BlockDXT5
* ---------------------------------------------------------------------------*/
void AlphaBlockDXT5::evaluatePalette(uint8 alpha[8]) const
{
if (alpha0() > alpha1()) {
evaluatePalette8(alpha);
}
else {
evaluatePalette6(alpha);
}
}
void AlphaBlockDXT5::evaluatePalette8(uint8 alpha[8]) const
{
/* 8-alpha block: derive the other six alphas.
* Bit code 000 = alpha0, 001 = alpha1, others are interpolated. */
alpha[0] = alpha0();
alpha[1] = alpha1();
alpha[2] = (6 * alpha[0] + 1 * alpha[1]) / 7; /* bit code 010 */
alpha[3] = (5 * alpha[0] + 2 * alpha[1]) / 7; /* bit code 011 */
alpha[4] = (4 * alpha[0] + 3 * alpha[1]) / 7; /* bit code 100 */
alpha[5] = (3 * alpha[0] + 4 * alpha[1]) / 7; /* bit code 101 */
alpha[6] = (2 * alpha[0] + 5 * alpha[1]) / 7; /* bit code 110 */
alpha[7] = (1 * alpha[0] + 6 * alpha[1]) / 7; /* bit code 111 */
}
void AlphaBlockDXT5::evaluatePalette6(uint8 alpha[8]) const
{
/* 6-alpha block.
* Bit code 000 = alpha0, 001 = alpha1, others are interpolated. */
alpha[0] = alpha0();
alpha[1] = alpha1();
alpha[2] = (4 * alpha[0] + 1 * alpha[1]) / 5; /* Bit code 010 */
alpha[3] = (3 * alpha[0] + 2 * alpha[1]) / 5; /* Bit code 011 */
alpha[4] = (2 * alpha[0] + 3 * alpha[1]) / 5; /* Bit code 100 */
alpha[5] = (1 * alpha[0] + 4 * alpha[1]) / 5; /* Bit code 101 */
alpha[6] = 0x00; /* Bit code 110 */
alpha[7] = 0xFF; /* Bit code 111 */
}
void AlphaBlockDXT5::indices(uint8 index_array[16]) const
{
index_array[0x0] = bits0();
index_array[0x1] = bits1();
index_array[0x2] = bits2();
index_array[0x3] = bits3();
index_array[0x4] = bits4();
index_array[0x5] = bits5();
index_array[0x6] = bits6();
index_array[0x7] = bits7();
index_array[0x8] = bits8();
index_array[0x9] = bits9();
index_array[0xA] = bitsA();
index_array[0xB] = bitsB();
index_array[0xC] = bitsC();
index_array[0xD] = bitsD();
index_array[0xE] = bitsE();
index_array[0xF] = bitsF();
}
uint AlphaBlockDXT5::index(uint index) const
{
int offset = (3 * index + 16);
return uint((this->u >> offset) & 0x7);
}
void AlphaBlockDXT5::setIndex(uint index, uint value)
{
int offset = (3 * index + 16);
uint64 mask = uint64(0x7) << offset;
this->u = (this->u & ~mask) | (uint64(value) << offset);
}
void AlphaBlockDXT5::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
evaluatePalette(alpha_array);
uint8 index_array[16];
indices(index_array);
for (uint i = 0; i < 16; i++) {
block->color(i).a = alpha_array[index_array[i]];
}
}
void AlphaBlockDXT5::flip4()
{
uint64 *b = (uint64 *)this;
/* @@ The masks might have to be byte swapped. */
uint64 tmp = (*b & (uint64)(0x000000000000FFFFLL));
tmp |= (*b & (uint64)(0x000000000FFF0000LL)) << 36;
tmp |= (*b & (uint64)(0x000000FFF0000000LL)) << 12;
tmp |= (*b & (uint64)(0x000FFF0000000000LL)) >> 12;
tmp |= (*b & (uint64)(0xFFF0000000000000LL)) >> 36;
*b = tmp;
}
void AlphaBlockDXT5::flip2()
{
uint *b = (uint *)this;
/* @@ The masks might have to be byte swapped. */
uint tmp = (*b & 0xFF000000);
tmp |= (*b & 0x00000FFF) << 12;
tmp |= (*b & 0x00FFF000) >> 12;
*b = tmp;
}
void BlockDXT5::decodeBlock(ColorBlock *block) const
{
/* Decode color. */
color.decodeBlock(block);
/* Decode alpha. */
alpha.decodeBlock(block);
}
void BlockDXT5::decodeBlockNV5x(ColorBlock *block) const
{
/* Decode color. */
color.decodeBlockNV5x(block);
/* Decode alpha. */
alpha.decodeBlock(block);
}
void BlockDXT5::flip4()
{
alpha.flip4();
color.flip4();
}
void BlockDXT5::flip2()
{
alpha.flip2();
color.flip2();
}
void BlockATI1::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
alpha.evaluatePalette(alpha_array);
uint8 index_array[16];
alpha.indices(index_array);
for (uint i = 0; i < 16; i++) {
Color32 &c = block->color(i);
c.b = c.g = c.r = alpha_array[index_array[i]];
c.a = 255;
}
}
void BlockATI1::flip4()
{
alpha.flip4();
}
void BlockATI1::flip2()
{
alpha.flip2();
}
void BlockATI2::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
uint8 index_array[16];
x.evaluatePalette(alpha_array);
x.indices(index_array);
for (uint i = 0; i < 16; i++) {
Color32 &c = block->color(i);
c.r = alpha_array[index_array[i]];
}
y.evaluatePalette(alpha_array);
y.indices(index_array);
for (uint i = 0; i < 16; i++) {
Color32 &c = block->color(i);
c.g = alpha_array[index_array[i]];
c.b = 0;
c.a = 255;
}
}
void BlockATI2::flip4()
{
x.flip4();
y.flip4();
}
void BlockATI2::flip2()
{
x.flip2();
y.flip2();
}
void BlockCTX1::evaluatePalette(Color32 color_array[4]) const
{
/* Does bit expansion before interpolation. */
color_array[0].b = 0x00;
color_array[0].g = col0[1];
color_array[0].r = col0[0];
color_array[0].a = 0xFF;
color_array[1].r = 0x00;
color_array[1].g = col0[1];
color_array[1].b = col1[0];
color_array[1].a = 0xFF;
color_array[2].r = 0x00;
color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
color_array[2].a = 0xFF;
color_array[3].r = 0x00;
color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
color_array[3].a = 0xFF;
}
void BlockCTX1::decodeBlock(ColorBlock *block) const
{
/* Decode color block. */
Color32 color_array[4];
evaluatePalette(color_array);
/* Write color block. */
for (uint j = 0; j < 4; j++) {
for (uint i = 0; i < 4; i++) {
uint idx = (row[j] >> (2 * i)) & 3;
block->color(i, j) = color_array[idx];
}
}
}
void BlockCTX1::setIndices(const int *idx)
{
indices = 0;
for (uint i = 0; i < 16; i++) {
indices |= (idx[i] & 3) << (2 * i);
}
}
inline void BlockCTX1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
inline void BlockCTX1::flip2()
{
swap(row[0], row[1]);
}
void mem_read(Stream &mem, BlockDXT1 &block)
{
mem_read(mem, block.col0.u);
mem_read(mem, block.col1.u);
mem_read(mem, block.indices);
}
void mem_read(Stream &mem, AlphaBlockDXT3 &block)
{
for (ushort &alpha : block.row) {
mem_read(mem, alpha);
}
}
void mem_read(Stream &mem, BlockDXT3 &block)
{
mem_read(mem, block.alpha);
mem_read(mem, block.color);
}
void mem_read(Stream &mem, AlphaBlockDXT5 &block)
{
mem_read(mem, block.u);
}
void mem_read(Stream &mem, BlockDXT5 &block)
{
mem_read(mem, block.alpha);
mem_read(mem, block.color);
}
void mem_read(Stream &mem, BlockATI1 &block)
{
mem_read(mem, block.alpha);
}
void mem_read(Stream &mem, BlockATI2 &block)
{
mem_read(mem, block.x);
mem_read(mem, block.y);
}
void mem_read(Stream &mem, BlockCTX1 &block)
{
mem_read(mem, block.col0[0]);
mem_read(mem, block.col0[1]);
mem_read(mem, block.col1[0]);
mem_read(mem, block.col1[1]);
mem_read(mem, block.indices);
}

View File

@@ -1,310 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* 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. */
#pragma once
#include <Color.h>
#include <ColorBlock.h>
#include <Common.h>
#include <Stream.h>
/** DXT1 block. */
struct BlockDXT1 {
Color16 col0;
Color16 col1;
union {
uint8 row[4];
uint indices;
};
bool isFourColorMode() const;
uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePaletteNV5x(Color32 color_array[4]) const;
/** Evaluate palette assuming 3 color block. */
void evaluatePalette3(Color32 color_array[4]) const;
/** Evaluate palette assuming 4 color block. */
void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
void setIndices(const int *idx);
/** Flip DXT1 block vertically. */
void flip4();
/** Flip half DXT1 block vertically. */
void flip2();
};
/** Return true if the block uses four color mode, false otherwise. */
inline bool BlockDXT1::isFourColorMode() const
{
return col0.u > col1.u;
}
/** DXT3 alpha block with explicit alpha. */
struct AlphaBlockDXT3 {
union {
struct {
uint alpha0 : 4;
uint alpha1 : 4;
uint alpha2 : 4;
uint alpha3 : 4;
uint alpha4 : 4;
uint alpha5 : 4;
uint alpha6 : 4;
uint alpha7 : 4;
uint alpha8 : 4;
uint alpha9 : 4;
uint alphaA : 4;
uint alphaB : 4;
uint alphaC : 4;
uint alphaD : 4;
uint alphaE : 4;
uint alphaF : 4;
};
uint16 row[4];
};
void decodeBlock(ColorBlock *block) const;
/** Flip DXT3 alpha block vertically. */
void flip4();
/** Flip half DXT3 alpha block vertically. */
void flip2();
};
/** DXT3 block. */
struct BlockDXT3 {
AlphaBlockDXT3 alpha;
BlockDXT1 color;
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
/** Flip DXT3 block vertically. */
void flip4();
/** Flip half DXT3 block vertically. */
void flip2();
};
/** DXT5 alpha block. */
struct AlphaBlockDXT5 {
/* uint64 unions do not compile on all platforms */
#if 0
union {
struct {
uint64 alpha0 : 8; /* 8 */
uint64 alpha1 : 8; /* 16 */
uint64 bits0 : 3; /* 3 - 19 */
uint64 bits1 : 3; /* 6 - 22 */
uint64 bits2 : 3; /* 9 - 25 */
uint64 bits3 : 3; /* 12 - 28 */
uint64 bits4 : 3; /* 15 - 31 */
uint64 bits5 : 3; /* 18 - 34 */
uint64 bits6 : 3; /* 21 - 37 */
uint64 bits7 : 3; /* 24 - 40 */
uint64 bits8 : 3; /* 27 - 43 */
uint64 bits9 : 3; /* 30 - 46 */
uint64 bitsA : 3; /* 33 - 49 */
uint64 bitsB : 3; /* 36 - 52 */
uint64 bitsC : 3; /* 39 - 55 */
uint64 bitsD : 3; /* 42 - 58 */
uint64 bitsE : 3; /* 45 - 61 */
uint64 bitsF : 3; /* 48 - 64 */
};
uint64 u;
};
#endif
uint64 u;
uint8 alpha0() const
{
return u & 0xffLL;
}
uint8 alpha1() const
{
return (u >> 8) & 0xffLL;
}
uint8 bits0() const
{
return (u >> 16) & 0x7LL;
}
uint8 bits1() const
{
return (u >> 19) & 0x7LL;
}
uint8 bits2() const
{
return (u >> 22) & 0x7LL;
}
uint8 bits3() const
{
return (u >> 25) & 0x7LL;
}
uint8 bits4() const
{
return (u >> 28) & 0x7LL;
}
uint8 bits5() const
{
return (u >> 31) & 0x7LL;
}
uint8 bits6() const
{
return (u >> 34) & 0x7LL;
}
uint8 bits7() const
{
return (u >> 37) & 0x7LL;
}
uint8 bits8() const
{
return (u >> 40) & 0x7LL;
}
uint8 bits9() const
{
return (u >> 43) & 0x7LL;
}
uint8 bitsA() const
{
return (u >> 46) & 0x7LL;
}
uint8 bitsB() const
{
return (u >> 49) & 0x7LL;
}
uint8 bitsC() const
{
return (u >> 52) & 0x7LL;
}
uint8 bitsD() const
{
return (u >> 55) & 0x7LL;
}
uint8 bitsE() const
{
return (u >> 58) & 0x7LL;
}
uint8 bitsF() const
{
return (u >> 61) & 0x7LL;
}
void evaluatePalette(uint8 alpha[8]) const;
void evaluatePalette8(uint8 alpha[8]) const;
void evaluatePalette6(uint8 alpha[8]) const;
void indices(uint8 index_array[16]) const;
uint index(uint index) const;
void setIndex(uint index, uint value);
void decodeBlock(ColorBlock *block) const;
void flip4();
void flip2();
};
/** DXT5 block. */
struct BlockDXT5 {
AlphaBlockDXT5 alpha;
BlockDXT1 color;
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
/** Flip DXT5 block vertically. */
void flip4();
/** Flip half DXT5 block vertically. */
void flip2();
};
/** ATI1 block. */
struct BlockATI1 {
AlphaBlockDXT5 alpha;
/** Decode ATI1 block. */
void decodeBlock(ColorBlock *block) const;
/** Flip ATI1 block vertically. */
void flip4();
/** Flip half ATI1 block vertically. */
void flip2();
};
/** ATI2 block. */
struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
/** Decode ATI2 block. */
void decodeBlock(ColorBlock *block) const;
/** Flip ATI2 block vertically. */
void flip4();
/** Flip half ATI2 block vertically. */
void flip2();
};
/** CTX1 block. */
struct BlockCTX1 {
uint8 col0[2];
uint8 col1[2];
union {
uint8 row[4];
uint indices;
};
void evaluatePalette(Color32 color_array[4]) const;
void setIndices(const int *idx);
void decodeBlock(ColorBlock *block) const;
/** Flip CTX1 block vertically. */
void flip4();
/** Flip half CTX1 block vertically. */
void flip2();
};
void mem_read(Stream &mem, BlockDXT1 &block);
void mem_read(Stream &mem, AlphaBlockDXT3 &block);
void mem_read(Stream &mem, BlockDXT3 &block);
void mem_read(Stream &mem, AlphaBlockDXT5 &block);
void mem_read(Stream &mem, BlockDXT5 &block);
void mem_read(Stream &mem, BlockATI1 &block);
void mem_read(Stream &mem, BlockATI2 &block);
void mem_read(Stream &mem, BlockCTX1 &block);

View File

@@ -1,47 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2006 Blender Foundation
set(INC
.
..
../..
../../../blenkernel
../../../blenlib
../../../makesdna
../../../../../intern/guardedalloc
../../../../../intern/utfconv
)
set(INC_SYS
)
set(SRC
BlockDXT.h
Color.h
ColorBlock.h
Common.h
DirectDrawSurface.h
FlipDXT.h
Image.h
PixelFormat.h
Stream.h
dds_api.h
BlockDXT.cpp
ColorBlock.cpp
DirectDrawSurface.cpp
FlipDXT.cpp
Image.cpp
Stream.cpp
dds_api.cpp
)
set(LIB
)
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
blender_add_lib(bf_imbuf_dds "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@@ -1,92 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es> */
#pragma once
/** 32 bit color stored as BGRA. */
class Color32 {
public:
Color32() {}
Color32(const Color32 &) = default;
Color32(unsigned char R, unsigned char G, unsigned char B)
{
setRGBA(R, G, B, 0xFF);
}
Color32(unsigned char R, unsigned char G, unsigned char B, unsigned char A)
{
setRGBA(R, G, B, A);
}
#if 0
Color32(unsigned char c[4])
{
setRGBA(c[0], c[1], c[2], c[3]);
}
Color32(float R, float G, float B)
{
setRGBA(uint(R * 255), uint(G * 255), uint(B * 255), 0xFF);
}
Color32(float R, float G, float B, float A)
{
setRGBA(uint(R * 255), uint(G * 255), uint(B * 255), uint(A * 255));
}
#endif
Color32(unsigned int U) : u(U) {}
void setRGBA(unsigned char R, unsigned char G, unsigned char B, unsigned char A)
{
r = R;
g = G;
b = B;
a = A;
}
void setBGRA(unsigned char B, unsigned char G, unsigned char R, unsigned char A = 0xFF)
{
r = R;
g = G;
b = B;
a = A;
}
operator unsigned int() const
{
return u;
}
union {
struct {
unsigned char b, g, r, a;
};
unsigned int u;
};
};
/** 16 bit 565 BGR color. */
class Color16 {
public:
Color16() {}
Color16(const Color16 &c) : u(c.u) {}
explicit Color16(unsigned short U) : u(U) {}
union {
struct {
unsigned short b : 5;
unsigned short g : 6;
unsigned short r : 5;
};
unsigned short u;
};
};

View File

@@ -1,468 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain - <castanyo@yahoo.es> */
#include <ColorBlock.h>
#include <Common.h>
#include <Image.h>
#if 0
/* Get approximate luminance. */
inline static uint colorLuminance(Color32 c)
{
return c.r + c.g + c.b;
}
/* Get the euclidean distance between the given colors. */
inline static uint colorDistance(Color32 c0, Color32 c1)
{
return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) +
(c0.b - c1.b) * (c0.b - c1.b);
}
#endif
ColorBlock::ColorBlock(const uint *linearImage)
{
for (uint i = 0; i < 16; i++) {
color(i) = Color32(linearImage[i]);
}
}
ColorBlock::ColorBlock(const ColorBlock &block)
{
for (uint i = 0; i < 16; i++) {
color(i) = block.color(i);
}
}
ColorBlock::ColorBlock(const Image *img, uint x, uint y)
{
init(img, x, y);
}
void ColorBlock::init(const Image *img, uint x, uint y)
{
init(img->width(), img->height(), (const uint *)img->pixels(), x, y);
}
void ColorBlock::init(uint w, uint h, const uint *data, uint x, uint y)
{
const uint bw = MIN(w - x, 4U);
const uint bh = MIN(h - y, 4U);
/* Blocks that are smaller than 4x4 are handled by repeating the pixels.
* @@ That's only correct when block size is 1, 2 or 4, but not with 3. :(
* @@ Ideally we should zero the weights of the pixels out of range. */
for (uint i = 0; i < 4; i++) {
const int by = i % bh;
for (uint e = 0; e < 4; e++) {
const int bx = e % bw;
const uint idx = (y + by) * w + x + bx;
color(e, i).u = data[idx];
}
}
}
void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y)
{
const uint bw = MIN(w - x, 4U);
const uint bh = MIN(h - y, 4U);
/* Blocks that are smaller than 4x4 are handled by repeating the pixels.
* @@ That's only correct when block size is 1, 2 or 4, but not with 3. :(
* @@ Ideally we should zero the weights of the pixels out of range. */
uint srcPlane = w * h;
for (uint i = 0; i < 4; i++) {
const uint by = i % bh;
for (uint e = 0; e < 4; e++) {
const uint bx = e % bw;
const uint idx = ((y + by) * w + x + bx);
Color32 &c = color(e, i);
/* @@ Is this the right way to quantize floats to bytes? */
c.r = uint8(255 * CLAMP(data[idx + 0 * srcPlane], 0.0f, 1.0f));
c.g = uint8(255 * CLAMP(data[idx + 1 * srcPlane], 0.0f, 1.0f));
c.b = uint8(255 * CLAMP(data[idx + 2 * srcPlane], 0.0f, 1.0f));
c.a = uint8(255 * CLAMP(data[idx + 3 * srcPlane], 0.0f, 1.0f));
}
}
}
static inline uint8 component(Color32 c, uint i)
{
if (i == 0) {
return c.r;
}
if (i == 1) {
return c.g;
}
if (i == 2) {
return c.b;
}
if (i == 3) {
return c.a;
}
if (i == 4) {
return 0xFF;
}
return 0;
}
void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
{
for (Color32 &color : m_color) {
const Color32 c = color;
color.r = component(c, x);
color.g = component(c, y);
color.b = component(c, z);
color.a = component(c, w);
}
}
bool ColorBlock::isSingleColor(Color32 mask /*= Color32(0xFF, 0xFF, 0xFF, 0x00) */) const
{
uint u = m_color[0].u & mask.u;
for (int i = 1; i < 16; i++) {
if (u != (m_color[i].u & mask.u)) {
return false;
}
}
return true;
}
#if 0
/** Returns true if the block has a single color, ignoring transparent pixels. */
bool ColorBlock::isSingleColorNoAlpha() const
{
Color32 c;
int i;
for (i = 0; i < 16; i++) {
if (m_color[i].a != 0) {
c = m_color[i];
}
}
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
uint u = c.u & mask.u;
for (; i < 16; i++) {
if (u != (m_color[i].u & mask.u)) {
return false;
}
}
return true;
}
#endif
#if 0
/** Count number of unique colors in this color block. */
uint ColorBlock::countUniqueColors() const
{
uint count = 0;
/* @@ This does not have to be o(n^2) */
for (int i = 0; i < 16; i++) {
bool unique = true;
for (int j = 0; j < i; j++) {
if (m_color[i] != m_color[j]) {
unique = false;
}
}
if (unique) {
count++;
}
}
return count;
}
#endif
#if 0
/** Get average color of the block. */
Color32 ColorBlock::averageColor() const
{
uint r, g, b, a;
r = g = b = a = 0;
for (uint i = 0; i < 16; i++) {
r += m_color[i].r;
g += m_color[i].g;
b += m_color[i].b;
a += m_color[i].a;
}
return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
}
#endif
bool ColorBlock::hasAlpha() const
{
for (const auto &i : m_color) {
if (i.a != 255) {
return true;
}
}
return false;
}
#if 0
/** Get diameter color range. */
void ColorBlock::diameterRange(Color32 *start, Color32 *end) const
{
Color32 c0, c1;
uint best_dist = 0;
for (int i = 0; i < 16; i++) {
for (int j = i + 1; j < 16; j++) {
uint dist = colorDistance(m_color[i], m_color[j]);
if (dist > best_dist) {
best_dist = dist;
c0 = m_color[i];
c1 = m_color[j];
}
}
}
*start = c0;
*end = c1;
}
/** Get luminance color range. */
void ColorBlock::luminanceRange(Color32 *start, Color32 *end) const
{
Color32 minColor, maxColor;
uint minLuminance, maxLuminance;
maxLuminance = minLuminance = colorLuminance(m_color[0]);
for (uint i = 1; i < 16; i++) {
uint luminance = colorLuminance(m_color[i]);
if (luminance > maxLuminance) {
maxLuminance = luminance;
maxColor = m_color[i];
}
else if (luminance < minLuminance) {
minLuminance = luminance;
minColor = m_color[i];
}
}
*start = minColor;
*end = maxColor;
}
/** Get color range based on the bounding box. */
void ColorBlock::boundsRange(Color32 *start, Color32 *end) const
{
Color32 minColor(255, 255, 255);
Color32 maxColor(0, 0, 0);
for (uint i = 0; i < 16; i++) {
if (m_color[i].r < minColor.r) {
minColor.r = m_color[i].r;
}
if (m_color[i].g < minColor.g) {
minColor.g = m_color[i].g;
}
if (m_color[i].b < minColor.b) {
minColor.b = m_color[i].b;
}
if (m_color[i].r > maxColor.r) {
maxColor.r = m_color[i].r;
}
if (m_color[i].g > maxColor.g) {
maxColor.g = m_color[i].g;
}
if (m_color[i].b > maxColor.b) {
maxColor.b = m_color[i].b;
}
}
/* Offset range by 1/16 of the extents */
Color32 inset;
inset.r = (maxColor.r - minColor.r) >> 4;
inset.g = (maxColor.g - minColor.g) >> 4;
inset.b = (maxColor.b - minColor.b) >> 4;
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
*start = minColor;
*end = maxColor;
}
/** Get color range based on the bounding box. */
void ColorBlock::boundsRangeAlpha(Color32 *start, Color32 *end) const
{
Color32 minColor(255, 255, 255, 255);
Color32 maxColor(0, 0, 0, 0);
for (uint i = 0; i < 16; i++) {
if (m_color[i].r < minColor.r) {
minColor.r = m_color[i].r;
}
if (m_color[i].g < minColor.g) {
minColor.g = m_color[i].g;
}
if (m_color[i].b < minColor.b) {
minColor.b = m_color[i].b;
}
if (m_color[i].a < minColor.a) {
minColor.a = m_color[i].a;
}
if (m_color[i].r > maxColor.r) {
maxColor.r = m_color[i].r;
}
if (m_color[i].g > maxColor.g) {
maxColor.g = m_color[i].g;
}
if (m_color[i].b > maxColor.b) {
maxColor.b = m_color[i].b;
}
if (m_color[i].a > maxColor.a) {
maxColor.a = m_color[i].a;
}
}
/* Offset range by 1/16 of the extents */
Color32 inset;
inset.r = (maxColor.r - minColor.r) >> 4;
inset.g = (maxColor.g - minColor.g) >> 4;
inset.b = (maxColor.b - minColor.b) >> 4;
inset.a = (maxColor.a - minColor.a) >> 4;
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255;
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
*start = minColor;
*end = maxColor;
}
#endif
#if 0
/** Sort colors by absolute value in their 16 bit representation. */
void ColorBlock::sortColorsByAbsoluteValue()
{
/* Dummy selection sort. */
for (uint a = 0; a < 16; a++) {
uint max = a;
Color16 cmax(m_color[a]);
for (uint b = a + 1; b < 16; b++) {
Color16 cb(m_color[b]);
if (cb.u > cmax.u) {
max = b;
cmax = cb;
}
}
swap(m_color[a], m_color[max]);
}
}
#endif
#if 0
/** Find extreme colors in the given axis. */
void ColorBlock::computeRange(Vector3::Arg axis, Color32 *start, Color32 *end) const
{
int mini, maxi;
mini = maxi = 0;
float min, max;
min = max = dot(Vector3(m_color[0].r, m_color[0].g, m_color[0].b), axis);
for (uint i = 1; i < 16; i++) {
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
float val = dot(vec, axis);
if (val < min) {
mini = i;
min = val;
}
else if (val > max) {
maxi = i;
max = val;
}
}
*start = m_color[mini];
*end = m_color[maxi];
}
#endif
#if 0
/** Sort colors in the given axis. */
void ColorBlock::sortColors(const Vector3 &axis)
{
float luma_array[16];
for (uint i = 0; i < 16; i++) {
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
luma_array[i] = dot(vec, axis);
}
/* Dummy selection sort. */
for (uint a = 0; a < 16; a++) {
uint min = a;
for (uint b = a + 1; b < 16; b++) {
if (luma_array[b] < luma_array[min]) {
min = b;
}
}
swap(luma_array[a], luma_array[min]);
swap(m_color[a], m_color[min]);
}
}
#endif
#if 0
/** Get the volume of the color block. */
float ColorBlock::volume() const
{
Box bounds;
bounds.clearBounds();
for (int i = 0; i < 16; i++) {
const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
bounds.addPointToBounds(point);
}
return bounds.volume();
}
#endif

View File

@@ -1,83 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es> */
#pragma once
#include <Color.h>
#include <Image.h>
/** Uncompressed 4x4 color block. */
struct ColorBlock {
ColorBlock() = default;
/** Initialize the color block from an array of colors. */
ColorBlock(const uint *linearImage);
/** Initialize the color block with the contents of the given block. */
ColorBlock(const ColorBlock &block);
/** Initialize this color block. */
ColorBlock(const Image *img, uint x, uint y);
void init(const Image *img, uint x, uint y);
void init(uint w, uint h, const uint *data, uint x, uint y);
void init(uint w, uint h, const float *data, uint x, uint y);
void swizzle(uint x, uint y, uint z, uint w); /* 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0 */
/** Returns true if the block has a single color. */
bool isSingleColor(Color32 mask = Color32(0xFF, 0xFF, 0xFF, 0x00)) const;
/** Return true if the block is not fully opaque. */
bool hasAlpha() const;
/* Accessors */
const Color32 *colors() const;
Color32 color(uint i) const;
Color32 &color(uint i);
Color32 color(uint x, uint y) const;
Color32 &color(uint x, uint y);
private:
Color32 m_color[4 * 4];
};
/** Get pointer to block colors. */
inline const Color32 *ColorBlock::colors() const
{
return m_color;
}
/** Get block color. */
inline Color32 ColorBlock::color(uint i) const
{
return m_color[i];
}
/** Get block color. */
inline Color32 &ColorBlock::color(uint i)
{
return m_color[i];
}
/** Get block color. */
inline Color32 ColorBlock::color(uint x, uint y) const
{
return m_color[y * 4 + x];
}
/** Get block color. */
inline Color32 &ColorBlock::color(uint x, uint y)
{
return m_color[y * 4 + x];
}

View File

@@ -1,36 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#pragma once
#ifndef MIN
# define MIN(a, b) ((a) <= (b) ? (a) : (b))
#endif
#ifndef MAX
# define MAX(a, b) ((a) >= (b) ? (a) : (b))
#endif
#ifndef CLAMP
# define CLAMP(x, a, b) MIN(MAX((x), (a)), (b))
#endif
template<typename T> inline void swap(T &a, T &b)
{
T tmp = a;
a = b;
b = tmp;
}
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint;
typedef unsigned int uint32;
typedef unsigned long long uint64;
// copied from nvtt src/nvimage/nvimage.h
inline uint computePitch(uint w, uint bitsize, uint alignment)
{
return ((w * bitsize + 8 * alignment - 1) / (8 * alignment)) * alignment;
}

View File

@@ -1,1569 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* 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 "BLI_utildefines.h"
#undef CLAMP
#include <BlockDXT.h>
#include <DirectDrawSurface.h>
#include <PixelFormat.h>
#include <cmath> /* sqrt */
#include <cstdio> /* printf */
#include <cstdlib> /* malloc */
#include <sys/types.h>
/*** declarations ***/
#if !defined(DDS_MAKEFOURCC)
# define DDS_MAKEFOURCC(ch0, ch1, ch2, ch3) \
(uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | (uint(uint8(ch2)) << 16) | \
(uint(uint8(ch3)) << 24))
#endif
static const uint FOURCC_NVTT = DDS_MAKEFOURCC('N', 'V', 'T', 'T');
static const uint FOURCC_DDS = DDS_MAKEFOURCC('D', 'D', 'S', ' ');
static const uint FOURCC_DXT1 = DDS_MAKEFOURCC('D', 'X', 'T', '1');
static const uint FOURCC_DXT2 = DDS_MAKEFOURCC('D', 'X', 'T', '2');
static const uint FOURCC_DXT3 = DDS_MAKEFOURCC('D', 'X', 'T', '3');
static const uint FOURCC_DXT4 = DDS_MAKEFOURCC('D', 'X', 'T', '4');
static const uint FOURCC_DXT5 = DDS_MAKEFOURCC('D', 'X', 'T', '5');
static const uint FOURCC_RXGB = DDS_MAKEFOURCC('R', 'X', 'G', 'B');
static const uint FOURCC_ATI1 = DDS_MAKEFOURCC('A', 'T', 'I', '1');
static const uint FOURCC_ATI2 = DDS_MAKEFOURCC('A', 'T', 'I', '2');
#if 0 /* Valid but currently unused. */
static const uint FOURCC_A2XY = DDS_MAKEFOURCC('A', '2', 'X', 'Y');
#endif
static const uint FOURCC_DX10 = DDS_MAKEFOURCC('D', 'X', '1', '0');
static const uint FOURCC_UVER = DDS_MAKEFOURCC('U', 'V', 'E', 'R');
/* 32 bit RGB formats. */
static const uint D3DFMT_R8G8B8 = 20;
static const uint D3DFMT_A8R8G8B8 = 21;
static const uint D3DFMT_X8R8G8B8 = 22;
static const uint D3DFMT_R5G6B5 = 23;
static const uint D3DFMT_X1R5G5B5 = 24;
static const uint D3DFMT_A1R5G5B5 = 25;
static const uint D3DFMT_A4R4G4B4 = 26;
static const uint D3DFMT_R3G3B2 = 27;
static const uint D3DFMT_A8 = 28;
static const uint D3DFMT_A8R3G3B2 = 29;
static const uint D3DFMT_X4R4G4B4 = 30;
static const uint D3DFMT_A2B10G10R10 = 31;
static const uint D3DFMT_A8B8G8R8 = 32;
static const uint D3DFMT_X8B8G8R8 = 33;
static const uint D3DFMT_G16R16 = 34;
static const uint D3DFMT_A2R10G10B10 = 35;
#if 0 /* Valid but currently unused. */
static const uint D3DFMT_A16B16G16R16 = 36;
#endif
/* Palette formats. */
#if 0 /* Valid but currently unused. */
static const uint D3DFMT_A8P8 = 40;
static const uint D3DFMT_P8 = 41;
#endif
/* Luminance formats. */
static const uint D3DFMT_L8 = 50;
#if 0 /* Valid but currently unused. */
static const uint D3DFMT_A8L8 = 51;
static const uint D3DFMT_A4L4 = 52;
#endif
static const uint D3DFMT_L16 = 81;
/* Floating point formats */
#if 0 /* Valid but currently unused. */
static const uint D3DFMT_R16F = 111;
static const uint D3DFMT_G16R16F = 112;
static const uint D3DFMT_A16B16G16R16F = 113;
static const uint D3DFMT_R32F = 114;
static const uint D3DFMT_G32R32F = 115;
static const uint D3DFMT_A32B32G32R32F = 116;
#endif
static const uint DDSD_CAPS = 0x00000001U;
static const uint DDSD_PIXELFORMAT = 0x00001000U;
static const uint DDSD_WIDTH = 0x00000004U;
static const uint DDSD_HEIGHT = 0x00000002U;
static const uint DDSD_PITCH = 0x00000008U;
static const uint DDSD_MIPMAPCOUNT = 0x00020000U;
static const uint DDSD_LINEARSIZE = 0x00080000U;
static const uint DDSD_DEPTH = 0x00800000U;
static const uint DDSCAPS_COMPLEX = 0x00000008U;
static const uint DDSCAPS_TEXTURE = 0x00001000U;
static const uint DDSCAPS_MIPMAP = 0x00400000U;
static const uint DDSCAPS2_VOLUME = 0x00200000U;
static const uint DDSCAPS2_CUBEMAP = 0x00000200U;
static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U;
static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U;
static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U;
static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U;
static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U;
static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U;
static const uint DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U;
static const uint DDPF_ALPHAPIXELS = 0x00000001U;
static const uint DDPF_ALPHA = 0x00000002U;
static const uint DDPF_FOURCC = 0x00000004U;
static const uint DDPF_RGB = 0x00000040U;
static const uint DDPF_PALETTEINDEXED1 = 0x00000800U;
static const uint DDPF_PALETTEINDEXED2 = 0x00001000U;
static const uint DDPF_PALETTEINDEXED4 = 0x00000008U;
static const uint DDPF_PALETTEINDEXED8 = 0x00000020U;
static const uint DDPF_LUMINANCE = 0x00020000U;
static const uint DDPF_ALPHAPREMULT = 0x00008000U;
/* Custom NVTT flags. */
static const uint DDPF_NORMAL = 0x80000000U;
static const uint DDPF_SRGB = 0x40000000U;
/* DX10 formats. */
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,
};
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,
};
static const char *getDxgiFormatString(DXGI_FORMAT dxgiFormat)
{
#define CASE(format) \
case DXGI_FORMAT_##format: \
return #format
switch (dxgiFormat) {
CASE(UNKNOWN);
CASE(R32G32B32A32_TYPELESS);
CASE(R32G32B32A32_FLOAT);
CASE(R32G32B32A32_UINT);
CASE(R32G32B32A32_SINT);
CASE(R32G32B32_TYPELESS);
CASE(R32G32B32_FLOAT);
CASE(R32G32B32_UINT);
CASE(R32G32B32_SINT);
CASE(R16G16B16A16_TYPELESS);
CASE(R16G16B16A16_FLOAT);
CASE(R16G16B16A16_UNORM);
CASE(R16G16B16A16_UINT);
CASE(R16G16B16A16_SNORM);
CASE(R16G16B16A16_SINT);
CASE(R32G32_TYPELESS);
CASE(R32G32_FLOAT);
CASE(R32G32_UINT);
CASE(R32G32_SINT);
CASE(R32G8X24_TYPELESS);
CASE(D32_FLOAT_S8X24_UINT);
CASE(R32_FLOAT_X8X24_TYPELESS);
CASE(X32_TYPELESS_G8X24_UINT);
CASE(R10G10B10A2_TYPELESS);
CASE(R10G10B10A2_UNORM);
CASE(R10G10B10A2_UINT);
CASE(R11G11B10_FLOAT);
CASE(R8G8B8A8_TYPELESS);
CASE(R8G8B8A8_UNORM);
CASE(R8G8B8A8_UNORM_SRGB);
CASE(R8G8B8A8_UINT);
CASE(R8G8B8A8_SNORM);
CASE(R8G8B8A8_SINT);
CASE(R16G16_TYPELESS);
CASE(R16G16_FLOAT);
CASE(R16G16_UNORM);
CASE(R16G16_UINT);
CASE(R16G16_SNORM);
CASE(R16G16_SINT);
CASE(R32_TYPELESS);
CASE(D32_FLOAT);
CASE(R32_FLOAT);
CASE(R32_UINT);
CASE(R32_SINT);
CASE(R24G8_TYPELESS);
CASE(D24_UNORM_S8_UINT);
CASE(R24_UNORM_X8_TYPELESS);
CASE(X24_TYPELESS_G8_UINT);
CASE(R8G8_TYPELESS);
CASE(R8G8_UNORM);
CASE(R8G8_UINT);
CASE(R8G8_SNORM);
CASE(R8G8_SINT);
CASE(R16_TYPELESS);
CASE(R16_FLOAT);
CASE(D16_UNORM);
CASE(R16_UNORM);
CASE(R16_UINT);
CASE(R16_SNORM);
CASE(R16_SINT);
CASE(R8_TYPELESS);
CASE(R8_UNORM);
CASE(R8_UINT);
CASE(R8_SNORM);
CASE(R8_SINT);
CASE(A8_UNORM);
CASE(R1_UNORM);
CASE(R9G9B9E5_SHAREDEXP);
CASE(R8G8_B8G8_UNORM);
CASE(G8R8_G8B8_UNORM);
CASE(BC1_TYPELESS);
CASE(BC1_UNORM);
CASE(BC1_UNORM_SRGB);
CASE(BC2_TYPELESS);
CASE(BC2_UNORM);
CASE(BC2_UNORM_SRGB);
CASE(BC3_TYPELESS);
CASE(BC3_UNORM);
CASE(BC3_UNORM_SRGB);
CASE(BC4_TYPELESS);
CASE(BC4_UNORM);
CASE(BC4_SNORM);
CASE(BC5_TYPELESS);
CASE(BC5_UNORM);
CASE(BC5_SNORM);
CASE(B5G6R5_UNORM);
CASE(B5G5R5A1_UNORM);
CASE(B8G8R8A8_UNORM);
CASE(B8G8R8X8_UNORM);
default:
return "UNKNOWN";
}
#undef CASE
}
static const char *getD3d10ResourceDimensionString(D3D10_RESOURCE_DIMENSION resourceDimension)
{
switch (resourceDimension) {
default:
case D3D10_RESOURCE_DIMENSION_UNKNOWN:
return "UNKNOWN";
case D3D10_RESOURCE_DIMENSION_BUFFER:
return "BUFFER";
case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
return "TEXTURE1D";
case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
return "TEXTURE2D";
case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
return "TEXTURE3D";
}
}
/*** implementation ***/
void mem_read(Stream &mem, DDSPixelFormat &pf)
{
mem_read(mem, pf.size);
mem_read(mem, pf.flags);
mem_read(mem, pf.fourcc);
mem_read(mem, pf.bitcount);
mem_read(mem, pf.rmask);
mem_read(mem, pf.gmask);
mem_read(mem, pf.bmask);
mem_read(mem, pf.amask);
}
void mem_read(Stream &mem, DDSCaps &caps)
{
mem_read(mem, caps.caps1);
mem_read(mem, caps.caps2);
mem_read(mem, caps.caps3);
mem_read(mem, caps.caps4);
}
void mem_read(Stream &mem, DDSHeader10 &header)
{
mem_read(mem, header.dxgiFormat);
mem_read(mem, header.resourceDimension);
mem_read(mem, header.miscFlag);
mem_read(mem, header.arraySize);
mem_read(mem, header.reserved);
}
void mem_read(Stream &mem, DDSHeader &header)
{
mem_read(mem, header.fourcc);
mem_read(mem, header.size);
mem_read(mem, header.flags);
mem_read(mem, header.height);
mem_read(mem, header.width);
mem_read(mem, header.pitch);
mem_read(mem, header.depth);
mem_read(mem, header.mipmapcount);
for (uint i = 0; i < 11; i++) {
mem_read(mem, header.reserved[i]);
}
mem_read(mem, header.pf);
mem_read(mem, header.caps);
mem_read(mem, header.notused);
if (header.hasDX10Header()) {
mem_read(mem, header.header10);
}
}
namespace {
struct FormatDescriptor {
uint format;
uint bitcount;
uint rmask;
uint gmask;
uint bmask;
uint amask;
};
const FormatDescriptor s_d3dFormats[] = {
{D3DFMT_R8G8B8, 24, 0xFF0000, 0xFF00, 0xFF, 0},
{D3DFMT_A8R8G8B8, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000}, /* DXGI_FORMAT_B8G8R8A8_UNORM */
{D3DFMT_X8R8G8B8, 32, 0xFF0000, 0xFF00, 0xFF, 0}, /* DXGI_FORMAT_B8G8R8X8_UNORM */
{D3DFMT_R5G6B5, 16, 0xF800, 0x7E0, 0x1F, 0}, /* DXGI_FORMAT_B5G6R5_UNORM */
{D3DFMT_X1R5G5B5, 16, 0x7C00, 0x3E0, 0x1F, 0},
{D3DFMT_A1R5G5B5, 16, 0x7C00, 0x3E0, 0x1F, 0x8000}, /* DXGI_FORMAT_B5G5R5A1_UNORM */
{D3DFMT_A4R4G4B4, 16, 0xF00, 0xF0, 0xF, 0xF000},
{D3DFMT_R3G3B2, 8, 0xE0, 0x1C, 0x3, 0},
{D3DFMT_A8, 8, 0, 0, 0, 8}, /* DXGI_FORMAT_A8_UNORM */
{D3DFMT_A8R3G3B2, 16, 0xE0, 0x1C, 0x3, 0xFF00},
{D3DFMT_X4R4G4B4, 16, 0xF00, 0xF0, 0xF, 0},
{D3DFMT_A2B10G10R10, 32, 0x3FF, 0xFFC00, 0x3FF00000, 0xC0000000}, /* DXGI_FORMAT_R10G10B10A2 */
{D3DFMT_A8B8G8R8, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000}, /* DXGI_FORMAT_R8G8B8A8_UNORM */
{D3DFMT_X8B8G8R8, 32, 0xFF, 0xFF00, 0xFF0000, 0},
{D3DFMT_G16R16, 32, 0xFFFF, 0xFFFF0000, 0, 0}, /* DXGI_FORMAT_R16G16_UNORM */
{D3DFMT_A2R10G10B10, 32, 0x3FF00000, 0xFFC00, 0x3FF, 0xC0000000},
{D3DFMT_A2B10G10R10, 32, 0x3FF, 0xFFC00, 0x3FF00000, 0xC0000000},
{D3DFMT_L8, 8, 8, 0, 0, 0}, /* DXGI_FORMAT_R8_UNORM */
{D3DFMT_L16, 16, 16, 0, 0, 0}, /* DXGI_FORMAT_R16_UNORM */
};
const uint s_d3dFormatCount = ARRAY_SIZE(s_d3dFormats);
} /* namespace */
static uint findD3D9Format(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
{
for (int i = 0; i < s_d3dFormatCount; i++) {
if (s_d3dFormats[i].bitcount == bitcount && s_d3dFormats[i].rmask == rmask &&
s_d3dFormats[i].gmask == gmask && s_d3dFormats[i].bmask == bmask &&
s_d3dFormats[i].amask == amask)
{
return s_d3dFormats[i].format;
}
}
return 0;
}
DDSHeader::DDSHeader()
{
this->fourcc = FOURCC_DDS;
this->size = 124;
this->flags = (DDSD_CAPS | DDSD_PIXELFORMAT);
this->height = 0;
this->width = 0;
this->pitch = 0;
this->depth = 0;
this->mipmapcount = 0;
for (uint i = 0; i < 11; i++) {
this->reserved[i] = 0;
}
/* Store version information on the reserved header attributes. */
this->reserved[9] = FOURCC_NVTT;
this->reserved[10] = (2 << 16) | (1 << 8) | (0); /* major.minor.revision */
this->pf.size = 32;
this->pf.flags = 0;
this->pf.fourcc = 0;
this->pf.bitcount = 0;
this->pf.rmask = 0;
this->pf.gmask = 0;
this->pf.bmask = 0;
this->pf.amask = 0;
this->caps.caps1 = DDSCAPS_TEXTURE;
this->caps.caps2 = 0;
this->caps.caps3 = 0;
this->caps.caps4 = 0;
this->notused = 0;
this->header10.dxgiFormat = DXGI_FORMAT_UNKNOWN;
this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_UNKNOWN;
this->header10.miscFlag = 0;
this->header10.arraySize = 0;
this->header10.reserved = 0;
}
void DDSHeader::setWidth(uint w)
{
this->flags |= DDSD_WIDTH;
this->width = w;
}
void DDSHeader::setHeight(uint h)
{
this->flags |= DDSD_HEIGHT;
this->height = h;
}
void DDSHeader::setDepth(uint d)
{
this->flags |= DDSD_DEPTH;
this->depth = d;
}
void DDSHeader::setMipmapCount(uint count)
{
if (ELEM(count, 0, 1)) {
this->flags &= ~DDSD_MIPMAPCOUNT;
this->mipmapcount = 1;
if (this->caps.caps2 == 0) {
this->caps.caps1 = DDSCAPS_TEXTURE;
}
else {
this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
}
}
else {
this->flags |= DDSD_MIPMAPCOUNT;
this->mipmapcount = count;
this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
}
}
void DDSHeader::setTexture2D()
{
this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
this->header10.arraySize = 1;
}
void DDSHeader::setTexture3D()
{
this->caps.caps2 = DDSCAPS2_VOLUME;
this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D;
this->header10.arraySize = 1;
}
void DDSHeader::setTextureCube()
{
this->caps.caps1 |= DDSCAPS_COMPLEX;
this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES;
this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
this->header10.arraySize = 6;
}
void DDSHeader::setLinearSize(uint size)
{
this->flags &= ~DDSD_PITCH;
this->flags |= DDSD_LINEARSIZE;
this->pitch = size;
}
void DDSHeader::setPitch(uint pitch)
{
this->flags &= ~DDSD_LINEARSIZE;
this->flags |= DDSD_PITCH;
this->pitch = pitch;
}
void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3)
{
/* set fourcc pixel format. */
this->pf.flags = DDPF_FOURCC;
this->pf.fourcc = DDS_MAKEFOURCC(c0, c1, c2, c3);
this->pf.bitcount = 0;
this->pf.rmask = 0;
this->pf.gmask = 0;
this->pf.bmask = 0;
this->pf.amask = 0;
}
void DDSHeader::setFormatCode(uint32 code)
{
/* set fourcc pixel format. */
this->pf.flags = DDPF_FOURCC;
this->pf.fourcc = code;
this->pf.bitcount = 0;
this->pf.rmask = 0;
this->pf.gmask = 0;
this->pf.bmask = 0;
this->pf.amask = 0;
}
void DDSHeader::setSwizzleCode(uint8 c0, uint8 c1, uint8 c2, uint8 c3)
{
this->pf.bitcount = DDS_MAKEFOURCC(c0, c1, c2, c3);
}
void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
{
/* Make sure the masks are correct. */
if ((rmask & gmask) || (rmask & bmask) || (rmask & amask) || (gmask & bmask) ||
(gmask & amask) || (bmask & amask))
{
printf("DDS: bad RGBA masks, pixel format not set\n");
return;
}
if (rmask != 0 || gmask != 0 || bmask != 0) {
if (gmask == 0 && bmask == 0) {
this->pf.flags = DDPF_LUMINANCE;
}
else {
this->pf.flags = DDPF_RGB;
}
if (amask != 0) {
this->pf.flags |= DDPF_ALPHAPIXELS;
}
}
else if (amask != 0) {
this->pf.flags |= DDPF_ALPHA;
}
if (bitcount == 0) {
/* Compute bit count from the masks. */
uint total = rmask | gmask | bmask | amask;
while (total != 0) {
bitcount++;
total >>= 1;
}
}
/* D3DX functions do not like this: */
this->pf.fourcc = 0; // findD3D9Format(bitcount, rmask, gmask, bmask, amask);
#if 0
if (this->pf.fourcc) {
this->pf.flags |= DDPF_FOURCC;
}
#endif
if (!(bitcount > 0 && bitcount <= 32)) {
printf("DDS: bad bit count, pixel format not set\n");
return;
}
this->pf.bitcount = bitcount;
this->pf.rmask = rmask;
this->pf.gmask = gmask;
this->pf.bmask = bmask;
this->pf.amask = amask;
}
void DDSHeader::setDX10Format(uint format)
{
// this->pf.flags = 0;
this->pf.fourcc = FOURCC_DX10;
this->header10.dxgiFormat = format;
}
void DDSHeader::setNormalFlag(bool b)
{
if (b) {
this->pf.flags |= DDPF_NORMAL;
}
else {
this->pf.flags &= ~DDPF_NORMAL;
}
}
void DDSHeader::setSrgbFlag(bool b)
{
if (b) {
this->pf.flags |= DDPF_SRGB;
}
else {
this->pf.flags &= ~DDPF_SRGB;
}
}
void DDSHeader::setHasAlphaFlag(bool b)
{
if (b) {
this->pf.flags |= DDPF_ALPHAPIXELS;
}
else {
this->pf.flags &= ~DDPF_ALPHAPIXELS;
}
}
void DDSHeader::setUserVersion(int version)
{
this->reserved[7] = FOURCC_UVER;
this->reserved[8] = version;
}
#if 0
void DDSHeader::swapBytes()
{
this->fourcc = POSH_LittleU32(this->fourcc);
this->size = POSH_LittleU32(this->size);
this->flags = POSH_LittleU32(this->flags);
this->height = POSH_LittleU32(this->height);
this->width = POSH_LittleU32(this->width);
this->pitch = POSH_LittleU32(this->pitch);
this->depth = POSH_LittleU32(this->depth);
this->mipmapcount = POSH_LittleU32(this->mipmapcount);
for (int i = 0; i < 11; i++) {
this->reserved[i] = POSH_LittleU32(this->reserved[i]);
}
this->pf.size = POSH_LittleU32(this->pf.size);
this->pf.flags = POSH_LittleU32(this->pf.flags);
this->pf.fourcc = POSH_LittleU32(this->pf.fourcc);
this->pf.bitcount = POSH_LittleU32(this->pf.bitcount);
this->pf.rmask = POSH_LittleU32(this->pf.rmask);
this->pf.gmask = POSH_LittleU32(this->pf.gmask);
this->pf.bmask = POSH_LittleU32(this->pf.bmask);
this->pf.amask = POSH_LittleU32(this->pf.amask);
this->caps.caps1 = POSH_LittleU32(this->caps.caps1);
this->caps.caps2 = POSH_LittleU32(this->caps.caps2);
this->caps.caps3 = POSH_LittleU32(this->caps.caps3);
this->caps.caps4 = POSH_LittleU32(this->caps.caps4);
this->notused = POSH_LittleU32(this->notused);
this->header10.dxgiFormat = POSH_LittleU32(this->header10.dxgiFormat);
this->header10.resourceDimension = POSH_LittleU32(this->header10.resourceDimension);
this->header10.miscFlag = POSH_LittleU32(this->header10.miscFlag);
this->header10.arraySize = POSH_LittleU32(this->header10.arraySize);
this->header10.reserved = POSH_LittleU32(this->header10.reserved);
}
#endif
bool DDSHeader::hasDX10Header() const
{
return this->pf.fourcc == FOURCC_DX10;
}
uint DDSHeader::signature() const
{
return this->reserved[9];
}
uint DDSHeader::toolVersion() const
{
return this->reserved[10];
}
uint DDSHeader::userVersion() const
{
if (this->reserved[7] == FOURCC_UVER) {
return this->reserved[8];
}
return 0;
}
bool DDSHeader::isNormalMap() const
{
return (pf.flags & DDPF_NORMAL) != 0;
}
bool DDSHeader::isSrgb() const
{
return (pf.flags & DDPF_SRGB) != 0;
}
bool DDSHeader::hasAlpha() const
{
return (pf.flags & DDPF_ALPHAPIXELS) != 0;
}
uint DDSHeader::d3d9Format() const
{
if (pf.flags & DDPF_FOURCC) {
return pf.fourcc;
}
return findD3D9Format(pf.bitcount, pf.rmask, pf.gmask, pf.bmask, pf.amask);
}
DirectDrawSurface::DirectDrawSurface(uchar *mem, uint size) : stream(mem, size), header()
{
mem_read(stream, header);
/* Some ATI2 compressed normal maps do not have their
* normal flag set, so force it here (the original `nvtt` don't do
* this, but the decompressor has a `-forcenormal` flag). */
if (header.pf.fourcc == FOURCC_ATI2) {
header.setNormalFlag(true);
}
}
bool DirectDrawSurface::isValid() const
{
if (header.fourcc != FOURCC_DDS || header.size != 124) {
return false;
}
const uint required = (DDSD_WIDTH | DDSD_HEIGHT /*|DDSD_CAPS|DDSD_PIXELFORMAT*/);
if ((header.flags & required) != required) {
return false;
}
if (header.pf.size != 32) {
return false;
}
/* in some files DDSCAPS_TEXTURE is missing: silently ignore */
#if 0
if (!(header.caps.caps1 & DDSCAPS_TEXTURE)) {
return false;
}
#endif
return true;
}
bool DirectDrawSurface::isSupported() const
{
if (header.hasDX10Header()) {
if (ELEM(header.header10.dxgiFormat,
DXGI_FORMAT_BC1_UNORM,
DXGI_FORMAT_BC2_UNORM,
DXGI_FORMAT_BC3_UNORM,
DXGI_FORMAT_BC4_UNORM,
DXGI_FORMAT_BC5_UNORM))
{
return true;
}
return false;
}
if (header.pf.flags & DDPF_FOURCC) {
if (!ELEM(header.pf.fourcc,
FOURCC_DXT1,
FOURCC_DXT2,
FOURCC_DXT3,
FOURCC_DXT4,
FOURCC_DXT5,
FOURCC_RXGB,
FOURCC_ATI1,
FOURCC_ATI2))
{
/* Unknown fourcc code. */
return false;
}
}
else if ((header.pf.flags & DDPF_RGB) || (header.pf.flags & DDPF_LUMINANCE)) {
/* All RGB and luminance formats are supported now. */
}
else {
return false;
}
if (isTextureCube() &&
(header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES)
{
/* Cube-maps must contain all faces. */
return false;
}
if (isTexture3D()) {
/* @@ 3D textures not supported yet. */
return false;
}
return true;
}
bool DirectDrawSurface::hasAlpha() const
{
if (header.hasDX10Header()) {
/* TODO: Update hasAlpha to handle all DX10 formats. */
return header.header10.dxgiFormat == DXGI_FORMAT_BC1_UNORM ||
header.header10.dxgiFormat == DXGI_FORMAT_BC2_UNORM ||
header.header10.dxgiFormat == DXGI_FORMAT_BC3_UNORM;
}
if (header.pf.flags & DDPF_RGB) {
return header.pf.amask != 0;
}
if (header.pf.flags & DDPF_FOURCC) {
if (header.pf.fourcc == FOURCC_RXGB || header.pf.fourcc == FOURCC_ATI1 ||
header.pf.fourcc == FOURCC_ATI2 || header.pf.flags & DDPF_NORMAL)
{
return false;
}
/* @@ Here we could check the ALPHA_PIXELS flag, but nobody sets it. (except us?) */
return true;
}
return false;
}
uint DirectDrawSurface::mipmapCount() const
{
if (header.flags & DDSD_MIPMAPCOUNT) {
return header.mipmapcount;
}
return 1;
}
uint DirectDrawSurface::fourCC() const
{
return header.pf.fourcc;
}
uint DirectDrawSurface::width() const
{
if (header.flags & DDSD_WIDTH) {
return header.width;
}
return 1;
}
uint DirectDrawSurface::height() const
{
if (header.flags & DDSD_HEIGHT) {
return header.height;
}
return 1;
}
uint DirectDrawSurface::depth() const
{
if (header.flags & DDSD_DEPTH) {
return header.depth;
}
return 1;
}
bool DirectDrawSurface::isTexture1D() const
{
if (header.hasDX10Header()) {
return header.header10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE1D;
}
return false;
}
bool DirectDrawSurface::isTexture2D() const
{
if (header.hasDX10Header()) {
return header.header10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE2D;
}
return !isTexture3D() && !isTextureCube();
}
bool DirectDrawSurface::isTexture3D() const
{
if (header.hasDX10Header()) {
return header.header10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D;
}
return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0;
}
bool DirectDrawSurface::isTextureCube() const
{
return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0;
}
void DirectDrawSurface::setNormalFlag(bool b)
{
header.setNormalFlag(b);
}
void DirectDrawSurface::setHasAlphaFlag(bool b)
{
header.setHasAlphaFlag(b);
}
void DirectDrawSurface::setUserVersion(int version)
{
header.setUserVersion(version);
}
void DirectDrawSurface::mipmap(Image *img, uint face, uint mipmap)
{
stream.seek(offset(face, mipmap));
uint w = width();
uint h = height();
/* Compute width and height. */
for (uint m = 0; m < mipmap; m++) {
w = MAX(1U, w / 2);
h = MAX(1U, h / 2);
}
img->allocate(w, h);
if (hasAlpha()) {
img->setFormat(Image::Format_ARGB);
}
else {
img->setFormat(Image::Format_RGB);
}
if (header.hasDX10Header()) {
/* So far only block formats supported. */
readBlockImage(img);
}
else {
if (header.pf.flags & DDPF_RGB) {
readLinearImage(img);
}
else if (header.pf.flags & DDPF_FOURCC) {
readBlockImage(img);
}
}
}
void *DirectDrawSurface::readData(uint &rsize)
{
uint header_size = 128; // sizeof(DDSHeader);
if (header.hasDX10Header()) {
header_size += 20; // sizeof(DDSHeader10);
}
uint size = stream.size - header_size;
rsize = size;
uchar *data = (uchar *)malloc(sizeof(*data) * size);
stream.seek(header_size);
mem_read(stream, data, size);
if (stream.failed) {
free(data);
data = nullptr;
rsize = 0;
}
/* Maybe check if size == rsize? assert() isn't in this scope. */
return data;
}
void DirectDrawSurface::readLinearImage(Image *img)
{
const uint w = img->width();
const uint h = img->height();
uint rshift, rsize;
PixelFormat::maskShiftAndSize(header.pf.rmask, &rshift, &rsize);
uint gshift, gsize;
PixelFormat::maskShiftAndSize(header.pf.gmask, &gshift, &gsize);
uint bshift, bsize;
PixelFormat::maskShiftAndSize(header.pf.bmask, &bshift, &bsize);
uint ashift, asize;
PixelFormat::maskShiftAndSize(header.pf.amask, &ashift, &asize);
uint byteCount = (header.pf.bitcount + 7) / 8;
if (byteCount > 4) {
/* just in case... we could have segfaults later on if byteCount > 4 */
printf("DDS: bitcount too large");
return;
}
/* Read linear RGB images. */
for (uint y = 0; y < h; y++) {
for (uint x = 0; x < w; x++) {
uint c = 0;
mem_read(stream, (uchar *)(&c), byteCount);
Color32 pixel(0, 0, 0, 0xFF);
pixel.r = PixelFormat::convert((c & header.pf.rmask) >> rshift, rsize, 8);
pixel.g = PixelFormat::convert((c & header.pf.gmask) >> gshift, gsize, 8);
pixel.b = PixelFormat::convert((c & header.pf.bmask) >> bshift, bsize, 8);
pixel.a = PixelFormat::convert((c & header.pf.amask) >> ashift, asize, 8);
img->pixel(x, y) = pixel;
}
}
}
void DirectDrawSurface::readBlockImage(Image *img)
{
const uint w = img->width();
const uint h = img->height();
const uint bw = (w + 3) / 4;
const uint bh = (h + 3) / 4;
for (uint by = 0; by < bh; by++) {
for (uint bx = 0; bx < bw; bx++) {
ColorBlock block;
/* Read color block. */
readBlock(&block);
/* Write color block. */
for (uint y = 0; y < MIN(4U, h - 4 * by); y++) {
for (uint x = 0; x < MIN(4U, w - 4 * bx); x++) {
img->pixel(4 * bx + x, 4 * by + y) = block.color(x, y);
}
}
}
}
}
static Color32 buildNormal(uint8 x, uint8 y)
{
float nx = 2 * (x / 255.0f) - 1;
float ny = 2 * (y / 255.0f) - 1;
float nz = 0.0f;
if (1 - nx * nx - ny * ny > 0) {
nz = sqrt(1 - nx * nx - ny * ny);
}
uint8 z = CLAMP(int(255.0f * (nz + 1) / 2.0f), 0, 255);
return Color32(x, y, z);
}
void DirectDrawSurface::readBlock(ColorBlock *rgba)
{
uint fourcc = header.pf.fourcc;
/* Map DX10 block formats to fourcc codes. */
if (header.hasDX10Header()) {
if (header.header10.dxgiFormat == DXGI_FORMAT_BC1_UNORM) {
fourcc = FOURCC_DXT1;
}
if (header.header10.dxgiFormat == DXGI_FORMAT_BC2_UNORM) {
fourcc = FOURCC_DXT3;
}
if (header.header10.dxgiFormat == DXGI_FORMAT_BC3_UNORM) {
fourcc = FOURCC_DXT5;
}
if (header.header10.dxgiFormat == DXGI_FORMAT_BC4_UNORM) {
fourcc = FOURCC_ATI1;
}
if (header.header10.dxgiFormat == DXGI_FORMAT_BC5_UNORM) {
fourcc = FOURCC_ATI2;
}
}
if (fourcc == FOURCC_DXT1) {
BlockDXT1 block;
mem_read(stream, block);
block.decodeBlock(rgba);
}
else if (fourcc == FOURCC_DXT2 || header.pf.fourcc == FOURCC_DXT3) {
BlockDXT3 block;
mem_read(stream, block);
block.decodeBlock(rgba);
}
else if (fourcc == FOURCC_DXT4 || header.pf.fourcc == FOURCC_DXT5 ||
header.pf.fourcc == FOURCC_RXGB)
{
BlockDXT5 block;
mem_read(stream, block);
block.decodeBlock(rgba);
if (fourcc == FOURCC_RXGB) {
/* Swap R & A. */
for (int i = 0; i < 16; i++) {
Color32 &c = rgba->color(i);
uint tmp = c.r;
c.r = c.a;
c.a = tmp;
}
}
}
else if (fourcc == FOURCC_ATI1) {
BlockATI1 block;
mem_read(stream, block);
block.decodeBlock(rgba);
}
else if (fourcc == FOURCC_ATI2) {
BlockATI2 block;
mem_read(stream, block);
block.decodeBlock(rgba);
}
/* If normal flag set, convert to normal. */
if (header.pf.flags & DDPF_NORMAL) {
if (fourcc == FOURCC_ATI2) {
for (int i = 0; i < 16; i++) {
Color32 &c = rgba->color(i);
c = buildNormal(c.r, c.g);
}
}
else if (fourcc == FOURCC_DXT5) {
for (int i = 0; i < 16; i++) {
Color32 &c = rgba->color(i);
c = buildNormal(c.a, c.g);
}
}
}
}
uint DirectDrawSurface::blockSize() const
{
switch (header.pf.fourcc) {
case FOURCC_DXT1:
case FOURCC_ATI1:
return 8;
case FOURCC_DXT2:
case FOURCC_DXT3:
case FOURCC_DXT4:
case FOURCC_DXT5:
case FOURCC_RXGB:
case FOURCC_ATI2:
return 16;
case FOURCC_DX10:
switch (header.header10.dxgiFormat) {
case DXGI_FORMAT_BC1_TYPELESS:
case DXGI_FORMAT_BC1_UNORM:
case DXGI_FORMAT_BC1_UNORM_SRGB:
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM:
return 8;
case DXGI_FORMAT_BC2_TYPELESS:
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC2_UNORM_SRGB:
case DXGI_FORMAT_BC3_TYPELESS:
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC3_UNORM_SRGB:
case DXGI_FORMAT_BC5_TYPELESS:
case DXGI_FORMAT_BC5_UNORM:
case DXGI_FORMAT_BC5_SNORM:
return 16;
}
}
/* Not a block image. */
return 0;
}
uint DirectDrawSurface::mipmapSize(uint mipmap) const
{
uint w = width();
uint h = height();
uint d = depth();
for (uint m = 0; m < mipmap; m++) {
w = MAX(1U, w / 2);
h = MAX(1U, h / 2);
d = MAX(1U, d / 2);
}
if (header.pf.flags & DDPF_FOURCC) {
/* @@ How are 3D textures aligned? */
w = (w + 3) / 4;
h = (h + 3) / 4;
return blockSize() * w * h;
}
if (header.pf.flags & DDPF_RGB || (header.pf.flags & DDPF_LUMINANCE)) {
/* Assuming 8 bit alignment, which is the same D3DX expects. */
uint pitch = computePitch(w, header.pf.bitcount, 8);
return pitch * h * d;
}
printf("DDS: mipmap format not supported\n");
return 0;
}
uint DirectDrawSurface::faceSize() const
{
const uint count = mipmapCount();
uint size = 0;
for (uint m = 0; m < count; m++) {
size += mipmapSize(m);
}
return size;
}
uint DirectDrawSurface::offset(const uint face, const uint mipmap)
{
uint size = 128; // sizeof(DDSHeader);
if (header.hasDX10Header()) {
size += 20; // sizeof(DDSHeader10);
}
if (face != 0) {
size += face * faceSize();
}
for (uint m = 0; m < mipmap; m++) {
size += mipmapSize(m);
}
return size;
}
void DirectDrawSurface::printInfo() const
{
printf("Flags: 0x%.8X\n", header.flags);
if (header.flags & DDSD_CAPS) {
printf("\tDDSD_CAPS\n");
}
if (header.flags & DDSD_PIXELFORMAT) {
printf("\tDDSD_PIXELFORMAT\n");
}
if (header.flags & DDSD_WIDTH) {
printf("\tDDSD_WIDTH\n");
}
if (header.flags & DDSD_HEIGHT) {
printf("\tDDSD_HEIGHT\n");
}
if (header.flags & DDSD_DEPTH) {
printf("\tDDSD_DEPTH\n");
}
if (header.flags & DDSD_PITCH) {
printf("\tDDSD_PITCH\n");
}
if (header.flags & DDSD_LINEARSIZE) {
printf("\tDDSD_LINEARSIZE\n");
}
if (header.flags & DDSD_MIPMAPCOUNT) {
printf("\tDDSD_MIPMAPCOUNT\n");
}
printf("Height: %u\n", header.height);
printf("Width: %u\n", header.width);
printf("Depth: %u\n", header.depth);
if (header.flags & DDSD_PITCH) {
printf("Pitch: %u\n", header.pitch);
}
else if (header.flags & DDSD_LINEARSIZE) {
printf("Linear size: %u\n", header.pitch);
}
printf("Mipmap count: %u\n", header.mipmapcount);
printf("Pixel Format:\n");
printf("\tFlags: 0x%.8X\n", header.pf.flags);
if (header.pf.flags & DDPF_RGB) {
printf("\t\tDDPF_RGB\n");
}
if (header.pf.flags & DDPF_LUMINANCE) {
printf("\t\tDDPF_LUMINANCE\n");
}
if (header.pf.flags & DDPF_FOURCC) {
printf("\t\tDDPF_FOURCC\n");
}
if (header.pf.flags & DDPF_ALPHAPIXELS) {
printf("\t\tDDPF_ALPHAPIXELS\n");
}
if (header.pf.flags & DDPF_ALPHA) {
printf("\t\tDDPF_ALPHA\n");
}
if (header.pf.flags & DDPF_PALETTEINDEXED1) {
printf("\t\tDDPF_PALETTEINDEXED1\n");
}
if (header.pf.flags & DDPF_PALETTEINDEXED2) {
printf("\t\tDDPF_PALETTEINDEXED2\n");
}
if (header.pf.flags & DDPF_PALETTEINDEXED4) {
printf("\t\tDDPF_PALETTEINDEXED4\n");
}
if (header.pf.flags & DDPF_PALETTEINDEXED8) {
printf("\t\tDDPF_PALETTEINDEXED8\n");
}
if (header.pf.flags & DDPF_ALPHAPREMULT) {
printf("\t\tDDPF_ALPHAPREMULT\n");
}
if (header.pf.flags & DDPF_NORMAL) {
printf("\t\tDDPF_NORMAL\n");
}
if (header.pf.fourcc != 0) {
/* Display fourcc code even when DDPF_FOURCC flag not set. */
printf("\tFourCC: '%c%c%c%c' (0x%.8X)\n",
int((header.pf.fourcc >> 0) & 0xFF),
int((header.pf.fourcc >> 8) & 0xFF),
int((header.pf.fourcc >> 16) & 0xFF),
int((header.pf.fourcc >> 24) & 0xFF),
header.pf.fourcc);
}
if ((header.pf.flags & DDPF_FOURCC) && (header.pf.bitcount != 0)) {
printf("\tSwizzle: '%c%c%c%c' (0x%.8X)\n",
int(header.pf.bitcount >> 0) & 0xFF,
int(header.pf.bitcount >> 8) & 0xFF,
int(header.pf.bitcount >> 16) & 0xFF,
int(header.pf.bitcount >> 24) & 0xFF,
header.pf.bitcount);
}
else {
printf("\tBit count: %u\n", header.pf.bitcount);
}
printf("\tRed mask: 0x%.8X\n", header.pf.rmask);
printf("\tGreen mask: 0x%.8X\n", header.pf.gmask);
printf("\tBlue mask: 0x%.8X\n", header.pf.bmask);
printf("\tAlpha mask: 0x%.8X\n", header.pf.amask);
printf("Caps:\n");
printf("\tCaps 1: 0x%.8X\n", header.caps.caps1);
if (header.caps.caps1 & DDSCAPS_COMPLEX) {
printf("\t\tDDSCAPS_COMPLEX\n");
}
if (header.caps.caps1 & DDSCAPS_TEXTURE) {
printf("\t\tDDSCAPS_TEXTURE\n");
}
if (header.caps.caps1 & DDSCAPS_MIPMAP) {
printf("\t\tDDSCAPS_MIPMAP\n");
}
printf("\tCaps 2: 0x%.8X\n", header.caps.caps2);
if (header.caps.caps2 & DDSCAPS2_VOLUME) {
printf("\t\tDDSCAPS2_VOLUME\n");
}
else if (header.caps.caps2 & DDSCAPS2_CUBEMAP) {
printf("\t\tDDSCAPS2_CUBEMAP\n");
if ((header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) == DDSCAPS2_CUBEMAP_ALL_FACES) {
printf("\t\tDDSCAPS2_CUBEMAP_ALL_FACES\n");
}
else {
if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) {
printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEX\n");
}
if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) {
printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEX\n");
}
if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) {
printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEY\n");
}
if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) {
printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEY\n");
}
if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) {
printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEZ\n");
}
if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) {
printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEZ\n");
}
}
}
printf("\tCaps 3: 0x%.8X\n", header.caps.caps3);
printf("\tCaps 4: 0x%.8X\n", header.caps.caps4);
if (header.hasDX10Header()) {
printf("DX10 Header:\n");
printf("\tDXGI Format: %u (%s)\n",
header.header10.dxgiFormat,
getDxgiFormatString((DXGI_FORMAT)header.header10.dxgiFormat));
printf("\tResource dimension: %u (%s)\n",
header.header10.resourceDimension,
getD3d10ResourceDimensionString(
(D3D10_RESOURCE_DIMENSION)header.header10.resourceDimension));
printf("\tMisc flag: %u\n", header.header10.miscFlag);
printf("\tArray size: %u\n", header.header10.arraySize);
}
if (header.reserved[9] == FOURCC_NVTT) {
int major = (header.reserved[10] >> 16) & 0xFF;
int minor = (header.reserved[10] >> 8) & 0xFF;
int revision = header.reserved[10] & 0xFF;
printf("Version:\n");
printf("\tNVIDIA Texture Tools %d.%d.%d\n", major, minor, revision);
}
if (header.reserved[7] == FOURCC_UVER) {
printf("User Version: %u\n", header.reserved[8]);
}
}

View File

@@ -1,175 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* 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. */
#pragma once
#include <ColorBlock.h>
#include <Common.h>
#include <Image.h>
#include <Stream.h>
struct DDSPixelFormat {
uint size;
uint flags;
uint fourcc;
uint bitcount;
uint rmask;
uint gmask;
uint bmask;
uint amask;
};
struct DDSCaps {
uint caps1;
uint caps2;
uint caps3;
uint caps4;
};
/** DDS file header for DX10. */
struct DDSHeader10 {
uint dxgiFormat;
uint resourceDimension;
uint miscFlag;
uint arraySize;
uint reserved;
};
/** DDS file header. */
struct DDSHeader {
uint fourcc;
uint size;
uint flags;
uint height;
uint width;
uint pitch;
uint depth;
uint mipmapcount;
uint reserved[11];
DDSPixelFormat pf;
DDSCaps caps;
uint notused;
DDSHeader10 header10;
/* Helper methods. */
DDSHeader();
void setWidth(uint w);
void setHeight(uint h);
void setDepth(uint d);
void setMipmapCount(uint count);
void setTexture2D();
void setTexture3D();
void setTextureCube();
void setLinearSize(uint size);
void setPitch(uint pitch);
void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
void setFormatCode(uint code);
void setSwizzleCode(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
void setDX10Format(uint format);
void setNormalFlag(bool b);
void setSrgbFlag(bool b);
void setHasAlphaFlag(bool b);
void setUserVersion(int version);
// void swapBytes();
bool hasDX10Header() const;
uint signature() const;
uint toolVersion() const;
uint userVersion() const;
bool isNormalMap() const;
bool isSrgb() const;
bool hasAlpha() const;
uint d3d9Format() const;
};
/** DirectDraw Surface. (DDS) */
class DirectDrawSurface {
public:
DirectDrawSurface(unsigned char *mem, uint size);
bool isValid() const;
bool isSupported() const;
bool hasAlpha() const;
uint mipmapCount() const;
uint fourCC() const;
uint width() const;
uint height() const;
uint depth() const;
bool isTexture1D() const;
bool isTexture2D() const;
bool isTexture3D() const;
bool isTextureCube() const;
void setNormalFlag(bool b);
void setHasAlphaFlag(bool b);
void setUserVersion(int version);
void mipmap(Image *img, uint f, uint m);
/**
* It was easier to copy this function from upstream than to resync.
* This should be removed if a resync ever occurs.
*/
void *readData(uint &size);
// void mipmap(FloatImage *img, uint f, uint m);
void printInfo() const;
private:
uint blockSize() const;
uint faceSize() const;
uint mipmapSize(uint m) const;
uint offset(uint f, uint m);
void readLinearImage(Image *img);
void readBlockImage(Image *img);
void readBlock(ColorBlock *rgba);
private:
/** Memory where DDS file resides. */
Stream stream;
DDSHeader header;
};
void mem_read(Stream &mem, DDSPixelFormat &pf);
void mem_read(Stream &mem, DDSCaps &caps);
void mem_read(Stream &mem, DDSHeader &header);
void mem_read(Stream &mem, DDSHeader10 &header);

View File

@@ -1,247 +0,0 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2009 Google Inc. All rights reserved. */
/** \file
* \ingroup imbdds
* This file comes from the chromium project, adapted to Blender to add DDS
* flipping to OpenGL convention for Blender.
*/
#include "IMB_imbuf_types.h"
#include <cstring>
#include <BlockDXT.h>
#include <ColorBlock.h>
#include <Common.h>
#include <FlipDXT.h>
#include <Stream.h>
/* A function that flips a DXTC block. */
using FlipBlockFunction = void (*)(uint8_t *block);
/* Flips a full DXT1 block in the y direction. */
static void FlipDXT1BlockFull(uint8_t *block)
{
/* A DXT1 block layout is:
* [0-1] color0.
* [2-3] color1.
* [4-7] color bitmap, 2 bits per pixel.
* So each of the 4-7 bytes represents one line, flipping a block is just
* flipping those bytes. */
uint8_t tmp = block[4];
block[4] = block[7];
block[7] = tmp;
tmp = block[5];
block[5] = block[6];
block[6] = tmp;
}
/* Flips the first 2 lines of a DXT1 block in the y direction. */
static void FlipDXT1BlockHalf(uint8_t *block)
{
/* See layout above. */
uint8_t tmp = block[4];
block[4] = block[5];
block[5] = tmp;
}
/* Flips a full DXT3 block in the y direction. */
static void FlipDXT3BlockFull(uint8_t *block)
{
/* A DXT3 block layout is:
* [0-7] alpha bitmap, 4 bits per pixel.
* [8-15] a DXT1 block. */
/* We can flip the alpha bits at the byte level (2 bytes per line). */
uint8_t tmp = block[0];
block[0] = block[6];
block[6] = tmp;
tmp = block[1];
block[1] = block[7];
block[7] = tmp;
tmp = block[2];
block[2] = block[4];
block[4] = tmp;
tmp = block[3];
block[3] = block[5];
block[5] = tmp;
/* And flip the DXT1 block using the above function. */
FlipDXT1BlockFull(block + 8);
}
/* Flips the first 2 lines of a DXT3 block in the y direction. */
static void FlipDXT3BlockHalf(uint8_t *block)
{
/* See layout above. */
uint8_t tmp = block[0];
block[0] = block[2];
block[2] = tmp;
tmp = block[1];
block[1] = block[3];
block[3] = tmp;
FlipDXT1BlockHalf(block + 8);
}
/* Flips a full DXT5 block in the y direction. */
static void FlipDXT5BlockFull(uint8_t *block)
{
/* A DXT5 block layout is:
* [0] alpha0.
* [1] alpha1.
* [2-7] alpha bitmap, 3 bits per pixel.
* [8-15] a DXT1 block. */
/* The alpha bitmap doesn't easily map lines to bytes, so we have to
* interpret it correctly. Extracted from
* http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
*
* The 6 "bits" bytes of the block are decoded into one 48-bit integer:
*
* bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
* 256 * (bits_4 + 256 * bits_5))))
*
* bits is a 48-bit unsigned-integer, from which a three-bit control code
* is extracted for a texel at location (x,y) in the block using:
*
* code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
*
* where bit 47 is the most significant and bit 0 is the least
* significant bit. */
uint line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
uint line_2_3 = block[5] + 256 * (block[6] + 256 * block[7]);
/* swap lines 0 and 1 in line_0_1. */
uint line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
/* swap lines 2 and 3 in line_2_3. */
uint line_3_2 = ((line_2_3 & 0x000fff) << 12) | ((line_2_3 & 0xfff000) >> 12);
block[2] = line_3_2 & 0xff;
block[3] = (line_3_2 & 0xff00) >> 8;
block[4] = (line_3_2 & 0xff0000) >> 16;
block[5] = line_1_0 & 0xff;
block[6] = (line_1_0 & 0xff00) >> 8;
block[7] = (line_1_0 & 0xff0000) >> 16;
/* And flip the DXT1 block using the above function. */
FlipDXT1BlockFull(block + 8);
}
/* Flips the first 2 lines of a DXT5 block in the y direction. */
static void FlipDXT5BlockHalf(uint8_t *block)
{
/* See layout above. */
uint line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
uint line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
block[2] = line_1_0 & 0xff;
block[3] = (line_1_0 & 0xff00) >> 8;
block[4] = (line_1_0 & 0xff0000) >> 16;
FlipDXT1BlockHalf(block + 8);
}
int FlipDXTCImage(uint width,
uint height,
uint levels,
int fourcc,
uint8_t *data,
int data_size,
uint *r_num_valid_levels)
{
*r_num_valid_levels = 0;
/* Must have valid dimensions. */
if (width == 0 || height == 0) {
return 0;
}
/* Height must be a power-of-two. */
if ((height & (height - 1)) != 0) {
return 0;
}
FlipBlockFunction full_block_function;
FlipBlockFunction half_block_function;
uint block_bytes = 0;
switch (fourcc) {
case FOURCC_DXT1:
full_block_function = FlipDXT1BlockFull;
half_block_function = FlipDXT1BlockHalf;
block_bytes = 8;
break;
case FOURCC_DXT3:
full_block_function = FlipDXT3BlockFull;
half_block_function = FlipDXT3BlockHalf;
block_bytes = 16;
break;
case FOURCC_DXT5:
full_block_function = FlipDXT5BlockFull;
half_block_function = FlipDXT5BlockHalf;
block_bytes = 16;
break;
default:
return 0;
}
*r_num_valid_levels = levels;
uint mip_width = width;
uint mip_height = height;
const uint8_t *data_end = data + data_size;
for (uint i = 0; i < levels; i++) {
uint blocks_per_row = (mip_width + 3) / 4;
uint blocks_per_col = (mip_height + 3) / 4;
uint blocks = blocks_per_row * blocks_per_col;
if (data + block_bytes * blocks > data_end) {
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
* on a malformed files. */
*r_num_valid_levels = i;
break;
}
if (mip_height == 1) {
/* no flip to do, and we're done. */
break;
}
if (mip_height == 2) {
/* flip the first 2 lines in each block. */
for (uint i = 0; i < blocks_per_row; i++) {
half_block_function(data + i * block_bytes);
}
}
else {
/* flip each block. */
for (uint i = 0; i < blocks; i++) {
full_block_function(data + i * block_bytes);
}
/* Swap each block line in the first half of the image with the
* corresponding one in the second half.
* note that this is a no-op if mip_height is 4. */
uint row_bytes = block_bytes * blocks_per_row;
uint8_t *temp_line = new uint8_t[row_bytes];
for (uint y = 0; y < blocks_per_col / 2; y++) {
uint8_t *line1 = data + y * row_bytes;
uint8_t *line2 = data + (blocks_per_col - y - 1) * row_bytes;
memcpy(temp_line, line1, row_bytes);
memcpy(line1, line2, row_bytes);
memcpy(line2, temp_line, row_bytes);
}
delete[] temp_line;
}
/* mip levels are contiguous. */
data += block_bytes * blocks;
mip_width = MAX(1U, mip_width >> 1);
mip_height = MAX(1U, mip_height >> 1);
}
return 1;
}

View File

@@ -1,18 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_sys_types.h"
/**
* Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
*
* Use to flip vertically to fit OpenGL convention.
*/
int FlipDXTCImage(unsigned int width,
unsigned int height,
unsigned int levels,
int fourcc,
uint8_t *data,
int data_size,
unsigned int *r_num_valid_levels);

View File

@@ -1,106 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es>. */
#include <Color.h>
#include <Image.h>
#include <cstdio> /* printf */
Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(nullptr) {}
Image::~Image()
{
free();
}
void Image::allocate(uint w, uint h)
{
free();
m_width = w;
m_height = h;
m_data = new Color32[w * h];
}
void Image::free()
{
delete[] m_data;
m_data = nullptr;
}
uint Image::width() const
{
return m_width;
}
uint Image::height() const
{
return m_height;
}
const Color32 *Image::scanline(uint h) const
{
if (h >= m_height) {
printf("DDS: scanline beyond dimensions of image\n");
return m_data;
}
return m_data + h * m_width;
}
Color32 *Image::scanline(uint h)
{
if (h >= m_height) {
printf("DDS: scanline beyond dimensions of image\n");
return m_data;
}
return m_data + h * m_width;
}
const Color32 *Image::pixels() const
{
return m_data;
}
Color32 *Image::pixels()
{
return m_data;
}
const Color32 &Image::pixel(uint idx) const
{
if (idx >= m_width * m_height) {
printf("DDS: pixel beyond dimensions of image\n");
return m_data[0];
}
return m_data[idx];
}
Color32 &Image::pixel(uint idx)
{
if (idx >= m_width * m_height) {
printf("DDS: pixel beyond dimensions of image\n");
return m_data[0];
}
return m_data[idx];
}
Image::Format Image::format() const
{
return m_format;
}
void Image::setFormat(Image::Format f)
{
m_format = f;
}

View File

@@ -1,76 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es> */
#pragma once
#include "Color.h"
#include "Common.h"
/** 32 bit RGBA image. */
class Image {
public:
enum Format {
Format_RGB,
Format_ARGB,
};
Image();
~Image();
void allocate(uint w, uint h);
#if 0
bool load(const char *name);
void wrap(void *data, uint w, uint h);
void unwrap();
#endif
uint width() const;
uint height() const;
const Color32 *scanline(uint h) const;
Color32 *scanline(uint h);
const Color32 *pixels() const;
Color32 *pixels();
const Color32 &pixel(uint idx) const;
Color32 &pixel(uint idx);
const Color32 &pixel(uint x, uint y) const;
Color32 &pixel(uint x, uint y);
Format format() const;
void setFormat(Format f);
private:
void free();
private:
uint m_width;
uint m_height;
Format m_format;
Color32 *m_data;
};
inline const Color32 &Image::pixel(uint x, uint y) const
{
return pixel(y * width() + x);
}
inline Color32 &Image::pixel(uint x, uint y)
{
return pixel(y * width() + x);
}

View File

@@ -1,117 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* 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.
*/
#pragma once
#include "Common.h"
namespace PixelFormat {
/** Convert component \a c having \a inbits to the returned value having \a outbits. */
inline uint convert(uint c, uint inbits, uint outbits)
{
if (inbits == 0) {
return 0;
}
else if (inbits >= outbits) {
/* truncate */
return c >> (inbits - outbits);
}
else {
/* bitexpand */
return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits);
}
}
/* Get pixel component shift and size given its mask. */
inline void maskShiftAndSize(uint mask, uint *shift, uint *size)
{
if (!mask) {
*shift = 0;
*size = 0;
return;
}
*shift = 0;
while ((mask & 1) == 0) {
++(*shift);
mask >>= 1;
}
*size = 0;
while ((mask & 1) == 1) {
++(*size);
mask >>= 1;
}
}
inline float quantizeCeil(float f, int inbits, int outbits)
{
#if 0
uint i = f * (float(1 << inbits) - 1);
i = convert(i, inbits, outbits);
float result = float(i) / (float(1 << outbits) - 1);
nvCheck(result >= f);
#endif
float result;
int offset = 0;
do {
uint i = offset + uint(f * (float(1 << inbits) - 1));
i = convert(i, inbits, outbits);
result = float(i) / (float(1 << outbits) - 1);
offset++;
} while (result < f);
return result;
}
#if 0
inline float quantizeRound(float f, int bits)
{
float scale = float(1 << bits);
return fround(f * scale) / scale;
}
inline float quantizeFloor(float f, int bits)
{
float scale = float(1 << bits);
return floor(f * scale) / scale;
}
#endif
} /* namespace PixelFormat */

View File

@@ -1,105 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#include "BLI_sys_types.h" /* For `uint`. */
#include <Stream.h>
#include <cstdio> /* printf */
#include <cstring> /* memcpy */
static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)";
static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)";
inline bool is_read_within_bounds(const Stream &mem, uint count)
{
if (mem.pos >= mem.size) {
/* No more data remained in the memory buffer. */
return false;
}
if (count > mem.size - mem.pos) {
/* Reading past the memory bounds. */
return false;
}
return true;
}
uint Stream::seek(uint p)
{
if (p > size) {
set_failed(msg_error_seek);
}
else {
pos = p;
}
return pos;
}
uint mem_read(Stream &mem, unsigned long long &i)
{
if (!is_read_within_bounds(mem, 8)) {
mem.set_failed(msg_error_seek);
return 0;
}
memcpy(&i, mem.mem + mem.pos, 8); /* TODO: make sure little endian. */
mem.pos += 8;
return 8;
}
uint mem_read(Stream &mem, uint &i)
{
if (!is_read_within_bounds(mem, 4)) {
mem.set_failed(msg_error_read);
return 0;
}
memcpy(&i, mem.mem + mem.pos, 4); /* TODO: make sure little endian. */
mem.pos += 4;
return 4;
}
uint mem_read(Stream &mem, ushort &i)
{
if (!is_read_within_bounds(mem, 2)) {
mem.set_failed(msg_error_read);
return 0;
}
memcpy(&i, mem.mem + mem.pos, 2); /* TODO: make sure little endian. */
mem.pos += 2;
return 2;
}
uint mem_read(Stream &mem, uchar &i)
{
if (!is_read_within_bounds(mem, 1)) {
mem.set_failed(msg_error_read);
return 0;
}
i = (mem.mem + mem.pos)[0];
mem.pos += 1;
return 1;
}
uint mem_read(Stream &mem, uchar *i, uint count)
{
if (!is_read_within_bounds(mem, count)) {
mem.set_failed(msg_error_read);
return 0;
}
memcpy(i, mem.mem + mem.pos, count);
mem.pos += count;
return count;
}
void Stream::set_failed(const char *msg)
{
if (!failed) {
puts(msg);
failed = true;
}
}

View File

@@ -1,25 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/* simple memory stream functions with buffer overflow check */
#pragma once
struct Stream {
unsigned char *mem; /* location in memory */
unsigned int size; /* size */
unsigned int pos; /* current position */
bool failed; /* error occurred when seeking */
Stream(unsigned char *m, unsigned int s) : mem(m), size(s), pos(0), failed(false) {}
unsigned int seek(unsigned int p);
void set_failed(const char *msg);
};
unsigned int mem_read(Stream &mem, unsigned long long &i);
unsigned int mem_read(Stream &mem, unsigned int &i);
unsigned int mem_read(Stream &mem, unsigned short &i);
unsigned int mem_read(Stream &mem, unsigned char &i);
unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int count);

View File

@@ -1,193 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#include "BLI_utildefines.h"
#include <DirectDrawSurface.h>
#include <FlipDXT.h>
#include <Stream.h>
#include <cstddef>
#include <cstdio> /* printf */
#include <dds_api.h>
#include <fstream>
#if defined(WIN32)
# include "utfconv.h"
#endif
#include "IMB_allocimbuf.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "imbuf.h"
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
extern "C" {
bool imb_save_dds(struct ImBuf *ibuf, const char *filepath, int /*flags*/)
{
return false; /* TODO: finish this function. */
/* check image buffer */
if (ibuf == nullptr) {
return false;
}
if (ibuf->rect == nullptr) {
return false;
}
/* open file for writing */
std::ofstream fildes;
#if defined(WIN32)
wchar_t *wname = alloc_utf16_from_8(filepath, 0);
fildes.open(wname);
free(wname);
#else
fildes.open(filepath);
#endif
/* write header */
fildes << "DDS ";
fildes.close();
return true;
}
bool imb_is_a_dds(const uchar *mem, const size_t size)
{
if (size < 8) {
return false;
}
/* heuristic check to see if mem contains a DDS file */
/* header.fourcc == FOURCC_DDS */
if ((mem[0] != 'D') || (mem[1] != 'D') || (mem[2] != 'S') || (mem[3] != ' ')) {
return false;
}
/* header.size == 124 */
if ((mem[4] != 124) || mem[5] || mem[6] || mem[7]) {
return false;
}
return true;
}
struct ImBuf *imb_load_dds(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = nullptr;
DirectDrawSurface dds((uchar *)mem, size); /* reads header */
uchar bits_per_pixel;
uint *rect;
Image img;
uint numpixels = 0;
int col;
uchar *cp = (uchar *)&col;
Color32 pixel;
Color32 *pixels = nullptr;
/* OCIO_TODO: never was able to save DDS, so can't test loading
* but profile used to be set to sRGB and can't see rect_float here, so
* default byte space should work fine
*/
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
if (!imb_is_a_dds(mem, size)) {
return nullptr;
}
/* check if DDS is valid and supported */
if (!dds.isValid()) {
/* no need to print error here, just testing if it is a DDS */
if (flags & IB_test) {
return nullptr;
}
printf("DDS: not valid; header follows\n");
dds.printInfo();
return nullptr;
}
if (!dds.isSupported()) {
printf("DDS: format not supported\n");
return nullptr;
}
if ((dds.width() > 65535) || (dds.height() > 65535)) {
printf("DDS: dimensions too large\n");
return nullptr;
}
/* convert DDS into ImBuf */
dds.mipmap(&img, 0, 0); /* load first face, first mipmap */
pixels = img.pixels();
numpixels = dds.width() * dds.height();
bits_per_pixel = 24;
if (img.format() == Image::Format_ARGB) {
/* check that there is effectively an alpha channel */
for (uint i = 0; i < numpixels; i++) {
pixel = pixels[i];
if (pixel.a != 255) {
bits_per_pixel = 32;
break;
}
}
}
ibuf = IMB_allocImBuf(dds.width(), dds.height(), bits_per_pixel, 0);
if (ibuf == nullptr) {
return nullptr; /* memory allocation failed */
}
ibuf->ftype = IMB_FTYPE_DDS;
ibuf->dds_data.fourcc = dds.fourCC();
ibuf->dds_data.nummipmaps = dds.mipmapCount();
if ((flags & IB_test) == 0) {
if (!imb_addrectImBuf(ibuf)) {
return ibuf;
}
if (ibuf->rect == nullptr) {
return ibuf;
}
rect = ibuf->rect;
cp[3] = 0xff; /* default alpha if alpha channel is not present */
for (uint i = 0; i < numpixels; i++) {
pixel = pixels[i];
cp[0] = pixel.r; /* set R component of col */
cp[1] = pixel.g; /* set G component of col */
cp[2] = pixel.b; /* set B component of col */
if (dds.hasAlpha()) {
cp[3] = pixel.a; /* set A component of col */
}
rect[i] = col;
}
if (ibuf->dds_data.fourcc != FOURCC_DDS) {
ibuf->dds_data.data = (uchar *)dds.readData(ibuf->dds_data.size);
/* flip compressed texture */
if (ibuf->dds_data.data) {
FlipDXTCImage(dds.width(),
dds.height(),
ibuf->dds_data.nummipmaps,
dds.fourCC(),
ibuf->dds_data.data,
ibuf->dds_data.size,
&ibuf->dds_data.nummipmaps);
}
}
else {
ibuf->dds_data.data = nullptr;
ibuf->dds_data.size = 0;
}
/* flip uncompressed texture */
IMB_flipy(ibuf);
}
return ibuf;
}
} /* extern "C" */

View File

@@ -1,24 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#pragma once
#include "../../IMB_imbuf.h"
#ifdef __cplusplus
extern "C" {
#endif
bool imb_is_a_dds(const unsigned char *mem, size_t size);
bool imb_save_dds(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_dds(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
#ifdef __cplusplus
}
#endif