Cleanup: remove unused "dds" directory
Missing from [0] which duplicates some code into format_dds.cc.
[0]: aa3bdfd76a
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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}")
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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" */
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user