diff --git a/src/nvimage/BlockDXT.cpp b/src/nvimage/BlockDXT.cpp index 7b08e4b..2a38947 100644 --- a/src/nvimage/BlockDXT.cpp +++ b/src/nvimage/BlockDXT.cpp @@ -1,666 +1,666 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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 - -#include "ColorBlock.h" -#include "BlockDXT.h" - -using namespace nv; - - -/*---------------------------------------------------------------------------- - 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; - } - else { - // 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; - } -} - -// Evaluate palette assuming 3 color block. -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; -} - -// Evaluate palette assuming 4 color block. -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; -} - - -/* Jason Dorie's code. -// ---------------------------------------------------------------------------- -// Build palette for a 3 color + traparent black block -// ---------------------------------------------------------------------------- -void DXTCGen::BuildCodes3(cbVector *pVects, cbVector &v1, cbVector &v2) -{ - //pVects[0] = v1; - //pVects[2] = v2; - //pVects[1][0] = v1[0]; - //pVects[1][1] = (BYTE)( ((long)v1[1] + (long)v2[1]) / 2 ); - //pVects[1][2] = (BYTE)( ((long)v1[2] + (long)v2[2]) / 2 ); - //pVects[1][3] = (BYTE)( ((long)v1[3] + (long)v2[3]) / 2 ); - - __asm { - mov ecx, dword ptr pVects - mov eax, dword ptr v1 - mov ebx, dword ptr v2 - - movd mm0, [eax] - movd mm1, [ebx] - pxor mm2, mm2 - nop - - movd [ecx], mm0 - movd [ecx+8], mm1 - - punpcklbw mm0, mm2 - punpcklbw mm1, mm2 - - paddw mm0, mm1 - psrlw mm0, 1 - - packuswb mm0, mm0 - movd [ecx+4], mm0 - } - // *(long *)&pVects[1] = r1; -} - -__int64 ScaleOneThird = 0x5500550055005500; - -// ---------------------------------------------------------------------------- -// Build palette for a 4 color block -// ---------------------------------------------------------------------------- -void DXTCGen::BuildCodes4(cbVector *pVects, cbVector &v1, cbVector &v2) -{ -// pVects[0] = v1; -// pVects[3] = v2; -// -// pVects[1][0] = v1[0]; -// pVects[1][1] = (BYTE)( ((long)v1[1] * 2 + (long)v2[1]) / 3 ); -// pVects[1][2] = (BYTE)( ((long)v1[2] * 2 + (long)v2[2]) / 3 ); -// pVects[1][3] = (BYTE)( ((long)v1[3] * 2 + (long)v2[3]) / 3 ); -// -// pVects[2][0] = v1[0]; -// pVects[2][1] = (BYTE)( ((long)v2[1] * 2 + (long)v1[1]) / 3 ); -// pVects[2][2] = (BYTE)( ((long)v2[2] * 2 + (long)v1[2]) / 3 ); -// pVects[2][3] = (BYTE)( ((long)v2[3] * 2 + (long)v1[3]) / 3 ); - - __asm { - mov ecx, dword ptr pVects - mov eax, dword ptr v1 - mov ebx, dword ptr v2 - - movd mm0, [eax] - movd mm1, [ebx] - - pxor mm2, mm2 - movd [ecx], mm0 - movd [ecx+12], mm1 - - punpcklbw mm0, mm2 - punpcklbw mm1, mm2 - movq mm3, mm0 // mm3 = v0 - - paddw mm0, mm1 // mm0 = v0 + v1 - paddw mm3, mm3 // mm3 = v0*2 - - paddw mm0, mm1 // mm0 = v0 + v1*2 - paddw mm1, mm3 // mm1 = v0*2 + v1 - - pmulhw mm0, ScaleOneThird - pmulhw mm1, ScaleOneThird - packuswb mm1, mm0 - - movq [ecx+4], mm1 - } -} -*/ - -void BlockDXT1::decodeBlock(ColorBlock * block) const -{ - nvDebugCheck(block != NULL); - - // 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::setIndices(int * idx) -{ - indices = 0; - for(uint i = 0; i < 16; i++) { - indices |= (idx[i] & 3) << (2 * i); - } -} - - -/// Flip DXT1 block vertically. -inline void BlockDXT1::flip4() -{ - swap(row[0], row[3]); - swap(row[1], row[2]); -} - -/// Flip half DXT1 block vertically. -inline void BlockDXT1::flip2() -{ - swap(row[0], row[1]); -} - - -/*---------------------------------------------------------------------------- - BlockDXT3 -----------------------------------------------------------------------------*/ - -void BlockDXT3::decodeBlock(ColorBlock * block) const -{ - nvDebugCheck(block != NULL); - - // Decode color. - color.decodeBlock(block); - - // Decode alpha. - alpha.decodeBlock(block); -} - -void AlphaBlockDXT3::decodeBlock(ColorBlock * block) const -{ - nvDebugCheck(block != NULL); - - 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; -} - -/// Flip DXT3 alpha block vertically. -void AlphaBlockDXT3::flip4() -{ - swap(row[0], row[3]); - swap(row[1], row[2]); -} - -/// Flip half DXT3 alpha block vertically. -void AlphaBlockDXT3::flip2() -{ - swap(row[0], row[1]); -} - -/// Flip DXT3 block vertically. -void BlockDXT3::flip4() -{ - alpha.flip4(); - color.flip4(); -} - -/// Flip half DXT3 block vertically. -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 * alpha0 + 1 * alpha1) / 7; // bit code 010 - alpha[3] = (5 * alpha0 + 2 * alpha1) / 7; // bit code 011 - alpha[4] = (4 * alpha0 + 3 * alpha1) / 7; // bit code 100 - alpha[5] = (3 * alpha0 + 4 * alpha1) / 7; // bit code 101 - alpha[6] = (2 * alpha0 + 5 * alpha1) / 7; // bit code 110 - alpha[7] = (1 * alpha0 + 6 * alpha1) / 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 * alpha0 + 1 * alpha1) / 5; // Bit code 010 - alpha[3] = (3 * alpha0 + 2 * alpha1) / 5; // Bit code 011 - alpha[4] = (2 * alpha0 + 3 * alpha1) / 5; // Bit code 100 - alpha[5] = (1 * alpha0 + 4 * alpha1) / 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 -{ - nvDebugCheck(index < 16); - - int offset = (3 * index + 16); - return (this->u >> offset) & 0x7; -} - -void AlphaBlockDXT5::setIndex(uint index, uint value) -{ - nvDebugCheck(index < 16); - nvDebugCheck(value < 8); - - int offset = (3 * index + 16); - uint64 mask = uint64(0x7) << offset; - this->u = (this->u & ~mask) | (uint64(value) << offset); -} - -void AlphaBlockDXT5::decodeBlock(ColorBlock * block) const -{ - nvDebugCheck(block != NULL); - - 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 & POSH_U64(0x000000000000FFFF)); - tmp |= (*b & POSH_U64(0x000000000FFF0000)) << 36; - tmp |= (*b & POSH_U64(0x000000FFF0000000)) << 12; - tmp |= (*b & POSH_U64(0x000FFF0000000000)) >> 12; - tmp |= (*b & POSH_U64(0xFFF0000000000000)) >> 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 -{ - nvDebugCheck(block != NULL); - - // Decode color. - color.decodeBlock(block); - - // Decode alpha. - alpha.decodeBlock(block); - -} - -/// Flip DXT5 block vertically. -void BlockDXT5::flip4() -{ - alpha.flip4(); - color.flip4(); -} - -/// Flip half DXT5 block vertically. -void BlockDXT5::flip2() -{ - alpha.flip2(); - color.flip2(); -} - - -/// Decode ATI1 block. -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; - } -} - -/// Flip ATI1 block vertically. -void BlockATI1::flip4() -{ - alpha.flip4(); -} - -/// Flip half ATI1 block vertically. -void BlockATI1::flip2() -{ - alpha.flip2(); -} - - -/// Decode ATI2 block. -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; - } -} - -/// Flip ATI2 block vertically. -void BlockATI2::flip4() -{ - x.flip4(); - y.flip4(); -} - -/// Flip half ATI2 block vertically. -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 -{ - nvDebugCheck(block != NULL); - - // 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(int * idx) -{ - indices = 0; - for(uint i = 0; i < 16; i++) { - indices |= (idx[i] & 3) << (2 * i); - } -} - - -/// Flip CTX1 block vertically. -inline void BlockCTX1::flip4() -{ - swap(row[0], row[3]); - swap(row[1], row[2]); -} - -/// Flip half CTX1 block vertically. -inline void BlockCTX1::flip2() -{ - swap(row[0], row[1]); -} - - - - -Stream & nv::operator<<(Stream & stream, BlockDXT1 & block) -{ - stream << block.col0.u << block.col1.u; - stream.serialize(&block.indices, sizeof(block.indices)); - return stream; -} - -Stream & nv::operator<<(Stream & stream, AlphaBlockDXT3 & block) -{ - stream.serialize(&block, sizeof(block)); - return stream; -} - -Stream & nv::operator<<(Stream & stream, BlockDXT3 & block) -{ - return stream << block.alpha << block.color; -} - -Stream & nv::operator<<(Stream & stream, AlphaBlockDXT5 & block) -{ - stream.serialize(&block, sizeof(block)); - return stream; -} - -Stream & nv::operator<<(Stream & stream, BlockDXT5 & block) -{ - return stream << block.alpha << block.color; -} - -Stream & nv::operator<<(Stream & stream, BlockATI1 & block) -{ - return stream << block.alpha; -} - -Stream & nv::operator<<(Stream & stream, BlockATI2 & block) -{ - return stream << block.x << block.y; -} - -Stream & nv::operator<<(Stream & stream, BlockCTX1 & block) -{ - stream.serialize(&block, sizeof(block)); - return stream; -} - +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 + +#include "ColorBlock.h" +#include "BlockDXT.h" + +using namespace nv; + + +/*---------------------------------------------------------------------------- + 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; + } + else { + // 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; + } +} + +// Evaluate palette assuming 3 color block. +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; +} + +// Evaluate palette assuming 4 color block. +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; +} + + +/* Jason Dorie's code. +// ---------------------------------------------------------------------------- +// Build palette for a 3 color + traparent black block +// ---------------------------------------------------------------------------- +void DXTCGen::BuildCodes3(cbVector *pVects, cbVector &v1, cbVector &v2) +{ + //pVects[0] = v1; + //pVects[2] = v2; + //pVects[1][0] = v1[0]; + //pVects[1][1] = (BYTE)( ((long)v1[1] + (long)v2[1]) / 2 ); + //pVects[1][2] = (BYTE)( ((long)v1[2] + (long)v2[2]) / 2 ); + //pVects[1][3] = (BYTE)( ((long)v1[3] + (long)v2[3]) / 2 ); + + __asm { + mov ecx, dword ptr pVects + mov eax, dword ptr v1 + mov ebx, dword ptr v2 + + movd mm0, [eax] + movd mm1, [ebx] + pxor mm2, mm2 + nop + + movd [ecx], mm0 + movd [ecx+8], mm1 + + punpcklbw mm0, mm2 + punpcklbw mm1, mm2 + + paddw mm0, mm1 + psrlw mm0, 1 + + packuswb mm0, mm0 + movd [ecx+4], mm0 + } + // *(long *)&pVects[1] = r1; +} + +__int64 ScaleOneThird = 0x5500550055005500; + +// ---------------------------------------------------------------------------- +// Build palette for a 4 color block +// ---------------------------------------------------------------------------- +void DXTCGen::BuildCodes4(cbVector *pVects, cbVector &v1, cbVector &v2) +{ +// pVects[0] = v1; +// pVects[3] = v2; +// +// pVects[1][0] = v1[0]; +// pVects[1][1] = (BYTE)( ((long)v1[1] * 2 + (long)v2[1]) / 3 ); +// pVects[1][2] = (BYTE)( ((long)v1[2] * 2 + (long)v2[2]) / 3 ); +// pVects[1][3] = (BYTE)( ((long)v1[3] * 2 + (long)v2[3]) / 3 ); +// +// pVects[2][0] = v1[0]; +// pVects[2][1] = (BYTE)( ((long)v2[1] * 2 + (long)v1[1]) / 3 ); +// pVects[2][2] = (BYTE)( ((long)v2[2] * 2 + (long)v1[2]) / 3 ); +// pVects[2][3] = (BYTE)( ((long)v2[3] * 2 + (long)v1[3]) / 3 ); + + __asm { + mov ecx, dword ptr pVects + mov eax, dword ptr v1 + mov ebx, dword ptr v2 + + movd mm0, [eax] + movd mm1, [ebx] + + pxor mm2, mm2 + movd [ecx], mm0 + movd [ecx+12], mm1 + + punpcklbw mm0, mm2 + punpcklbw mm1, mm2 + movq mm3, mm0 // mm3 = v0 + + paddw mm0, mm1 // mm0 = v0 + v1 + paddw mm3, mm3 // mm3 = v0*2 + + paddw mm0, mm1 // mm0 = v0 + v1*2 + paddw mm1, mm3 // mm1 = v0*2 + v1 + + pmulhw mm0, ScaleOneThird + pmulhw mm1, ScaleOneThird + packuswb mm1, mm0 + + movq [ecx+4], mm1 + } +} +*/ + +void BlockDXT1::decodeBlock(ColorBlock * block) const +{ + nvDebugCheck(block != NULL); + + // 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::setIndices(int * idx) +{ + indices = 0; + for(uint i = 0; i < 16; i++) { + indices |= (idx[i] & 3) << (2 * i); + } +} + + +/// Flip DXT1 block vertically. +inline void BlockDXT1::flip4() +{ + swap(row[0], row[3]); + swap(row[1], row[2]); +} + +/// Flip half DXT1 block vertically. +inline void BlockDXT1::flip2() +{ + swap(row[0], row[1]); +} + + +/*---------------------------------------------------------------------------- + BlockDXT3 +----------------------------------------------------------------------------*/ + +void BlockDXT3::decodeBlock(ColorBlock * block) const +{ + nvDebugCheck(block != NULL); + + // Decode color. + color.decodeBlock(block); + + // Decode alpha. + alpha.decodeBlock(block); +} + +void AlphaBlockDXT3::decodeBlock(ColorBlock * block) const +{ + nvDebugCheck(block != NULL); + + 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; +} + +/// Flip DXT3 alpha block vertically. +void AlphaBlockDXT3::flip4() +{ + swap(row[0], row[3]); + swap(row[1], row[2]); +} + +/// Flip half DXT3 alpha block vertically. +void AlphaBlockDXT3::flip2() +{ + swap(row[0], row[1]); +} + +/// Flip DXT3 block vertically. +void BlockDXT3::flip4() +{ + alpha.flip4(); + color.flip4(); +} + +/// Flip half DXT3 block vertically. +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 * alpha0 + 1 * alpha1) / 7; // bit code 010 + alpha[3] = (5 * alpha0 + 2 * alpha1) / 7; // bit code 011 + alpha[4] = (4 * alpha0 + 3 * alpha1) / 7; // bit code 100 + alpha[5] = (3 * alpha0 + 4 * alpha1) / 7; // bit code 101 + alpha[6] = (2 * alpha0 + 5 * alpha1) / 7; // bit code 110 + alpha[7] = (1 * alpha0 + 6 * alpha1) / 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 * alpha0 + 1 * alpha1) / 5; // Bit code 010 + alpha[3] = (3 * alpha0 + 2 * alpha1) / 5; // Bit code 011 + alpha[4] = (2 * alpha0 + 3 * alpha1) / 5; // Bit code 100 + alpha[5] = (1 * alpha0 + 4 * alpha1) / 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 +{ + nvDebugCheck(index < 16); + + int offset = (3 * index + 16); + return (this->u >> offset) & 0x7; +} + +void AlphaBlockDXT5::setIndex(uint index, uint value) +{ + nvDebugCheck(index < 16); + nvDebugCheck(value < 8); + + int offset = (3 * index + 16); + uint64 mask = uint64(0x7) << offset; + this->u = (this->u & ~mask) | (uint64(value) << offset); +} + +void AlphaBlockDXT5::decodeBlock(ColorBlock * block) const +{ + nvDebugCheck(block != NULL); + + 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 & POSH_U64(0x000000000000FFFF)); + tmp |= (*b & POSH_U64(0x000000000FFF0000)) << 36; + tmp |= (*b & POSH_U64(0x000000FFF0000000)) << 12; + tmp |= (*b & POSH_U64(0x000FFF0000000000)) >> 12; + tmp |= (*b & POSH_U64(0xFFF0000000000000)) >> 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 +{ + nvDebugCheck(block != NULL); + + // Decode color. + color.decodeBlock(block); + + // Decode alpha. + alpha.decodeBlock(block); + +} + +/// Flip DXT5 block vertically. +void BlockDXT5::flip4() +{ + alpha.flip4(); + color.flip4(); +} + +/// Flip half DXT5 block vertically. +void BlockDXT5::flip2() +{ + alpha.flip2(); + color.flip2(); +} + + +/// Decode ATI1 block. +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; + } +} + +/// Flip ATI1 block vertically. +void BlockATI1::flip4() +{ + alpha.flip4(); +} + +/// Flip half ATI1 block vertically. +void BlockATI1::flip2() +{ + alpha.flip2(); +} + + +/// Decode ATI2 block. +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; + } +} + +/// Flip ATI2 block vertically. +void BlockATI2::flip4() +{ + x.flip4(); + y.flip4(); +} + +/// Flip half ATI2 block vertically. +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 +{ + nvDebugCheck(block != NULL); + + // 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(int * idx) +{ + indices = 0; + for(uint i = 0; i < 16; i++) { + indices |= (idx[i] & 3) << (2 * i); + } +} + + +/// Flip CTX1 block vertically. +inline void BlockCTX1::flip4() +{ + swap(row[0], row[3]); + swap(row[1], row[2]); +} + +/// Flip half CTX1 block vertically. +inline void BlockCTX1::flip2() +{ + swap(row[0], row[1]); +} + + + + +Stream & nv::operator<<(Stream & stream, BlockDXT1 & block) +{ + stream << block.col0.u << block.col1.u; + stream.serialize(&block.indices, sizeof(block.indices)); + return stream; +} + +Stream & nv::operator<<(Stream & stream, AlphaBlockDXT3 & block) +{ + stream.serialize(&block, sizeof(block)); + return stream; +} + +Stream & nv::operator<<(Stream & stream, BlockDXT3 & block) +{ + return stream << block.alpha << block.color; +} + +Stream & nv::operator<<(Stream & stream, AlphaBlockDXT5 & block) +{ + stream.serialize(&block, sizeof(block)); + return stream; +} + +Stream & nv::operator<<(Stream & stream, BlockDXT5 & block) +{ + return stream << block.alpha << block.color; +} + +Stream & nv::operator<<(Stream & stream, BlockATI1 & block) +{ + return stream << block.alpha; +} + +Stream & nv::operator<<(Stream & stream, BlockATI2 & block) +{ + return stream << block.x << block.y; +} + +Stream & nv::operator<<(Stream & stream, BlockCTX1 & block) +{ + stream.serialize(&block, sizeof(block)); + return stream; +} + diff --git a/src/nvimage/BlockDXT.h b/src/nvimage/BlockDXT.h index 2c12fe1..5a45c40 100644 --- a/src/nvimage/BlockDXT.h +++ b/src/nvimage/BlockDXT.h @@ -1,223 +1,223 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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. - -#ifndef NV_IMAGE_BLOCKDXT_H -#define NV_IMAGE_BLOCKDXT_H - -#include - -#include - -namespace nv -{ - struct ColorBlock; - class Stream; - - - /// 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 evaluatePaletteFast(Color32 color_array[4]) const; - void evaluatePalette3(Color32 color_array[4]) const; - void evaluatePalette4(Color32 color_array[4]) const; - - void decodeBlock(ColorBlock * block) const; - - void setIndices(int * idx); - - void flip4(); - 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; - - void flip4(); - void flip2(); - }; - - - /// DXT3 block. - struct BlockDXT3 - { - AlphaBlockDXT3 alpha; - BlockDXT1 color; - - void decodeBlock(ColorBlock * block) const; - - void flip4(); - void flip2(); - }; - - - /// DXT5 alpha block. - struct AlphaBlockDXT5 - { - 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; - }; - - 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 flip4(); - void flip2(); - }; - - /// ATI1 block. - struct BlockATI1 - { - AlphaBlockDXT5 alpha; - - void decodeBlock(ColorBlock * block) const; - - void flip4(); - void flip2(); - }; - - /// ATI2 block. - struct BlockATI2 - { - AlphaBlockDXT5 x; - AlphaBlockDXT5 y; - - void decodeBlock(ColorBlock * block) const; - - void flip4(); - 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(int * idx); - - void decodeBlock(ColorBlock * block) const; - - void flip4(); - void flip2(); - }; - - - // Serialization functions. - NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT1 & block); - NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT3 & block); - NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT3 & block); - NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT5 & block); - NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT5 & block); - NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI1 & block); - NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI2 & block); - NVIMAGE_API Stream & operator<<(Stream & stream, BlockCTX1 & block); - -} // nv namespace - -#endif // NV_IMAGE_BLOCKDXT_H +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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. + +#ifndef NV_IMAGE_BLOCKDXT_H +#define NV_IMAGE_BLOCKDXT_H + +#include + +#include + +namespace nv +{ + struct ColorBlock; + class Stream; + + + /// 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 evaluatePaletteFast(Color32 color_array[4]) const; + void evaluatePalette3(Color32 color_array[4]) const; + void evaluatePalette4(Color32 color_array[4]) const; + + void decodeBlock(ColorBlock * block) const; + + void setIndices(int * idx); + + void flip4(); + 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; + + void flip4(); + void flip2(); + }; + + + /// DXT3 block. + struct BlockDXT3 + { + AlphaBlockDXT3 alpha; + BlockDXT1 color; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); + }; + + + /// DXT5 alpha block. + struct AlphaBlockDXT5 + { + 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; + }; + + 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 flip4(); + void flip2(); + }; + + /// ATI1 block. + struct BlockATI1 + { + AlphaBlockDXT5 alpha; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); + }; + + /// ATI2 block. + struct BlockATI2 + { + AlphaBlockDXT5 x; + AlphaBlockDXT5 y; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + 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(int * idx); + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); + }; + + + // Serialization functions. + NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT1 & block); + NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT3 & block); + NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT3 & block); + NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT5 & block); + NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT5 & block); + NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI1 & block); + NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI2 & block); + NVIMAGE_API Stream & operator<<(Stream & stream, BlockCTX1 & block); + +} // nv namespace + +#endif // NV_IMAGE_BLOCKDXT_H diff --git a/src/nvimage/CMakeLists.txt b/src/nvimage/CMakeLists.txt index f3f487e..3f66b00 100644 --- a/src/nvimage/CMakeLists.txt +++ b/src/nvimage/CMakeLists.txt @@ -44,6 +44,11 @@ IF(TIFF_FOUND) INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR}) ENDIF(TIFF_FOUND) +IF(OPENEXR_FOUND) + SET(LIBS ${LIBS} ${OPENEXR_LIBRARIES}) + INCLUDE_DIRECTORIES(${OPENEXR_INCLUDE_PATHS}) +ENDIF(OPENEXR_FOUND) + # targets ADD_DEFINITIONS(-DNVIMAGE_EXPORTS) diff --git a/src/nvimage/ConeMap.cpp b/src/nvimage/ConeMap.cpp index 66951bd..ef7bb85 100644 --- a/src/nvimage/ConeMap.cpp +++ b/src/nvimage/ConeMap.cpp @@ -1,122 +1,122 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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 - -#include - -#include -#include -#include -#include - -using namespace nv; - - -static float processPixel(const FloatImage * img, uint x, uint y) -{ - nvDebugCheck(img != NULL); - - const uint w = img->width(); - const uint h = img->height(); - - float d = img->pixel(x, y, 0); - - float fx0 = (float) x / w; - float fy0 = (float) y / h; - - float best_ratio = INF; - uint best_x = w; - uint best_y = h; - - for (uint yy = 0; yy < h; yy++) - { - for (uint xx = 0; xx < w; xx++) - { - float ch = d - img->pixel(xx, yy, 0); - - if (ch > 0) - { - float dx = float(xx - x); - float dy = float(yy - y); - - float ratio = (dx * dx + dy * dy) / ch; - - if (ratio < best_ratio) - { - best_x = xx; - best_y = yy; - } - } - } - } - - if (best_x != w) - { - nvDebugCheck(best_y !=h); - - float dx = float(best_x - x) / w; - float dy = float(best_y - y) / h; - - float cw = sqrtf(dx*dx + dy*dy); - float ch = d - img->pixel(xx, yy, 0); - - return min(1, sqrtf(cw / ch)); - } - - return 1; -} - - -// Create cone map using the given kernels. -FloatImage * createConeMap(const Image * img, Vector4::Arg heightWeights) -{ - nvCheck(img != NULL); - - const uint w = img->width(); - const uint h = img->height(); - - AutoPtr fimage(new FloatImage()); - //fimage->allocate(2, w, h); - fimage->allocate(4, w, h); - - // Compute height and store in red channel: - float * heightChannel = fimage->channel(0); - for(uint i = 0; i < w*h; i++) - { - Vector4 color = toVector4(img->pixel(i)); - heightChannel[i] = dot(color, heightWeights); - } - - // Compute cones: - for(uint y = 0; y < h; y++) - { - for(uint x = 0; x < w; x++) - { - processPixel(fimage, x, y); - } - } - - return fimage.release(); -} - +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 + +#include + +#include +#include +#include +#include + +using namespace nv; + + +static float processPixel(const FloatImage * img, uint x, uint y) +{ + nvDebugCheck(img != NULL); + + const uint w = img->width(); + const uint h = img->height(); + + float d = img->pixel(x, y, 0); + + float fx0 = (float) x / w; + float fy0 = (float) y / h; + + float best_ratio = INF; + uint best_x = w; + uint best_y = h; + + for (uint yy = 0; yy < h; yy++) + { + for (uint xx = 0; xx < w; xx++) + { + float ch = d - img->pixel(xx, yy, 0); + + if (ch > 0) + { + float dx = float(xx - x); + float dy = float(yy - y); + + float ratio = (dx * dx + dy * dy) / ch; + + if (ratio < best_ratio) + { + best_x = xx; + best_y = yy; + } + } + } + } + + if (best_x != w) + { + nvDebugCheck(best_y !=h); + + float dx = float(best_x - x) / w; + float dy = float(best_y - y) / h; + + float cw = sqrtf(dx*dx + dy*dy); + float ch = d - img->pixel(xx, yy, 0); + + return min(1, sqrtf(cw / ch)); + } + + return 1; +} + + +// Create cone map using the given kernels. +FloatImage * createConeMap(const Image * img, Vector4::Arg heightWeights) +{ + nvCheck(img != NULL); + + const uint w = img->width(); + const uint h = img->height(); + + AutoPtr fimage(new FloatImage()); + //fimage->allocate(2, w, h); + fimage->allocate(4, w, h); + + // Compute height and store in red channel: + float * heightChannel = fimage->channel(0); + for(uint i = 0; i < w*h; i++) + { + Vector4 color = toVector4(img->pixel(i)); + heightChannel[i] = dot(color, heightWeights); + } + + // Compute cones: + for(uint y = 0; y < h; y++) + { + for(uint x = 0; x < w; x++) + { + processPixel(fimage, x, y); + } + } + + return fimage.release(); +} + diff --git a/src/nvimage/ConeMap.h b/src/nvimage/ConeMap.h index b769638..0c79533 100644 --- a/src/nvimage/ConeMap.h +++ b/src/nvimage/ConeMap.h @@ -1,24 +1,24 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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 +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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. #ifndef NV_IMAGE_CONEMAP_H @@ -29,7 +29,7 @@ namespace nv { - class Image; + class Image; class FloatImage; FloatImage * createConeMap(const Image * img, Vector4::Arg heightWeights); diff --git a/src/nvimage/DirectDrawSurface.cpp b/src/nvimage/DirectDrawSurface.cpp index d80cfe8..496d0a1 100644 --- a/src/nvimage/DirectDrawSurface.cpp +++ b/src/nvimage/DirectDrawSurface.cpp @@ -1,1093 +1,1093 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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 -#include // max -#include - -#include -#include -#include -#include -#include - -#include // memset - - -using namespace nv; - -#if !defined(MAKEFOURCC) -# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ - (uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | \ - (uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 )) -#endif - -namespace -{ - static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); - static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); - static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); - static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); - static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); - static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); - static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); - static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1'); - static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); - - // 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; - - static const uint D3DFMT_A16B16G16R16 = 36; - - // Palette formats. - static const uint D3DFMT_A8P8 = 40; - static const uint D3DFMT_P8 = 41; - - // Luminance formats. - static const uint D3DFMT_L8 = 50; - static const uint D3DFMT_A8L8 = 51; - static const uint D3DFMT_A4L4 = 52; - static const uint D3DFMT_L16 = 81; - - // Floating point formats - 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; - - 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; - static const uint DDPF_NORMAL = 0x80000000U; // @@ Custom nv flag. - - // 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, - }; - - 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, - }; - -} // namespace - -namespace nv -{ - static Stream & operator<< (Stream & s, DDSPixelFormat & pf) - { - nvStaticCheck(sizeof(DDSPixelFormat) == 32); - s << pf.size; - s << pf.flags; - s << pf.fourcc; - s << pf.bitcount; - s << pf.rmask; - s << pf.gmask; - s << pf.bmask; - s << pf.amask; - return s; - } - - static Stream & operator<< (Stream & s, DDSCaps & caps) - { - nvStaticCheck(sizeof(DDSCaps) == 16); - s << caps.caps1; - s << caps.caps2; - s << caps.caps3; - s << caps.caps4; - return s; - } - - static Stream & operator<< (Stream & s, DDSHeader10 & header) - { - nvStaticCheck(sizeof(DDSHeader10) == 20); - s << header.dxgiFormat; - s << header.resourceDimension; - s << header.miscFlag; - s << header.arraySize; - s << header.reserved; - return s; - } - - Stream & operator<< (Stream & s, DDSHeader & header) - { - nvStaticCheck(sizeof(DDSHeader) == 148); - s << header.fourcc; - s << header.size; - s << header.flags; - s << header.height; - s << header.width; - s << header.pitch; - s << header.depth; - s << header.mipmapcount; - s.serialize(header.reserved, 11 * sizeof(uint)); - s << header.pf; - s << header.caps; - s << header.notused; - - if (header.hasDX10Header()) - { - s << header.header10; - } - - return s; - } - -} // nv namespace - -/* Not used! -namespace -{ - struct FormatDescriptor - { - uint format; - uint bitcount; - uint rmask; - uint gmask; - uint bmask; - uint amask; - }; - - static 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_L8, 8, 8, 0, 0, 0 }, // DXGI_FORMAT_R8_UNORM - { D3DFMT_L16, 16, 16, 0, 0, 0 }, // DXGI_FORMAT_R16_UNORM - }; - - static const uint s_d3dFormatCount = sizeof(s_d3dFormats) / sizeof(s_d3dFormats[0]); - - 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; - } - -} // nv namespace -*/ - -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; - memset(this->reserved, 0, sizeof(this->reserved)); - - // Store version information on the reserved header attributes. - this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T'); - this->reserved[10] = (0 << 16) | (9 << 8) | (5); // 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->height = d; -} - -void DDSHeader::setMipmapCount(uint count) -{ - if (count == 0) - { - this->flags &= ~DDSD_MIPMAPCOUNT; - this->mipmapcount = 0; - - 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; -} - -void DDSHeader::setTexture3D() -{ - this->caps.caps2 = DDSCAPS2_VOLUME; - - this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; -} - -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 = 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::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask) -{ - // Make sure the masks are correct. - nvCheck((rmask & gmask) == 0); - nvCheck((rmask & bmask) == 0); - nvCheck((rmask & amask) == 0); - nvCheck((gmask & bmask) == 0); - nvCheck((gmask & amask) == 0); - nvCheck((bmask & amask) == 0); - - this->pf.flags = DDPF_RGB; - - if (amask != 0) { - this->pf.flags |= DDPF_ALPHAPIXELS; - } - - if (bitcount == 0) - { - // Compute bit count from the masks. - uint total = rmask | gmask | bmask | amask; - while(total != 0) { - bitcount++; - total >>= 1; - } - } - - nvCheck(bitcount > 0 && bitcount <= 32); - - // Align to 8. - if (bitcount < 8) bitcount = 8; - else if (bitcount < 16) bitcount = 16; - else if (bitcount < 24) bitcount = 24; - else bitcount = 32; - - this->pf.fourcc = 0; //findD3D9Format(bitcount, rmask, gmask, bmask, amask); - 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->header10.dxgiFormat = format; -} - -void DDSHeader::setNormalFlag(bool b) -{ - if (b) this->pf.flags |= DDPF_NORMAL; - else this->pf.flags &= ~DDPF_NORMAL; -} - -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); -} - -bool DDSHeader::hasDX10Header() const -{ - return this->pf.flags == 0; -} - - - -DirectDrawSurface::DirectDrawSurface(const char * name) : stream(new StdInputStream(name)) -{ - if (!stream->isError()) - { - (*stream) << header; - } -} - -DirectDrawSurface::~DirectDrawSurface() -{ - delete stream; -} - -bool DirectDrawSurface::isValid() const -{ - if (stream->isError()) - { - return false; - } - - 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; - } - - if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { - return false; - } - - return true; -} - -bool DirectDrawSurface::isSupported() const -{ - nvDebugCheck(isValid()); - - if (header.pf.flags & DDPF_FOURCC) - { - if (header.pf.fourcc != FOURCC_DXT1 && - header.pf.fourcc != FOURCC_DXT2 && - header.pf.fourcc != FOURCC_DXT3 && - header.pf.fourcc != FOURCC_DXT4 && - header.pf.fourcc != FOURCC_DXT5 && - header.pf.fourcc != FOURCC_RXGB && - header.pf.fourcc != FOURCC_ATI1 && - header.pf.fourcc != FOURCC_ATI2) - { - // Unknown fourcc code. - return false; - } - } - else if (header.pf.flags & DDPF_RGB) - { - // All RGB formats are supported now. - } - else - { - return false; - } - - if (isTextureCube() && (header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES) - { - // Cubemaps must contain all faces. - return false; - } - - if (isTexture3D()) - { - // @@ 3D textures not supported yet. - return false; - } - - return true; -} - - -uint DirectDrawSurface::mipmapCount() const -{ - nvDebugCheck(isValid()); - if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount; - else return 0; -} - - -uint DirectDrawSurface::width() const -{ - nvDebugCheck(isValid()); - if (header.flags & DDSD_WIDTH) return header.width; - else return 1; -} - -uint DirectDrawSurface::height() const -{ - nvDebugCheck(isValid()); - if (header.flags & DDSD_HEIGHT) return header.height; - else return 1; -} - -uint DirectDrawSurface::depth() const -{ - nvDebugCheck(isValid()); - if (header.flags & DDSD_DEPTH) return header.depth; - else return 1; -} - -bool DirectDrawSurface::isTexture2D() const -{ - nvDebugCheck(isValid()); - return !isTexture3D() && !isTextureCube(); -} - -bool DirectDrawSurface::isTexture3D() const -{ - nvDebugCheck(isValid()); - return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0; -} - -bool DirectDrawSurface::isTextureCube() const -{ - nvDebugCheck(isValid()); - return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0; -} - -void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap) -{ - nvDebugCheck(isValid()); - - 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 (header.pf.flags & DDPF_RGB) - { - readLinearImage(img); - } - else if (header.pf.flags & DDPF_FOURCC) - { - readBlockImage(img); - } -} - -void DirectDrawSurface::readLinearImage(Image * img) -{ - nvDebugCheck(stream != NULL); - nvDebugCheck(img != NULL); - - 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 (header.pf.amask != 0) - { - img->setFormat(Image::Format_ARGB); - } - - // Read linear RGB images. - for (uint y = 0; y < h; y++) - { - for (uint x = 0; x < w; x++) - { - uint c = 0; - stream->serialize(&c, byteCount); - - Color32 pixel(0, 0, 0, 0xFF); - pixel.r = PixelFormat::convert(c >> rshift, rsize, 8); - pixel.g = PixelFormat::convert(c >> gshift, gsize, 8); - pixel.b = PixelFormat::convert(c >> bshift, bsize, 8); - pixel.a = PixelFormat::convert(c >> ashift, asize, 8); - - img->pixel(x, y) = pixel; - } - } -} - -void DirectDrawSurface::readBlockImage(Image * img) -{ - nvDebugCheck(stream != NULL); - nvDebugCheck(img != NULL); - - 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 = sqrtf(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) -{ - nvDebugCheck(stream != NULL); - nvDebugCheck(rgba != NULL); - - if (header.pf.fourcc == FOURCC_DXT1) - { - BlockDXT1 block; - *stream << block; - block.decodeBlock(rgba); - } - else if (header.pf.fourcc == FOURCC_DXT2 || - header.pf.fourcc == FOURCC_DXT3) - { - BlockDXT3 block; - *stream << block; - block.decodeBlock(rgba); - } - else if (header.pf.fourcc == FOURCC_DXT4 || - header.pf.fourcc == FOURCC_DXT5 || - header.pf.fourcc == FOURCC_RXGB) - { - BlockDXT5 block; - *stream << block; - block.decodeBlock(rgba); - - if (header.pf.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 (header.pf.fourcc == FOURCC_ATI1) - { - BlockATI1 block; - *stream << block; - block.decodeBlock(rgba); - } - else if (header.pf.fourcc == FOURCC_ATI2) - { - BlockATI2 block; - *stream << block; - block.decodeBlock(rgba); - } - - // If normal flag set, convert to normal. - if (header.pf.flags & DDPF_NORMAL) - { - if (header.pf.fourcc == FOURCC_ATI2) - { - for (int i = 0; i < 16; i++) - { - Color32 & c = rgba->color(i); - c = buildNormal(c.r, c.g); - } - } - else if (header.pf.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; - }; - - // 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; - } - else - { - nvDebugCheck(header.pf.flags & DDPF_RGB); - - // Align pixels to bytes. - uint byteCount = (header.pf.bitcount + 7) / 8; - - // Align pitch to 4 bytes. - uint pitch = 4 * ((w * byteCount + 3) / 4); - - return pitch * h * d; - } -} - -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 (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: %d\n", header.height); - printf("Width: %d\n", header.width); - printf("Depth: %d\n", header.depth); - if (header.flags & DDSD_PITCH) printf("Pitch: %d\n", header.pitch); - else if (header.flags & DDSD_LINEARSIZE) printf("Linear size: %d\n", header.pitch); - printf("Mipmap count: %d\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_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"); - - printf("\tFourCC: '%c%c%c%c'\n", ((header.pf.fourcc >> 0) & 0xFF), ((header.pf.fourcc >> 8) & 0xFF), ((header.pf.fourcc >> 16) & 0xFF), ((header.pf.fourcc >> 24) & 0xFF)); - printf("\tBit count: %d\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.pf.flags == 0) - { - printf("DX10 Header:\n"); - printf("\tDXGI Format: %u\n", header.header10.dxgiFormat); - printf("\tResource dimension: %u\n", header.header10.resourceDimension); - printf("\tMisc flag: %u\n", header.header10.miscFlag); - printf("\tArray size: %u\n", header.header10.arraySize); - } - - if (header.reserved[9] == MAKEFOURCC('N', 'V', 'T', 'T')) - { - 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); - } -} - +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 +#include // max +#include + +#include +#include +#include +#include +#include + +#include // memset + + +using namespace nv; + +#if !defined(MAKEFOURCC) +# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + (uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | \ + (uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 )) +#endif + +namespace +{ + static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); + static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); + static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); + static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); + static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); + static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); + static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); + static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1'); + static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); + + // 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; + + static const uint D3DFMT_A16B16G16R16 = 36; + + // Palette formats. + static const uint D3DFMT_A8P8 = 40; + static const uint D3DFMT_P8 = 41; + + // Luminance formats. + static const uint D3DFMT_L8 = 50; + static const uint D3DFMT_A8L8 = 51; + static const uint D3DFMT_A4L4 = 52; + static const uint D3DFMT_L16 = 81; + + // Floating point formats + 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; + + 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; + static const uint DDPF_NORMAL = 0x80000000U; // @@ Custom nv flag. + + // 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, + }; + + 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, + }; + +} // namespace + +namespace nv +{ + static Stream & operator<< (Stream & s, DDSPixelFormat & pf) + { + nvStaticCheck(sizeof(DDSPixelFormat) == 32); + s << pf.size; + s << pf.flags; + s << pf.fourcc; + s << pf.bitcount; + s << pf.rmask; + s << pf.gmask; + s << pf.bmask; + s << pf.amask; + return s; + } + + static Stream & operator<< (Stream & s, DDSCaps & caps) + { + nvStaticCheck(sizeof(DDSCaps) == 16); + s << caps.caps1; + s << caps.caps2; + s << caps.caps3; + s << caps.caps4; + return s; + } + + static Stream & operator<< (Stream & s, DDSHeader10 & header) + { + nvStaticCheck(sizeof(DDSHeader10) == 20); + s << header.dxgiFormat; + s << header.resourceDimension; + s << header.miscFlag; + s << header.arraySize; + s << header.reserved; + return s; + } + + Stream & operator<< (Stream & s, DDSHeader & header) + { + nvStaticCheck(sizeof(DDSHeader) == 148); + s << header.fourcc; + s << header.size; + s << header.flags; + s << header.height; + s << header.width; + s << header.pitch; + s << header.depth; + s << header.mipmapcount; + s.serialize(header.reserved, 11 * sizeof(uint)); + s << header.pf; + s << header.caps; + s << header.notused; + + if (header.hasDX10Header()) + { + s << header.header10; + } + + return s; + } + +} // nv namespace + +/* Not used! +namespace +{ + struct FormatDescriptor + { + uint format; + uint bitcount; + uint rmask; + uint gmask; + uint bmask; + uint amask; + }; + + static 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_L8, 8, 8, 0, 0, 0 }, // DXGI_FORMAT_R8_UNORM + { D3DFMT_L16, 16, 16, 0, 0, 0 }, // DXGI_FORMAT_R16_UNORM + }; + + static const uint s_d3dFormatCount = sizeof(s_d3dFormats) / sizeof(s_d3dFormats[0]); + + 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; + } + +} // nv namespace +*/ + +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; + memset(this->reserved, 0, sizeof(this->reserved)); + + // Store version information on the reserved header attributes. + this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T'); + this->reserved[10] = (0 << 16) | (9 << 8) | (5); // 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->height = d; +} + +void DDSHeader::setMipmapCount(uint count) +{ + if (count == 0) + { + this->flags &= ~DDSD_MIPMAPCOUNT; + this->mipmapcount = 0; + + 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; +} + +void DDSHeader::setTexture3D() +{ + this->caps.caps2 = DDSCAPS2_VOLUME; + + this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; +} + +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 = 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::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask) +{ + // Make sure the masks are correct. + nvCheck((rmask & gmask) == 0); + nvCheck((rmask & bmask) == 0); + nvCheck((rmask & amask) == 0); + nvCheck((gmask & bmask) == 0); + nvCheck((gmask & amask) == 0); + nvCheck((bmask & amask) == 0); + + this->pf.flags = DDPF_RGB; + + if (amask != 0) { + this->pf.flags |= DDPF_ALPHAPIXELS; + } + + if (bitcount == 0) + { + // Compute bit count from the masks. + uint total = rmask | gmask | bmask | amask; + while(total != 0) { + bitcount++; + total >>= 1; + } + } + + nvCheck(bitcount > 0 && bitcount <= 32); + + // Align to 8. + if (bitcount < 8) bitcount = 8; + else if (bitcount < 16) bitcount = 16; + else if (bitcount < 24) bitcount = 24; + else bitcount = 32; + + this->pf.fourcc = 0; //findD3D9Format(bitcount, rmask, gmask, bmask, amask); + 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->header10.dxgiFormat = format; +} + +void DDSHeader::setNormalFlag(bool b) +{ + if (b) this->pf.flags |= DDPF_NORMAL; + else this->pf.flags &= ~DDPF_NORMAL; +} + +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); +} + +bool DDSHeader::hasDX10Header() const +{ + return this->pf.flags == 0; +} + + + +DirectDrawSurface::DirectDrawSurface(const char * name) : stream(new StdInputStream(name)) +{ + if (!stream->isError()) + { + (*stream) << header; + } +} + +DirectDrawSurface::~DirectDrawSurface() +{ + delete stream; +} + +bool DirectDrawSurface::isValid() const +{ + if (stream->isError()) + { + return false; + } + + 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; + } + + if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { + return false; + } + + return true; +} + +bool DirectDrawSurface::isSupported() const +{ + nvDebugCheck(isValid()); + + if (header.pf.flags & DDPF_FOURCC) + { + if (header.pf.fourcc != FOURCC_DXT1 && + header.pf.fourcc != FOURCC_DXT2 && + header.pf.fourcc != FOURCC_DXT3 && + header.pf.fourcc != FOURCC_DXT4 && + header.pf.fourcc != FOURCC_DXT5 && + header.pf.fourcc != FOURCC_RXGB && + header.pf.fourcc != FOURCC_ATI1 && + header.pf.fourcc != FOURCC_ATI2) + { + // Unknown fourcc code. + return false; + } + } + else if (header.pf.flags & DDPF_RGB) + { + // All RGB formats are supported now. + } + else + { + return false; + } + + if (isTextureCube() && (header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES) + { + // Cubemaps must contain all faces. + return false; + } + + if (isTexture3D()) + { + // @@ 3D textures not supported yet. + return false; + } + + return true; +} + + +uint DirectDrawSurface::mipmapCount() const +{ + nvDebugCheck(isValid()); + if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount; + else return 0; +} + + +uint DirectDrawSurface::width() const +{ + nvDebugCheck(isValid()); + if (header.flags & DDSD_WIDTH) return header.width; + else return 1; +} + +uint DirectDrawSurface::height() const +{ + nvDebugCheck(isValid()); + if (header.flags & DDSD_HEIGHT) return header.height; + else return 1; +} + +uint DirectDrawSurface::depth() const +{ + nvDebugCheck(isValid()); + if (header.flags & DDSD_DEPTH) return header.depth; + else return 1; +} + +bool DirectDrawSurface::isTexture2D() const +{ + nvDebugCheck(isValid()); + return !isTexture3D() && !isTextureCube(); +} + +bool DirectDrawSurface::isTexture3D() const +{ + nvDebugCheck(isValid()); + return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0; +} + +bool DirectDrawSurface::isTextureCube() const +{ + nvDebugCheck(isValid()); + return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0; +} + +void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap) +{ + nvDebugCheck(isValid()); + + 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 (header.pf.flags & DDPF_RGB) + { + readLinearImage(img); + } + else if (header.pf.flags & DDPF_FOURCC) + { + readBlockImage(img); + } +} + +void DirectDrawSurface::readLinearImage(Image * img) +{ + nvDebugCheck(stream != NULL); + nvDebugCheck(img != NULL); + + 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 (header.pf.amask != 0) + { + img->setFormat(Image::Format_ARGB); + } + + // Read linear RGB images. + for (uint y = 0; y < h; y++) + { + for (uint x = 0; x < w; x++) + { + uint c = 0; + stream->serialize(&c, byteCount); + + Color32 pixel(0, 0, 0, 0xFF); + pixel.r = PixelFormat::convert(c >> rshift, rsize, 8); + pixel.g = PixelFormat::convert(c >> gshift, gsize, 8); + pixel.b = PixelFormat::convert(c >> bshift, bsize, 8); + pixel.a = PixelFormat::convert(c >> ashift, asize, 8); + + img->pixel(x, y) = pixel; + } + } +} + +void DirectDrawSurface::readBlockImage(Image * img) +{ + nvDebugCheck(stream != NULL); + nvDebugCheck(img != NULL); + + 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 = sqrtf(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) +{ + nvDebugCheck(stream != NULL); + nvDebugCheck(rgba != NULL); + + if (header.pf.fourcc == FOURCC_DXT1) + { + BlockDXT1 block; + *stream << block; + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_DXT2 || + header.pf.fourcc == FOURCC_DXT3) + { + BlockDXT3 block; + *stream << block; + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_DXT4 || + header.pf.fourcc == FOURCC_DXT5 || + header.pf.fourcc == FOURCC_RXGB) + { + BlockDXT5 block; + *stream << block; + block.decodeBlock(rgba); + + if (header.pf.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 (header.pf.fourcc == FOURCC_ATI1) + { + BlockATI1 block; + *stream << block; + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_ATI2) + { + BlockATI2 block; + *stream << block; + block.decodeBlock(rgba); + } + + // If normal flag set, convert to normal. + if (header.pf.flags & DDPF_NORMAL) + { + if (header.pf.fourcc == FOURCC_ATI2) + { + for (int i = 0; i < 16; i++) + { + Color32 & c = rgba->color(i); + c = buildNormal(c.r, c.g); + } + } + else if (header.pf.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; + }; + + // 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; + } + else + { + nvDebugCheck(header.pf.flags & DDPF_RGB); + + // Align pixels to bytes. + uint byteCount = (header.pf.bitcount + 7) / 8; + + // Align pitch to 4 bytes. + uint pitch = 4 * ((w * byteCount + 3) / 4); + + return pitch * h * d; + } +} + +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 (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: %d\n", header.height); + printf("Width: %d\n", header.width); + printf("Depth: %d\n", header.depth); + if (header.flags & DDSD_PITCH) printf("Pitch: %d\n", header.pitch); + else if (header.flags & DDSD_LINEARSIZE) printf("Linear size: %d\n", header.pitch); + printf("Mipmap count: %d\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_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"); + + printf("\tFourCC: '%c%c%c%c'\n", ((header.pf.fourcc >> 0) & 0xFF), ((header.pf.fourcc >> 8) & 0xFF), ((header.pf.fourcc >> 16) & 0xFF), ((header.pf.fourcc >> 24) & 0xFF)); + printf("\tBit count: %d\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.pf.flags == 0) + { + printf("DX10 Header:\n"); + printf("\tDXGI Format: %u\n", header.header10.dxgiFormat); + printf("\tResource dimension: %u\n", header.header10.resourceDimension); + printf("\tMisc flag: %u\n", header.header10.miscFlag); + printf("\tArray size: %u\n", header.header10.arraySize); + } + + if (header.reserved[9] == MAKEFOURCC('N', 'V', 'T', 'T')) + { + 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); + } +} + diff --git a/src/nvimage/DirectDrawSurface.h b/src/nvimage/DirectDrawSurface.h index 82ad785..70b5b9f 100644 --- a/src/nvimage/DirectDrawSurface.h +++ b/src/nvimage/DirectDrawSurface.h @@ -1,152 +1,152 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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. - -#ifndef NV_IMAGE_DIRECTDRAWSURFACE_H -#define NV_IMAGE_DIRECTDRAWSURFACE_H - -#include - -namespace nv -{ - class Image; - class Stream; - struct ColorBlock; - - 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 setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask); - void setDX10Format(uint format); - void setNormalFlag(bool b); - - void swapBytes(); - - bool hasDX10Header() const; - }; - - NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header); - - - /// DirectDraw Surface. (DDS) - class NVIMAGE_CLASS DirectDrawSurface - { - public: - DirectDrawSurface(const char * file); - ~DirectDrawSurface(); - - bool isValid() const; - bool isSupported() const; - - uint mipmapCount() const; - uint width() const; - uint height() const; - uint depth() const; - bool isTexture2D() const; - bool isTexture3D() const; - bool isTextureCube() const; - - void mipmap(Image * img, uint f, uint m); - // 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: - Stream * const stream; - DDSHeader header; - DDSHeader10 header10; - }; - -} // nv namespace - -#endif // NV_IMAGE_DIRECTDRAWSURFACE_H +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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. + +#ifndef NV_IMAGE_DIRECTDRAWSURFACE_H +#define NV_IMAGE_DIRECTDRAWSURFACE_H + +#include + +namespace nv +{ + class Image; + class Stream; + struct ColorBlock; + + 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 setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask); + void setDX10Format(uint format); + void setNormalFlag(bool b); + + void swapBytes(); + + bool hasDX10Header() const; + }; + + NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header); + + + /// DirectDraw Surface. (DDS) + class NVIMAGE_CLASS DirectDrawSurface + { + public: + DirectDrawSurface(const char * file); + ~DirectDrawSurface(); + + bool isValid() const; + bool isSupported() const; + + uint mipmapCount() const; + uint width() const; + uint height() const; + uint depth() const; + bool isTexture2D() const; + bool isTexture3D() const; + bool isTextureCube() const; + + void mipmap(Image * img, uint f, uint m); + // 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: + Stream * const stream; + DDSHeader header; + DDSHeader10 header10; + }; + +} // nv namespace + +#endif // NV_IMAGE_DIRECTDRAWSURFACE_H diff --git a/src/nvimage/FloatImage.cpp b/src/nvimage/FloatImage.cpp index 93ba781..fe7e578 100644 --- a/src/nvimage/FloatImage.cpp +++ b/src/nvimage/FloatImage.cpp @@ -15,15 +15,29 @@ using namespace nv; namespace { - static int round(float f) + static int iround(float f) { return int(f); } + static int ifloor(float f) + { + return int(floor(f)); + } + static float frac(float f) { return f - floor(f); } + + static int mirror(int x, int w) + { + x = fabs(x); + while (x >= w) { + x = 2 * w - x - 2; + } + return x; + } } @@ -161,7 +175,7 @@ void FloatImage::normalize(uint base_component) for(uint i = 0; i < size; i++) { Vector3 normal(xChannel[i], yChannel[i], zChannel[i]); - normal = normalizeSafe(normal, Vector3(zero)); + normal = normalizeSafe(normal, Vector3(zero), 0.0f); xChannel[i] = normal.x(); yChannel[i] = normal.y(); @@ -226,72 +240,42 @@ void FloatImage::exponentiate(uint base_component, uint num, float power) } } -#if 0 -float FloatImage::nearest(float x, float y, int c, WrapMode wm) const +float FloatImage::sampleNearest(const float x, const float y, const int c, const WrapMode wm) const { - if( wm == WrapMode_Clamp ) return nearest_clamp(x, y, c); - /*if( wm == WrapMode_Repeat )*/ return nearest_repeat(x, y, c); - //if( wm == WrapMode_Mirror ) return nearest_mirror(x, y, c); + if( wm == WrapMode_Clamp ) return sampleNearestClamp(x, y, c); + else if( wm == WrapMode_Repeat ) return sampleNearestRepeat(x, y, c); + else /*if( wm == WrapMode_Mirror )*/ return sampleNearestMirror(x, y, c); } -float FloatImage::nearest_clamp(int x, int y, const int c) const +float FloatImage::sampleLinear(const float x, const float y, const int c, const WrapMode wm) const { - const int w = m_width; - const int h = m_height; - int ix = ::clamp(x, 0, w-1); - int iy = ::clamp(y, 0, h-1); + if( wm == WrapMode_Clamp ) return sampleLinearClamp(x, y, c); + else if( wm == WrapMode_Repeat ) return sampleLinearRepeat(x, y, c); + else /*if( wm == WrapMode_Mirror )*/ return sampleLinearMirror(x, y, c); +} + +float FloatImage::sampleNearestClamp(const float x, const float y, const int c) const +{ + int ix = ::clamp(iround(x * m_width), 0, m_width-1); + int iy = ::clamp(iround(y * m_height), 0, m_height-1); return pixel(ix, iy, c); } -float FloatImage::nearest_repeat(int x, int y, const int c) const +float FloatImage::sampleNearestRepeat(const float x, const float y, const int c) const { - const int w = m_width; - const int h = m_height; - int ix = x % w; - int iy = y % h; - return pixel(ix, iy, c); -} -#endif - -float FloatImage::nearest(float x, float y, int c, WrapMode wm) const -{ - if( wm == WrapMode_Clamp ) return nearest_clamp(x, y, c); - /*if( wm == WrapMode_Repeat )*/ return nearest_repeat(x, y, c); - //if( wm == WrapMode_Mirror ) return nearest_mirror(x, y, c); -} - -float FloatImage::linear(float x, float y, int c, WrapMode wm) const -{ - if( wm == WrapMode_Clamp ) return linear_clamp(x, y, c); - /*if( wm == WrapMode_Repeat )*/ return linear_repeat(x, y, c); - //if( wm == WrapMode_Mirror ) return linear_mirror(x, y, c); -} - -float FloatImage::nearest_clamp(float x, float y, const int c) const -{ - const int w = m_width; - const int h = m_height; - int ix = ::clamp(round(x * w), 0, w-1); - int iy = ::clamp(round(y * h), 0, h-1); + int ix = iround(frac(x) * m_width); + int iy = iround(frac(y) * m_height); return pixel(ix, iy, c); } -float FloatImage::nearest_repeat(float x, float y, const int c) const +float FloatImage::sampleNearestMirror(const float x, const float y, const int c) const { - const int w = m_width; - const int h = m_height; - int ix = round(frac(x) * w); - int iy = round(frac(y) * h); + int ix = mirror(iround(x * m_width), m_width); + int iy = mirror(iround(y * m_height), m_height); return pixel(ix, iy, c); } -float FloatImage::nearest_mirror(float x, float y, const int c) const -{ - // @@ TBD - return 0.0f; -} - -float FloatImage::linear_clamp(float x, float y, const int c) const +float FloatImage::sampleLinearClamp(float x, float y, const int c) const { const int w = m_width; const int h = m_height; @@ -302,10 +286,10 @@ float FloatImage::linear_clamp(float x, float y, const int c) const const float fracX = frac(x); const float fracY = frac(y); - const int ix0 = ::clamp(round(x), 0, w-1); - const int iy0 = ::clamp(round(y), 0, h-1); - const int ix1 = ::clamp(round(x)+1, 0, w-1); - const int iy1 = ::clamp(round(y)+1, 0, h-1); + const int ix0 = ::clamp(ifloor(x), 0, w-1); + const int iy0 = ::clamp(ifloor(y), 0, h-1); + const int ix1 = ::clamp(ifloor(x)+1, 0, w-1); + const int iy1 = ::clamp(ifloor(y)+1, 0, h-1); float f1 = pixel(ix0, iy0, c); float f2 = pixel(ix1, iy0, c); @@ -318,7 +302,7 @@ float FloatImage::linear_clamp(float x, float y, const int c) const return lerp(i1, i2, fracY); } -float FloatImage::linear_repeat(float x, float y, int c) const +float FloatImage::sampleLinearRepeat(float x, float y, int c) const { const int w = m_width; const int h = m_height; @@ -326,10 +310,10 @@ float FloatImage::linear_repeat(float x, float y, int c) const const float fracX = frac(x * w); const float fracY = frac(y * h); - int ix0 = round(frac(x) * w); - int iy0 = round(frac(y) * h); - int ix1 = round(frac(x + 1.0f/w) * w); - int iy1 = round(frac(y + 1.0f/h) * h); + int ix0 = ifloor(frac(x) * w); + int iy0 = ifloor(frac(y) * h); + int ix1 = ifloor(frac(x + 1.0f/w) * w); + int iy1 = ifloor(frac(y + 1.0f/h) * h); float f1 = pixel(ix0, iy0, c); float f2 = pixel(ix1, iy0, c); @@ -342,10 +326,31 @@ float FloatImage::linear_repeat(float x, float y, int c) const return lerp(i1, i2, fracY); } -float FloatImage::linear_mirror(float x, float y, int c) const +float FloatImage::sampleLinearMirror(float x, float y, int c) const { - // @@ TBD - return 0.0f; + const int w = m_width; + const int h = m_height; + + x *= w; + y *= h; + + const float fracX = frac(x); + const float fracY = frac(y); + + int ix0 = mirror(x, w); + int iy0 = mirror(y, h); + int ix1 = mirror(x + 1, w); + int iy1 = mirror(y + 1, h); + + float f1 = pixel(ix0, iy0, c); + float f2 = pixel(ix1, iy0, c); + float f3 = pixel(ix0, iy1, c); + float f4 = pixel(ix1, iy1, c); + + float i1 = lerp(f1, f2, fracX); + float i2 = lerp(f3, f4, fracX); + + return lerp(i1, i2, fracY); } diff --git a/src/nvimage/FloatImage.h b/src/nvimage/FloatImage.h index 83e74df..a91a689 100644 --- a/src/nvimage/FloatImage.h +++ b/src/nvimage/FloatImage.h @@ -97,18 +97,16 @@ public: void setPixel(float f, uint idx); float pixel(uint idx) const; - float nearest(int x, int y, int c, WrapMode wm) const; + float sampleNearest(float x, float y, int c, WrapMode wm) const; + float sampleLinear(float x, float y, int c, WrapMode wm) const; - float nearest(float x, float y, int c, WrapMode wm) const; - float linear(float x, float y, int c, WrapMode wm) const; + float sampleNearestClamp(float x, float y, int c) const; + float sampleNearestRepeat(float x, float y, int c) const; + float sampleNearestMirror(float x, float y, int c) const; - float nearest_clamp(float x, float y, int c) const; - float nearest_repeat(float x, float y, int c) const; - float nearest_mirror(float x, float y, int c) const; - - float linear_clamp(float x, float y, int c) const; - float linear_repeat(float x, float y, int c) const; - float linear_mirror(float x, float y, int c) const; + float sampleLinearClamp(float x, float y, int c) const; + float sampleLinearRepeat(float x, float y, int c) const; + float sampleLinearMirror(float x, float y, int c) const; //@} public: diff --git a/src/nvimage/HoleFilling.cpp b/src/nvimage/HoleFilling.cpp index c96c6e3..a825a24 100644 --- a/src/nvimage/HoleFilling.cpp +++ b/src/nvimage/HoleFilling.cpp @@ -1,6 +1,7 @@ // This code is in the public domain -- castanyo@yahoo.es #include +#include #include @@ -11,7 +12,7 @@ using namespace nv; // This is a variation of Sapiro's inpainting method. -void nv::fillExtrapolateOnce(FloatImage * img, BitMap * bmap) +void nv::fillExtrapolate(int passCount, FloatImage * img, BitMap * bmap) { nvCheck(img != NULL); nvCheck(bmap != NULL); @@ -23,83 +24,73 @@ void nv::fillExtrapolateOnce(FloatImage * img, BitMap * bmap) nvCheck(bmap->width() == uint(w)); nvCheck(bmap->height() == uint(h)); - BitMap * newbmap = new BitMap(w, h); + AutoPtr newbmap(new BitMap(w, h)); - for(int c = 0; c < count; c++) { - - float * channel = img->channel(c); - - for(int y = 0; y < h; y++) { - for(int x = 0; x < w; x++) { - - if (bmap->bitAt(x, y)) { - // Not a hole. - newbmap->setBitAt(x, y); - continue; - } - - const bool west = bmap->bitAt(img->indexClamp(x-1, y)); - const bool east = bmap->bitAt(img->indexClamp(x+1, y)); - const bool north = bmap->bitAt(img->indexClamp(x, y-1)); - const bool south = bmap->bitAt(img->indexClamp(x, y+1)); - const bool northwest = bmap->bitAt(img->indexClamp(x-1, y-1)); - const bool northeast = bmap->bitAt(img->indexClamp(x+1, y-1)); - const bool southwest = bmap->bitAt(img->indexClamp(x-1, y+1)); - const bool southeast = bmap->bitAt(img->indexClamp(x+1, y+1)); - - int num = west + east + north + south + northwest + northeast + southwest + southeast; - - if (num != 0) { - - float average = 0.0f; - if (num == 3 && west && northwest && southwest) { - average = channel[img->indexClamp(x-1, y)]; - } - else if (num == 3 && east && northeast && southeast) { - average = channel[img->indexClamp(x+1, y)]; - } - else if (num == 3 && north && northwest && northeast) { - average = channel[img->indexClamp(x, y-1)]; - } - else if (num == 3 && south && southwest && southeast) { - average = channel[img->indexClamp(x, y+1)]; - } - else { - float total = 0.0f; - if (west) { average += 1 * channel[img->indexClamp(x-1, y)]; total += 1; } - if (east) { average += 1 * channel[img->indexClamp(x+1, y)]; total += 1; } - if (north) { average += 1 * channel[img->indexClamp(x, y-1)]; total += 1; } - if (south) { average += 1 * channel[img->indexClamp(x, y+1)]; total += 1; } + for(int p = 0; p < passCount; p++) + { + for(int c = 0; c < count; c++) + { + float * channel = img->channel(c); + + for(int y = 0; y < h; y++) { + for(int x = 0; x < w; x++) { - if (northwest) { average += channel[img->indexClamp(x-1, y-1)]; ++total; } - if (northeast) { average += channel[img->indexClamp(x+1, y-1)]; ++total; } - if (southwest) { average += channel[img->indexClamp(x-1, y+1)]; ++total; } - if (southeast) { average += channel[img->indexClamp(x+1, y+1)]; ++total; } - - average /= total; + if (bmap->bitAt(x, y)) { + // Not a hole. + newbmap->setBitAt(x, y); + continue; } + + const bool west = bmap->bitAt(img->indexClamp(x-1, y)); + const bool east = bmap->bitAt(img->indexClamp(x+1, y)); + const bool north = bmap->bitAt(img->indexClamp(x, y-1)); + const bool south = bmap->bitAt(img->indexClamp(x, y+1)); + const bool northwest = bmap->bitAt(img->indexClamp(x-1, y-1)); + const bool northeast = bmap->bitAt(img->indexClamp(x+1, y-1)); + const bool southwest = bmap->bitAt(img->indexClamp(x-1, y+1)); + const bool southeast = bmap->bitAt(img->indexClamp(x+1, y+1)); + + int num = west + east + north + south + northwest + northeast + southwest + southeast; + + if (num != 0) { - channel[img->indexClamp(x, y)] = average; - newbmap->setBitAt(x, y); + float average = 0.0f; + if (num == 3 && west && northwest && southwest) { + average = channel[img->indexClamp(x-1, y)]; + } + else if (num == 3 && east && northeast && southeast) { + average = channel[img->indexClamp(x+1, y)]; + } + else if (num == 3 && north && northwest && northeast) { + average = channel[img->indexClamp(x, y-1)]; + } + else if (num == 3 && south && southwest && southeast) { + average = channel[img->indexClamp(x, y+1)]; + } + else { + float total = 0.0f; + if (west) { average += 1 * channel[img->indexClamp(x-1, y)]; total += 1; } + if (east) { average += 1 * channel[img->indexClamp(x+1, y)]; total += 1; } + if (north) { average += 1 * channel[img->indexClamp(x, y-1)]; total += 1; } + if (south) { average += 1 * channel[img->indexClamp(x, y+1)]; total += 1; } + + if (northwest) { average += channel[img->indexClamp(x-1, y-1)]; ++total; } + if (northeast) { average += channel[img->indexClamp(x+1, y-1)]; ++total; } + if (southwest) { average += channel[img->indexClamp(x-1, y+1)]; ++total; } + if (southeast) { average += channel[img->indexClamp(x+1, y+1)]; ++total; } + + average /= total; + } + + channel[img->indexClamp(x, y)] = average; + newbmap->setBitAt(x, y); + } } } } - } - // Update the bit mask. - swap(*newbmap, *bmap); - -} - -void nv::fillExtrapolateNTimes(FloatImage * img, BitMap * bmap, int n) -{ - nvCheck(img != NULL); - nvCheck(bmap != NULL); - nvCheck(n > 0); - - for(int i = 0; i < n; i++) - { - fillExtrapolateOnce(img, bmap); + // Update the bit mask. + swap(*newbmap, *bmap); } } @@ -134,7 +125,7 @@ namespace { } // namespace // Voronoi filling using EDT-4 -void nv::fillVoronoi(FloatImage * img, const BitMap & bmap) +void nv::fillVoronoi(FloatImage * img, const BitMap * bmap) { nvCheck(img != NULL); @@ -142,8 +133,8 @@ void nv::fillVoronoi(FloatImage * img, const BitMap & bmap) const int h = img->height(); const int count = img->componentNum(); - nvCheck(bmap.width() == uint(w)); - nvCheck(bmap.height() == uint(h)); + nvCheck(bmap->width() == uint(w)); + nvCheck(bmap->height() == uint(h)); Array edm; edm.resize(w * h); @@ -154,7 +145,7 @@ void nv::fillVoronoi(FloatImage * img, const BitMap & bmap) // Init edm. for( y = 0; y < h; y++ ) { for( x = 0; x < w; x++ ) { - if( bmap.bitAt(x, y) ) { + if( bmap->bitAt(x, y) ) { edm[y * w + x].x = x; edm[y * w + x].y = y; edm[y * w + x].d = 0; @@ -229,7 +220,7 @@ void nv::fillVoronoi(FloatImage * img, const BitMap & bmap) } -void nv::fillBlur(FloatImage * img, const BitMap & bmap) +void nv::fillBlur(FloatImage * img, const BitMap * bmap) { nvCheck(img != NULL); @@ -306,7 +297,7 @@ static bool downsample(const FloatImage * src, const BitMap * srcMask, const Flo } // This is the filter used in the Lumigraph paper. The Unreal engine uses something similar. -void nv::fillPullPush(FloatImage * img, const BitMap & bmap) +void nv::fillPullPush(FloatImage * img, const BitMap * bmap) { nvCheck(img != NULL); @@ -320,7 +311,7 @@ void nv::fillPullPush(FloatImage * img, const BitMap & bmap) Array mipmapMasks(num); mipmaps.append(img); - mipmapMasks.append(&bmap); + mipmapMasks.append(bmap); const FloatImage * current; const BitMap * currentMask; @@ -336,16 +327,22 @@ void nv::fillPullPush(FloatImage * img, const BitMap & bmap) for(uint y = 0; y < h; y++) { for(uint x = 0; x < w; x++) { - uint sx = x; - uint sy = y; + int sx = x; + int sy = y; + //float sx = x; + //float sy = y; const uint levelCount = mipmaps.count(); - for(uint l = 0; l < levelCount; l++) { + for (uint l = 0; l < levelCount; l++) + { + //const float fx = sx / mipmaps[l]->width(); + //const float fy = sy / mipmaps[l]->height(); if (mipmapMasks[l]->bitAt(sx, sy)) { // Sample mipmaps[l](sx, sy) and copy to img(x, y) for(uint c = 0; c < count; c++) { + //img->setPixel(mipmaps[l]->linear_clamp(fx, fy, c), x, y, c); img->setPixel(mipmaps[l]->pixel(sx, sy, c), x, y, c); } break; @@ -357,20 +354,20 @@ void nv::fillPullPush(FloatImage * img, const BitMap & bmap) } } + // Don't delete the original image and mask. + mipmaps[0] = NULL; + mipmapMasks[0] = NULL; + + // Delete the mipmaps. deleteAll(mipmaps); deleteAll(mipmapMasks); } + /* -void nv::fillSeamFix(FloatImage * img, const BitMap & bmap) -{ -} -*/ -#if 0 // Code below is under the BPL license. - -/** +This Code is from Charles Bloom: DoPixelSeamFix 10-20-02 @@ -386,7 +383,7 @@ Note that I'm working on normals, but I treat them just as 3 scalars and normali at the end. To be more correct, I would work on the surface of a sphere, but that just seems like way too much work. -**/ +*/ struct LocalPixels { @@ -395,11 +392,11 @@ struct LocalPixels // index [y][x] bool fill[5][5]; float data[5][5]; + mutable float result; mutable float weight; - - bool Quad3SubH(gVec4 * pQ,int row) const + bool Quad3SubH(float * pQ, int row) const { const bool * pFill = fill[row]; const float * pDat = data[row]; @@ -426,7 +423,7 @@ struct LocalPixels } // improve result with a horizontal quad in row 1 and/or - bool Quad3SubV(gVec4 * pQ,int col) const + bool Quad3SubV(float * pQ, int col) const { if ( fill[1][col] && fill[2][col] && fill[3][col] ) { @@ -449,14 +446,14 @@ struct LocalPixels return false; } - bool Quad3H(gVec4 * pQ) const + bool Quad3H(float * pQ) const { - if ( ! Quad3SubH(pQ,1) ) + if (!Quad3SubH(pQ,1)) { return Quad3SubH(pQ,3); } - gVec4 q(0,0,0,0); // initializer not needed, just make it shut up - if ( Quad3SubH(&q,3) ) + float q = 0.0f; // initializer not needed, just make it shut up + if (Quad3SubH(&q, 3)) { // got q and pQ *pQ = (*pQ+q)*0.5f; @@ -464,17 +461,17 @@ struct LocalPixels return true; } - bool Quad3V(gVec4 * pQ) const + bool Quad3V(float * pQ) const { - if ( ! Quad3SubV(pQ,1) ) + if (!Quad3SubV(pQ, 1)) { - return Quad3SubV(pQ,3); + return Quad3SubV(pQ, 3); } - gVec4 q(0,0,0,0); // initializer not needed, just make it shut up - if ( Quad3SubV(&q,3) ) + float q = 0.0f; // initializer not needed, just make it shut up + if (Quad3SubV(&q, 3)) { // got q and pQ - *pQ = (*pQ+q)*0.5f; + *pQ = (*pQ + q) * 0.5f; } return true; } @@ -482,7 +479,7 @@ struct LocalPixels // a common want is [1] - ([0]+[2])*0.5f ; // so use -0.5f*Quad - bool TryQuads() const + bool tryQuads() const { bool res = false; @@ -490,7 +487,7 @@ struct LocalPixels if ( fill[2][1] && fill[2][3] ) { // got horizontal straddle - gVec4 q; + float q; if ( Quad3H(&q) ) { result += (data[2][1] + data[2][3] - q) * 0.5f; @@ -501,7 +498,7 @@ struct LocalPixels if ( fill[1][2] && fill[3][2] ) { // got vertical straddle - gVec4 q; + float q; if ( Quad3V(&q) ) { result += (data[1][2] + data[3][2] - q) * 0.5f; @@ -514,7 +511,7 @@ struct LocalPixels if ( fill[2][0] && fill[2][1] ) { // got left-side pair - gVec4 q; + float q; if ( Quad3H(&q) ) { result += data[2][1]*2.f - data[2][0] + q; @@ -525,7 +522,7 @@ struct LocalPixels if ( fill[2][3] && fill[2][4] ) { // got right-side pair - gVec4 q; + float q; if ( Quad3H(&q) ) { result += data[2][3]*2.f - data[2][4] + q; @@ -536,7 +533,7 @@ struct LocalPixels if ( fill[0][2] && fill[1][2] ) { // got left-side pair - gVec4 q; + float q; if ( Quad3V(&q) ) { result += data[1][2]*2.f - data[0][2] + q; @@ -547,7 +544,7 @@ struct LocalPixels if ( fill[3][2] && fill[4][2] ) { // got right-side pair - gVec4 q; + float q; if ( Quad3V(&q) ) { result += data[3][2]*2.f - data[4][2] + q; @@ -558,7 +555,7 @@ struct LocalPixels return res; } - bool TryPlanar() const + bool tryPlanar() const { // four cases : const int indices[] = @@ -569,37 +566,37 @@ struct LocalPixels 2,3, 3,2, 3,3 }; bool res = false; - for(int i=0;i<4;i++) + for (int i = 0; i < 4; i++) { const int * I = indices + i*6; - if ( ! fill[ I[0] ][ I[1] ] ) + if (!fill[ I[0] ][ I[1] ]) continue; - if ( ! fill[ I[2] ][ I[3] ] ) + if (!fill[ I[2] ][ I[3] ]) continue; - if ( ! fill[ I[4] ][ I[5] ] ) + if (!fill[ I[4] ][ I[5] ]) continue; result += data[ I[0] ][ I[1] ] + data[ I[2] ][ I[3] ] - data[ I[4] ][ I[5] ]; - weight += 1.f; + weight += 1.0f; res = true; } return res; } - bool TryTwos() const + bool tryTwos() const { bool res = false; - if ( fill[2][1] && fill[2][3] ) + if (fill[2][1] && fill[2][3]) { result += (data[2][1] + data[2][3]) * 0.5f; - weight += 1.f; + weight += 1.0f; res = true; } - if ( fill[1][2] && fill[3][2] ) + if (fill[1][2] && fill[3][2]) { result += (data[1][2] + data[3][2]) * 0.5f; - weight += 1.f; + weight += 1.0f; res = true; } @@ -611,141 +608,146 @@ struct LocalPixels 1,2, 0,2, 3,2, 4,2, }; - for(int i=0;i<4;i++) + for (int i = 0; i < 4; i++) { const int * I = indices + i*4; - if ( ! fill[ I[0] ][ I[1] ] ) + if (!fill[ I[0] ][ I[1] ]) continue; - if ( ! fill[ I[2] ][ I[3] ] ) + if (!fill[ I[2] ][ I[3] ]) continue; - result += data[ I[0] ][ I[1] ]*2.f - data[ I[2] ][ I[3] ]; - weight += 1.f; + result += data[ I[0] ][ I[1] ]*2.0f - data[ I[2] ][ I[3] ]; + weight += 1.0f; res = true; } return res; } - - bool DoLocalPixelFill() const + bool doLocalPixelFill() const { - result = gVec4::zero; - weight = 0.f; - - if ( TryQuads() ) + result = 0.0f; + weight = 0.0f; + + if (tryQuads()) { return true; - - if ( TryPlanar() ) + } + + if (tryPlanar()) { return true; - - return TryTwos(); + } + + return tryTwos(); } -}; // LocalPixels ----------------------------------------------- +}; // struct LocalPixels -void gNormalMap::DoPixelSeamFix() + + +// This is a cubic extrapolation filter from Charles Bloom (DoPixelSeamFix). +void nv::fillCubicExtrapolate(int passCount, FloatImage * img, BitMap * bmap, int coverageIndex /*= -1*/) { - gLog::Printf("gNormalMap::DoPixelSeamFix.."); + nvCheck(passCount > 0); + nvCheck(img != NULL); + nvCheck(bmap != NULL); - const int desiredTicks = 30; - const int heightPerTick = NUM_SEAMFIX_PASSES * m_height / desiredTicks; - int tick = 0; + const int w = img->width(); + const int h = img->height(); + const int count = img->componentNum(); - for(int pass=0;passwidth() == uint(w)); + nvCheck(bmap->height() == uint(h)); + + AutoPtr newbmap( new BitMap(w, h) ); + + float * coverageChannel = NULL; + if (coverageIndex != -1) { - for(int yb=0;ybchannel(coverageIndex); + } - // make the local neighborhood: - int numFill = 0; - LocalPixels lp; - for(int ny=0;ny<5;ny++) - { - int y = (yb + ny - 2); - if ( y < 0 || y >= m_height ) - { - // out of range - for(int i=0;i<5;i++) - { - lp.fill[ny][i] = false; - } + int firstChannel = -1; + + for (int p = 0; p < passCount; p++) + { + for (int c = 0; c < count; c++) + { + if (c == coverageIndex) continue; + if (firstChannel == -1) firstChannel = c; + + float * channel = img->channel(c); + + for (int yb = 0; yb < h; yb++) { + for (int xb = 0; xb < w; xb++) { + + if (bmap->bitAt(xb, yb)) { + // Not a hole. + newbmap->setBitAt(xb, yb); continue; } - gVec4 * pRow = m_normals + m_width * y; - const EState * pStateRow = m_states + m_width * y; - for(int nx=0;nx<5;nx++) + + int numFill = 0; + + LocalPixels lp; + for (int ny = 0; ny < 5; ny++) { - int x = (xb + nx - 2); - if ( x < 0 || x >= m_width ) + int y = (yb + ny - 2); + if ( y < 0 || y >= h ) { - lp.fill[ny][nx] = false; + // out of range + for(int i = 0; i < 5; i++) + { + lp.fill[ny][i] = false; + } + continue; } - else if ( pStateRow[x] == eNull || pStateRow[x] == eEdge ) + + for (int nx = 0; nx < 5; nx++) { - lp.fill[ny][nx] = false; + int x = (xb + nx - 2); + if (x < 0 || x >= w) + { + lp.fill[ny][nx] = false; + } + else + { + int idx = img->index(x, y); + if (!bmap->bitAt(idx)) + { + lp.fill[ny][nx] = false; + } + else + { + lp.fill[ny][nx] = true; + lp.data[ny][nx] = channel[idx]; + numFill++; + } + } } - else + } + + // need at least 3 to do anything decent + if (numFill < 2) + continue; + + nvDebugCheck(lp.fill[2][2] == false); + + if (lp.doLocalPixelFill()) + { + const int idx = img->index(xb, yb); + channel[idx] = lp.result / lp.weight; + + if (c == firstChannel) { - lp.fill[ny][nx] = true; - lp.data[ny][nx] = pRow[x]; - numFill++; + //coverageChannel[idx] /= lp.weight; // @@ Not sure what this was for, coverageChannel[idx] is always zero. + newbmap->setBitAt(xb, yb); } } } - - // need at least 3 to do anything decent - if ( numFill < 2 ) - continue; - - ASSERT(lp.fill[2][2] == false); - if ( lp.DoLocalPixelFill() ) - { - if ( lp.result.MutableVec3().NormalizeSafe() ) - { - pRow[xb] = lp.result; - pRow[xb][3] /= lp.weight; - } - } - } - - if ( ++tick == heightPerTick ) - { - tick = 0; - gLog::Printf("."); } } - // now run back over and stamp anything that's not null as being ok - - for(int y=0;y -#include - -#include - -#include -#include - - -using namespace nv; - -Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL) -{ -} - -Image::~Image() -{ - free(); -} - -void Image::allocate(uint w, uint h) -{ - m_width = w; - m_height = h; - m_data = (Color32 *)realloc(m_data, w * h * sizeof(Color32)); -} - -bool Image::load(const char * name) -{ - free(); - - AutoPtr img(ImageIO::load(name)); - if (img == NULL) { - return false; - } - - swap(m_width, img->m_width); - swap(m_height, img->m_height); - swap(m_format, img->m_format); - swap(m_data, img->m_data); - - return true; -} - -void Image::wrap(void * data, uint w, uint h) -{ - free(); - m_data = (Color32 *)data; - m_width = w; - m_height = h; -} - -void Image::unwrap() -{ - m_data = NULL; - m_width = 0; - m_height = 0; -} - - -void Image::free() -{ - ::free(m_data); - m_data = NULL; -} - - -uint Image::width() const -{ - return m_width; -} - -uint Image::height() const -{ - return m_height; -} - -const Color32 * Image::scanline(uint h) const -{ - nvDebugCheck(h < m_height); - return m_data + h * m_width; -} - -Color32 * Image::scanline(uint h) -{ - nvDebugCheck(h < m_height); - 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 -{ - nvDebugCheck(idx < m_width * m_height); - return m_data[idx]; -} - -Color32 & Image::pixel(uint idx) -{ - nvDebugCheck(idx < m_width * m_height); - return m_data[idx]; -} - - -Image::Format Image::format() const -{ - return m_format; -} - -void Image::setFormat(Image::Format f) -{ - m_format = f; -} - -void Image::fill(Color32 c) -{ - const uint size = m_width * m_height; - for (uint i = 0; i < size; ++i) - { - m_data[i] = c; - } -} - +// This code is in the public domain -- castanyo@yahoo.es + +#include +#include + +#include + +#include +#include + + +using namespace nv; + +Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL) +{ +} + +Image::~Image() +{ + free(); +} + +void Image::allocate(uint w, uint h) +{ + m_width = w; + m_height = h; + m_data = (Color32 *)realloc(m_data, w * h * sizeof(Color32)); +} + +bool Image::load(const char * name) +{ + free(); + + AutoPtr img(ImageIO::load(name)); + if (img == NULL) { + return false; + } + + swap(m_width, img->m_width); + swap(m_height, img->m_height); + swap(m_format, img->m_format); + swap(m_data, img->m_data); + + return true; +} + +void Image::wrap(void * data, uint w, uint h) +{ + free(); + m_data = (Color32 *)data; + m_width = w; + m_height = h; +} + +void Image::unwrap() +{ + m_data = NULL; + m_width = 0; + m_height = 0; +} + + +void Image::free() +{ + ::free(m_data); + m_data = NULL; +} + + +uint Image::width() const +{ + return m_width; +} + +uint Image::height() const +{ + return m_height; +} + +const Color32 * Image::scanline(uint h) const +{ + nvDebugCheck(h < m_height); + return m_data + h * m_width; +} + +Color32 * Image::scanline(uint h) +{ + nvDebugCheck(h < m_height); + 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 +{ + nvDebugCheck(idx < m_width * m_height); + return m_data[idx]; +} + +Color32 & Image::pixel(uint idx) +{ + nvDebugCheck(idx < m_width * m_height); + return m_data[idx]; +} + + +Image::Format Image::format() const +{ + return m_format; +} + +void Image::setFormat(Image::Format f) +{ + m_format = f; +} + +void Image::fill(Color32 c) +{ + const uint size = m_width * m_height; + for (uint i = 0; i < size; ++i) + { + m_data[i] = c; + } +} + diff --git a/src/nvimage/ImageIO.cpp b/src/nvimage/ImageIO.cpp index 2391abc..61ed501 100644 --- a/src/nvimage/ImageIO.cpp +++ b/src/nvimage/ImageIO.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include @@ -29,11 +31,13 @@ extern "C" { # include #endif -#if defined(HAVE_EXR) -# include -# include // ??? +#if defined(HAVE_OPENEXR) +# include +# include +# include +# include +# include # include -using namespace Imf; #endif using namespace nv; @@ -55,23 +59,28 @@ namespace { } // namespace -Image * nv::ImageIO::load(const char * name) +Image * nv::ImageIO::load(const char * fileName) { - StdInputStream stream(name); + nvDebugCheck(fileName != NULL); + + StdInputStream stream(fileName); if (stream.isError()) { - return false; + return NULL; } - return load(name, stream); + return ImageIO::load(fileName, stream); } -Image * nv::ImageIO::load(const char * name, Stream & s) +Image * nv::ImageIO::load(const char * fileName, Stream & s) { - const char * extension = Path::extension(name); + nvDebugCheck(fileName != NULL); + nvDebugCheck(s.isLoading()); + + const char * extension = Path::extension(fileName); if (strCaseCmp(extension, ".tga") == 0) { - return loadTGA(s); + return ImageIO::loadTGA(s); } #if defined(HAVE_JPEG) if (strCaseCmp(extension, ".jpg") == 0 || strCaseCmp(extension, ".jpeg") == 0) { @@ -90,36 +99,113 @@ Image * nv::ImageIO::load(const char * name, Stream & s) return NULL; } -NVIMAGE_API FloatImage * nv::ImageIO::loadFloat(const char * name) +bool nv::ImageIO::save(const char * fileName, Stream & s, Image * img) { - StdInputStream stream(name); + nvDebugCheck(fileName != NULL); + nvDebugCheck(s.isSaving()); + nvDebugCheck(img != NULL); + + const char * extension = Path::extension(fileName); + + if (strCaseCmp(extension, ".tga") == 0) { + return ImageIO::saveTGA(s, img); + } + + return false; +} + +bool nv::ImageIO::save(const char * fileName, Image * img) +{ + nvDebugCheck(fileName != NULL); + nvDebugCheck(img != NULL); + + StdOutputStream stream(fileName); + if (stream.isError()) + { + return false; + } + + return ImageIO::save(fileName, stream, img); +} + +FloatImage * nv::ImageIO::loadFloat(const char * fileName) +{ + nvDebugCheck(fileName != NULL); + + StdInputStream stream(fileName); if (stream.isError()) { return false; } - return loadFloat(name, stream); + return loadFloat(fileName, stream); } -NVIMAGE_API FloatImage * nv::ImageIO::loadFloat(const char * name, Stream & s) +FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s) { - const char * extension = Path::extension(name); + nvDebugCheck(fileName != NULL); + + const char * extension = Path::extension(fileName); #if defined(HAVE_TIFF) if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) { - return loadFloatTIFF(name, s); + return loadFloatTIFF(fileName, s); } #endif -#if defined(HAVE_EXR) +#if defined(HAVE_OPENEXR) if (strCaseCmp(extension, ".exr") == 0) { - return loadFloatEXR(name, s); + return loadFloatEXR(fileName, s); } #endif + if (strCaseCmp(extension, ".pfm") == 0) { + return loadFloatPFM(fileName, s); + } + return NULL; } +bool nv::ImageIO::saveFloat(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components) +{ + const char * extension = Path::extension(fileName); + +#if defined(HAVE_OPENEXR) + if (strCaseCmp(extension, ".exr") == 0) + { + return ImageIO::saveFloatEXR(fileName, fimage, base_component, num_components); + } +#endif + +#if defined(HAVE_TIFF) + if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) + { + return ImageIO::saveFloatTIFF(fileName, fimage, base_component, num_components); + } +#endif + + if (strCaseCmp(extension, ".pfm") == 0) + { +// return ImageIO::saveFloatPFM(fileName, fimage, base_component, num_components); + } + + if (num_components == 3 || num_components == 4) + { + AutoPtr image(fimage->createImage(base_component, num_components)); + nvCheck(image != NULL); + + if (num_components == 4) + { + image->setFormat(Image::Format_ARGB); + } + + return ImageIO::save(fileName, image.ptr()); + } + + return false; +} + + /// Load TGA image. Image * nv::ImageIO::loadTGA(Stream & s) { @@ -912,7 +998,7 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage { nvCheck(fileName != NULL); nvCheck(fimage != NULL); - nvCheck(fimage->componentNum() <= base_component + num_components); + nvCheck(base_component + num_components <= fimage->componentNum()); const int iW = fimage->width(); const int iH = fimage->height(); @@ -936,7 +1022,12 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage uint32 rowsperstrip = TIFFDefaultStripSize(image, (uint32)-1); TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); - TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); + TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); + if (num_components == 3) + { + // Set this so that it can be visualized with pfstools. + TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + } TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); @@ -963,14 +1054,14 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage #endif -#if defined(HAVE_EXR) +#if defined(HAVE_OPENEXR) namespace { class ExrStream : public Imf::IStream { public: - ExrStream(Stream & s) : m_stream(s) + ExrStream(const char * name, Stream & s) : Imf::IStream(name), m_stream(s) { nvDebugCheck(s.isLoading()); } @@ -987,12 +1078,12 @@ namespace return m_stream.isAtEnd(); } - virtual Int64 tellg() + virtual Imf::Int64 tellg() { return m_stream.tell(); } - virtual void seekg(Int64 pos) + virtual void seekg(Imf::Int64 pos) { m_stream.seek(pos); } @@ -1010,12 +1101,13 @@ namespace FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) { + nvCheck(s.isLoading()); nvCheck(!s.isError()); - ExrStream stream(s); - RgbaInputFile inputFile(stream); + ExrStream stream(fileName, s); + Imf::InputFile inputFile(stream); - Box2i box = inputFile.dataWindow(); + Imath::Box2i box = inputFile.header().dataWindow(); int width = box.max.x - box.min.y + 1; int height = box.max.x - box.min.y + 1; @@ -1024,7 +1116,7 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) // Count channels. uint channelCount= 0; - for (ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it) + for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it) { channelCount++; } @@ -1034,11 +1126,11 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) fimage->allocate(channelCount, width, height); // Describe image's layout with a framebuffer. - FrameBuffer frameBuffer; + Imf::FrameBuffer frameBuffer; uint i = 0; - for (ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it, ++i) + for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it, ++i) { - frameBuffer.insert(it.name(), Slice(FLOAT, fimage->channel(i), sizeof(float), sizeof(float) * width)); + frameBuffer.insert(it.name(), Imf::Slice(Imf::FLOAT, (char *)fimage->channel(i), sizeof(float), sizeof(float) * width)); } // Read it. @@ -1048,22 +1140,11 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) return fimage.release(); } -FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName) -{ - StdInputStream stream(fileName); - - if (stream.isError()) { - return false; - } - - return loadFloatExr(fileName, stream); -} - bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components) { nvCheck(fileName != NULL); nvCheck(fimage != NULL); - nvCheck(fimage->componentNum() <= base_component + num_components); + nvCheck(base_component + num_components <= fimage->componentNum()); nvCheck(num_components > 0 && num_components <= 4); const int w = fimage->width(); @@ -1071,29 +1152,146 @@ bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage, const char * channelNames[] = {"R", "G", "B", "A"}; - Header header (width, height); + Imf::Header header (w, h); for (uint c = 0; c < num_components; c++) { - header.channels().insert(channelNames[c], Channel(FLOAT)); + header.channels().insert(channelNames[c], Imf::Channel(Imf::FLOAT)); } - OutputFile file(fileName, header); - FrameBuffer frameBuffer; + Imf::OutputFile file(fileName, header); + Imf::FrameBuffer frameBuffer; for (uint c = 0; c < num_components; c++) { - const char * channel = (char *) fimage->channel(base_component + c); - frameBuffer.insert(channelNames[c], Slice(FLOAT, channel, sizeof(float), sizeof(float) * w)); + char * channel = (char *) fimage->channel(base_component + c); + frameBuffer.insert(channelNames[c], Imf::Slice(Imf::FLOAT, channel, sizeof(float), sizeof(float) * w)); } file.setFrameBuffer(frameBuffer); - file.writePixels(height); + file.writePixels(h); - return false; + return true; } -#endif // defined(HAVE_EXR) +#endif // defined(HAVE_OPENEXR) + + +FloatImage * nv::ImageIO::loadFloatPFM(const char * fileName, Stream & s) +{ + nvCheck(s.isLoading()); + nvCheck(!s.isError()); + + Tokenizer parser(&s); + + parser.nextToken(); + + bool grayscale; + if (parser.token() == "PF") + { + grayscale = false; + } + else if (parser.token() == "Pf") + { + grayscale = true; + } + else + { + // Invalid file. + return NULL; + } + + parser.nextLine(); + + int width = parser.token().toInt(); parser.nextToken(); + int height = parser.token().toInt(); + + parser.nextLine(); + + float scaleFactor = parser.token().toFloat(); + + if (scaleFactor >= 0) + { + s.setByteOrder(Stream::BigEndian); + } + else + { + s.setByteOrder(Stream::LittleEndian); + } + scaleFactor = fabsf(scaleFactor); + + // Allocate image. + AutoPtr fimage(new FloatImage()); + + if (grayscale) + { + fimage->allocate(1, width, height); + + float * channel = fimage->channel(0); + + for (int i = 0; i < width * height; i++) + { + s << channel[i]; + } + } + else + { + fimage->allocate(3, width, height); + + float * rchannel = fimage->channel(0); + float * gchannel = fimage->channel(1); + float * bchannel = fimage->channel(2); + + for (int i = 0; i < width * height; i++) + { + s << rchannel[i] << gchannel[i] << bchannel[i]; + } + } + + return fimage.release(); +} + +bool nv::ImageIO::saveFloatPFM(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components) +{ + nvCheck(fileName != NULL); + nvCheck(fimage != NULL); + nvCheck(fimage->componentNum() <= base_component + num_components); + nvCheck(num_components == 1 || num_components == 3); + + StdOutputStream stream(fileName); + TextWriter writer(&stream); + + if (num_components == 1) writer.write("Pf\n"); + else /*if (num_components == 3)*/ writer.write("PF\n"); + + int w = fimage->width(); + int h = fimage->height(); + writer.write("%d %d\n", w, h); + writer.write("%f\n", -1.0f); // little endian with 1.0 scale. + + if (num_components == 1) + { + float * channel = const_cast(fimage->channel(0)); + + for (int i = 0; i < w * h; i++) + { + stream << channel[i]; + } + } + else + { + float * rchannel = const_cast(fimage->channel(0)); + float * gchannel = const_cast(fimage->channel(1)); + float * bchannel = const_cast(fimage->channel(2)); + + for (int i = 0; i < w * h; i++) + { + stream << rchannel[i] << gchannel[i] << bchannel[i]; + } + } + + return true; +} #if 0 diff --git a/src/nvimage/ImageIO.h b/src/nvimage/ImageIO.h index 3f16dd3..014d292 100644 --- a/src/nvimage/ImageIO.h +++ b/src/nvimage/ImageIO.h @@ -15,9 +15,14 @@ namespace nv { NVIMAGE_API Image * load(const char * fileName); NVIMAGE_API Image * load(const char * fileName, Stream & s); + NVIMAGE_API FloatImage * loadFloat(const char * fileName); NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s); + NVIMAGE_API bool save(const char * fileName, Stream & s, Image * img); + NVIMAGE_API bool save(const char * fileName, Image * img); + NVIMAGE_API bool saveFloat(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); + NVIMAGE_API Image * loadTGA(Stream & s); NVIMAGE_API bool saveTGA(Stream & s, const Image * img); @@ -37,12 +42,15 @@ namespace nv NVIMAGE_API bool saveFloatTIFF(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); #endif -#if defined(HAVE_EXR) +#if defined(HAVE_OPENEXR) NVIMAGE_API FloatImage * loadFloatEXR(const char * fileName, Stream & s); NVIMAGE_API bool saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); #endif + NVIMAGE_API FloatImage * loadFloatPFM(const char * fileName, Stream & s); + NVIMAGE_API bool saveFloatPFM(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); + } // ImageIO namespace } // nv namespace diff --git a/src/nvimage/NormalMap.cpp b/src/nvimage/NormalMap.cpp index 1433a8f..841c5ae 100644 --- a/src/nvimage/NormalMap.cpp +++ b/src/nvimage/NormalMap.cpp @@ -1,140 +1,140 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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 - -#include - -#include -#include -#include -#include - -using namespace nv; - -// Create normal map using the given kernels. -static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, const Kernel2 * kdu, const Kernel2 * kdv) -{ - nvCheck(kdu != NULL); - nvCheck(kdv != NULL); - nvCheck(img != NULL); - - const uint w = img->width(); - const uint h = img->height(); - - AutoPtr fimage(new FloatImage()); - fimage->allocate(4, w, h); - - // Compute height and store in alpha channel: - float * alphaChannel = fimage->channel(3); - for(uint i = 0; i < w*h; i++) - { - Vector4 color = toVector4(img->pixel(i)); - alphaChannel[i] = dot(color, heightWeights); - } - - float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor. - - for(uint y = 0; y < h; y++) - { - for(uint x = 0; x < w; x++) - { - const float du = fimage->applyKernel(kdu, x, y, 3, wm); - const float dv = fimage->applyKernel(kdv, x, y, 3, wm); - - Vector3 n = normalize(Vector3(du, dv, heightScale)); - - fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0); - fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1); - fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2); - } - } - - return fimage.release(); -} - - -/// Create normal map using the given filter. -FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/) -{ - nvCheck(img != NULL); - - // Init the kernels. - Kernel2 * kdu = NULL; - Kernel2 * kdv = NULL; - - switch(filter) - { - case NormalMapFilter_Sobel3x3: - kdu = new Kernel2(3); - break; - case NormalMapFilter_Sobel5x5: - kdu = new Kernel2(5); - break; - case NormalMapFilter_Sobel7x7: - kdu = new Kernel2(7); - break; - case NormalMapFilter_Sobel9x9: - kdu = new Kernel2(9); - break; - default: - nvDebugCheck(false); - }; - - kdu->initSobel(); - kdu->normalize(); - - kdv = new Kernel2(*kdu); - kdv->transpose(); - - return ::createNormalMap(img, wm, heightWeights, kdu, kdv); -} - - -/// Create normal map combining multiple sobel filters. -FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights) -{ - nvCheck(img != NULL); - - Kernel2 * kdu = NULL; - Kernel2 * kdv = NULL; - - kdu = new Kernel2(9); - kdu->initBlendedSobel(filterWeights); - kdu->normalize(); - - kdv = new Kernel2(*kdu); - kdv->transpose(); - - return ::createNormalMap(img, wm, heightWeights, kdu, kdv); -} - -/// Normalize the given image in place. -void nv::normalizeNormalMap(FloatImage * img) -{ - nvCheck(img != NULL); - img->expandNormals(0); - img->normalize(0); - img->packNormals(0); -} - +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 + +#include + +#include +#include +#include +#include + +using namespace nv; + +// Create normal map using the given kernels. +static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, const Kernel2 * kdu, const Kernel2 * kdv) +{ + nvCheck(kdu != NULL); + nvCheck(kdv != NULL); + nvCheck(img != NULL); + + const uint w = img->width(); + const uint h = img->height(); + + AutoPtr fimage(new FloatImage()); + fimage->allocate(4, w, h); + + // Compute height and store in alpha channel: + float * alphaChannel = fimage->channel(3); + for(uint i = 0; i < w*h; i++) + { + Vector4 color = toVector4(img->pixel(i)); + alphaChannel[i] = dot(color, heightWeights); + } + + float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor. + + for(uint y = 0; y < h; y++) + { + for(uint x = 0; x < w; x++) + { + const float du = fimage->applyKernel(kdu, x, y, 3, wm); + const float dv = fimage->applyKernel(kdv, x, y, 3, wm); + + Vector3 n = normalize(Vector3(du, dv, heightScale)); + + fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0); + fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1); + fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2); + } + } + + return fimage.release(); +} + + +/// Create normal map using the given filter. +FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/) +{ + nvCheck(img != NULL); + + // Init the kernels. + Kernel2 * kdu = NULL; + Kernel2 * kdv = NULL; + + switch(filter) + { + case NormalMapFilter_Sobel3x3: + kdu = new Kernel2(3); + break; + case NormalMapFilter_Sobel5x5: + kdu = new Kernel2(5); + break; + case NormalMapFilter_Sobel7x7: + kdu = new Kernel2(7); + break; + case NormalMapFilter_Sobel9x9: + kdu = new Kernel2(9); + break; + default: + nvDebugCheck(false); + }; + + kdu->initSobel(); + kdu->normalize(); + + kdv = new Kernel2(*kdu); + kdv->transpose(); + + return ::createNormalMap(img, wm, heightWeights, kdu, kdv); +} + + +/// Create normal map combining multiple sobel filters. +FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights) +{ + nvCheck(img != NULL); + + Kernel2 * kdu = NULL; + Kernel2 * kdv = NULL; + + kdu = new Kernel2(9); + kdu->initBlendedSobel(filterWeights); + kdu->normalize(); + + kdv = new Kernel2(*kdu); + kdv->transpose(); + + return ::createNormalMap(img, wm, heightWeights, kdu, kdv); +} + +/// Normalize the given image in place. +void nv::normalizeNormalMap(FloatImage * img) +{ + nvCheck(img != NULL); + img->expandNormals(0); + img->normalize(0); + img->packNormals(0); +} + diff --git a/src/nvimage/NormalMap.h b/src/nvimage/NormalMap.h index 541e7b5..670ead4 100644 --- a/src/nvimage/NormalMap.h +++ b/src/nvimage/NormalMap.h @@ -1,55 +1,55 @@ -// Copyright NVIDIA Corporation 2007 -- Ignacio Castano -// -// 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. - -#ifndef NV_IMAGE_NORMALMAP_H -#define NV_IMAGE_NORMALMAP_H - -#include -#include -#include - - -namespace nv -{ - class Image; - - enum NormalMapFilter - { - NormalMapFilter_Sobel3x3, // fine detail - NormalMapFilter_Sobel5x5, // medium detail - NormalMapFilter_Sobel7x7, // large detail - NormalMapFilter_Sobel9x9, // very large - }; - - FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter = NormalMapFilter_Sobel3x3); - - FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights); - - void normalizeNormalMap(FloatImage * img); - - // @@ Add generation of DU/DV maps. - - -} // nv namespace - -#endif // NV_IMAGE_NORMALMAP_H +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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. + +#ifndef NV_IMAGE_NORMALMAP_H +#define NV_IMAGE_NORMALMAP_H + +#include +#include +#include + + +namespace nv +{ + class Image; + + enum NormalMapFilter + { + NormalMapFilter_Sobel3x3, // fine detail + NormalMapFilter_Sobel5x5, // medium detail + NormalMapFilter_Sobel7x7, // large detail + NormalMapFilter_Sobel9x9, // very large + }; + + FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter = NormalMapFilter_Sobel3x3); + + FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights); + + void normalizeNormalMap(FloatImage * img); + + // @@ Add generation of DU/DV maps. + + +} // nv namespace + +#endif // NV_IMAGE_NORMALMAP_H