summaryrefslogtreecommitdiffstats
path: root/kernel/kls_dds
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kls_dds')
-rw-r--r--kernel/kls_dds/Makefile.am9
-rw-r--r--kernel/kls_dds/dds.cpp1066
-rw-r--r--kernel/kls_dds/dds.h36
-rw-r--r--kernel/kls_dds/fmt_codec_dds.cpp143
-rw-r--r--kernel/kls_dds/fmt_codec_dds_defs.h27
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