diff options
Diffstat (limited to 'kernel/kls_dds')
-rw-r--r-- | kernel/kls_dds/Makefile.am | 9 | ||||
-rw-r--r-- | kernel/kls_dds/dds.cpp | 1066 | ||||
-rw-r--r-- | kernel/kls_dds/dds.h | 36 | ||||
-rw-r--r-- | kernel/kls_dds/fmt_codec_dds.cpp | 143 | ||||
-rw-r--r-- | kernel/kls_dds/fmt_codec_dds_defs.h | 27 |
5 files changed, 1281 insertions, 0 deletions
diff --git a/kernel/kls_dds/Makefile.am b/kernel/kls_dds/Makefile.am new file mode 100644 index 0000000..753dfb6 --- /dev/null +++ b/kernel/kls_dds/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I../include + +pkglib_LTLIBRARIES = libkls_dds.la + +libkls_dds_la_SOURCES = fmt_codec_dds.cpp fmt_codec_dds_defs.h dds.cpp + +libkls_dds_la_LDFLAGS = ${SQ_RELEASE} + +libkls_dds_la_LIBADD = ${SQ_LOCAL_RPATH} diff --git a/kernel/kls_dds/dds.cpp b/kernel/kls_dds/dds.cpp new file mode 100644 index 0000000..c5551f0 --- /dev/null +++ b/kernel/kls_dds/dds.cpp @@ -0,0 +1,1066 @@ +/* + * (C) 2007 Dmitry Baryshev, KSquirrel project + */ + +/* This file is part of the KDE project + Copyright (C) 2003 Ignacio Casta�o <castano@ludicon.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of the Lesser GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + Almost all this code is based on nVidia's DDS-loading example + and the DevIl's source code by Denton Woods. +*/ + +/* this code supports: + * reading: + * rgb and dxt dds files + * cubemap dds files + * volume dds files -- TODO + * writing: + * rgb dds files only -- TODO + */ + +#include <cmath> // sqrtf +#include <fstream> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "ksquirrel-libs/fileio.h" +#include "ksquirrel-libs/fmt_types.h" +#include "ksquirrel-libs/fmt_defs.h" + +#include "dds.h" + +#ifndef __USE_ISOC99 +#define sqrtf(x) ((float)sqrt(x)) +#endif + +typedef u32 uint; +typedef u16 ushort; +typedef u8 uchar; + +typedef RGBA* RGBAP; + +namespace { // Private. + +static bool MALLOC_ROWS(RGBAP **A, const int RB, const int H) +{ + *A = (RGBAP *)malloc(H * sizeof(RGBA*)); + + if(!*A) + return false; + + for(s32 row = 0; row < H; row++) + (*A)[row] = 0; + + for(s32 row = 0; row < (s32)H; row++) + { + (*A)[row] = (RGBA *)malloc(RB); + + if(!(*A)[row]) + return false; + + memset((*A)[row], 0, RB); + } + + return true; +} +/* +static void FREE_ROWS(RGBAP **A, const int H) +{ + if(*A) + { + for(s32 i = 0;i < H;i++) + { + if((*A)[i]) + free((*A)[i]); + } + + free(*A); + *A = 0; + } +} +*/ +#if !defined(MAKEFOURCC) +# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \ + (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 )) +#endif + +//#ifdef max +#undef max +#define max(a,b) ((a)>(b)?(a):(b)) +//#endif + +#define HORIZONTAL 1 +#define VERTICAL 2 +#define CUBE_LAYOUT HORIZONTAL + + struct Color8888 + { + uchar r, g, b, a; + }; + + union Color565 + { + struct { + ushort b : 5; + ushort g : 6; + ushort r : 5; + } c; + ushort u; + }; + + union Color1555 { + struct { + ushort b : 5; + ushort g : 5; + ushort r : 5; + ushort a : 1; + } c; + ushort u; + }; + + union Color4444 { + struct { + ushort b : 4; + ushort g : 4; + ushort r : 4; + ushort a : 4; + } c; + ushort u; + }; + + + static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); + static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); + static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); + static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); + static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); + static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); + static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); + static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); + + static const uint DDSD_CAPS = 0x00000001l; + static const uint DDSD_PIXELFORMAT = 0x00001000l; + static const uint DDSD_WIDTH = 0x00000004l; + static const uint DDSD_HEIGHT = 0x00000002l; + static const uint DDSD_PITCH = 0x00000008l; + + static const uint DDSCAPS_TEXTURE = 0x00001000l; + static const uint DDSCAPS2_VOLUME = 0x00200000l; + static const uint DDSCAPS2_CUBEMAP = 0x00000200l; + + static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400l; + static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800l; + static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000l; + static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000l; + static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000l; + static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000l; + + static const uint DDPF_RGB = 0x00000040l; + static const uint DDPF_FOURCC = 0x00000004l; + static const uint DDPF_ALPHAPIXELS = 0x00000001l; + + enum DDSType { + DDS_A8R8G8B8 = 0, + DDS_A1R5G5B5 = 1, + DDS_A4R4G4B4 = 2, + DDS_R8G8B8 = 3, + DDS_R5G6B5 = 4, + DDS_DXT1 = 5, + DDS_DXT2 = 6, + DDS_DXT3 = 7, + DDS_DXT4 = 8, + DDS_DXT5 = 9, + DDS_RXGB = 10, + DDS_ATI2 = 11, + DDS_UNKNOWN + }; + + + struct DDSPixelFormat { + uint size; + uint flags; + uint fourcc; + uint bitcount; + uint rmask; + uint gmask; + uint bmask; + uint amask; + }; + + static ifstreamK & operator>> ( ifstreamK & s, DDSPixelFormat & pf ) + { + s.readK(&pf.size, sizeof(pf.size)); + s.readK(&pf.flags, sizeof(pf.flags)); + s.readK(&pf.fourcc, sizeof(pf.fourcc)); + s.readK(&pf.bitcount, sizeof(pf.bitcount)); + s.readK(&pf.rmask, sizeof(pf.rmask)); + s.readK(&pf.gmask, sizeof(pf.gmask)); + s.readK(&pf.bmask, sizeof(pf.bmask)); + s.readK(&pf.amask, sizeof(pf.amask)); + + return s; + } + + struct DDSCaps { + uint caps1; + uint caps2; + uint caps3; + uint caps4; + }; + + static ifstreamK & operator>> ( ifstreamK & s, DDSCaps & caps ) + { + s.readK(&caps.caps1, sizeof(caps.caps1)); + s.readK(&caps.caps2, sizeof(caps.caps2)); + s.readK(&caps.caps3, sizeof(caps.caps3)); + s.readK(&caps.caps4, sizeof(caps.caps4)); + + return s; + } + + struct DDSHeader { + uint size; + uint flags; + uint height; + uint width; + uint pitch; + uint depth; + uint mipmapcount; + uint reserved[11]; + DDSPixelFormat pf; + DDSCaps caps; + uint notused; + }; + + static ifstreamK & operator>> ( ifstreamK & s, DDSHeader & header ) + { + s.readK(&header.size, sizeof(header.size)); + s.readK(&header.flags, sizeof(header.flags)); + s.readK(&header.height, sizeof(header.height)); + s.readK(&header.width, sizeof(header.width)); + s.readK(&header.pitch, sizeof(header.pitch)); + s.readK(&header.depth, sizeof(header.depth)); + s.readK(&header.mipmapcount, sizeof(header.mipmapcount)); + + for( int i = 0; i < 11; i++ ) + { + s.readK(&header.reserved[i], sizeof(header.reserved[i])); + } + + s >> header.pf; + s >> header.caps; + + s.readK(&header.notused, sizeof(header.notused)); + + return s; + } + + static bool IsValid( const DDSHeader & header ) + { + if( header.size != 124 || !header.width || !header.height) { + return false; + } + + const uint required = (DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT); + + if( (header.flags & required) != required ) { + return false; + } + if( header.pf.size != 32 ) { + return false; + } + if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { + return false; + } + return true; + } + + // Get supported type. We currently support 10 different types. + static DDSType GetType( const DDSHeader & header ) + { + if( header.pf.flags & DDPF_RGB ) { + if( header.pf.flags & DDPF_ALPHAPIXELS ) { + switch( header.pf.bitcount ) { + case 16: + return (header.pf.amask == 0x7000) ? DDS_A1R5G5B5 : DDS_A4R4G4B4; + case 32: + return DDS_A8R8G8B8; + } + } + else { + switch( header.pf.bitcount ) { + case 16: + return DDS_R5G6B5; + case 24: + return DDS_R8G8B8; + } + } + } + else if( header.pf.flags & DDPF_FOURCC ) { + switch( header.pf.fourcc ) { + case FOURCC_DXT1: + return DDS_DXT1; + case FOURCC_DXT2: + return DDS_DXT2; + case FOURCC_DXT3: + return DDS_DXT3; + case FOURCC_DXT4: + return DDS_DXT4; + case FOURCC_DXT5: + return DDS_DXT5; + case FOURCC_RXGB: + return DDS_RXGB; + case FOURCC_ATI2: + return DDS_ATI2; + } + } + return DDS_UNKNOWN; + } + + static bool IsCubeMap( const DDSHeader & header ) + { + return header.caps.caps2 & DDSCAPS2_CUBEMAP; + } + + static bool IsSupported( const DDSHeader & header ) + { + if( header.caps.caps2 & DDSCAPS2_VOLUME ) { + return false; + } + if( GetType(header) == DDS_UNKNOWN ) { + return false; + } + return true; + } + + static bool LoadA8R8G8B8( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + for( uint y = 0; y < h; y++ ) { + RGBA *scanline = img[y]; + for( uint x = 0; x < w; x++ ) { + uchar r, g, b, a; + + s.readK(&b, sizeof(b)); + s.readK(&g, sizeof(g)); + s.readK(&r, sizeof(r)); + s.readK(&a, sizeof(a)); + + scanline[x] = RGBA(r, g, b, a); + } + } + + return true; + } + + static bool LoadR8G8B8( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + for( uint y = 0; y < h; y++ ) { + RGBA * scanline = img[y]; + for( uint x = 0; x < w; x++ ) + { + uchar r, g, b; + + s.readK(&b, sizeof(b)); + s.readK(&g, sizeof(g)); + s.readK(&r, sizeof(r)); + + scanline[x] = RGBA(r, g, b, 255); + } + } + + return true; + } + + static bool LoadA1R5G5B5( ifstreamK & s, const DDSHeader & header, RGBA **img ) + { + const uint w = header.width; + const uint h = header.height; + + for( uint y = 0; y < h; y++ ) { + RGBA * scanline = img[y]; + for( uint x = 0; x < w; x++ ) { + Color1555 color; + s.readK(&color.u, sizeof(color.u)); + uchar a = (color.c.a != 0) ? 0xFF : 0; + uchar r = (color.c.r << 3) | (color.c.r >> 2); + uchar g = (color.c.g << 3) | (color.c.g >> 2); + uchar b = (color.c.b << 3) | (color.c.b >> 2); + scanline[x] = RGBA(r, g, b, a); + } + } + + return true; + } + + static bool LoadA4R4G4B4( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + for( uint y = 0; y < h; y++ ) { + RGBA * scanline = img[y]; + for( uint x = 0; x < w; x++ ) { + Color4444 color; + s.readK(&color.u, sizeof(color.u)); + uchar a = (color.c.a << 4) | color.c.a; + uchar r = (color.c.r << 4) | color.c.r; + uchar g = (color.c.g << 4) | color.c.g; + uchar b = (color.c.b << 4) | color.c.b; + scanline[x] = RGBA(r, g, b, a); + } + } + + return true; + } + + static bool LoadR5G6B5( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + for( uint y = 0; y < h; y++ ) { + RGBA * scanline = img[y]; + for( uint x = 0; x < w; x++ ) { + Color565 color; + s.readK(&color.u, sizeof(color.u)); + uchar r = (color.c.r << 3) | (color.c.r >> 2); + uchar g = (color.c.g << 2) | (color.c.g >> 4); + uchar b = (color.c.b << 3) | (color.c.b >> 2); + scanline[x] = RGBA(r, g, b, 255); + } + } + + return true; + } + + static ifstreamK & operator>> ( ifstreamK & s, Color565 & c ) + { + s.readK(&c.u, sizeof(c.u)); + + return s; + } + + struct BlockDXT + { + Color565 col0; + Color565 col1; + uchar row[4]; + + void GetColors( Color8888 color_array[4] ) + { + color_array[0].r = (col0.c.r << 3) | (col0.c.r >> 2); + color_array[0].g = (col0.c.g << 2) | (col0.c.g >> 4); + color_array[0].b = (col0.c.b << 3) | (col0.c.b >> 2); + color_array[0].a = 0xFF; + + color_array[1].r = (col1.c.r << 3) | (col1.c.r >> 2); + color_array[1].g = (col1.c.g << 2) | (col1.c.g >> 4); + color_array[1].b = (col1.c.b << 3) | (col1.c.b >> 2); + color_array[1].a = 0xFF; + + 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; + } + 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; + } + } + }; + + static ifstreamK & operator>> ( ifstreamK & s, BlockDXT & c ) + { + s >> c.col0 >> c.col1; + + s.readK(&c.row[0], sizeof(uchar)); + s.readK(&c.row[1], sizeof(uchar)); + s.readK(&c.row[2], sizeof(uchar)); + s.readK(&c.row[3], sizeof(uchar)); + + return s; + } + + struct BlockDXTAlphaExplicit { + ushort row[4]; + }; + + static ifstreamK & operator>> ( ifstreamK & s, BlockDXTAlphaExplicit & c ) + { + s.readK(&c.row[0], sizeof(ushort)); + s.readK(&c.row[1], sizeof(ushort)); + s.readK(&c.row[2], sizeof(ushort)); + s.readK(&c.row[3], sizeof(ushort)); + + return s; + } + + struct BlockDXTAlphaLinear { + uchar alpha0; + uchar alpha1; + uchar bits[6]; + + void GetAlphas( uchar alpha_array[8] ) + { + alpha_array[0] = alpha0; + alpha_array[1] = alpha1; + + // 8-alpha or 6-alpha block? + if( alpha_array[0] > alpha_array[1] ) + { + // 8-alpha block: derive the other 6 alphas. + // 000 = alpha_0, 001 = alpha_1, others are interpolated + + alpha_array[2] = ( 6 * alpha0 + alpha1) / 7; // bit code 010 + alpha_array[3] = ( 5 * alpha0 + 2 * alpha1) / 7; // Bit code 011 + alpha_array[4] = ( 4 * alpha0 + 3 * alpha1) / 7; // Bit code 100 + alpha_array[5] = ( 3 * alpha0 + 4 * alpha1) / 7; // Bit code 101 + alpha_array[6] = ( 2 * alpha0 + 5 * alpha1) / 7; // Bit code 110 + alpha_array[7] = ( alpha0 + 6 * alpha1) / 7; // Bit code 111 + } + else + { + // 6-alpha block: derive the other alphas. + // 000 = alpha_0, 001 = alpha_1, others are interpolated + + alpha_array[2] = (4 * alpha0 + alpha1) / 5; // Bit code 010 + alpha_array[3] = (3 * alpha0 + 2 * alpha1) / 5; // Bit code 011 + alpha_array[4] = (2 * alpha0 + 3 * alpha1) / 5; // Bit code 100 + alpha_array[5] = ( alpha0 + 4 * alpha1) / 5; // Bit code 101 + alpha_array[6] = 0x00; // Bit code 110 + alpha_array[7] = 0xFF; // Bit code 111 + } + } + + void GetBits( uchar bit_array[16] ) + { + uint b = (uint &) bits[0]; + bit_array[0] = uchar(b & 0x07); b >>= 3; + bit_array[1] = uchar(b & 0x07); b >>= 3; + bit_array[2] = uchar(b & 0x07); b >>= 3; + bit_array[3] = uchar(b & 0x07); b >>= 3; + bit_array[4] = uchar(b & 0x07); b >>= 3; + bit_array[5] = uchar(b & 0x07); b >>= 3; + bit_array[6] = uchar(b & 0x07); b >>= 3; + bit_array[7] = uchar(b & 0x07); b >>= 3; + + b = (uint &) bits[3]; + bit_array[8] = uchar(b & 0x07); b >>= 3; + bit_array[9] = uchar(b & 0x07); b >>= 3; + bit_array[10] = uchar(b & 0x07); b >>= 3; + bit_array[11] = uchar(b & 0x07); b >>= 3; + bit_array[12] = uchar(b & 0x07); b >>= 3; + bit_array[13] = uchar(b & 0x07); b >>= 3; + bit_array[14] = uchar(b & 0x07); b >>= 3; + bit_array[15] = uchar(b & 0x07); b >>= 3; + } + }; + + static ifstreamK & operator>> ( ifstreamK & s, BlockDXTAlphaLinear & c ) + { + s.readK(&c.alpha0, sizeof(c.alpha0)); + s.readK(&c.alpha1, sizeof(c.alpha1)); + + s.readK(&c.bits[0], sizeof(uchar)); + s.readK(&c.bits[1], sizeof(uchar)); + s.readK(&c.bits[2], sizeof(uchar)); + s.readK(&c.bits[3], sizeof(uchar)); + s.readK(&c.bits[4], sizeof(uchar)); + s.readK(&c.bits[5], sizeof(uchar)); + + return s; + } + + static bool LoadDXT1( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + BlockDXT block; + RGBA * scanline[4]; + + for( uint y = 0; y < h; y += 4 ) { + for( uint j = 0; j < 4; j++ ) { + scanline[j] = img[y + j]; + } + + for( uint x = 0; x < w; x += 4 ) { + + // Read 64bit color block. + s >> block; + + // Decode color block. + Color8888 color_array[4]; + block.GetColors(color_array); + + // bit masks = 00000011, 00001100, 00110000, 11000000 + const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; + const int shift[4] = { 0, 2, 4, 6 }; + + // Write color block. + for( uint j = 0; j < 4; j++ ) { + for( uint i = 0; i < 4; i++ ) { + /*if( img.valid( x+i, y+j ) ) */{ + + uint idx = (block.row[j] & masks[i]) >> shift[i]; + scanline[j][x+i] = RGBA(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a); + } + } + } + } + } + + return true; + } + + static bool LoadDXT3( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + BlockDXT block; + BlockDXTAlphaExplicit alpha; + RGBA * scanline[4]; + + for( uint y = 0; y < h; y += 4 ) { + for( uint j = 0; j < 4; j++ ) { + scanline[j] = img[y + j]; + } + for( uint x = 0; x < w; x += 4 ) { + + // Read 128bit color block. + s >> alpha; + s >> block; + + // Decode color block. + Color8888 color_array[4]; + block.GetColors(color_array); + + // bit masks = 00000011, 00001100, 00110000, 11000000 + const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; + const int shift[4] = { 0, 2, 4, 6 }; + + // Write color block. + for( uint j = 0; j < 4; j++ ) { + ushort a = alpha.row[j]; + for( uint i = 0; i < 4; i++ ) { + /*if( img.valid( x+i, y+j ) ) */{ + uint idx = (block.row[j] & masks[i]) >> shift[i]; + color_array[idx].a = a & 0x0f; + color_array[idx].a = color_array[idx].a | (color_array[idx].a << 4); + scanline[j][x+i] = RGBA(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a); + } + a >>= 4; + } + } + } + } + return true; + } + + static bool LoadDXT2( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + if( !LoadDXT3(s, header, img) ) return false; + //UndoPremultiplyAlpha(img); + return true; + } + + static bool LoadDXT5( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + BlockDXT block; + BlockDXTAlphaLinear alpha; + RGBA * scanline[4]; + + for( uint y = 0; y < h; y += 4 ) { + for( uint j = 0; j < 4; j++ ) { + scanline[j] = img[y + j]; + } + for( uint x = 0; x < w; x += 4 ) { + + // Read 128bit color block. + s >> alpha; + s >> block; + + // Decode color block. + Color8888 color_array[4]; + block.GetColors(color_array); + + uchar alpha_array[8]; + alpha.GetAlphas(alpha_array); + + uchar bit_array[16]; + alpha.GetBits(bit_array); + + // bit masks = 00000011, 00001100, 00110000, 11000000 + const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; + const int shift[4] = { 0, 2, 4, 6 }; + + // Write color block. + for( uint j = 0; j < 4; j++ ) { + for( uint i = 0; i < 4; i++ ) { + /*if( img.valid( x+i, y+j ) ) */{ + uint idx = (block.row[j] & masks[i]) >> shift[i]; + color_array[idx].a = alpha_array[bit_array[j*4+i]]; + scanline[j][x+i] = RGBA(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a); + } + } + } + } + } + + return true; + } + static bool LoadDXT4( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + if( !LoadDXT5(s, header, img) ) return false; + //UndoPremultiplyAlpha(img); + return true; + } + + static bool LoadRXGB( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + BlockDXT block; + BlockDXTAlphaLinear alpha; + RGBA * scanline[4]; + + for( uint y = 0; y < h; y += 4 ) { + for( uint j = 0; j < 4; j++ ) { + scanline[j] = img[y + j]; + } + for( uint x = 0; x < w; x += 4 ) { + + // Read 128bit color block. + s >> alpha; + s >> block; + + // Decode color block. + Color8888 color_array[4]; + block.GetColors(color_array); + + uchar alpha_array[8]; + alpha.GetAlphas(alpha_array); + + uchar bit_array[16]; + alpha.GetBits(bit_array); + + // bit masks = 00000011, 00001100, 00110000, 11000000 + const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; + const int shift[4] = { 0, 2, 4, 6 }; + + // Write color block. + for( uint j = 0; j < 4; j++ ) { + for( uint i = 0; i < 4; i++ ) { + /*if( img.valid( x+i, y+j ) ) */{ + uint idx = (block.row[j] & masks[i]) >> shift[i]; + color_array[idx].a = alpha_array[bit_array[j*4+i]]; + scanline[j][x+i] = RGBA(color_array[idx].a, color_array[idx].g, color_array[idx].b, 255); + } + } + } + } + } + + return true; + } + + static bool LoadATI2( ifstreamK & s, const DDSHeader & header, RGBA **img) + { + const uint w = header.width; + const uint h = header.height; + + BlockDXTAlphaLinear xblock; + BlockDXTAlphaLinear yblock; + RGBA * scanline[4]; + + for( uint y = 0; y < h; y += 4 ) { + for( uint j = 0; j < 4; j++ ) { + scanline[j] = img[y + j]; + } + for( uint x = 0; x < w; x += 4 ) { + + // Read 128bit color block. + s >> xblock; + s >> yblock; + + // Decode color block. + uchar xblock_array[8]; + xblock.GetAlphas(xblock_array); + + uchar xbit_array[16]; + xblock.GetBits(xbit_array); + + uchar yblock_array[8]; + yblock.GetAlphas(yblock_array); + + uchar ybit_array[16]; + yblock.GetBits(ybit_array); + + // Write color block. + for( uint j = 0; j < 4; j++ ) { + for( uint i = 0; i < 4; i++ ) { + /*if( img.valid( x+i, y+j ) ) */{ + const uchar nx = xblock_array[xbit_array[j*4+i]]; + const uchar ny = yblock_array[ybit_array[j*4+i]]; + + const float fx = float(nx) / 127.5f - 1.0f; + const float fy = float(ny) / 127.5f - 1.0f; + const float fz = sqrtf(1.0f - fx*fx - fy*fy); + const uchar nz = uchar((fz + 1.0f) * 127.5f); + + scanline[j][x+i] = RGBA(nx, ny, nz, 255); + } + } + } + } + } + + return true; + } + + typedef bool (* TextureLoader)( ifstreamK & s, const DDSHeader & header, RGBA **); + + // Get an appropiate texture loader for the given type. + static TextureLoader GetTextureLoader( DDSType type ) { + switch( type ) { + case DDS_A8R8G8B8: + return LoadA8R8G8B8; + case DDS_A1R5G5B5: + return LoadA1R5G5B5; + case DDS_A4R4G4B4: + return LoadA4R4G4B4; + case DDS_R8G8B8: + return LoadR8G8B8; + case DDS_R5G6B5: + return LoadR5G6B5; + case DDS_DXT1: + return LoadDXT1; + case DDS_DXT2: + return LoadDXT2; + case DDS_DXT3: + return LoadDXT3; + case DDS_DXT4: + return LoadDXT4; + case DDS_DXT5: + return LoadDXT5; + case DDS_RXGB: + return LoadRXGB; + case DDS_ATI2: + return LoadATI2; + default: + return NULL; + }; + } + + + // Load a 2d texture. + static bool LoadTexture( ifstreamK & s, const DDSHeader & header, RGBA ***img) + { + if(!MALLOC_ROWS(img, header.width * sizeof(RGBA), header.height)) + return false; + + // Read image. + DDSType type = GetType( header ); + + TextureLoader loader = GetTextureLoader( type ); + if( loader == NULL ) { + return false; + } + + return loader( s, header, *img ); + } + + + static int FaceOffset( const DDSHeader & header ) { + + DDSType type = GetType( header ); + + int mipmap = max(header.mipmapcount, 1); + int size = 0; + int w = header.width; + int h = header.height; + + if( type >= DDS_DXT1 ) { + int multiplier = (type == DDS_DXT1) ? 8 : 16; + do { + int face_size = max(w/4,1) * max(h/4,1) * multiplier; + size += face_size; + w >>= 1; + h >>= 1; + } while( --mipmap ); + } + else { + int multiplier = header.pf.bitcount / 8; + do { + int face_size = w * h * multiplier; + size += face_size; + w = max( w>>1, 1 ); + h = max( h>>1, 1 ); + } while( --mipmap ); + } + + return size; + } + +#if CUBE_LAYOUT == HORIZONTAL + static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} }; +#elif CUBE_LAYOUT == VERTICAL + static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {1, 3} }; +#endif + static int face_flags[6] = { + DDSCAPS2_CUBEMAP_POSITIVEX, + DDSCAPS2_CUBEMAP_NEGATIVEX, + DDSCAPS2_CUBEMAP_POSITIVEY, + DDSCAPS2_CUBEMAP_NEGATIVEY, + DDSCAPS2_CUBEMAP_POSITIVEZ, + DDSCAPS2_CUBEMAP_NEGATIVEZ + }; + + // Load unwrapped cube map. + static bool LoadCubeMap( ifstreamK & s, const DDSHeader & header, RGBA ***img) + { + int dimw = 0, dimh = 0; +#if CUBE_LAYOUT == HORIZONTAL + dimw = 4 * header.width; + dimh = 3 * header.height; +#elif CUBE_LAYOUT == VERTICAL + dimw = 3 * header.width; + dimh = 4 * header.height; +#endif + + if(!MALLOC_ROWS(img, dimw * sizeof(RGBA), dimh)) + return false; + + // Create dst image. + + DDSType type = GetType( header ); + + // Select texture loader. + TextureLoader loader = GetTextureLoader( type ); + if( loader == NULL ) { + return false; + } + + RGBA **face; + if(!MALLOC_ROWS(&face, header.width * sizeof(RGBA), header.height)) + return false; + + // Create face image. + int offset = s.tellg(); + int size = FaceOffset( header ); + + for( int i = 0; i < 6; i++ ) { + + if( !(header.caps.caps2 & face_flags[i]) ) { + // Skip face. + continue; + } + + // Seek device. + s.seekg(offset); + offset += size; + + // Load face from stream. + if( !loader( s, header, face ) ) { + return false; + } + +#if CUBE_LAYOUT == VERTICAL + if( i == 5 ) { +// face = face.mirror(true, true); + } +#endif + + // Compute face offsets. + int offset_x = face_offset[i][0] * header.width; + int offset_y = face_offset[i][1] * header.height; + + // Copy face on the image. + for( uint y = 0; y < header.height; y++ ) + { + RGBA * src = face[y]; + RGBA * dst = (*img)[y + offset_y] + offset_x; + memcpy( dst, src, sizeof(RGBA) * header.width ); + } + } + + return true; + } + +} + +bool dds_read(const std::string &file, DDSINFO &dds) +{ + ifstreamK s; + s.open(file.c_str(), std::ios::binary | std::ios::in); + + if(!s.good()) + return false; + + // Validate header. + uint fourcc; + s.readK(&fourcc, sizeof(uint)); + + if(fourcc != FOURCC_DDS) + return false; + + // Read image header. + DDSHeader header; + s >> header; + + // Check image file format. + if(!s.good() || !IsValid(header) || !IsSupported(header)) + return false; + + RGBA **img = 0; + bool result; + + if(IsCubeMap(header)) + result = LoadCubeMap(s, header, &img); + else + result = LoadTexture(s, header, &img); + + if(result) + { + dds.w = header.width; + dds.h = header.height; + dds.img = img; + } + + return result; +} diff --git a/kernel/kls_dds/dds.h b/kernel/kls_dds/dds.h new file mode 100644 index 0000000..5e7af28 --- /dev/null +++ b/kernel/kls_dds/dds.h @@ -0,0 +1,36 @@ +/* This file is part of ksquirrel-libs (http://ksquirrel.sf.net) + + Copyright (c) 2007 Dmitry Baryshev <ksquirrel@tut.by> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later + version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef DDS_H +#define DDS_H + +struct RGBA; +struct DDSINFO; + +struct DDSINFO +{ + int w, h; + RGBA **img; +}; + +bool dds_read(const std::string &file, DDSINFO&); + +#endif diff --git a/kernel/kls_dds/fmt_codec_dds.cpp b/kernel/kls_dds/fmt_codec_dds.cpp new file mode 100644 index 0000000..305c207 --- /dev/null +++ b/kernel/kls_dds/fmt_codec_dds.cpp @@ -0,0 +1,143 @@ +/* This file is part of ksquirrel-libs (http://ksquirrel.sf.net) + + Copyright (c) 2007 Dmitry Baryshev <ksquirrel@tut.by> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later + version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <iostream> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "ksquirrel-libs/fmt_types.h" +#include "ksquirrel-libs/fileio.h" + +#include "fmt_codec_dds_defs.h" +#include "fmt_codec_dds.h" + +#include "ksquirrel-libs/error.h" +#include "ksquirrel-libs/fmt_utils.h" + +#include "../xpm/codec_dds.xpm" + +typedef RGBA* RGBAP; + +inline void FREE_ROWS(RGBAP **A, const int H) +{ + if(*A) + { + for(s32 i = 0;i < H;i++) + { + if((*A)[i]) + free((*A)[i]); + } + + free(*A); + *A = 0; + } +} + +/* + * + * DDS + * + */ + +fmt_codec::fmt_codec() : fmt_codec_base() +{} + +fmt_codec::~fmt_codec() +{} + +void fmt_codec::options(codec_options *o) +{ + o->version = "0.1.0"; + o->name = "DirectDraw Surface"; + o->filter = "*.dds "; + o->mime = ""; + o->mimetype = "image/x-dds"; + o->config = ""; + o->pixmap = codec_dds; + o->readable = true; + o->canbemultiple = false; + o->writestatic = false; + o->writeanimated = false; + o->needtempfile = false; +} + +s32 fmt_codec::read_init(const std::string &file) +{ + currentImage = -1; + read_error = false; + + finfo.animated = false; + + dds.img = 0; + dds.w = dds.h = 0; + + if(!dds_read(file, dds)) + return SQE_R_BADFILE; + + return SQE_OK; +} + +s32 fmt_codec::read_next() +{ + currentImage++; + + if(currentImage) + return SQE_NOTOK; + + fmt_image image; + + image.w = dds.w; + image.h = dds.h; + image.bpp = 32; + + image.compression = "-"; + image.colorspace = fmt_utils::colorSpaceByBpp(32); + + finfo.image.push_back(image); + line = -1; + + return SQE_OK; +} + +s32 fmt_codec::read_next_pass() +{ + return SQE_OK; +} + +s32 fmt_codec::read_scanline(RGBA *scan) +{ + line++; + + memcpy(scan, dds.img[line], dds.w * sizeof(RGBA)); + + return SQE_OK; +} + +void fmt_codec::read_close() +{ + FREE_ROWS(&dds.img, dds.h); + + finfo.meta.clear(); + finfo.image.clear(); +} + +#include "fmt_codec_cd_func.h" diff --git a/kernel/kls_dds/fmt_codec_dds_defs.h b/kernel/kls_dds/fmt_codec_dds_defs.h new file mode 100644 index 0000000..182687c --- /dev/null +++ b/kernel/kls_dds/fmt_codec_dds_defs.h @@ -0,0 +1,27 @@ +/* This file is part of ksquirrel-libs (http://ksquirrel.sf.net) + + Copyright (c) 2007 Dmitry Baryshev <ksquirrel@tut.by> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later + version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KSQUIRREL_CODEC_DEFS_dds +#define KSQUIRREL_CODEC_DEFS_dds + +// define constants here + +#endif |