From 613646b33e5fde13158a8d8644df8c97bdde2fbb Mon Sep 17 00:00:00 2001 From: Kent Mein Date: Mon, 25 Jun 2007 19:50:25 +0000 Subject: This commit is a modified version of patch #6860 It adds read only dds support. (Writing will come later) Kent --- source/blender/imbuf/IMB_imbuf_types.h | 8 + source/blender/imbuf/SConscript | 3 + source/blender/imbuf/intern/Makefile | 5 +- source/blender/imbuf/intern/dds/BlockDXT.cpp | 523 +++++++++++++ source/blender/imbuf/intern/dds/BlockDXT.h | 227 ++++++ source/blender/imbuf/intern/dds/Color.h | 99 +++ source/blender/imbuf/intern/dds/ColorBlock.cpp | 310 ++++++++ source/blender/imbuf/intern/dds/ColorBlock.h | 115 +++ source/blender/imbuf/intern/dds/Common.h | 44 ++ .../blender/imbuf/intern/dds/DirectDrawSurface.cpp | 828 +++++++++++++++++++++ .../blender/imbuf/intern/dds/DirectDrawSurface.h | 162 ++++ source/blender/imbuf/intern/dds/Image.cpp | 132 ++++ source/blender/imbuf/intern/dds/Image.h | 103 +++ source/blender/imbuf/intern/dds/Makefile | 67 ++ source/blender/imbuf/intern/dds/SConscript | 18 + source/blender/imbuf/intern/dds/Stream.cpp | 88 +++ source/blender/imbuf/intern/dds/Stream.h | 48 ++ source/blender/imbuf/intern/dds/dds_api.cpp | 120 +++ source/blender/imbuf/intern/dds/dds_api.h | 43 ++ source/blender/imbuf/intern/readimage.c | 9 + source/blender/imbuf/intern/util.c | 15 + source/blender/imbuf/intern/writeimage.c | 10 + 22 files changed, 2976 insertions(+), 1 deletion(-) create mode 100644 source/blender/imbuf/intern/dds/BlockDXT.cpp create mode 100644 source/blender/imbuf/intern/dds/BlockDXT.h create mode 100644 source/blender/imbuf/intern/dds/Color.h create mode 100644 source/blender/imbuf/intern/dds/ColorBlock.cpp create mode 100644 source/blender/imbuf/intern/dds/ColorBlock.h create mode 100644 source/blender/imbuf/intern/dds/Common.h create mode 100644 source/blender/imbuf/intern/dds/DirectDrawSurface.cpp create mode 100644 source/blender/imbuf/intern/dds/DirectDrawSurface.h create mode 100644 source/blender/imbuf/intern/dds/Image.cpp create mode 100644 source/blender/imbuf/intern/dds/Image.h create mode 100644 source/blender/imbuf/intern/dds/Makefile create mode 100644 source/blender/imbuf/intern/dds/SConscript create mode 100644 source/blender/imbuf/intern/dds/Stream.cpp create mode 100644 source/blender/imbuf/intern/dds/Stream.h create mode 100644 source/blender/imbuf/intern/dds/dds_api.cpp create mode 100644 source/blender/imbuf/intern/dds/dds_api.h (limited to 'source/blender/imbuf') diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index f5487bb9ac0..d43b78df0b6 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -174,6 +174,10 @@ typedef enum { #define CINEON (1 << 21) #define DPX (1 << 20) +#ifdef WITH_DDS +#define DDS (1 << 19) +#endif + #define RAWTGA (TGA | 1) #define JPG_STD (JPG | (0 << 8)) @@ -216,6 +220,10 @@ typedef enum { #define IS_tiff(x) (x->ftype & TIF) #define IS_radhdr(x) (x->ftype & RADHDR) +#ifdef WITH_DDS +#define IS_dds(x) (x->ftype & DDS) +#endif + #define IMAGIC 0732 #define IS_iris(x) (x->ftype == IMAGIC) diff --git a/source/blender/imbuf/SConscript b/source/blender/imbuf/SConscript index 7d3503dfe2d..f9e46b20d9a 100644 --- a/source/blender/imbuf/SConscript +++ b/source/blender/imbuf/SConscript @@ -20,6 +20,9 @@ if env['WITH_BF_VERSE']: if env['WITH_BF_OPENEXR'] == 1: defs.append('WITH_OPENEXR') +if env['WITH_BF_DDS'] == 1: + defs.append('WITH_DDS') + if env['WITH_BF_FFMPEG'] == 1: defs.append('WITH_FFMPEG') incs += ' ' + env['BF_FFMPEG_INC'] diff --git a/source/blender/imbuf/intern/Makefile b/source/blender/imbuf/intern/Makefile index f51844aad96..29332747a31 100644 --- a/source/blender/imbuf/intern/Makefile +++ b/source/blender/imbuf/intern/Makefile @@ -46,6 +46,10 @@ ifeq ($(WITH_OPENEXR), true) CFLAGS += -DWITH_OPENEXR endif +ifeq ($(WITH_DDS), true) + DIRS += dds + CPPFLAGS += -DWITH_DDS +endif ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris windows")) CFLAGS += -funsigned-char @@ -80,4 +84,3 @@ ifeq ($(WITH_FFMPEG), true) CPPFLAGS += -DWITH_FFMPEG CPPFLAGS += $(NAN_FFMPEGCFLAGS) endif - diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp new file mode 100644 index 00000000000..5290a677678 --- /dev/null +++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp @@ -0,0 +1,523 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 + +/*---------------------------------------------------------------------------- + BlockDXT1 +----------------------------------------------------------------------------*/ + +unsigned int 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; +} + +void BlockDXT1::decodeBlock(ColorBlock * block) const +{ + // Decode color block. + Color32 color_array[4]; + evaluatePalette(color_array); + + // Write color block. + for( unsigned int j = 0; j < 4; j++ ) { + for( unsigned int i = 0; i < 4; i++ ) { + unsigned int idx = (row[j] >> (2 * i)) & 3; + block->color(i, j) = color_array[idx]; + } + } +} + +void BlockDXT1::setIndices(int * idx) +{ + indices = 0; + for(unsigned int i = 0; i < 16; i++) { + indices |= (idx[i] & 3) << (2 * i); + } +} + + +/// Flip DXT1 block vertically. +inline void BlockDXT1::flip4() +{ + unsigned char tmp; + swap(row[0], row[3], tmp); + swap(row[1], row[2], tmp); +} + +/// Flip half DXT1 block vertically. +inline void BlockDXT1::flip2() +{ + unsigned char tmp; + swap(row[0], row[1], tmp); +} + + +/*---------------------------------------------------------------------------- + BlockDXT3 +----------------------------------------------------------------------------*/ + +void BlockDXT3::decodeBlock(ColorBlock * block) const +{ + // Decode color. + color.decodeBlock(block); + + // Decode alpha. + alpha.decodeBlock(block); +} + +void AlphaBlockDXT3::decodeBlock(ColorBlock * block) const +{ + block->color(0x0).a = (alpha0 << 4) | alpha0; + block->color(0x1).a = (alpha1 << 4) | alpha1; + block->color(0x2).a = (alpha2 << 4) | alpha2; + block->color(0x3).a = (alpha3 << 4) | alpha3; + block->color(0x4).a = (alpha4 << 4) | alpha4; + block->color(0x5).a = (alpha5 << 4) | alpha5; + block->color(0x6).a = (alpha6 << 4) | alpha6; + block->color(0x7).a = (alpha7 << 4) | alpha7; + block->color(0x8).a = (alpha8 << 4) | alpha8; + block->color(0x9).a = (alpha9 << 4) | alpha9; + block->color(0xA).a = (alphaA << 4) | alphaA; + block->color(0xB).a = (alphaB << 4) | alphaB; + block->color(0xC).a = (alphaC << 4) | alphaC; + block->color(0xD).a = (alphaD << 4) | alphaD; + block->color(0xE).a = (alphaE << 4) | alphaE; + block->color(0xF).a = (alphaF << 4) | alphaF; +} + +/// Flip DXT3 alpha block vertically. +void AlphaBlockDXT3::flip4() +{ + unsigned short tmp; + swap(row[0], row[3], tmp); + swap(row[1], row[2], tmp); +} + +/// Flip half DXT3 alpha block vertically. +void AlphaBlockDXT3::flip2() +{ + unsigned short tmp; + swap(row[0], row[1], tmp); +} + +/// 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(unsigned char alpha[8]) const +{ + if (alpha0 > alpha1) { + evaluatePalette8(alpha); + } + else { + evaluatePalette6(alpha); + } +} + +void AlphaBlockDXT5::evaluatePalette8(unsigned char 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(unsigned char 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(unsigned char 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; +} + +unsigned int AlphaBlockDXT5::index(unsigned int index) const +{ + int offset = (3 * index + 16); + return (this->u >> offset) & 0x7; +} + +void AlphaBlockDXT5::setIndex(unsigned int index, unsigned int value) +{ + int offset = (3 * index + 16); + unsigned long long mask = ((unsigned long long)(0x7)) << offset; + this->u = (this->u & ~mask) | (((unsigned long long)(value)) << offset); +} + +void AlphaBlockDXT5::decodeBlock(ColorBlock * block) const +{ + unsigned char alpha_array[8]; + evaluatePalette(alpha_array); + + unsigned char index_array[16]; + indices(index_array); + + for(unsigned int i = 0; i < 16; i++) { + block->color(i).a = alpha_array[index_array[i]]; + } +} + +void AlphaBlockDXT5::flip4() +{ + unsigned long long * b = (unsigned long long *)this; + + // @@ The masks might have to be byte swapped. + unsigned long long tmp = (*b & (unsigned long long)(0x000000000000FFFFLL)); + tmp |= (*b & (unsigned long long)(0x000000000FFF0000LL)) << 36; + tmp |= (*b & (unsigned long long)(0x000000FFF0000000LL)) << 12; + tmp |= (*b & (unsigned long long)(0x000FFF0000000000LL)) >> 12; + tmp |= (*b & (unsigned long long)(0xFFF0000000000000LL)) >> 36; + + *b = tmp; +} + +void AlphaBlockDXT5::flip2() +{ + unsigned int * b = (unsigned int *)this; + + // @@ The masks might have to be byte swapped. + unsigned int tmp = (*b & 0xFF000000); + tmp |= (*b & 0x00000FFF) << 12; + tmp |= (*b & 0x00FFF000) >> 12; + + *b = tmp; +} + +void BlockDXT5::decodeBlock(ColorBlock * block) const +{ + // Decode color. + color.decodeBlock(block); + + // Decode alpha. + alpha.decodeBlock(block); +} + +/// 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 +{ + unsigned char alpha_array[8]; + alpha.evaluatePalette(alpha_array); + + unsigned char index_array[16]; + alpha.indices(index_array); + + for(unsigned int 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 +{ + unsigned char alpha_array[8]; + unsigned char index_array[16]; + + x.evaluatePalette(alpha_array); + x.indices(index_array); + + for(unsigned int 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(unsigned int 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 mem_read(Stream & mem, BlockDXT1 & block) +{ + mem_read(mem, block.col0.u); + mem_read(mem, block.col1.u); + mem_read(mem, block.indices); +} + +void mem_read(Stream & mem, AlphaBlockDXT3 & block) +{ + for (unsigned int i = 0; i < 4; i++) mem_read(mem, block.row[i]); +} + +void mem_read(Stream & mem, BlockDXT3 & block) +{ + mem_read(mem, block.alpha); + mem_read(mem, block.color); +} + +void mem_read(Stream & mem, AlphaBlockDXT5 & block) +{ + mem_read(mem, block.u); +} + +void mem_read(Stream & mem, BlockDXT5 & block) +{ + mem_read(mem, block.alpha); + mem_read(mem, block.color); +} + +void mem_read(Stream & mem, BlockATI1 & block) +{ + mem_read(mem, block.alpha); +} + +void mem_read(Stream & mem, BlockATI2 & block) +{ + mem_read(mem, block.x); + mem_read(mem, block.y); +} + diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h new file mode 100644 index 00000000000..fde1bceac0d --- /dev/null +++ b/source/blender/imbuf/intern/dds/BlockDXT.h @@ -0,0 +1,227 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 _DDS_BLOCKDXT_H +#define _DDS_BLOCKDXT_H + +#include +#include +#include + +/// DXT1 block. +struct BlockDXT1 +{ + Color16 col0; + Color16 col1; + union { + unsigned char row[4]; + unsigned int indices; + }; + + bool isFourColorMode() const; + + unsigned int evaluatePalette(Color32 color_array[4]) const; + unsigned int 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; // @@ > or >= ? +} + + +/// DXT3 alpha block with explicit alpha. +struct AlphaBlockDXT3 +{ + union { + struct { + unsigned int alpha0 : 4; + unsigned int alpha1 : 4; + unsigned int alpha2 : 4; + unsigned int alpha3 : 4; + unsigned int alpha4 : 4; + unsigned int alpha5 : 4; + unsigned int alpha6 : 4; + unsigned int alpha7 : 4; + unsigned int alpha8 : 4; + unsigned int alpha9 : 4; + unsigned int alphaA : 4; + unsigned int alphaB : 4; + unsigned int alphaC : 4; + unsigned int alphaD : 4; + unsigned int alphaE : 4; + unsigned int alphaF : 4; + }; + unsigned short 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 { + unsigned long long alpha0 : 8; // 8 + unsigned long long alpha1 : 8; // 16 + unsigned long long bits0 : 3; // 3 - 19 + unsigned long long bits1 : 3; // 6 - 22 + unsigned long long bits2 : 3; // 9 - 25 + unsigned long long bits3 : 3; // 12 - 28 + unsigned long long bits4 : 3; // 15 - 31 + unsigned long long bits5 : 3; // 18 - 34 + unsigned long long bits6 : 3; // 21 - 37 + unsigned long long bits7 : 3; // 24 - 40 + unsigned long long bits8 : 3; // 27 - 43 + unsigned long long bits9 : 3; // 30 - 46 + unsigned long long bitsA : 3; // 33 - 49 + unsigned long long bitsB : 3; // 36 - 52 + unsigned long long bitsC : 3; // 39 - 55 + unsigned long long bitsD : 3; // 42 - 58 + unsigned long long bitsE : 3; // 45 - 61 + unsigned long long bitsF : 3; // 48 - 64 + }; + unsigned long long u; + }; + + void evaluatePalette(unsigned char alpha[8]) const; + void evaluatePalette8(unsigned char alpha[8]) const; + void evaluatePalette6(unsigned char alpha[8]) const; + void indices(unsigned char index_array[16]) const; + + unsigned int index(unsigned int index) const; + void setIndex(unsigned int index, unsigned int 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(); +}; + +void mem_read(Stream & mem, BlockDXT1 & block); +void mem_read(Stream & mem, AlphaBlockDXT3 & block); +void mem_read(Stream & mem, BlockDXT3 & block); +void mem_read(Stream & mem, AlphaBlockDXT5 & block); +void mem_read(Stream & mem, BlockDXT5 & block); +void mem_read(Stream & mem, BlockATI1 & block); +void mem_read(Stream & mem, BlockATI2 & block); + +#endif // _DDS_BLOCKDXT_H diff --git a/source/blender/imbuf/intern/dds/Color.h b/source/blender/imbuf/intern/dds/Color.h new file mode 100644 index 00000000000..f8055afdfc9 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Color.h @@ -0,0 +1,99 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#ifndef _DDS_COLOR_H +#define _DDS_COLOR_H + +/// 32 bit color stored as BGRA. +class Color32 +{ +public: + Color32() { } + Color32(const Color32 & c) : u(c.u) { } + Color32(unsigned char R, unsigned char G, unsigned char B) { setRGBA(R, G, B, 0xFF); } + Color32(unsigned char R, unsigned char G, unsigned char B, unsigned char A) { setRGBA( R, G, B, A); } + //Color32(unsigned char c[4]) { setRGBA(c[0], c[1], c[2], c[3]); } + //Color32(float R, float G, float B) { setRGBA(uint(R*255), uint(G*255), uint(B*255), 0xFF); } + //Color32(float R, float G, float B, float A) { setRGBA(uint(R*255), uint(G*255), uint(B*255), uint(A*255)); } + Color32(unsigned int U) : u(U) { } + + void setRGBA(unsigned char R, unsigned char G, unsigned char B, unsigned char A) + { + r = R; + g = G; + b = B; + a = A; + } + + void setBGRA(unsigned char B, unsigned char G, unsigned char R, unsigned char A = 0xFF) + { + r = R; + g = G; + b = B; + a = A; + } + + operator unsigned int () const { + return u; + } + + union { + struct { + unsigned char b, g, r, a; + }; + unsigned int u; + }; +}; + +/// 16 bit 565 BGR color. +class Color16 +{ +public: + Color16() { } + Color16(const Color16 & c) : u(c.u) { } + explicit Color16(unsigned short U) : u(U) { } + + union { + struct { + unsigned short b : 5; + unsigned short g : 6; + unsigned short r : 5; + }; + unsigned short u; + }; +}; + +#endif // _DDS_COLOR_H diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp new file mode 100644 index 00000000000..63997f93c8c --- /dev/null +++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp @@ -0,0 +1,310 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#include +#include +#include + + // Get approximate luminance. + inline static unsigned int colorLuminance(Color32 c) + { + return c.r + c.g + c.b; + } + + // Get the euclidean distance between the given colors. + inline static unsigned int colorDistance(Color32 c0, Color32 c1) + { + return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b); + } + + +/// Default constructor. +ColorBlock::ColorBlock() +{ +} + +/// Init the color block with the contents of the given block. +ColorBlock::ColorBlock(const ColorBlock & block) +{ + for(unsigned int i = 0; i < 16; i++) { + color(i) = block.color(i); + } +} + + +/// Initialize this color block. +ColorBlock::ColorBlock(const Image * img, unsigned int x, unsigned int y) +{ + init(img, x, y); +} + +void ColorBlock::init(const Image * img, unsigned int x, unsigned int y) +{ + const unsigned int bw = min(img->width() - x, 4U); + const unsigned int bh = min(img->height() - y, 4U); + + static int remainder[] = { + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 1, 2, 0, + 0, 1, 2, 3, + }; + + // Blocks that are smaller than 4x4 are handled by repeating the pixels. + // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( + + for(unsigned int i = 0; i < 4; i++) { + //const int by = i % bh; + const int by = remainder[(bh - 1) * 4 + i]; + for(unsigned int e = 0; e < 4; e++) { + //const int bx = e % bw; + const int bx = remainder[(bw - 1) * 4 + e]; + color(e, i) = img->pixel(x + bx, y + by); + } + } +} + + +void ColorBlock::swizzleDXT5n() +{ + for(int i = 0; i < 16; i++) + { + Color32 c = m_color[i]; + m_color[i] = Color32(0, c.g, 0, c.r); + } +} + +void ColorBlock::splatX() +{ + for(int i = 0; i < 16; i++) + { + unsigned char x = m_color[i].r; + m_color[i] = Color32(x, x, x, x); + } +} + +void ColorBlock::splatY() +{ + for(int i = 0; i < 16; i++) + { + unsigned char y = m_color[i].g; + m_color[i] = Color32(y, y, y, y); + } +} + + +/// Count number of unique colors in this color block. +unsigned int ColorBlock::countUniqueColors() const +{ + unsigned int count = 0; + + // @@ This does not have to be o(n^2) + for(int i = 0; i < 16; i++) + { + bool unique = true; + for(int j = 0; j < i; j++) { + if( m_color[i] != m_color[j] ) { + unique = false; + } + } + + if( unique ) { + count++; + } + } + + return count; +} + +/// Get average color of the block. +Color32 ColorBlock::averageColor() const +{ + unsigned int r, g, b, a; + r = g = b = a = 0; + + for(unsigned int i = 0; i < 16; i++) { + r += m_color[i].r; + g += m_color[i].g; + b += m_color[i].b; + a += m_color[i].a; + } + + return Color32((unsigned char)(r / 16), (unsigned char)(g / 16), (unsigned char)(b / 16), (unsigned char)(a / 16)); +} + + +/// Get diameter color range. +void ColorBlock::diameterRange(Color32 * start, Color32 * end) const +{ + Color32 c0, c1; + unsigned int best_dist = 0; + + for(int i = 0; i < 16; i++) { + for (int j = i+1; j < 16; j++) { + unsigned int dist = colorDistance(m_color[i], m_color[j]); + if( dist > best_dist ) { + best_dist = dist; + c0 = m_color[i]; + c1 = m_color[j]; + } + } + } + + *start = c0; + *end = c1; +} + +/// Get luminance color range. +void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const +{ + Color32 minColor, maxColor; + unsigned int minLuminance, maxLuminance; + + maxLuminance = minLuminance = colorLuminance(m_color[0]); + + for(unsigned int i = 1; i < 16; i++) + { + unsigned int luminance = colorLuminance(m_color[i]); + + if (luminance > maxLuminance) { + maxLuminance = luminance; + maxColor = m_color[i]; + } + else if (luminance < minLuminance) { + minLuminance = luminance; + minColor = m_color[i]; + } + } + + *start = minColor; + *end = maxColor; +} + +/// Get color range based on the bounding box. +void ColorBlock::boundsRange(Color32 * start, Color32 * end) const +{ + Color32 minColor(255, 255, 255); + Color32 maxColor(0, 0, 0); + + for(unsigned int i = 0; i < 16; i++) + { + if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; } + if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; } + if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; } + if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; } + if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; } + if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; } + } + + // Offset range by 1/16 of the extents + Color32 inset; + inset.r = (maxColor.r - minColor.r) >> 4; + inset.g = (maxColor.g - minColor.g) >> 4; + inset.b = (maxColor.b - minColor.b) >> 4; + + minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255; + minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255; + minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255; + + maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0; + maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0; + maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0; + + *start = minColor; + *end = maxColor; +} + +/// Get color range based on the bounding box. +void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const +{ + Color32 minColor(255, 255, 255, 255); + Color32 maxColor(0, 0, 0, 0); + + for(unsigned int i = 0; i < 16; i++) + { + if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; } + if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; } + if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; } + if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; } + if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; } + if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; } + if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; } + if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; } + } + + // Offset range by 1/16 of the extents + Color32 inset; + inset.r = (maxColor.r - minColor.r) >> 4; + inset.g = (maxColor.g - minColor.g) >> 4; + inset.b = (maxColor.b - minColor.b) >> 4; + inset.a = (maxColor.a - minColor.a) >> 4; + + minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255; + minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255; + minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255; + minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255; + + maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0; + maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0; + maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0; + maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0; + + *start = minColor; + *end = maxColor; +} + +/// Sort colors by abosolute value in their 16 bit representation. +void ColorBlock::sortColorsByAbsoluteValue() +{ + // Dummy selection sort. + for( unsigned int a = 0; a < 16; a++ ) { + unsigned int max = a; + Color16 cmax(m_color[a]); + + for( unsigned int b = a+1; b < 16; b++ ) { + Color16 cb(m_color[b]); + + if( cb.u > cmax.u ) { + max = b; + cmax = cb; + } + } + Color32 tmp; + swap( m_color[a], m_color[max], tmp ); + } +} + + diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h new file mode 100644 index 00000000000..eba372768ad --- /dev/null +++ b/source/blender/imbuf/intern/dds/ColorBlock.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#ifndef _DDS_COLORBLOCK_H +#define _DDS_COLORBLOCK_H + +#include +#include + +/// Uncompressed 4x4 color block. +struct ColorBlock +{ + ColorBlock(); + ColorBlock(const ColorBlock & block); + ColorBlock(const Image * img, unsigned int x, unsigned int y); + + void init(const Image * img, unsigned int x, unsigned int y); + + void swizzleDXT5n(); + void splatX(); + void splatY(); + + unsigned int countUniqueColors() const; + Color32 averageColor() const; + + void diameterRange(Color32 * start, Color32 * end) const; + void luminanceRange(Color32 * start, Color32 * end) const; + void boundsRange(Color32 * start, Color32 * end) const; + void boundsRangeAlpha(Color32 * start, Color32 * end) const; + void bestFitRange(Color32 * start, Color32 * end) const; + + void sortColorsByAbsoluteValue(); + + float volume() const; + + // Accessors + const Color32 * colors() const; + + Color32 color(unsigned int i) const; + Color32 & color(unsigned int i); + + Color32 color(unsigned int x, unsigned int y) const; + Color32 & color(unsigned int x, unsigned int y); + +private: + + Color32 m_color[4*4]; + +}; + + +/// Get pointer to block colors. +inline const Color32 * ColorBlock::colors() const +{ + return m_color; +} + +/// Get block color. +inline Color32 ColorBlock::color(unsigned int i) const +{ + return m_color[i]; +} + +/// Get block color. +inline Color32 & ColorBlock::color(unsigned int i) +{ + return m_color[i]; +} + +/// Get block color. +inline Color32 ColorBlock::color(unsigned int x, unsigned int y) const +{ + return m_color[y * 4 + x]; +} + +/// Get block color. +inline Color32 & ColorBlock::color(unsigned int x, unsigned int y) +{ + return m_color[y * 4 + x]; +} + +#endif // _DDS_COLORBLOCK_H diff --git a/source/blender/imbuf/intern/dds/Common.h b/source/blender/imbuf/intern/dds/Common.h new file mode 100644 index 00000000000..5aa8972e437 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Common.h @@ -0,0 +1,44 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef _DDS_COMMON_H +#define _DDS_COMMON_H + +#ifndef min +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#endif +#ifndef clamp +#define clamp(x,a,b) min(max((x), (a)), (b)) +#endif +#ifndef swap +#define swap(a,b,tmp) tmp=a; a=b; b=tmp; +#endif + +#endif diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp new file mode 100644 index 00000000000..6937840334d --- /dev/null +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp @@ -0,0 +1,828 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 // printf +#include // sqrt + +/*** declarations ***/ + +#if !defined(MAKEFOURCC) +# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned int)((unsigned char)(ch0)) | \ + ((unsigned int)((unsigned char)(ch1)) << 8) | \ + ((unsigned int)((unsigned char)(ch2)) << 16) | \ + ((unsigned int)((unsigned char)(ch3)) << 24 )) +#endif + +static const unsigned int FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); +static const unsigned int FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); +static const unsigned int FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); +static const unsigned int FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); +static const unsigned int FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); +static const unsigned int FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); +static const unsigned int FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); +static const unsigned int FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1'); +static const unsigned int FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); + +// RGB formats. +static const unsigned int D3DFMT_R8G8B8 = 20; +static const unsigned int D3DFMT_A8R8G8B8 = 21; +static const unsigned int D3DFMT_X8R8G8B8 = 22; +static const unsigned int D3DFMT_R5G6B5 = 23; +static const unsigned int D3DFMT_X1R5G5B5 = 24; +static const unsigned int D3DFMT_A1R5G5B5 = 25; +static const unsigned int D3DFMT_A4R4G4B4 = 26; +static const unsigned int D3DFMT_R3G3B2 = 27; +static const unsigned int D3DFMT_A8 = 28; +static const unsigned int D3DFMT_A8R3G3B2 = 29; +static const unsigned int D3DFMT_X4R4G4B4 = 30; +static const unsigned int D3DFMT_A2B10G10R10 = 31; +static const unsigned int D3DFMT_A8B8G8R8 = 32; +static const unsigned int D3DFMT_X8B8G8R8 = 33; +static const unsigned int D3DFMT_G16R16 = 34; +static const unsigned int D3DFMT_A2R10G10B10 = 35; +static const unsigned int D3DFMT_A16B16G16R16 = 36; + +// Palette formats. +static const unsigned int D3DFMT_A8P8 = 40; +static const unsigned int D3DFMT_P8 = 41; + +// Luminance formats. +static const unsigned int D3DFMT_L8 = 50; +static const unsigned int D3DFMT_A8L8 = 51; +static const unsigned int D3DFMT_A4L4 = 52; + +// Floating point formats +static const unsigned int D3DFMT_R16F = 111; +static const unsigned int D3DFMT_G16R16F = 112; +static const unsigned int D3DFMT_A16B16G16R16F = 113; +static const unsigned int D3DFMT_R32F = 114; +static const unsigned int D3DFMT_G32R32F = 115; +static const unsigned int D3DFMT_A32B32G32R32F = 116; + +static const unsigned int DDSD_CAPS = 0x00000001U; +static const unsigned int DDSD_PIXELFORMAT = 0x00001000U; +static const unsigned int DDSD_WIDTH = 0x00000004U; +static const unsigned int DDSD_HEIGHT = 0x00000002U; +static const unsigned int DDSD_PITCH = 0x00000008U; +static const unsigned int DDSD_MIPMAPCOUNT = 0x00020000U; +static const unsigned int DDSD_LINEARSIZE = 0x00080000U; +static const unsigned int DDSD_DEPTH = 0x00800000U; + +static const unsigned int DDSCAPS_COMPLEX = 0x00000008U; +static const unsigned int DDSCAPS_TEXTURE = 0x00001000U; +static const unsigned int DDSCAPS_MIPMAP = 0x00400000U; +static const unsigned int DDSCAPS2_VOLUME = 0x00200000U; +static const unsigned int DDSCAPS2_CUBEMAP = 0x00000200U; + +static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U; +static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U; +static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U; +static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U; +static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U; +static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U; +static const unsigned int DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U; + +static const unsigned int DDPF_ALPHAPIXELS = 0x00000001U; +static const unsigned int DDPF_ALPHA = 0x00000002U; +static const unsigned int DDPF_FOURCC = 0x00000004U; +static const unsigned int DDPF_RGB = 0x00000040U; +static const unsigned int DDPF_PALETTEINDEXED1 = 0x00000800U; +static const unsigned int DDPF_PALETTEINDEXED2 = 0x00001000U; +static const unsigned int DDPF_PALETTEINDEXED4 = 0x00000008U; +static const unsigned int DDPF_PALETTEINDEXED8 = 0x00000020U; +static const unsigned int DDPF_LUMINANCE = 0x00020000U; +static const unsigned int DDPF_ALPHAPREMULT = 0x00008000U; +static const unsigned int DDPF_NORMAL = 0x80000000U; // @@ Custom nv flag. + +/*** implementation ***/ + +void mem_read(Stream & mem, DDSPixelFormat & pf) +{ + mem_read(mem, pf.size); + mem_read(mem, pf.flags); + mem_read(mem, pf.fourcc); + mem_read(mem, pf.bitcount); + mem_read(mem, pf.rmask); + mem_read(mem, pf.gmask); + mem_read(mem, pf.bmask); + mem_read(mem, pf.amask); +} + +void mem_read(Stream & mem, DDSCaps & caps) +{ + mem_read(mem, caps.caps1); + mem_read(mem, caps.caps2); + mem_read(mem, caps.caps3); + mem_read(mem, caps.caps4); +} + +void mem_read(Stream & mem, DDSHeader & header) +{ + mem_read(mem, header.fourcc); + mem_read(mem, header.size); + mem_read(mem, header.flags); + mem_read(mem, header.height); + mem_read(mem, header.width); + mem_read(mem, header.pitch); + mem_read(mem, header.depth); + mem_read(mem, header.mipmapcount); + for (unsigned int i = 0; i < 11; i++) mem_read(mem, header.reserved[i]); + mem_read(mem, header.pf); + mem_read(mem, header.caps); + mem_read(mem, header.notused); +} + +DDSHeader::DDSHeader() +{ + this->fourcc = FOURCC_DDS; + this->size = 124; + this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT); + this->height = 0; + this->width = 0; + this->pitch = 0; + this->depth = 0; + this->mipmapcount = 0; + for (unsigned int i = 0; i < 11; i++) this->reserved[i] = 0; + + // Store version information on the reserved header attributes. + this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T'); + this->reserved[10] = (0 << 16) | (9 << 8) | (3); // 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; +} + +void DDSHeader::setWidth(unsigned int w) +{ + this->flags |= DDSD_WIDTH; + this->width = w; +} + +void DDSHeader::setHeight(unsigned int h) +{ + this->flags |= DDSD_HEIGHT; + this->height = h; +} + +void DDSHeader::setDepth(unsigned int d) +{ + this->flags |= DDSD_DEPTH; + this->height = d; +} + +void DDSHeader::setMipmapCount(unsigned int 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() +{ + // nothing to do here. +} + +void DDSHeader::setTexture3D() +{ + this->caps.caps2 = DDSCAPS2_VOLUME; +} + +void DDSHeader::setTextureCube() +{ + this->caps.caps1 |= DDSCAPS_COMPLEX; + this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES; +} + +void DDSHeader::setLinearSize(unsigned int size) +{ + this->flags &= ~DDSD_PITCH; + this->flags |= DDSD_LINEARSIZE; + this->pitch = size; +} + +void DDSHeader::setPitch(unsigned int pitch) +{ + this->flags &= ~DDSD_LINEARSIZE; + this->flags |= DDSD_PITCH; + this->pitch = pitch; +} + +void DDSHeader::setFourCC(unsigned char c0, unsigned char c1, unsigned char c2, unsigned char 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(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask) +{ + // Make sure the masks are correct. + if ((rmask & gmask) || \ + (rmask & bmask) || \ + (rmask & amask) || \ + (gmask & bmask) || \ + (gmask & amask) || \ + (bmask & amask)) { + printf("DDS: bad RGBA masks, pixel format not set\n"); + return; + } + + this->pf.flags = DDPF_RGB; + + if (amask != 0) { + this->pf.flags |= DDPF_ALPHAPIXELS; + } + + if (bitcount == 0) + { + // Compute bit count from the masks. + unsigned int total = rmask | gmask | bmask | amask; + while(total != 0) { + bitcount++; + total >>= 1; + } + // @@ Align to 8? + } + + this->pf.fourcc = 0; + this->pf.bitcount = bitcount; + this->pf.rmask = rmask; + this->pf.gmask = gmask; + this->pf.bmask = bmask; + this->pf.amask = amask; +} + +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); +} +*/ + + +DirectDrawSurface::DirectDrawSurface(unsigned char *mem, unsigned int size) : stream(mem, size), header() +{ + mem_read(stream, header); +} + +DirectDrawSurface::~DirectDrawSurface() +{ +} + +bool DirectDrawSurface::isValid() const +{ + if (header.fourcc != FOURCC_DDS || header.size != 124) + { + return false; + } + + const unsigned int required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT); + if( (header.flags & required) != required ) { + return false; + } + + if (header.pf.size != 32) { + return false; + } + + /* in some files DDSCAPS_TEXTURE is missing: silently ignore */ + /* + if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { + return false; + } + */ + + return true; +} + +bool DirectDrawSurface::isSupported() const +{ + 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) + { + if (header.pf.bitcount == 24) + { + return false; + } + else if (header.pf.bitcount == 32) + { + return false; + } + else + { + // Unsupported pixel format. + return false; + } + } + */ + 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; +} + + +unsigned int DirectDrawSurface::mipmapCount() const +{ + if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount; + else return 0; +} + + +unsigned int DirectDrawSurface::width() const +{ + if (header.flags & DDSD_WIDTH) return header.width; + else return 1; +} + +unsigned int DirectDrawSurface::height() const +{ + if (header.flags & DDSD_HEIGHT) return header.height; + else return 1; +} + +unsigned int DirectDrawSurface::depth() const +{ + if (header.flags & DDSD_DEPTH) return header.depth; + else return 1; +} + +bool DirectDrawSurface::hasAlpha() const +{ + if (header.pf.fourcc == FOURCC_DXT1) return false; + else return true; +} + +bool DirectDrawSurface::isTexture2D() const +{ + return !isTexture3D() && !isTextureCube(); +} + +bool DirectDrawSurface::isTexture3D() const +{ + return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0; +} + +bool DirectDrawSurface::isTextureCube() const +{ + return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0; +} + +void DirectDrawSurface::mipmap(Image * img, unsigned int face, unsigned int mipmap) +{ + stream.seek(offset(face, mipmap)); + + unsigned int w = width(); + unsigned int h = height(); + + // Compute width and height. + for (unsigned int m = 0; m < mipmap; m++) + { + w = max(w/2, 1U); + h = max(h/2, 1U); + } + + 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) +{ + // @@ Read linear RGB images. + printf("DDS: linear RGB images not supported\n"); +} + +void DirectDrawSurface::readBlockImage(Image * img) +{ + const unsigned int w = img->width(); + const unsigned int h = img->height(); + + const unsigned int bw = (w + 3) / 4; + const unsigned int bh = (h + 3) / 4; + + for (unsigned int by = 0; by < bh; by++) + { + for (unsigned int bx = 0; bx < bw; bx++) + { + ColorBlock block; + + // Read color block. + readBlock(&block); + + // Write color block. + for (unsigned int y = 0; y < min(4U, h-4*by); y++) + { + for (unsigned int x = 0; x < min(4U, w-4*bx); x++) + { + img->pixel(4*bx+x, 4*by+y) = block.color(x, y); + } + } + } + } +} + +static Color32 buildNormal(unsigned char x, unsigned char y) +{ + float nx = 2 * (x / 255) - 1; + float ny = 2 * (x / 255) - 1; + float nz = sqrt(1 - nx*nx - ny*ny); + unsigned char z = clamp(int(255 * (nz + 1) / 2), 0, 255); + + return Color32(x, y, z); +} + + +void DirectDrawSurface::readBlock(ColorBlock * rgba) +{ + if (header.pf.fourcc == FOURCC_DXT1) + { + BlockDXT1 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_DXT2 || + header.pf.fourcc == FOURCC_DXT3) + { + BlockDXT3 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_DXT4 || + header.pf.fourcc == FOURCC_DXT5 || + header.pf.fourcc == FOURCC_RXGB) + { + BlockDXT5 block; + mem_read(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); + unsigned int tmp = c.r; + c.r = c.a; + c.a = tmp; + } + } + } + else if (header.pf.fourcc == FOURCC_ATI1) + { + BlockATI1 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + else if (header.pf.fourcc == FOURCC_ATI2) + { + BlockATI2 block; + mem_read(stream, block); + block.decodeBlock(rgba); + } + + // If normal flag set, convert to normal. + if (header.pf.flags & DDPF_NORMAL) + { + if (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.g, c.a); + } + } + } +} + + +unsigned int 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; +} + +unsigned int DirectDrawSurface::mipmapSize(unsigned int mipmap) const +{ + unsigned int w = width(); + unsigned int h = height(); + unsigned int d = depth(); + + for (unsigned int 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 if (header.pf.flags & DDPF_RGB) + { + // Align pixels to bytes. + unsigned int byteCount = (header.pf.bitcount + 7) / 8; + + // Align pitch to 4 bytes. + unsigned int pitch = 4 * ((w * byteCount + 3) / 4); + + return pitch * h * d; + } + else { + printf("DDS: mipmap format not supported\n"); + return(0); + }; +} + +unsigned int DirectDrawSurface::faceSize() const +{ + const unsigned int count = mipmapCount(); + unsigned int size = 0; + + for (unsigned int m = 0; m < count; m++) + { + size += mipmapSize(m); + } + + return size; +} + +unsigned int DirectDrawSurface::offset(const unsigned int face, const unsigned int mipmap) +{ + unsigned int size = sizeof(DDSHeader); + + if (face != 0) + { + size += face * faceSize(); + } + + for (unsigned int m = 0; m < mipmap; m++) + { + size += mipmapSize(m); + } + + return size; +} + + +void DirectDrawSurface::printInfo() const +{ + /* printf("FOURCC: %c%c%c%c\n", ((unsigned char *)&header.fourcc)[0], ((unsigned char *)&header.fourcc)[1], ((unsigned char *)&header.fourcc)[2], ((unsigned char *)&header.fourcc)[3]); */ + 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("\tSize: %d\n", header.pf.size); */ + 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.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/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h new file mode 100644 index 00000000000..2b3319d05a1 --- /dev/null +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h @@ -0,0 +1,162 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// 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 _DDS_DIRECTDRAWSURFACE_H +#define _DDS_DIRECTDRAWSURFACE_H + +#include +#include +#include + +struct DDSPixelFormat { + unsigned int size; + unsigned int flags; + unsigned int fourcc; + unsigned int bitcount; + unsigned int rmask; + unsigned int gmask; + unsigned int bmask; + unsigned int amask; +}; + +struct DDSCaps { + unsigned int caps1; + unsigned int caps2; + unsigned int caps3; + unsigned int caps4; +}; + +/// DDS file header. +struct DDSHeader { + unsigned int fourcc; + unsigned int size; + unsigned int flags; + unsigned int height; + unsigned int width; + unsigned int pitch; + unsigned int depth; + unsigned int mipmapcount; + unsigned int reserved[11]; + DDSPixelFormat pf; + DDSCaps caps; + unsigned int notused; + + // Helper methods. + DDSHeader(); + + void setWidth(unsigned int w); + void setHeight(unsigned int h); + void setDepth(unsigned int d); + void setMipmapCount(unsigned int count); + void setTexture2D(); + void setTexture3D(); + void setTextureCube(); + void setLinearSize(unsigned int size); + void setPitch(unsigned int pitch); + void setFourCC(unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3); + void setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask); + void setNormalFlag(bool b); + + /* void swapBytes(); */ +}; + +/// DirectDraw Surface. (DDS) +class DirectDrawSurface +{ +public: + DirectDrawSurface(unsigned char *mem, unsigned int size); + ~DirectDrawSurface(); + + bool isValid() const; + bool isSupported() const; + + unsigned int mipmapCount() const; + unsigned int width() const; + unsigned int height() const; + unsigned int depth() const; + bool isTexture2D() const; + bool isTexture3D() const; + bool isTextureCube() const; + bool hasAlpha() const; /* false for DXT1, true for all others */ + + void mipmap(Image * img, unsigned int f, unsigned int m); + + void printInfo() const; + +private: + + unsigned int blockSize() const; + unsigned int faceSize() const; + unsigned int mipmapSize(unsigned int m) const; + + unsigned int offset(unsigned int f, unsigned int m); + + void readLinearImage(Image * img); + void readBlockImage(Image * img); + void readBlock(ColorBlock * rgba); + + +private: + Stream stream; // memory where DDS file resides + DDSHeader header; +}; + +void mem_read(Stream & mem, DDSPixelFormat & pf); +void mem_read(Stream & mem, DDSCaps & caps); +void mem_read(Stream & mem, DDSHeader & header); + +#endif // _DDS_DIRECTDRAWSURFACE_H diff --git a/source/blender/imbuf/intern/dds/Image.cpp b/source/blender/imbuf/intern/dds/Image.cpp new file mode 100644 index 00000000000..f3e6fa38955 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Image.cpp @@ -0,0 +1,132 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#include +#include + +#include // printf + +Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(0) +{ +} + +Image::~Image() +{ + free(); +} + +void Image::allocate(unsigned int w, unsigned int h) +{ + free(); + m_width = w; + m_height = h; + m_data = new Color32[w * h]; +} + +void Image::free() +{ + if (m_data) delete [] m_data; + m_data = 0; +} + + +unsigned int Image::width() const +{ + return m_width; +} + +unsigned int Image::height() const +{ + return m_height; +} + +const Color32 * Image::scanline(unsigned int h) const +{ + if (h >= m_height) { + printf("DDS: scanline beyond dimensions of image"); + return m_data; + } + return m_data + h * m_width; +} + +Color32 * Image::scanline(unsigned int h) +{ + if (h >= m_height) { + printf("DDS: scanline beyond dimensions of image"); + return m_data; + } + return m_data + h * m_width; +} + +const Color32 * Image::pixels() const +{ + return m_data; +} + +Color32 * Image::pixels() +{ + return m_data; +} + +const Color32 & Image::pixel(unsigned int idx) const +{ + if (idx >= m_width * m_height) { + printf("DDS: pixel beyond dimensions of image"); + return m_data[0]; + } + return m_data[idx]; +} + +Color32 & Image::pixel(unsigned int idx) +{ + if (idx >= m_width * m_height) { + printf("DDS: pixel beyond dimensions of image"); + return m_data[0]; + } + return m_data[idx]; +} + + +Image::Format Image::format() const +{ + return m_format; +} + +void Image::setFormat(Image::Format f) +{ + m_format = f; +} + diff --git a/source/blender/imbuf/intern/dds/Image.h b/source/blender/imbuf/intern/dds/Image.h new file mode 100644 index 00000000000..10356774777 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Image.h @@ -0,0 +1,103 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + * This file is based on a similar file from the NVIDIA texture tools + * (http://nvidia-texture-tools.googlecode.com/) + * + * Original license from NVIDIA follows. + */ + +// This code is in the public domain -- castanyo@yahoo.es + +#ifndef _DDS_IMAGE_H +#define _DDS_IMAGE_H + +#include + +/// 32 bit RGBA image. +class Image +{ +public: + + enum Format + { + Format_RGB, + Format_ARGB, + }; + + Image(); + ~Image(); + + void allocate(unsigned int w, unsigned int h); + /* + bool load(const char * name); + + void wrap(void * data, unsigned int w, unsigned int h); + void unwrap(); + */ + + unsigned int width() const; + unsigned int height() const; + + const Color32 * scanline(unsigned int h) const; + Color32 * scanline(unsigned int h); + + const Color32 * pixels() const; + Color32 * pixels(); + + const Color32 & pixel(unsigned int idx) const; + Color32 & pixel(unsigned int idx); + + const Color32 & pixel(unsigned int x, unsigned int y) const; + Color32 & pixel(unsigned int x, unsigned int y); + + Format format() const; + void setFormat(Format f); + +private: + void free(); + +private: + unsigned int m_width; + unsigned int m_height; + Format m_format; + Color32 * m_data; +}; + + +inline const Color32 & Image::pixel(unsigned int x, unsigned int y) const +{ + return pixel(y * width() + x); +} + +inline Color32 & Image::pixel(unsigned int x, unsigned int y) +{ + return pixel(y * width() + x); +} + +#endif // _DDS_IMAGE_H diff --git a/source/blender/imbuf/intern/dds/Makefile b/source/blender/imbuf/intern/dds/Makefile new file mode 100644 index 00000000000..2bab1de1fc4 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Makefile @@ -0,0 +1,67 @@ +# +# $Id: Makefile 7037 2006-03-12 14:11:23Z ton $ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = dds +DIR = $(OCGDIR)/blender/imbuf/dds +SOURCEDIR = source/blender/imbuf/intern/dds + +include nan_compile.mk +include nan_definitions.mk + +ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris windows")) + CFLAGS += -funsigned-char +endif + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I$(NAN_JPEG)/include +CPPFLAGS += -I$(NAN_PNG)/include +CPPFLAGS += -I$(NAN_ZLIB)/include +CPPFLAGS += -I$(NAN_TIFF)/include +CPPFLAGS += -I../../../include +CPPFLAGS += -I../../../blenkernel +CPPFLAGS += -I../../../blenlib +CPPFLAGS += -I../../../avi +CPPFLAGS += -I../../../quicktime +# path to the guarded memory allocator +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +# This is not really needed, but until /include is cleaned, it must be +# there for proper compilation. +# - No, it is also needed in antialias, for listbase (nzc) +CPPFLAGS += -I../../../makesdna +# external interface of this module +CPPFLAGS += -I../.. +CPPFLAGS += -I.. +CPPFLAGS += -I. +CPPFLAGS += -DWITH_DDS diff --git a/source/blender/imbuf/intern/dds/SConscript b/source/blender/imbuf/intern/dds/SConscript new file mode 100644 index 00000000000..0618e32b3c6 --- /dev/null +++ b/source/blender/imbuf/intern/dds/SConscript @@ -0,0 +1,18 @@ +#!/usr/bin/python +Import ('env') + +source_files = ['dds_api.cpp', 'DirectDrawSurface.cpp', 'Stream.cpp', 'BlockDXT.cpp', 'ColorBlock.cpp', 'Image.cpp'] + +incs = ['.', + '../../', + '..', + '../../../makesdna', + '../../../blenkernel', + '../../../blenlib', + 'intern/include', + '#/intern/guardedalloc'] + + +defs = [] + +env.BlenderLib ('bf_dds', source_files, incs, defs, libtype=['core','player'], priority = [90, 200]) diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp new file mode 100644 index 00000000000..a181ec74476 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Stream.cpp @@ -0,0 +1,88 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include // printf +#include // memcpy + +unsigned int Stream::seek(unsigned int p) +{ + if (p > size) { + printf("DDS: trying to seek beyond end of stream (corrupt file?)"); + } + else { + pos = p; + } + + return pos; +} + +unsigned int mem_read(Stream & mem, unsigned long long & i) +{ + if (mem.pos + 8 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(&i, mem.mem + mem.pos, 8); // @@ todo: make sure little endian + mem.pos += 8; + return(8); +} + +unsigned int mem_read(Stream & mem, unsigned int & i) +{ + if (mem.pos + 4 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(&i, mem.mem + mem.pos, 4); // @@ todo: make sure little endian + mem.pos += 4; + return(4); +} + +unsigned int mem_read(Stream & mem, unsigned short & i) +{ + if (mem.pos + 2 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(&i, mem.mem + mem.pos, 2); // @@ todo: make sure little endian + mem.pos += 2; + return(2); +} + +unsigned int mem_read(Stream & mem, unsigned char & i) +{ + if (mem.pos + 1 > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + i = (mem.mem + mem.pos)[0]; + mem.pos += 1; + return(1); +} + diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h new file mode 100644 index 00000000000..1e7d3c6b536 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Stream.h @@ -0,0 +1,48 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* simple memory stream functions with buffer overflow check */ + +#ifndef _STREAM_H +#define _STREAM_H + +struct Stream +{ + unsigned char *mem; // location in memory + unsigned int size; // size + unsigned int pos; // current position + Stream(unsigned char *m, unsigned int s) : mem(m), size(s), pos(0) {}; + unsigned int seek(unsigned int p); +}; + +unsigned int mem_read(Stream & mem, unsigned long long & i); +unsigned int mem_read(Stream & mem, unsigned int & i); +unsigned int mem_read(Stream & mem, unsigned short & i); +unsigned int mem_read(Stream & mem, unsigned char & i); + +#endif // _STREAM_H + diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp new file mode 100644 index 00000000000..0e06fd3e50b --- /dev/null +++ b/source/blender/imbuf/intern/dds/dds_api.cpp @@ -0,0 +1,120 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include // printf + +extern "C" { + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" + +/* not supported yet +short imb_save_dds(struct ImBuf * ibuf, char *name, int flags) +{ + return(0); +} +*/ + +int imb_is_a_dds(unsigned char *mem) // note: use at most first 32 bytes +{ + /* heuristic check to see if mem contains a DDS file */ + /* header.fourcc == FOURCC_DDS */ + if ((mem[0] != 'D') || (mem[1] != 'D') || (mem[2] != 'S') || (mem[3] != ' ')) return(0); + /* header.size == 124 */ + if ((mem[4] != 124) || mem[5] || mem[6] || mem[7]) return(0); + return(1); +} + +struct ImBuf *imb_load_dds(unsigned char *mem, int size, int flags) +{ + struct ImBuf * ibuf = 0; + DirectDrawSurface dds(mem, size); /* reads header */ + unsigned char bytes_per_pixel; + unsigned int *rect; + Image img; + unsigned int numpixels = 0; + int col; + unsigned char *cp = (unsigned char *) &col; + Color32 pixel; + Color32 *pixels = 0; + + /* check if DDS is valid and supported */ + if (!dds.isValid()) { + printf("DDS: not valid; header follows\n"); + dds.printInfo(); + return(0); + } + if (!dds.isSupported()) { + printf("DDS: format not supported\n"); + return(0); + } + if ((dds.width() > 65535) || (dds.height() > 65535)) { + printf("DDS: dimensions too large\n"); + return(0); + } + + /* convert DDS into ImBuf */ + if (dds.hasAlpha()) bytes_per_pixel = 32; + else bytes_per_pixel = 24; + ibuf = IMB_allocImBuf(dds.width(), dds.height(), bytes_per_pixel, 0, 0); + if (ibuf == 0) return(0); /* memory allocation failed */ + + ibuf->ftype = DDS; + + if ((flags & IB_test) == 0) { + if (!imb_addrectImBuf(ibuf)) return(ibuf); + if (ibuf->rect == 0) return(ibuf); + + rect = ibuf->rect; + dds.mipmap(&img, 0, 0); /* load first face, first mipmap */ + pixels = img.pixels(); + numpixels = dds.width() * dds.height(); + cp[3] = 0xff; /* default alpha if alpha channel is not present */ + + for (unsigned int i = 0; i < numpixels; i++) { + pixel = pixels[i]; + cp[0] = pixel.r; /* set R component of col */ + cp[1] = pixel.g; /* set G component of col */ + cp[2] = pixel.b; /* set B component of col */ + if (bytes_per_pixel == 32) + cp[3] = pixel.a; /* set A component of col */ + rect[i] = col; + } + IMB_flipy(ibuf); + } + + return(ibuf); +} + +} // extern "C" diff --git a/source/blender/imbuf/intern/dds/dds_api.h b/source/blender/imbuf/intern/dds/dds_api.h new file mode 100644 index 00000000000..8a0f966dd68 --- /dev/null +++ b/source/blender/imbuf/intern/dds/dds_api.h @@ -0,0 +1,43 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Amorilia (amorilia@gamebox.net) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef _DDS_API_H +#define _DDS_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +short imb_save_dds(struct ImBuf *ibuf, char *name, int flags); +int imb_is_a_dds(unsigned char *mem); /* use only first 32 bytes of mem */ +struct ImBuf *imb_load_dds(unsigned char *mem, int size, int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* __DDS_API_H */ diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index bfa6200d23b..c5901ccad90 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -59,6 +59,10 @@ #include "openexr/openexr_api.h" #endif +#ifdef WITH_DDS +#include "dds/dds_api.h" +#endif + #ifdef WITH_QUICKTIME #if defined(_WIN32) || defined (__APPLE__) #include "quicktime_import.h" @@ -153,6 +157,11 @@ ImBuf *IMB_ibImageFromMemory(int *mem, int size, int flags) { ibuf = imb_load_openexr((uchar *)mem, size, flags); if (ibuf) return (ibuf); #endif + +#ifdef WITH_DDS + ibuf = imb_load_dds((uchar *)mem, size, flags); + if (ibuf) return (ibuf); +#endif #ifdef WITH_QUICKTIME #if defined(_WIN32) || defined (__APPLE__) diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 69390951a25..4c7b5fec2c4 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -44,6 +44,11 @@ #include "IMB_targa.h" #include "IMB_png.h" + +#ifdef WITH_DDS +#include "dds/dds_api.h" +#endif + #include "IMB_bmp.h" #include "IMB_tiff.h" #include "IMB_radiance_hdr.h" @@ -113,6 +118,9 @@ static int IMB_ispic_name(char *name) } if (imb_is_a_png(buf)) return(PNG); +#ifdef WITH_DDS + if (imb_is_a_dds((uchar *)buf)) return(DDS); +#endif if (imb_is_a_targa(buf)) return(TGA); #ifdef WITH_OPENEXR if (imb_is_a_openexr((uchar *)buf)) return(OPENEXR); @@ -162,6 +170,9 @@ int IMB_ispic(char *filename) || BLI_testextensie(filename, ".rgb") || BLI_testextensie(filename, ".bmp") || BLI_testextensie(filename, ".png") +#ifdef WITH_DDS + || BLI_testextensie(filename, ".dds") +#endif || BLI_testextensie(filename, ".iff") || BLI_testextensie(filename, ".lbm") || BLI_testextensie(filename, ".gif") @@ -188,6 +199,9 @@ int IMB_ispic(char *filename) || BLI_testextensie(filename, ".bmp") || BLI_testextensie(filename, ".png") || BLI_testextensie(filename, ".cin") +#ifdef WITH_DDS + || BLI_testextensie(filename, ".dds") +#endif #ifdef WITH_BF_OPENEXR || BLI_testextensie(filename, ".exr") #endif @@ -251,6 +265,7 @@ static int isffmpeg (char *filename) { if( BLI_testextensie(filename, ".swf") || BLI_testextensie(filename, ".jpg") || BLI_testextensie(filename, ".png") || + BLI_testextensie(filename, ".dds") || BLI_testextensie(filename, ".tga") || BLI_testextensie(filename, ".bmp") || BLI_testextensie(filename, ".exr") || diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c index 2e922c65827..ccca8e9f859 100644 --- a/source/blender/imbuf/intern/writeimage.c +++ b/source/blender/imbuf/intern/writeimage.c @@ -61,6 +61,9 @@ #ifdef WITH_OPENEXR #include "openexr/openexr_api.h" #endif +#ifdef WITH_DDS +#include "dds/dds_api.h" +#endif #include "IMB_iff.h" #include "IMB_bitplanes.h" @@ -115,6 +118,13 @@ short IMB_saveiff(struct ImBuf *ibuf, char *name, int flags) return imb_save_openexr(ibuf, name, flags); } #endif +/* not supported yet +#ifdef WITH_DDS + if (IS_dds(ibuf)) { + return imb_save_dds(ibuf, name, flags); + } +#endif +*/ if (IS_cineon(ibuf)) { return imb_savecineon(ibuf, name, flags); -- cgit v1.2.3