diff options
Diffstat (limited to 'source/blender/imbuf/intern')
53 files changed, 6038 insertions, 242 deletions
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 602b13df4ca..f3514a92ae4 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -81,6 +81,7 @@ #ifdef WITH_FFMPEG #include <ffmpeg/avformat.h> #include <ffmpeg/avcodec.h> +#include <ffmpeg/swscale.h> #endif #include "IMB_imbuf_types.h" @@ -181,7 +182,8 @@ struct anim { AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrameRGB; - AVFrame *pFrame; + AVFrame *pFrame; + struct SwsContext *img_convert_ctx; int videoStream; #endif diff --git a/source/blender/imbuf/intern/IMB_imginfo.h b/source/blender/imbuf/intern/IMB_imginfo.h new file mode 100644 index 00000000000..e82cc5f32af --- /dev/null +++ b/source/blender/imbuf/intern/IMB_imginfo.h @@ -0,0 +1,85 @@ +/** + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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) 2005 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Austin Benesh. Ton Roosendaal. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef _IMB_IMGINFO_H +#define _IMB_IMGINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct ImBuf; + +typedef struct ImgInfo { + struct ImgInfo *next, *prev; + char* key; + char* value; + int len; +} ImgInfo; + +/** The imginfo is a list of key/value pairs (both char*) that can me + saved in the header of several image formats. + Apart from some common keys like + 'Software' and 'Description' (png standard) we'll use keys within the + Blender namespace, so should be called 'Blender::StampInfo' or 'Blender::FrameNum' + etc... +*/ + + +/* free blender ImgInfo struct */ +void IMB_imginfo_free(struct ImBuf* img); + +/** read the field from the image info into the field + * @param img - the ImBuf that contains the image data + * @param key - the key of the field + * @param value - the data in the field, first one found with key is returned, + memory has to be allocated by user. + * @param len - length of value buffer allocated by user. + * @return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise + */ +int IMB_imginfo_get_field(struct ImBuf* img, const char* key, char* value, int len); + +/** set user data in the ImgInfo struct, which has to be allocated with IMB_imginfo_create + * before calling this function. + * @param img - the ImBuf that contains the image data + * @param key - the key of the field + * @param value - the data to be written to the field. zero terminated string + * @return - 1 (true) if ImageInfo present, 0 (false) otherwise + */ +int IMB_imginfo_add_field(struct ImBuf* img, const char* key, const char* field); + +/** delete the key/field par in the ImgInfo struct. + * @param img - the ImBuf that contains the image data + * @param key - the key of the field + * @return - 1 (true) if delete the key/field, 0 (false) otherwise + */ +int IMB_imginfo_del_field(struct ImBuf *img, const char *key); + +#endif /* _IMB_IMGINFO_H */ + diff --git a/source/blender/imbuf/intern/IMB_jpeg.h b/source/blender/imbuf/intern/IMB_jpeg.h index 4a86a72ca77..f78810d27ee 100644 --- a/source/blender/imbuf/intern/IMB_jpeg.h +++ b/source/blender/imbuf/intern/IMB_jpeg.h @@ -45,7 +45,7 @@ struct jpeg_compress_struct; int imb_is_a_jpeg(unsigned char *mem); int imb_savejpeg(struct ImBuf * ibuf, char * name, int flags); -struct ImBuf * imb_ibJpegImageFromFilename (char * filename, int flags); +struct ImBuf * imb_ibJpegImageFromFilename (const char * filename, int flags); struct ImBuf * imb_ibJpegImageFromMemory (unsigned char * buffer, int size, int flags); #endif diff --git a/source/blender/imbuf/intern/Makefile b/source/blender/imbuf/intern/Makefile index f51844aad96..09eb487b3a6 100644 --- a/source/blender/imbuf/intern/Makefile +++ b/source/blender/imbuf/intern/Makefile @@ -46,9 +46,9 @@ ifeq ($(WITH_OPENEXR), true) CFLAGS += -DWITH_OPENEXR endif - -ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris windows")) - CFLAGS += -funsigned-char +ifeq ($(WITH_DDS), true) + DIRS += dds + CPPFLAGS += -DWITH_DDS endif CFLAGS += $(LEVEL_1_C_WARNINGS) @@ -80,4 +80,3 @@ ifeq ($(WITH_FFMPEG), true) CPPFLAGS += -DWITH_FFMPEG CPPFLAGS += $(NAN_FFMPEGCFLAGS) endif - diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 003d377389b..bc750e455a6 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -43,6 +43,7 @@ #include "IMB_divers.h" #include "IMB_allocimbuf.h" +#include "IMB_imginfo.h" #include "MEM_CacheLimiterC-Api.h" static unsigned int dfltcmap[16] = { @@ -163,6 +164,7 @@ void IMB_freeImBuf(struct ImBuf * ibuf) IMB_freecmapImBuf(ibuf); freeencodedbufferImBuf(ibuf); IMB_cache_limiter_unmanage(ibuf); + IMB_imginfo_free(ibuf); MEM_freeN(ibuf); } } @@ -278,6 +280,7 @@ short imb_addrectfloatImBuf(struct ImBuf * ibuf) size = ibuf->x * ibuf->y; size = size * 4 * sizeof(float); + ibuf->channels= 4; if ( (ibuf->rect_float = MEM_mapallocN(size, "imb_addrectfloatImBuf")) ){ ibuf->mall |= IB_rectfloat; @@ -443,7 +446,7 @@ struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1) memcpy(ibuf2->rect, ibuf1->rect, x * y * sizeof(int)); if (flags & IB_rectfloat) - memcpy(ibuf2->rect_float, ibuf1->rect_float, 4 * x * y * sizeof(float)); + memcpy(ibuf2->rect_float, ibuf1->rect_float, ibuf1->channels * x * y * sizeof(float)); if (flags & IB_planes) memcpy(*(ibuf2->planes),*(ibuf1->planes),ibuf1->depth * ibuf1->skipx * y * sizeof(int)); @@ -476,6 +479,9 @@ struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1) tbuf.mall = ibuf2->mall; tbuf.c_handle = 0; + // for now don't duplicate image info + tbuf.img_info = 0; + *ibuf2 = tbuf; if (ibuf1->cmap){ diff --git a/source/blender/imbuf/intern/anim.c b/source/blender/imbuf/intern/anim.c index a1ef735ffdb..1700790c4fa 100644 --- a/source/blender/imbuf/intern/anim.c +++ b/source/blender/imbuf/intern/anim.c @@ -89,6 +89,7 @@ #include <ffmpeg/avformat.h> #include <ffmpeg/avcodec.h> #include <ffmpeg/rational.h> +#include <ffmpeg/swscale.h> #if LIBAVFORMAT_VERSION_INT < (49 << 16) #define FFMPEG_OLD_FRAME_RATE 1 @@ -338,12 +339,12 @@ void IMB_close_anim(struct anim * anim) { } -struct anim * IMB_open_anim(char * name, int ib_flags) { +struct anim * IMB_open_anim( const char * name, int ib_flags) { struct anim * anim; anim = (struct anim*)MEM_callocN(sizeof(struct anim), "anim struct"); if (anim != NULL) { - strcpy(anim->name, name); + strcpy(anim->name, name); /* fixme: possible buffer overflow here? */ anim->ib_flags = ib_flags; } return(anim); @@ -593,7 +594,7 @@ static int startffmpeg(struct anim * anim) { anim->pFrame = avcodec_alloc_frame(); anim->pFrameRGB = avcodec_alloc_frame(); - if (avpicture_get_size(PIX_FMT_RGBA32, anim->x, anim->y) + if (avpicture_get_size(PIX_FMT_BGR32, anim->x, anim->y) != anim->x * anim->y * 4) { fprintf (stderr, "ffmpeg has changed alloc scheme ... ARGHHH!\n"); @@ -609,7 +610,17 @@ static int startffmpeg(struct anim * anim) { } else { anim->preseek = 0; } - + + anim->img_convert_ctx = sws_getContext( + anim->pCodecCtx->width, + anim->pCodecCtx->height, + anim->pCodecCtx->pix_fmt, + anim->pCodecCtx->width, + anim->pCodecCtx->height, + PIX_FMT_BGR32, + SWS_FAST_BILINEAR | SWS_PRINT_INFO, + NULL, NULL, NULL); + return (0); } @@ -626,7 +637,7 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { avpicture_fill((AVPicture *)anim->pFrameRGB, (unsigned char*) ibuf->rect, - PIX_FMT_RGBA32, anim->x, anim->y); + PIX_FMT_BGR32, anim->x, anim->y); if (position != anim->curposition + 1) { if (position > anim->curposition + 1 @@ -703,36 +714,98 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { } if(frameFinished && pos_found == 1) { - unsigned char * p =(unsigned char*) ibuf->rect; - unsigned char * e = p + anim->x * anim->y * 4; - - img_convert((AVPicture *)anim->pFrameRGB, - PIX_FMT_RGBA32, - (AVPicture*)anim->pFrame, - anim->pCodecCtx->pix_fmt, - anim->pCodecCtx->width, - anim->pCodecCtx->height); - IMB_flipy(ibuf); - if (G.order == L_ENDIAN) { - /* BGRA -> RGBA */ - while (p != e) { - unsigned char a = p[0]; - p[0] = p[2]; - p[2] = a; - p += 4; + if (G.order == B_ENDIAN) { + int * dstStride + = anim->pFrameRGB->linesize; + uint8_t** dst = anim->pFrameRGB->data; + int dstStride2[4] + = { dstStride[0], 0, 0, 0 }; + uint8_t* dst2[4]= { + dst[0], 0, 0, 0 }; + int x,y,h,w; + unsigned char* bottom; + unsigned char* top; + + sws_scale(anim->img_convert_ctx, + anim->pFrame->data, + anim->pFrame->linesize, + 0, + anim->pCodecCtx->height, + dst2, + dstStride2); + + /* workaround: sws_scale + sets alpha = 0 and compensate + for altivec-bugs and flipy... */ + + bottom = (unsigned char*) ibuf->rect; + top = bottom + + ibuf->x * (ibuf->y-1) * 4; + + h = (ibuf->y + 1) / 2; + w = ibuf->x; + + for (y = 0; y < h; y++) { + unsigned char tmp[4]; + unsigned long * tmp_l = + (unsigned long*) tmp; + tmp[3] = 0xff; + + for (x = 0; x < w; x++) { + tmp[0] = bottom[3]; + tmp[1] = bottom[2]; + tmp[2] = bottom[1]; + + bottom[0] = top[3]; + bottom[1] = top[2]; + bottom[2] = top[1]; + bottom[3] = 0xff; + + *(unsigned long*) top + = *tmp_l; + + bottom +=4; + top += 4; + } + top -= 8 * w; } + + av_free_packet(&packet); + break; } else { - /* ARGB -> RGBA */ - while (p != e) { - unsigned long a = - *(unsigned long*) p; - a = (a << 8) | p[0]; - *(unsigned long*) p = a; - p += 4; + int * dstStride + = anim->pFrameRGB->linesize; + uint8_t** dst = anim->pFrameRGB->data; + int dstStride2[4] + = { -dstStride[0], 0, 0, 0 }; + uint8_t* dst2[4]= { + dst[0] + + (anim->y - 1)*dstStride[0], + 0, 0, 0 }; + int i; + unsigned char* r; + + sws_scale(anim->img_convert_ctx, + anim->pFrame->data, + anim->pFrame->linesize, + 0, + anim->pCodecCtx->height, + dst2, + dstStride2); + + /* workaround: sws_scale + sets alpha = 0... */ + + r = (unsigned char*) ibuf->rect; + + for (i = 0; i < ibuf->x * ibuf->y;i++){ + r[3] = 0xff; + r+=4; } + + av_free_packet(&packet); + break; } - av_free_packet(&packet); - break; } } @@ -750,6 +823,7 @@ static void free_anim_ffmpeg(struct anim * anim) { av_close_input_file(anim->pFormatCtx); av_free(anim->pFrameRGB); av_free(anim->pFrame); + sws_freeContext(anim->img_convert_ctx); } anim->duration = 0; } @@ -819,6 +893,18 @@ static struct ImBuf * anim_getnew(struct anim * anim) { return(ibuf); } +struct ImBuf * IMB_anim_previewframe(struct anim * anim) { + struct ImBuf * ibuf = 0; + int position = 0; + + ibuf = IMB_anim_absolute(anim, 0); + if (ibuf) { + IMB_freeImBuf(ibuf); + position = anim->duration / 2; + ibuf = IMB_anim_absolute(anim, position); + } + return ibuf; +} struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) { struct ImBuf * ibuf = 0; diff --git a/source/blender/imbuf/intern/cineon/Makefile b/source/blender/imbuf/intern/cineon/Makefile index 596a6647093..e61c8dd59ed 100644 --- a/source/blender/imbuf/intern/cineon/Makefile +++ b/source/blender/imbuf/intern/cineon/Makefile @@ -38,10 +38,6 @@ SOURCEDIR = source/blender/imbuf/intern/cineon 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 diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index 691b81745e0..f00f6bc38c5 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -42,14 +42,29 @@ #include "MEM_guardedalloc.h" +/* ugly bad level, should be fixed */ +#include "DNA_scene_types.h" +#include "BKE_global.h" + +static void cineon_conversion_parameters(LogImageByteConversionParameters *params) +{ + params->blackPoint = G.scene->r.cineonblack; + params->whitePoint = G.scene->r.cineonwhite; + params->gamma = G.scene->r.cineongamma; + params->doLogarithm = G.scene->r.subimtype & R_CINEON_LOG; +} + static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, int use_cineon, int size, int flags) { + LogImageByteConversionParameters conversion; ImBuf *ibuf; LogImageFile *image; int x, y; unsigned short *row, *upix; int width, height, depth; float *frow; + + cineon_conversion_parameters(&conversion); image = logImageOpenFromMem(mem, size, use_cineon); @@ -70,6 +85,8 @@ static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, int use_cineon, int return NULL; } + logImageSetByteConversion(image, &conversion); + ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat | flags, 0); row = MEM_mallocN(sizeof(unsigned short)*width*depth, "row in cineon_dpx.c"); @@ -107,10 +124,9 @@ static int imb_save_dpx_cineon(ImBuf *buf, char *filename, int use_cineon, int f int i, j; int index; float *fline; - - conversion.blackPoint = 95; - conversion.whitePoint = 685; - conversion.gamma = 1; + + cineon_conversion_parameters(&conversion); + /* * Get the drawable for the current image... */ diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index 20f4e0d4de4..3b45a9de822 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -350,8 +350,10 @@ cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y) { /* extract required pixels */ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { - /* row[pixelIndex] = cineon->lut10[cineon->pixelBuffer[pixelIndex]]; */ - row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6; + if(cineon->params.doLogarithm) + row[pixelIndex] = cineon->lut10_16[cineon->pixelBuffer[pixelIndex]]; + else + row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6; } return 0; @@ -367,8 +369,10 @@ cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y) { /* put new pixels into pixelBuffer */ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { - /* cineon->pixelBuffer[pixelIndex] = cineon->lut8[row[pixelIndex]]; */ - cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6; + if(cineon->params.doLogarithm) + cineon->pixelBuffer[pixelIndex] = cineon->lut16_16[row[pixelIndex]]; + else + cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6; } /* pack into longwords */ diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index b769d1e6132..a81e632a797 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -199,7 +199,7 @@ dumpDpxMainHeader(DpxMainHeader* header) { #endif } -static int verbose = 0; +static int verbose = 1; void dpxSetVerbose(int verbosity) { verbose = verbosity; @@ -275,8 +275,10 @@ dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y) { /* extract required pixels */ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { - /* row[pixelIndex] = dpx->lut10[dpx->pixelBuffer[pixelIndex]]; */ - row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6; + if(dpx->params.doLogarithm) + row[pixelIndex] = dpx->lut10_16[dpx->pixelBuffer[pixelIndex]]; + else + row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6; } /* save remaining pixels */ @@ -316,8 +318,10 @@ dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y) { /* put new pixels into pixelBuffer */ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { - /* dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut8[row[pixelIndex]]; */ - dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6; + if(dpx->params.doLogarithm) + dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut16_16[row[pixelIndex]]; + else + dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6; } dpx->pixelBufferUsed += numPixels; diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c index e88e9241443..6032f342ed8 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.c +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -93,6 +93,35 @@ setupLut(LogImageFile *logImage) { } } +/* set up the 10 bit to 16 bit and 16 bit to 10 bit tables */ +void +setupLut16(LogImageFile *logImage) { + + int i; + double f_black; + double scale; + + f_black = convertTo(logImage->params.blackPoint, logImage->params.whitePoint, logImage->params.gamma); + scale = 65535.0 / (1.0 - f_black); + + for (i = 0; i <= logImage->params.blackPoint; ++i) { + logImage->lut10_16[i] = 0; + } + for (; i < logImage->params.whitePoint; ++i) { + double f_i; + f_i = convertTo(i, logImage->params.whitePoint, logImage->params.gamma); + logImage->lut10_16[i] = (int)rint(scale * (f_i - f_black)); + } + for (; i < 1024; ++i) { + logImage->lut10_16[i] = 65535; + } + + for (i = 0; i < 65536; ++i) { + double f_i = f_black + (i / 65535.0) * (1.0 - f_black); + logImage->lut16_16[i] = convertFrom(f_i, logImage->params.whitePoint, logImage->params.gamma); + } +} + /* how many longwords to hold this many pixels? */ int pixelsToLongs(int numPixels) { diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h index 1af18d5e3b8..01eff8d570d 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.h +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -71,6 +71,9 @@ struct _Log_Image_File_t_ unsigned char lut10[1024]; unsigned short lut8[256]; + unsigned short lut10_16[1024]; + unsigned short lut16_16[65536]; + /* pixel access functions */ GetRowFn* getRow; SetRowFn* setRow; @@ -82,6 +85,7 @@ struct _Log_Image_File_t_ }; void setupLut(LogImageFile*); +void setupLut16(LogImageFile*); int pixelsToLongs(int numPixels); diff --git a/source/blender/imbuf/intern/cineon/logImageLib.c b/source/blender/imbuf/intern/cineon/logImageLib.c index ff209d5ebd0..2fc52959ff6 100644 --- a/source/blender/imbuf/intern/cineon/logImageLib.c +++ b/source/blender/imbuf/intern/cineon/logImageLib.c @@ -89,6 +89,7 @@ logImageGetByteConversionDefaults(LogImageByteConversionParameters* params) { params->gamma = DEFAULT_GAMMA; params->blackPoint = DEFAULT_BLACK_POINT; params->whitePoint = DEFAULT_WHITE_POINT; + params->doLogarithm = 0; return 0; } @@ -97,6 +98,7 @@ logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionPa params->gamma = logImage->params.gamma; params->blackPoint = logImage->params.blackPoint; params->whitePoint = logImage->params.whitePoint; + params->doLogarithm = 0; return 0; } @@ -110,7 +112,8 @@ logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionPa logImage->params.gamma = params->gamma; logImage->params.blackPoint = params->blackPoint; logImage->params.whitePoint = params->whitePoint; - setupLut(logImage); + logImage->params.doLogarithm = params->doLogarithm; + setupLut16(logImage); return 0; } return 1; diff --git a/source/blender/imbuf/intern/cineon/logImageLib.h b/source/blender/imbuf/intern/cineon/logImageLib.h index ea45c675fe2..617da1d0d92 100644 --- a/source/blender/imbuf/intern/cineon/logImageLib.h +++ b/source/blender/imbuf/intern/cineon/logImageLib.h @@ -47,6 +47,7 @@ typedef struct { float gamma; int blackPoint; int whitePoint; + int doLogarithm; } LogImageByteConversionParameters; /* int functions return 0 for OK */ diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp new file mode 100644 index 00000000000..24a090d93f6 --- /dev/null +++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp @@ -0,0 +1,591 @@ +/** + * $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 <icastano@nvidia.com> +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <Common.h> +#include <Stream.h> +#include <ColorBlock.h> +#include <BlockDXT.h> + +/*---------------------------------------------------------------------------- + BlockDXT1 +----------------------------------------------------------------------------*/ + +uint BlockDXT1::evaluatePalette(Color32 color_array[4]) const +{ + // Does bit expansion before interpolation. + color_array[0].b = (col0.b << 3) | (col0.b >> 2); + color_array[0].g = (col0.g << 2) | (col0.g >> 4); + color_array[0].r = (col0.r << 3) | (col0.r >> 2); + color_array[0].a = 0xFF; + + // @@ Same as above, but faster? +// Color32 c; +// c.u = ((col0.u << 3) & 0xf8) | ((col0.u << 5) & 0xfc00) | ((col0.u << 8) & 0xf80000); +// c.u |= (c.u >> 5) & 0x070007; +// c.u |= (c.u >> 6) & 0x000300; +// color_array[0].u = c.u; + + color_array[1].r = (col1.r << 3) | (col1.r >> 2); + color_array[1].g = (col1.g << 2) | (col1.g >> 4); + color_array[1].b = (col1.b << 3) | (col1.b >> 2); + color_array[1].a = 0xFF; + + // @@ Same as above, but faster? +// c.u = ((col1.u << 3) & 0xf8) | ((col1.u << 5) & 0xfc00) | ((col1.u << 8) & 0xf80000); +// c.u |= (c.u >> 5) & 0x070007; +// c.u |= (c.u >> 6) & 0x000300; +// color_array[1].u = c.u; + + if( col0.u > col1.u ) { + // Four-color block: derive the other two colors. + color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3; + color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3; + color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3; + color_array[2].a = 0xFF; + + color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3; + color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3; + color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3; + color_array[3].a = 0xFF; + + return 4; + } + 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( uint j = 0; j < 4; j++ ) { + for( uint i = 0; i < 4; i++ ) { + uint idx = (row[j] >> (2 * i)) & 3; + block->color(i, j) = color_array[idx]; + } + } +} + +void BlockDXT1::setIndices(int * idx) +{ + indices = 0; + for(uint i = 0; i < 16; i++) { + indices |= (idx[i] & 3) << (2 * i); + } +} + + +/// Flip DXT1 block vertically. +inline void BlockDXT1::flip4() +{ + swap(row[0], row[3]); + swap(row[1], row[2]); +} + +/// Flip half DXT1 block vertically. +inline void BlockDXT1::flip2() +{ + swap(row[0], row[1]); +} + + +/*---------------------------------------------------------------------------- + BlockDXT3 +----------------------------------------------------------------------------*/ + +void BlockDXT3::decodeBlock(ColorBlock * block) const +{ + // 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() +{ + swap(row[0], row[3]); + swap(row[1], row[2]); +} + +/// Flip half DXT3 alpha block vertically. +void AlphaBlockDXT3::flip2() +{ + swap(row[0], row[1]); +} + +/// Flip DXT3 block vertically. +void BlockDXT3::flip4() +{ + alpha.flip4(); + color.flip4(); +} + +/// Flip half DXT3 block vertically. +void BlockDXT3::flip2() +{ + alpha.flip2(); + color.flip2(); +} + + +/*---------------------------------------------------------------------------- + BlockDXT5 +----------------------------------------------------------------------------*/ + +void AlphaBlockDXT5::evaluatePalette(uint8 alpha[8]) const +{ + if (alpha0 > alpha1) { + evaluatePalette8(alpha); + } + else { + evaluatePalette6(alpha); + } +} + +void AlphaBlockDXT5::evaluatePalette8(uint8 alpha[8]) const +{ + // 8-alpha block: derive the other six alphas. + // Bit code 000 = alpha0, 001 = alpha1, others are interpolated. + alpha[0] = alpha0; + alpha[1] = alpha1; + alpha[2] = (6 * alpha[0] + 1 * alpha[1]) / 7; // bit code 010 + alpha[3] = (5 * alpha[0] + 2 * alpha[1]) / 7; // bit code 011 + alpha[4] = (4 * alpha[0] + 3 * alpha[1]) / 7; // bit code 100 + alpha[5] = (3 * alpha[0] + 4 * alpha[1]) / 7; // bit code 101 + alpha[6] = (2 * alpha[0] + 5 * alpha[1]) / 7; // bit code 110 + alpha[7] = (1 * alpha[0] + 6 * alpha[1]) / 7; // bit code 111 +} + +void AlphaBlockDXT5::evaluatePalette6(uint8 alpha[8]) const +{ + // 6-alpha block. + // Bit code 000 = alpha0, 001 = alpha1, others are interpolated. + alpha[0] = alpha0; + alpha[1] = alpha1; + alpha[2] = (4 * alpha[0] + 1 * alpha[1]) / 5; // Bit code 010 + alpha[3] = (3 * alpha[0] + 2 * alpha[1]) / 5; // Bit code 011 + alpha[4] = (2 * alpha[0] + 3 * alpha[1]) / 5; // Bit code 100 + alpha[5] = (1 * alpha[0] + 4 * alpha[1]) / 5; // Bit code 101 + alpha[6] = 0x00; // Bit code 110 + alpha[7] = 0xFF; // Bit code 111 +} + +void AlphaBlockDXT5::indices(uint8 index_array[16]) const +{ + index_array[0x0] = bits0; + index_array[0x1] = bits1; + index_array[0x2] = bits2; + index_array[0x3] = bits3; + index_array[0x4] = bits4; + index_array[0x5] = bits5; + index_array[0x6] = bits6; + index_array[0x7] = bits7; + index_array[0x8] = bits8; + index_array[0x9] = bits9; + index_array[0xA] = bitsA; + index_array[0xB] = bitsB; + index_array[0xC] = bitsC; + index_array[0xD] = bitsD; + index_array[0xE] = bitsE; + index_array[0xF] = bitsF; +} + +uint AlphaBlockDXT5::index(uint index) const +{ + int offset = (3 * index + 16); + return uint((this->u >> offset) & 0x7); +} + +void AlphaBlockDXT5::setIndex(uint index, uint value) +{ + int offset = (3 * index + 16); + uint64 mask = uint64(0x7) << offset; + this->u = (this->u & ~mask) | (uint64(value) << offset); +} + +void AlphaBlockDXT5::decodeBlock(ColorBlock * block) const +{ + uint8 alpha_array[8]; + evaluatePalette(alpha_array); + + uint8 index_array[16]; + indices(index_array); + + for(uint i = 0; i < 16; i++) { + block->color(i).a = alpha_array[index_array[i]]; + } +} + +void AlphaBlockDXT5::flip4() +{ + uint64 * b = (uint64 *)this; + + // @@ The masks might have to be byte swapped. + uint64 tmp = (*b & (uint64)(0x000000000000FFFFLL)); + tmp |= (*b & (uint64)(0x000000000FFF0000LL)) << 36; + tmp |= (*b & (uint64)(0x000000FFF0000000LL)) << 12; + tmp |= (*b & (uint64)(0x000FFF0000000000LL)) >> 12; + tmp |= (*b & (uint64)(0xFFF0000000000000LL)) >> 36; + + *b = tmp; +} + +void AlphaBlockDXT5::flip2() +{ + uint * b = (uint *)this; + + // @@ The masks might have to be byte swapped. + uint tmp = (*b & 0xFF000000); + tmp |= (*b & 0x00000FFF) << 12; + tmp |= (*b & 0x00FFF000) >> 12; + + *b = tmp; +} + +void BlockDXT5::decodeBlock(ColorBlock * block) const +{ + // Decode color. + color.decodeBlock(block); + + // Decode alpha. + alpha.decodeBlock(block); + +} + +/// Flip DXT5 block vertically. +void BlockDXT5::flip4() +{ + alpha.flip4(); + color.flip4(); +} + +/// Flip half DXT5 block vertically. +void BlockDXT5::flip2() +{ + alpha.flip2(); + color.flip2(); +} + + +/// Decode ATI1 block. +void BlockATI1::decodeBlock(ColorBlock * block) const +{ + uint8 alpha_array[8]; + alpha.evaluatePalette(alpha_array); + + uint8 index_array[16]; + alpha.indices(index_array); + + for(uint i = 0; i < 16; i++) { + Color32 & c = block->color(i); + c.b = c.g = c.r = alpha_array[index_array[i]]; + c.a = 255; + } +} + +/// Flip ATI1 block vertically. +void BlockATI1::flip4() +{ + alpha.flip4(); +} + +/// Flip half ATI1 block vertically. +void BlockATI1::flip2() +{ + alpha.flip2(); +} + + +/// Decode ATI2 block. +void BlockATI2::decodeBlock(ColorBlock * block) const +{ + uint8 alpha_array[8]; + uint8 index_array[16]; + + x.evaluatePalette(alpha_array); + x.indices(index_array); + + for(uint i = 0; i < 16; i++) { + Color32 & c = block->color(i); + c.r = alpha_array[index_array[i]]; + } + + y.evaluatePalette(alpha_array); + y.indices(index_array); + + for(uint i = 0; i < 16; i++) { + Color32 & c = block->color(i); + c.g = alpha_array[index_array[i]]; + c.b = 0; + c.a = 255; + } +} + +/// Flip ATI2 block vertically. +void BlockATI2::flip4() +{ + x.flip4(); + y.flip4(); +} + +/// Flip half ATI2 block vertically. +void BlockATI2::flip2() +{ + x.flip2(); + y.flip2(); +} + + +void BlockCTX1::evaluatePalette(Color32 color_array[4]) const +{ + // Does bit expansion before interpolation. + color_array[0].b = 0x00; + color_array[0].g = col0[1]; + color_array[0].r = col0[0]; + color_array[0].a = 0xFF; + + color_array[1].r = 0x00; + color_array[1].g = col0[1]; + color_array[1].b = col1[0]; + color_array[1].a = 0xFF; + + color_array[2].r = 0x00; + color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3; + color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3; + color_array[2].a = 0xFF; + + color_array[3].r = 0x00; + color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3; + color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3; + color_array[3].a = 0xFF; +} + +void BlockCTX1::decodeBlock(ColorBlock * block) const +{ + // Decode color block. + Color32 color_array[4]; + evaluatePalette(color_array); + + // Write color block. + for( uint j = 0; j < 4; j++ ) { + for( uint i = 0; i < 4; i++ ) { + uint idx = (row[j] >> (2 * i)) & 3; + block->color(i, j) = color_array[idx]; + } + } +} + +void BlockCTX1::setIndices(int * idx) +{ + indices = 0; + for(uint i = 0; i < 16; i++) { + indices |= (idx[i] & 3) << (2 * i); + } +} + + +/// Flip CTX1 block vertically. +inline void BlockCTX1::flip4() +{ + swap(row[0], row[3]); + swap(row[1], row[2]); +} + +/// Flip half CTX1 block vertically. +inline void BlockCTX1::flip2() +{ + swap(row[0], row[1]); +} + +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); +} + +void mem_read(Stream & mem, BlockCTX1 & block) +{ + mem_read(mem, block.col0[0]); + mem_read(mem, block.col0[1]); + mem_read(mem, block.col1[0]); + mem_read(mem, block.col1[1]); + mem_read(mem, block.indices); +} + diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h new file mode 100644 index 00000000000..5c232201f0c --- /dev/null +++ b/source/blender/imbuf/intern/dds/BlockDXT.h @@ -0,0 +1,248 @@ +/** + * $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 <icastano@nvidia.com> +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef _DDS_BLOCKDXT_H +#define _DDS_BLOCKDXT_H + +#include <Common.h> +#include <Color.h> +#include <ColorBlock.h> +#include <Stream.h> + +/// DXT1 block. +struct BlockDXT1 +{ + Color16 col0; + Color16 col1; + union { + uint8 row[4]; + uint indices; + }; + + bool isFourColorMode() const; + + uint evaluatePalette(Color32 color_array[4]) const; + uint evaluatePaletteFast(Color32 color_array[4]) const; + void evaluatePalette3(Color32 color_array[4]) const; + void evaluatePalette4(Color32 color_array[4]) const; + + void decodeBlock(ColorBlock * block) const; + + void setIndices(int * idx); + + void flip4(); + void flip2(); +}; + +/// Return true if the block uses four color mode, false otherwise. +inline bool BlockDXT1::isFourColorMode() const +{ + return col0.u > col1.u; +} + + +/// DXT3 alpha block with explicit alpha. +struct AlphaBlockDXT3 +{ + union { + struct { + uint alpha0 : 4; + uint alpha1 : 4; + uint alpha2 : 4; + uint alpha3 : 4; + uint alpha4 : 4; + uint alpha5 : 4; + uint alpha6 : 4; + uint alpha7 : 4; + uint alpha8 : 4; + uint alpha9 : 4; + uint alphaA : 4; + uint alphaB : 4; + uint alphaC : 4; + uint alphaD : 4; + uint alphaE : 4; + uint alphaF : 4; + }; + uint16 row[4]; + }; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + + +/// DXT3 block. +struct BlockDXT3 +{ + AlphaBlockDXT3 alpha; + BlockDXT1 color; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + + +/// DXT5 alpha block. +struct AlphaBlockDXT5 +{ + union { + struct { + unsigned int alpha0 : 8; // 8 + unsigned int alpha1 : 8; // 16 + unsigned int bits0 : 3; // 3 - 19 + unsigned int bits1 : 3; // 6 - 22 + unsigned int bits2 : 3; // 9 - 25 + unsigned int bits3 : 3; // 12 - 28 + unsigned int bits4 : 3; // 15 - 31 + unsigned int bits5 : 3; // 18 - 34 + unsigned int bits6 : 3; // 21 - 37 + unsigned int bits7 : 3; // 24 - 40 + unsigned int bits8 : 3; // 27 - 43 + unsigned int bits9 : 3; // 30 - 46 + unsigned int bitsA : 3; // 33 - 49 + unsigned int bitsB : 3; // 36 - 52 + unsigned int bitsC : 3; // 39 - 55 + unsigned int bitsD : 3; // 42 - 58 + unsigned int bitsE : 3; // 45 - 61 + unsigned int bitsF : 3; // 48 - 64 + }; + uint64 u; + }; + + void evaluatePalette(uint8 alpha[8]) const; + void evaluatePalette8(uint8 alpha[8]) const; + void evaluatePalette6(uint8 alpha[8]) const; + void indices(uint8 index_array[16]) const; + + uint index(uint index) const; + void setIndex(uint index, uint value); + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + + +/// DXT5 block. +struct BlockDXT5 +{ + AlphaBlockDXT5 alpha; + BlockDXT1 color; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + +/// ATI1 block. +struct BlockATI1 +{ + AlphaBlockDXT5 alpha; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + +/// ATI2 block. +struct BlockATI2 +{ + AlphaBlockDXT5 x; + AlphaBlockDXT5 y; + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + +/// CTX1 block. +struct BlockCTX1 +{ + uint8 col0[2]; + uint8 col1[2]; + union { + uint8 row[4]; + uint indices; + }; + + void evaluatePalette(Color32 color_array[4]) const; + void setIndices(int * idx); + + void decodeBlock(ColorBlock * block) const; + + void flip4(); + void flip2(); +}; + +void mem_read(Stream & mem, BlockDXT1 & block); +void mem_read(Stream & mem, AlphaBlockDXT3 & block); +void mem_read(Stream & mem, BlockDXT3 & block); +void mem_read(Stream & mem, AlphaBlockDXT5 & block); +void mem_read(Stream & mem, BlockDXT5 & block); +void mem_read(Stream & mem, BlockATI1 & block); +void mem_read(Stream & mem, BlockATI2 & block); +void mem_read(Stream & mem, BlockCTX1 & block); + +#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..0199d15ada7 --- /dev/null +++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp @@ -0,0 +1,317 @@ +/** + * $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 <ColorBlock.h> +#include <Image.h> +#include <Common.h> + + // Get approximate luminance. + inline static uint colorLuminance(Color32 c) + { + return c.r + c.g + c.b; + } + + // Get the euclidean distance between the given colors. + inline static uint colorDistance(Color32 c0, Color32 c1) + { + return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b); + } + + +/// Default constructor. +ColorBlock::ColorBlock() +{ +} + +/// Init the color block with the contents of the given block. +ColorBlock::ColorBlock(const ColorBlock & block) +{ + for(uint i = 0; i < 16; i++) { + color(i) = block.color(i); + } +} + + +/// Initialize this color block. +ColorBlock::ColorBlock(const Image * img, uint x, uint y) +{ + init(img, x, y); +} + +void ColorBlock::init(const Image * img, uint x, uint y) +{ + const uint bw = min(img->width() - x, 4U); + const uint 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(uint i = 0; i < 4; i++) { + //const int by = i % bh; + const int by = remainder[(bh - 1) * 4 + i]; + for(uint 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++) + { + uint8 x = m_color[i].r; + m_color[i] = Color32(x, x, x, x); + } +} + +void ColorBlock::splatY() +{ + for(int i = 0; i < 16; i++) + { + uint8 y = m_color[i].g; + m_color[i] = Color32(y, y, y, y); + } +} + + +/// Count number of unique colors in this color block. +uint ColorBlock::countUniqueColors() const +{ + uint count = 0; + + // @@ This does not have to be o(n^2) + for(int i = 0; i < 16; i++) + { + bool unique = true; + for(int j = 0; j < i; j++) { + if( m_color[i] != m_color[j] ) { + unique = false; + } + } + + if( unique ) { + count++; + } + } + + return count; +} + +/// Get average color of the block. +Color32 ColorBlock::averageColor() const +{ + uint r, g, b, a; + r = g = b = a = 0; + + for(uint i = 0; i < 16; i++) { + r += m_color[i].r; + g += m_color[i].g; + b += m_color[i].b; + a += m_color[i].a; + } + + return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16)); +} + +/// Return true if the block is not fully opaque. +bool ColorBlock::hasAlpha() const +{ + for (uint i = 0; i < 16; i++) + { + if (m_color[i].a != 255) return true; + } + return false; +} + + +/// Get diameter color range. +void ColorBlock::diameterRange(Color32 * start, Color32 * end) const +{ + Color32 c0, c1; + uint best_dist = 0; + + for(int i = 0; i < 16; i++) { + for (int j = i+1; j < 16; j++) { + uint dist = colorDistance(m_color[i], m_color[j]); + if( dist > best_dist ) { + best_dist = dist; + c0 = m_color[i]; + c1 = m_color[j]; + } + } + } + + *start = c0; + *end = c1; +} + +/// Get luminance color range. +void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const +{ + Color32 minColor, maxColor; + uint minLuminance, maxLuminance; + + maxLuminance = minLuminance = colorLuminance(m_color[0]); + + for(uint i = 1; i < 16; i++) + { + uint luminance = colorLuminance(m_color[i]); + + if (luminance > maxLuminance) { + maxLuminance = luminance; + maxColor = m_color[i]; + } + else if (luminance < minLuminance) { + minLuminance = luminance; + minColor = m_color[i]; + } + } + + *start = minColor; + *end = maxColor; +} + +/// Get color range based on the bounding box. +void ColorBlock::boundsRange(Color32 * start, Color32 * end) const +{ + Color32 minColor(255, 255, 255); + Color32 maxColor(0, 0, 0); + + for(uint i = 0; i < 16; i++) + { + if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; } + if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; } + if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; } + if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; } + if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; } + if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; } + } + + // Offset range by 1/16 of the extents + Color32 inset; + inset.r = (maxColor.r - minColor.r) >> 4; + inset.g = (maxColor.g - minColor.g) >> 4; + inset.b = (maxColor.b - minColor.b) >> 4; + + minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255; + minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255; + minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255; + + maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0; + maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0; + maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0; + + *start = minColor; + *end = maxColor; +} + +/// Get color range based on the bounding box. +void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const +{ + Color32 minColor(255, 255, 255, 255); + Color32 maxColor(0, 0, 0, 0); + + for(uint i = 0; i < 16; i++) + { + if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; } + if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; } + if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; } + if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; } + if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; } + if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; } + if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; } + if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; } + } + + // Offset range by 1/16 of the extents + Color32 inset; + inset.r = (maxColor.r - minColor.r) >> 4; + inset.g = (maxColor.g - minColor.g) >> 4; + inset.b = (maxColor.b - minColor.b) >> 4; + inset.a = (maxColor.a - minColor.a) >> 4; + + minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255; + minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255; + minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255; + minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255; + + maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0; + maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0; + maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0; + maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0; + + *start = minColor; + *end = maxColor; +} + +/// Sort colors by abosolute value in their 16 bit representation. +void ColorBlock::sortColorsByAbsoluteValue() +{ + // Dummy selection sort. + for( uint a = 0; a < 16; a++ ) { + uint max = a; + Color16 cmax(m_color[a]); + + for( uint b = a+1; b < 16; b++ ) { + Color16 cb(m_color[b]); + + if( cb.u > cmax.u ) { + max = b; + cmax = cb; + } + } + swap( m_color[a], m_color[max] ); + } +} diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h new file mode 100644 index 00000000000..72049be5f3c --- /dev/null +++ b/source/blender/imbuf/intern/dds/ColorBlock.h @@ -0,0 +1,116 @@ +/** + * $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 <Color.h> +#include <Image.h> + +/// Uncompressed 4x4 color block. +struct ColorBlock +{ + ColorBlock(); + ColorBlock(const ColorBlock & block); + ColorBlock(const Image * img, uint x, uint y); + + void init(const Image * img, uint x, uint y); + + void swizzleDXT5n(); + void splatX(); + void splatY(); + + uint countUniqueColors() const; + Color32 averageColor() const; + bool hasAlpha() 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(uint i) const; + Color32 & color(uint i); + + Color32 color(uint x, uint y) const; + Color32 & color(uint x, uint y); + +private: + + Color32 m_color[4*4]; + +}; + + +/// Get pointer to block colors. +inline const Color32 * ColorBlock::colors() const +{ + return m_color; +} + +/// Get block color. +inline Color32 ColorBlock::color(uint i) const +{ + return m_color[i]; +} + +/// Get block color. +inline Color32 & ColorBlock::color(uint i) +{ + return m_color[i]; +} + +/// Get block color. +inline Color32 ColorBlock::color(uint x, uint y) const +{ + return m_color[y * 4 + x]; +} + +/// Get block color. +inline Color32 & ColorBlock::color(uint x, uint y) +{ + return m_color[y * 4 + x]; +} + +#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..0c687e2ca9a --- /dev/null +++ b/source/blender/imbuf/intern/dds/Common.h @@ -0,0 +1,56 @@ +/** + * $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 + +template<typename T> +inline void +swap(T & a, T & b) +{ + T tmp = a; + a = b; + b = tmp; +} + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +#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..f842c756ce1 --- /dev/null +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp @@ -0,0 +1,1023 @@ +/** + * $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 <icastano@nvidia.com> +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <DirectDrawSurface.h> +#include <BlockDXT.h> +#include <PixelFormat.h> + +#include <stdio.h> // printf +#include <math.h> // sqrt +#include <sys/types.h> + +/*** declarations ***/ + +#if !defined(MAKEFOURCC) +# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint)((unsigned char)(ch0)) | \ + ((uint)((unsigned char)(ch1)) << 8) | \ + ((uint)((unsigned char)(ch2)) << 16) | \ + ((uint)((unsigned char)(ch3)) << 24 )) +#endif + +static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); +static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); +static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); +static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); +static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); +static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); +static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); +static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1'); +static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); + +// 32 bit RGB formats. +static const uint D3DFMT_R8G8B8 = 20; +static const uint D3DFMT_A8R8G8B8 = 21; +static const uint D3DFMT_X8R8G8B8 = 22; +static const uint D3DFMT_R5G6B5 = 23; +static const uint D3DFMT_X1R5G5B5 = 24; +static const uint D3DFMT_A1R5G5B5 = 25; +static const uint D3DFMT_A4R4G4B4 = 26; +static const uint D3DFMT_R3G3B2 = 27; +static const uint D3DFMT_A8 = 28; +static const uint D3DFMT_A8R3G3B2 = 29; +static const uint D3DFMT_X4R4G4B4 = 30; +static const uint D3DFMT_A2B10G10R10 = 31; +static const uint D3DFMT_A8B8G8R8 = 32; +static const uint D3DFMT_X8B8G8R8 = 33; +static const uint D3DFMT_G16R16 = 34; +static const uint D3DFMT_A2R10G10B10 = 35; + +static const uint D3DFMT_A16B16G16R16 = 36; + +// Palette formats. +static const uint D3DFMT_A8P8 = 40; +static const uint D3DFMT_P8 = 41; + +// Luminance formats. +static const uint D3DFMT_L8 = 50; +static const uint D3DFMT_A8L8 = 51; +static const uint D3DFMT_A4L4 = 52; +static const uint D3DFMT_L16 = 81; + +// Floating point formats +static const uint D3DFMT_R16F = 111; +static const uint D3DFMT_G16R16F = 112; +static const uint D3DFMT_A16B16G16R16F = 113; +static const uint D3DFMT_R32F = 114; +static const uint D3DFMT_G32R32F = 115; +static const uint D3DFMT_A32B32G32R32F = 116; + +static const uint DDSD_CAPS = 0x00000001U; +static const uint DDSD_PIXELFORMAT = 0x00001000U; +static const uint DDSD_WIDTH = 0x00000004U; +static const uint DDSD_HEIGHT = 0x00000002U; +static const uint DDSD_PITCH = 0x00000008U; +static const uint DDSD_MIPMAPCOUNT = 0x00020000U; +static const uint DDSD_LINEARSIZE = 0x00080000U; +static const uint DDSD_DEPTH = 0x00800000U; + +static const uint DDSCAPS_COMPLEX = 0x00000008U; +static const uint DDSCAPS_TEXTURE = 0x00001000U; +static const uint DDSCAPS_MIPMAP = 0x00400000U; +static const uint DDSCAPS2_VOLUME = 0x00200000U; +static const uint DDSCAPS2_CUBEMAP = 0x00000200U; + +static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U; +static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U; +static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U; +static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U; +static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U; +static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U; +static const uint DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U; + +static const uint DDPF_ALPHAPIXELS = 0x00000001U; +static const uint DDPF_ALPHA = 0x00000002U; +static const uint DDPF_FOURCC = 0x00000004U; +static const uint DDPF_RGB = 0x00000040U; +static const uint DDPF_PALETTEINDEXED1 = 0x00000800U; +static const uint DDPF_PALETTEINDEXED2 = 0x00001000U; +static const uint DDPF_PALETTEINDEXED4 = 0x00000008U; +static const uint DDPF_PALETTEINDEXED8 = 0x00000020U; +static const uint DDPF_LUMINANCE = 0x00020000U; +static const uint DDPF_ALPHAPREMULT = 0x00008000U; +static const uint DDPF_NORMAL = 0x80000000U; // @@ Custom nv flag. + + // DX10 formats. + enum DXGI_FORMAT + { + DXGI_FORMAT_UNKNOWN = 0, + + DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, + DXGI_FORMAT_R32G32B32A32_FLOAT = 2, + DXGI_FORMAT_R32G32B32A32_UINT = 3, + DXGI_FORMAT_R32G32B32A32_SINT = 4, + + DXGI_FORMAT_R32G32B32_TYPELESS = 5, + DXGI_FORMAT_R32G32B32_FLOAT = 6, + DXGI_FORMAT_R32G32B32_UINT = 7, + DXGI_FORMAT_R32G32B32_SINT = 8, + + DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, + DXGI_FORMAT_R16G16B16A16_FLOAT = 10, + DXGI_FORMAT_R16G16B16A16_UNORM = 11, + DXGI_FORMAT_R16G16B16A16_UINT = 12, + DXGI_FORMAT_R16G16B16A16_SNORM = 13, + DXGI_FORMAT_R16G16B16A16_SINT = 14, + + DXGI_FORMAT_R32G32_TYPELESS = 15, + DXGI_FORMAT_R32G32_FLOAT = 16, + DXGI_FORMAT_R32G32_UINT = 17, + DXGI_FORMAT_R32G32_SINT = 18, + + DXGI_FORMAT_R32G8X24_TYPELESS = 19, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, + DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, + + DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, + DXGI_FORMAT_R10G10B10A2_UNORM = 24, + DXGI_FORMAT_R10G10B10A2_UINT = 25, + + DXGI_FORMAT_R11G11B10_FLOAT = 26, + + DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, + DXGI_FORMAT_R8G8B8A8_UNORM = 28, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, + DXGI_FORMAT_R8G8B8A8_UINT = 30, + DXGI_FORMAT_R8G8B8A8_SNORM = 31, + DXGI_FORMAT_R8G8B8A8_SINT = 32, + + DXGI_FORMAT_R16G16_TYPELESS = 33, + DXGI_FORMAT_R16G16_FLOAT = 34, + DXGI_FORMAT_R16G16_UNORM = 35, + DXGI_FORMAT_R16G16_UINT = 36, + DXGI_FORMAT_R16G16_SNORM = 37, + DXGI_FORMAT_R16G16_SINT = 38, + + DXGI_FORMAT_R32_TYPELESS = 39, + DXGI_FORMAT_D32_FLOAT = 40, + DXGI_FORMAT_R32_FLOAT = 41, + DXGI_FORMAT_R32_UINT = 42, + DXGI_FORMAT_R32_SINT = 43, + + DXGI_FORMAT_R24G8_TYPELESS = 44, + DXGI_FORMAT_D24_UNORM_S8_UINT = 45, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, + DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, + + DXGI_FORMAT_R8G8_TYPELESS = 48, + DXGI_FORMAT_R8G8_UNORM = 49, + DXGI_FORMAT_R8G8_UINT = 50, + DXGI_FORMAT_R8G8_SNORM = 51, + DXGI_FORMAT_R8G8_SINT = 52, + + DXGI_FORMAT_R16_TYPELESS = 53, + DXGI_FORMAT_R16_FLOAT = 54, + DXGI_FORMAT_D16_UNORM = 55, + DXGI_FORMAT_R16_UNORM = 56, + DXGI_FORMAT_R16_UINT = 57, + DXGI_FORMAT_R16_SNORM = 58, + DXGI_FORMAT_R16_SINT = 59, + + DXGI_FORMAT_R8_TYPELESS = 60, + DXGI_FORMAT_R8_UNORM = 61, + DXGI_FORMAT_R8_UINT = 62, + DXGI_FORMAT_R8_SNORM = 63, + DXGI_FORMAT_R8_SINT = 64, + DXGI_FORMAT_A8_UNORM = 65, + + DXGI_FORMAT_R1_UNORM = 66, + + DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, + + DXGI_FORMAT_R8G8_B8G8_UNORM = 68, + DXGI_FORMAT_G8R8_G8B8_UNORM = 69, + + DXGI_FORMAT_BC1_TYPELESS = 70, + DXGI_FORMAT_BC1_UNORM = 71, + DXGI_FORMAT_BC1_UNORM_SRGB = 72, + + DXGI_FORMAT_BC2_TYPELESS = 73, + DXGI_FORMAT_BC2_UNORM = 74, + DXGI_FORMAT_BC2_UNORM_SRGB = 75, + + DXGI_FORMAT_BC3_TYPELESS = 76, + DXGI_FORMAT_BC3_UNORM = 77, + DXGI_FORMAT_BC3_UNORM_SRGB = 78, + + DXGI_FORMAT_BC4_TYPELESS = 79, + DXGI_FORMAT_BC4_UNORM = 80, + DXGI_FORMAT_BC4_SNORM = 81, + + DXGI_FORMAT_BC5_TYPELESS = 82, + DXGI_FORMAT_BC5_UNORM = 83, + DXGI_FORMAT_BC5_SNORM = 84, + + DXGI_FORMAT_B5G6R5_UNORM = 85, + DXGI_FORMAT_B5G5R5A1_UNORM = 86, + DXGI_FORMAT_B8G8R8A8_UNORM = 87, + DXGI_FORMAT_B8G8R8X8_UNORM = 88, + }; + + enum D3D10_RESOURCE_DIMENSION + { + D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, + D3D10_RESOURCE_DIMENSION_BUFFER = 1, + D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2, + D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3, + D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4, + }; + +/*** implementation ***/ + +void mem_read(Stream & mem, DDSPixelFormat & pf) +{ + mem_read(mem, pf.size); + mem_read(mem, pf.flags); + mem_read(mem, pf.fourcc); + mem_read(mem, pf.bitcount); + mem_read(mem, pf.rmask); + mem_read(mem, pf.gmask); + mem_read(mem, pf.bmask); + mem_read(mem, pf.amask); +} + +void mem_read(Stream & mem, DDSCaps & caps) +{ + mem_read(mem, caps.caps1); + mem_read(mem, caps.caps2); + mem_read(mem, caps.caps3); + mem_read(mem, caps.caps4); +} + +void mem_read(Stream & mem, DDSHeader10 & header) +{ + mem_read(mem, header.dxgiFormat); + mem_read(mem, header.resourceDimension); + mem_read(mem, header.miscFlag); + mem_read(mem, header.arraySize); + mem_read(mem, header.reserved); +} + +void mem_read(Stream & mem, DDSHeader & header) +{ + mem_read(mem, header.fourcc); + mem_read(mem, header.size); + mem_read(mem, header.flags); + mem_read(mem, header.height); + mem_read(mem, header.width); + mem_read(mem, header.pitch); + mem_read(mem, header.depth); + mem_read(mem, header.mipmapcount); + for (uint i = 0; i < 11; i++) mem_read(mem, header.reserved[i]); + mem_read(mem, header.pf); + mem_read(mem, header.caps); + mem_read(mem, header.notused); + + if (header.hasDX10Header()) + { + mem_read(mem, header.header10); + } +} + + + +DDSHeader::DDSHeader() +{ + this->fourcc = FOURCC_DDS; + this->size = 124; + this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT); + this->height = 0; + this->width = 0; + this->pitch = 0; + this->depth = 0; + this->mipmapcount = 0; + for (uint i = 0; i < 11; i++) this->reserved[i] = 0; + + // Store version information on the reserved header attributes. + this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T'); + this->reserved[10] = (0 << 16) | (9 << 8) | (5); // major.minor.revision + + this->pf.size = 32; + this->pf.flags = 0; + this->pf.fourcc = 0; + this->pf.bitcount = 0; + this->pf.rmask = 0; + this->pf.gmask = 0; + this->pf.bmask = 0; + this->pf.amask = 0; + this->caps.caps1 = DDSCAPS_TEXTURE; + this->caps.caps2 = 0; + this->caps.caps3 = 0; + this->caps.caps4 = 0; + this->notused = 0; + + this->header10.dxgiFormat = DXGI_FORMAT_UNKNOWN; + this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_UNKNOWN; + this->header10.miscFlag = 0; + this->header10.arraySize = 0; + this->header10.reserved = 0; +} + +void DDSHeader::setWidth(uint w) +{ + this->flags |= DDSD_WIDTH; + this->width = w; +} + +void DDSHeader::setHeight(uint h) +{ + this->flags |= DDSD_HEIGHT; + this->height = h; +} + +void DDSHeader::setDepth(uint d) +{ + this->flags |= DDSD_DEPTH; + this->height = d; +} + +void DDSHeader::setMipmapCount(uint count) +{ + if (count == 0 || count == 1) + { + this->flags &= ~DDSD_MIPMAPCOUNT; + this->mipmapcount = 0; + + if (this->caps.caps2 == 0) { + this->caps.caps1 = DDSCAPS_TEXTURE; + } + else { + this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX; + } + } + else + { + this->flags |= DDSD_MIPMAPCOUNT; + this->mipmapcount = count; + + this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; + } +} + +void DDSHeader::setTexture2D() +{ + this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; +} + +void DDSHeader::setTexture3D() +{ + this->caps.caps2 = DDSCAPS2_VOLUME; + + this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; +} + +void DDSHeader::setTextureCube() +{ + this->caps.caps1 |= DDSCAPS_COMPLEX; + this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES; + + this->header10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + this->header10.arraySize = 6; +} + +void DDSHeader::setLinearSize(uint size) +{ + this->flags &= ~DDSD_PITCH; + this->flags |= DDSD_LINEARSIZE; + this->pitch = size; +} + +void DDSHeader::setPitch(uint pitch) +{ + this->flags &= ~DDSD_LINEARSIZE; + this->flags |= DDSD_PITCH; + this->pitch = pitch; +} + +void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3) +{ + // set fourcc pixel format. + this->pf.flags = DDPF_FOURCC; + this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3); + this->pf.bitcount = 0; + this->pf.rmask = 0; + this->pf.gmask = 0; + this->pf.bmask = 0; + this->pf.amask = 0; +} + +void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask) +{ + // Make sure the masks are correct. + 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. + uint total = rmask | gmask | bmask | amask; + while(total != 0) { + bitcount++; + total >>= 1; + } + } + + if (!(bitcount > 0 && bitcount <= 32)) { + printf("DDS: bad bit count, pixel format not set\n"); + return; + } + + // Align to 8. + if (bitcount < 8) bitcount = 8; + else if (bitcount < 16) bitcount = 16; + else if (bitcount < 24) bitcount = 24; + else bitcount = 32; + + this->pf.fourcc = 0; //findD3D9Format(bitcount, rmask, gmask, bmask, amask); + this->pf.bitcount = bitcount; + this->pf.rmask = rmask; + this->pf.gmask = gmask; + this->pf.bmask = bmask; + this->pf.amask = amask; +} + +void DDSHeader::setDX10Format(uint format) +{ + this->pf.flags = 0; + this->header10.dxgiFormat = format; +} + +void DDSHeader::setNormalFlag(bool b) +{ + if (b) this->pf.flags |= DDPF_NORMAL; + else this->pf.flags &= ~DDPF_NORMAL; +} + +bool DDSHeader::hasDX10Header() const +{ + return this->pf.flags == 0; +} + +DirectDrawSurface::DirectDrawSurface(unsigned char *mem, uint 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 uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT); + if( (header.flags & required) != required ) { + return false; + } + + if (header.pf.size != 32) { + return false; + } + + /* in some files DDSCAPS_TEXTURE is missing: silently ignore */ + /* + if( !(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) + { + // All RGB formats are supported now. + } + else + { + return false; + } + + if (isTextureCube() && (header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES) + { + // Cubemaps must contain all faces. + return false; + } + + if (isTexture3D()) + { + // @@ 3D textures not supported yet. + return false; + } + + return true; +} + + +uint DirectDrawSurface::mipmapCount() const +{ + if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount; + else return 0; +} + + +uint DirectDrawSurface::width() const +{ + if (header.flags & DDSD_WIDTH) return header.width; + else return 1; +} + +uint DirectDrawSurface::height() const +{ + if (header.flags & DDSD_HEIGHT) return header.height; + else return 1; +} + +uint DirectDrawSurface::depth() const +{ + if (header.flags & DDSD_DEPTH) return header.depth; + else return 1; +} + +bool DirectDrawSurface::hasAlpha() const +{ + if ((header.pf.flags & DDPF_RGB) && (header.pf.amask == 0)) + { + return false; + } + else 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, uint face, uint mipmap) +{ + stream.seek(offset(face, mipmap)); + + uint w = width(); + uint h = height(); + + // Compute width and height. + for (uint m = 0; m < mipmap; m++) + { + w = max(1U, w / 2); + h = max(1U, h / 2); + } + + img->allocate(w, h); + + if (header.pf.flags & DDPF_RGB) + { + readLinearImage(img); + } + else if (header.pf.flags & DDPF_FOURCC) + { + readBlockImage(img); + } +} + +void DirectDrawSurface::readLinearImage(Image * img) +{ + + const uint w = img->width(); + const uint h = img->height(); + + uint rshift, rsize; + PixelFormat::maskShiftAndSize(header.pf.rmask, &rshift, &rsize); + + uint gshift, gsize; + PixelFormat::maskShiftAndSize(header.pf.gmask, &gshift, &gsize); + + uint bshift, bsize; + PixelFormat::maskShiftAndSize(header.pf.bmask, &bshift, &bsize); + + uint ashift, asize; + PixelFormat::maskShiftAndSize(header.pf.amask, &ashift, &asize); + + uint byteCount = (header.pf.bitcount + 7) / 8; + + if (byteCount > 4) + { + /* just in case... we could have segfaults later on if byteCount > 4 */ + printf("DDS: bitcount too large"); + return; + } + + if (header.pf.amask != 0) + { + img->setFormat(Image::Format_ARGB); + } + + // Read linear RGB images. + for (uint y = 0; y < h; y++) + { + for (uint x = 0; x < w; x++) + { + uint c = 0; + mem_read(stream, (unsigned char *)(&c), byteCount); + + Color32 pixel(0, 0, 0, 0xFF); + pixel.r = PixelFormat::convert(c >> rshift, rsize, 8); + pixel.g = PixelFormat::convert(c >> gshift, gsize, 8); + pixel.b = PixelFormat::convert(c >> bshift, bsize, 8); + pixel.a = PixelFormat::convert(c >> ashift, asize, 8); + + img->pixel(x, y) = pixel; + } + } +} + +void DirectDrawSurface::readBlockImage(Image * img) +{ + const uint w = img->width(); + const uint h = img->height(); + + const uint bw = (w + 3) / 4; + const uint bh = (h + 3) / 4; + + for (uint by = 0; by < bh; by++) + { + for (uint bx = 0; bx < bw; bx++) + { + ColorBlock block; + + // Read color block. + readBlock(&block); + + // Write color block. + for (uint y = 0; y < min(4U, h-4*by); y++) + { + for (uint x = 0; x < min(4U, w-4*bx); x++) + { + img->pixel(4*bx+x, 4*by+y) = block.color(x, y); + } + } + } + } +} + +static Color32 buildNormal(uint8 x, uint8 y) +{ + float nx = 2 * (x / 255.0f) - 1; + float ny = 2 * (y / 255.0f) - 1; + float nz = 0.0f; + if (1 - nx*nx - ny*ny > 0) nz = sqrt(1 - nx*nx - ny*ny); + uint8 z = clamp(int(255.0f * (nz + 1) / 2.0f), 0, 255); + + return Color32(x, y, z); +} + + +void DirectDrawSurface::readBlock(ColorBlock * rgba) +{ + 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); + uint 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.a, c.g); + } + } + } +} + + +uint DirectDrawSurface::blockSize() const +{ + switch(header.pf.fourcc) + { + case FOURCC_DXT1: + case FOURCC_ATI1: + return 8; + case FOURCC_DXT2: + case FOURCC_DXT3: + case FOURCC_DXT4: + case FOURCC_DXT5: + case FOURCC_RXGB: + case FOURCC_ATI2: + return 16; + }; + + // Not a block image. + return 0; +} + +uint DirectDrawSurface::mipmapSize(uint mipmap) const +{ + uint w = width(); + uint h = height(); + uint d = depth(); + + for (uint m = 0; m < mipmap; m++) + { + w = max(1U, w / 2); + h = max(1U, h / 2); + d = max(1U, d / 2); + } + + if (header.pf.flags & DDPF_FOURCC) + { + // @@ How are 3D textures aligned? + w = (w + 3) / 4; + h = (h + 3) / 4; + return blockSize() * w * h; + } + else if (header.pf.flags & DDPF_RGB) + { + // Align pixels to bytes. + uint byteCount = (header.pf.bitcount + 7) / 8; + + // Align pitch to 4 bytes. + uint pitch = 4 * ((w * byteCount + 3) / 4); + + return pitch * h * d; + } + else { + printf("DDS: mipmap format not supported\n"); + return(0); + }; +} + +uint DirectDrawSurface::faceSize() const +{ + const uint count = mipmapCount(); + uint size = 0; + + for (uint m = 0; m < count; m++) + { + size += mipmapSize(m); + } + + return size; +} + +uint DirectDrawSurface::offset(const uint face, const uint mipmap) +{ + uint size = 128; //sizeof(DDSHeader); + + if (face != 0) + { + size += face * faceSize(); + } + + for (uint 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.pf.flags == 0) + { + printf("DX10 Header:\n"); + printf("\tDXGI Format: %u\n", header.header10.dxgiFormat); + printf("\tResource dimension: %u\n", header.header10.resourceDimension); + printf("\tMisc flag: %u\n", header.header10.miscFlag); + printf("\tArray size: %u\n", header.header10.arraySize); + } + + if (header.reserved[9] == MAKEFOURCC('N', 'V', 'T', 'T')) + { + int major = (header.reserved[10] >> 16) & 0xFF; + int minor = (header.reserved[10] >> 8) & 0xFF; + int revision= header.reserved[10] & 0xFF; + + printf("Version:\n"); + printf("\tNVIDIA Texture Tools %d.%d.%d\n", major, minor, revision); + } +} + diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h new file mode 100644 index 00000000000..d29d82f53f9 --- /dev/null +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h @@ -0,0 +1,181 @@ +/** + * $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 <icastano@nvidia.com> +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef _DDS_DIRECTDRAWSURFACE_H +#define _DDS_DIRECTDRAWSURFACE_H + +#include <Common.h> +#include <Stream.h> +#include <ColorBlock.h> +#include <Image.h> + +struct DDSPixelFormat +{ + uint size; + uint flags; + uint fourcc; + uint bitcount; + uint rmask; + uint gmask; + uint bmask; + uint amask; +}; + +struct DDSCaps +{ + uint caps1; + uint caps2; + uint caps3; + uint caps4; +}; + +/// DDS file header for DX10. +struct DDSHeader10 +{ + uint dxgiFormat; + uint resourceDimension; + uint miscFlag; + uint arraySize; + uint reserved; +}; + +/// DDS file header. +struct DDSHeader +{ + uint fourcc; + uint size; + uint flags; + uint height; + uint width; + uint pitch; + uint depth; + uint mipmapcount; + uint reserved[11]; + DDSPixelFormat pf; + DDSCaps caps; + uint notused; + DDSHeader10 header10; + + + // Helper methods. + DDSHeader(); + + void setWidth(uint w); + void setHeight(uint h); + void setDepth(uint d); + void setMipmapCount(uint count); + void setTexture2D(); + void setTexture3D(); + void setTextureCube(); + void setLinearSize(uint size); + void setPitch(uint pitch); + void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3); + void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask); + void setDX10Format(uint format); + void setNormalFlag(bool b); + + bool hasDX10Header() const; +}; + +/// DirectDraw Surface. (DDS) +class DirectDrawSurface +{ +public: + DirectDrawSurface(unsigned char *mem, uint size); + ~DirectDrawSurface(); + + bool isValid() const; + bool isSupported() const; + + uint mipmapCount() const; + uint width() const; + uint height() const; + uint depth() const; + bool isTexture2D() const; + bool isTexture3D() const; + bool isTextureCube() const; + bool hasAlpha() const; /* false for DXT1, true for all other DXTs */ + + void mipmap(Image * img, uint f, uint m); + // void mipmap(FloatImage * img, uint f, uint m); + + void printInfo() const; + +private: + + uint blockSize() const; + uint faceSize() const; + uint mipmapSize(uint m) const; + + uint offset(uint f, uint m); + + void readLinearImage(Image * img); + void readBlockImage(Image * img); + void readBlock(ColorBlock * rgba); + + +private: + Stream 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); +void mem_read(Stream & mem, DDSHeader10 & 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..d8be7857c3f --- /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 <Color.h> +#include <Image.h> + +#include <stdio.h> // printf + +Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(0) +{ +} + +Image::~Image() +{ + free(); +} + +void Image::allocate(uint w, uint h) +{ + free(); + m_width = w; + m_height = h; + m_data = new Color32[w * h]; +} + +void Image::free() +{ + if (m_data) delete [] m_data; + m_data = 0; +} + + +uint Image::width() const +{ + return m_width; +} + +uint Image::height() const +{ + return m_height; +} + +const Color32 * Image::scanline(uint h) const +{ + if (h >= m_height) { + printf("DDS: scanline beyond dimensions of image"); + return m_data; + } + return m_data + h * m_width; +} + +Color32 * Image::scanline(uint h) +{ + if (h >= m_height) { + printf("DDS: scanline beyond dimensions of image"); + return m_data; + } + return m_data + h * m_width; +} + +const Color32 * Image::pixels() const +{ + return m_data; +} + +Color32 * Image::pixels() +{ + return m_data; +} + +const Color32 & Image::pixel(uint idx) const +{ + if (idx >= m_width * m_height) { + printf("DDS: pixel beyond dimensions of image"); + return m_data[0]; + } + return m_data[idx]; +} + +Color32 & Image::pixel(uint idx) +{ + if (idx >= m_width * m_height) { + printf("DDS: pixel beyond dimensions of image"); + 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..0241839d01d --- /dev/null +++ b/source/blender/imbuf/intern/dds/Image.h @@ -0,0 +1,104 @@ +/** + * $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 <Common.h> +#include <Color.h> + +/// 32 bit RGBA image. +class Image +{ +public: + + enum Format + { + Format_RGB, + Format_ARGB, + }; + + Image(); + ~Image(); + + void allocate(uint w, uint h); + /* + bool load(const char * name); + + void wrap(void * data, uint w, uint h); + void unwrap(); + */ + + uint width() const; + uint height() const; + + const Color32 * scanline(uint h) const; + Color32 * scanline(uint h); + + const Color32 * pixels() const; + Color32 * pixels(); + + const Color32 & pixel(uint idx) const; + Color32 & pixel(uint idx); + + const Color32 & pixel(uint x, uint y) const; + Color32 & pixel(uint x, uint y); + + Format format() const; + void setFormat(Format f); + +private: + void free(); + +private: + uint m_width; + uint m_height; + Format m_format; + Color32 * m_data; +}; + + +inline const Color32 & Image::pixel(uint x, uint y) const +{ + return pixel(y * width() + x); +} + +inline Color32 & Image::pixel(uint x, uint y) +{ + return pixel(y * width() + x); +} + +#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..88d59080a47 --- /dev/null +++ b/source/blender/imbuf/intern/dds/Makefile @@ -0,0 +1,63 @@ +# +# $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 + +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/PixelFormat.h b/source/blender/imbuf/intern/dds/PixelFormat.h new file mode 100644 index 00000000000..93f55f8266a --- /dev/null +++ b/source/blender/imbuf/intern/dds/PixelFormat.h @@ -0,0 +1,110 @@ +/** + * $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 <icastano@nvidia.com> +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef _DDS_PIXELFORMAT_H +#define _DDS_PIXELFORMAT_H + +#include <Common.h> + + namespace PixelFormat + { + + // Convert component @a c having @a inbits to the returned value having @a outbits. + inline uint convert(uint c, uint inbits, uint outbits) + { + if (inbits == 0) + { + return 0; + } + else if (inbits >= outbits) + { + // truncate + return c >> (inbits - outbits); + } + else + { + // bitexpand + return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits); + } + } + + // Get pixel component shift and size given its mask. + inline void maskShiftAndSize(uint mask, uint * shift, uint * size) + { + if (!mask) + { + *shift = 0; + *size = 0; + return; + } + + *shift = 0; + while((mask & 1) == 0) { + ++(*shift); + mask >>= 1; + } + + *size = 0; + while((mask & 1) == 1) { + ++(*size); + mask >>= 1; + } + } + + } // PixelFormat namespace + +#endif // _DDS_IMAGE_PIXELFORMAT_H diff --git a/source/blender/imbuf/intern/dds/SConscript b/source/blender/imbuf/intern/dds/SConscript new file mode 100644 index 00000000000..d005bae02be --- /dev/null +++ b/source/blender/imbuf/intern/dds/SConscript @@ -0,0 +1,19 @@ +#!/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 = ['WITH_DDS'] + +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..2340598b4fa --- /dev/null +++ b/source/blender/imbuf/intern/dds/Stream.cpp @@ -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 ***** + */ + +#include <Stream.h> + +#include <stdio.h> // printf +#include <string.h> // 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); +} + +unsigned int mem_read(Stream & mem, unsigned char *i, unsigned int cnt) +{ + if (mem.pos + cnt > mem.size) { + printf("DDS: trying to read beyond end of stream (corrupt file?)"); + return(0); + }; + memcpy(i, mem.mem + mem.pos, cnt); + mem.pos += cnt; + return(cnt); +} + diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h new file mode 100644 index 00000000000..373e68db44e --- /dev/null +++ b/source/blender/imbuf/intern/dds/Stream.h @@ -0,0 +1,49 @@ +/** + * $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); +unsigned int mem_read(Stream & mem, unsigned char *i, unsigned int cnt); + +#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..3de30b9f183 --- /dev/null +++ b/source/blender/imbuf/intern/dds/dds_api.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 ***** + */ + +#include <dds_api.h> +#include <Stream.h> +#include <DirectDrawSurface.h> +#include <stdio.h> // printf +#include <fstream> + +extern "C" { + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_allocimbuf.h" + + +short imb_save_dds(struct ImBuf * ibuf, char *name, int flags) +{ + return(0); /* todo: finish this function */ + + /* check image buffer */ + if (ibuf == 0) return (0); + if (ibuf->rect == 0) return (0); + + /* open file for writing */ + std::ofstream fildes(name); + + /* write header */ + fildes << "DDS "; + fildes.close(); + + return(1); +} + +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 bits_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()) bits_per_pixel = 32; + else bits_per_pixel = 24; + ibuf = IMB_allocImBuf(dds.width(), dds.height(), bits_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 (bits_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/divers.c b/source/blender/imbuf/intern/divers.c index a4fab4a3572..8db07f581f5 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -174,7 +174,7 @@ void IMB_gamwarp(struct ImBuf *ibuf, double gamma) } } -#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.99f*val)) void IMB_rect_from_float(struct ImBuf *ibuf) { diff --git a/source/blender/imbuf/intern/dynlibtiff.c b/source/blender/imbuf/intern/dynlibtiff.c index cdcb995bcff..4a96af8bf2b 100644 --- a/source/blender/imbuf/intern/dynlibtiff.c +++ b/source/blender/imbuf/intern/dynlibtiff.c @@ -83,13 +83,19 @@ void libtiff_loadlibtiff(void) /* Try to find libtiff in a couple of standard places */ libtiff = PIL_dynlib_open("libtiff.so"); if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("libtiff.so.3"); + if (libtiff != NULL) return; libtiff = PIL_dynlib_open("libtiff.dll"); if (libtiff != NULL) return; libtiff = PIL_dynlib_open("/usr/lib/libtiff.so"); if (libtiff != NULL) return; - /* OSX has version specific library */ libtiff = PIL_dynlib_open("/usr/lib/libtiff.so.3"); if (libtiff != NULL) return; + /* OSX has version specific library */ +#ifdef __x86_64__ + libtiff = PIL_dynlib_open("/usr/lib64/libtiff.so.3"); + if (libtiff != NULL) return; +#endif libtiff = PIL_dynlib_open("/usr/local/lib/libtiff.so"); if (libtiff != NULL) return; /* For solaris */ diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c index fd9dac1af2b..1be5cf99e19 100644 --- a/source/blender/imbuf/intern/filter.c +++ b/source/blender/imbuf/intern/filter.c @@ -240,18 +240,72 @@ void IMB_filter(struct ImBuf *ibuf) imb_filterx(ibuf); } -#define EXTEND_PIXEL(a, w) if((a)[3]) {r+= w*(a)[0]; g+= w*(a)[1]; b+= w*(a)[2]; tot+=w;} +#define EXTEND_PIXEL(color, w) if((color)[3]) {r+= w*(color)[0]; g+= w*(color)[1]; b+= w*(color)[2]; a+= w*(color)[3]; tot+=w;} -/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 255 */ -void IMB_filter_extend(struct ImBuf *ibuf) +/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0 + * + * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c + * */ +void IMB_filter_extend(struct ImBuf *ibuf, char *mask) { register char *row1, *row2, *row3; - register char *cp; + register char *cp; int rowlen, x, y; rowlen= ibuf->x; - if(ibuf->rect) { + + if (ibuf->rect_float) { + float *temprect; + float *row1f, *row2f, *row3f; + float *fp; + temprect= MEM_dupallocN(ibuf->rect_float); + + for(y=1; y<=ibuf->y; y++) { + /* setup rows */ + row1f= (float *)(temprect + (y-2)*rowlen*4); + row2f= row1f + 4*rowlen; + row3f= row2f + 4*rowlen; + if(y==1) + row1f= row2f; + else if(y==ibuf->y) + row3f= row2f; + + fp= (float *)(ibuf->rect_float + (y-1)*rowlen*4); + + for(x=0; x<rowlen; x++) { + if((mask==NULL && fp[3]==0.0f) || (mask && mask[((y-1)*rowlen)+x]==1)) { + int tot= 0; + float r=0.0f, g=0.0f, b=0.0f, a=0.0f; + + EXTEND_PIXEL(row1f, 1); + EXTEND_PIXEL(row2f, 2); + EXTEND_PIXEL(row3f, 1); + EXTEND_PIXEL(row1f+4, 2); + EXTEND_PIXEL(row3f+4, 2); + if(x!=rowlen-1) { + EXTEND_PIXEL(row1f+8, 1); + EXTEND_PIXEL(row2f+8, 2); + EXTEND_PIXEL(row3f+8, 1); + } + if(tot) { + fp[0]= r/tot; + fp[1]= g/tot; + fp[2]= b/tot; + fp[3]= a/tot; + } + } + fp+=4; + + if(x!=0) { + row1f+=4; row2f+=4; row3f+=4; + } + } + } + + MEM_freeN(temprect); + } + else if(ibuf->rect) { int *temprect; /* make a copy, to prevent flooding */ @@ -270,8 +324,9 @@ void IMB_filter_extend(struct ImBuf *ibuf) cp= (char *)(ibuf->rect + (y-1)*rowlen); for(x=0; x<rowlen; x++) { - if(cp[3]==0) { - int tot= 0, r=0, g=0, b=0; + /*if(cp[3]==0) {*/ + if((mask==NULL && cp[3]==0) || (mask && mask[((y-1)*rowlen)+x]==1)) { + int tot= 0, r=0, g=0, b=0, a=0; EXTEND_PIXEL(row1, 1); EXTEND_PIXEL(row2, 2); @@ -287,10 +342,10 @@ void IMB_filter_extend(struct ImBuf *ibuf) cp[0]= r/tot; cp[1]= g/tot; cp[2]= b/tot; - cp[3]= 255; + cp[3]= a/tot; } } - cp+=4; + cp+=4; if(x!=0) { row1+=4; row2+=4; row3+=4; diff --git a/source/blender/imbuf/intern/gen_dynlibtiff.py b/source/blender/imbuf/intern/gen_dynlibtiff.py index 1ee0275854a..de3236da6c2 100755 --- a/source/blender/imbuf/intern/gen_dynlibtiff.py +++ b/source/blender/imbuf/intern/gen_dynlibtiff.py @@ -125,13 +125,19 @@ void libtiff_loadlibtiff(void) /* Try to find libtiff in a couple of standard places */ libtiff = PIL_dynlib_open("libtiff.so"); if (libtiff != NULL) return; + libtiff = PIL_dynlib_open("libtiff.so.3"); + if (libtiff != NULL) return; libtiff = PIL_dynlib_open("libtiff.dll"); if (libtiff != NULL) return; libtiff = PIL_dynlib_open("/usr/lib/libtiff.so"); if (libtiff != NULL) return; - /* OSX has version specific library */ libtiff = PIL_dynlib_open("/usr/lib/libtiff.so.3"); if (libtiff != NULL) return; + /* OSX has version specific library */ +#ifdef __x86_64__ + libtiff = PIL_dynlib_open("/usr/lib64/libtiff.so.3"); + if (libtiff != NULL) return; +#endif libtiff = PIL_dynlib_open("/usr/local/lib/libtiff.so"); if (libtiff != NULL) return; /* For solaris */ diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index f98244c5a0f..aa09fc3ee38 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -42,26 +42,37 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "math.h" + +/* This define should be relocated to a global header some where Kent Mein +I stole it from util.h in the plugins api */ +#define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) /* Only this one is used liberally here, and in imbuf */ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf) { - int size, do_float=0; + int size; unsigned char rt, *cp = (unsigned char *)ibuf->rect; float rtf, *cpf = ibuf->rect_float; - - if (ibuf->rect_float) do_float = 1; - size = ibuf->x * ibuf->y; - - while(size-- > 0) { - rt= cp[0]; - cp[0]= cp[3]; - cp[3]= rt; - rt= cp[1]; - cp[1]= cp[2]; - cp[2]= rt; - cp+= 4; - if (do_float) { + + if (ibuf->rect) { + size = ibuf->x * ibuf->y; + + while(size-- > 0) { + rt= cp[0]; + cp[0]= cp[3]; + cp[3]= rt; + rt= cp[1]; + cp[1]= cp[2]; + cp[2]= rt; + cp+= 4; + } + } + + if (ibuf->rect_float) { + size = ibuf->x * ibuf->y; + + while(size-- > 0) { rtf= cpf[0]; cpf[0]= cpf[3]; cpf[3]= rtf; @@ -73,3 +84,224 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf) } } +/************************************************************************** +* INTERPOLATIONS +* +* Reference and docs: +* http://wiki.blender.org/index.php/User:Damiles#Interpolations_Algorithms +***************************************************************************/ + +/* BICUBIC Interpolation functions */ +/* More info: http://wiki.blender.org/index.php/User:Damiles#Bicubic_pixel_interpolation +*/ +/* function assumes out to be zero'ed, only does RGBA */ +static float P(float k){ + float aux; + aux=(float)(1.0f/6.0f)*( pow( MAX2(k+2.0f,0) , 3.0f ) - 4.0f * pow( MAX2(k+1.0f,0) , 3.0f ) + 6.0f * pow( MAX2(k,0) , 3.0f ) - 4.0f * pow( MAX2(k-1.0f,0) , 3.0f)); + return aux ; +} + +void bicubic_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout) +{ + int i,j,n,m,x1,y1; + unsigned char *dataI,*outI; + float a,b, outR,outG,outB,outA,*dataF,*outF; + int do_rect, do_float; + + if (in == NULL) return; + if (in->rect == NULL && in->rect_float == NULL) return; + + do_rect= (out->rect != NULL); + do_float= (out->rect_float != NULL); + + i= (int)floor(x); + j= (int)floor(y); + a= x - i; + b= y - j; + + outR= 0.0f; + outG= 0.0f; + outB= 0.0f; + outA= 0.0f; + for(n= -1; n<= 2; n++){ + for(m= -1; m<= 2; m++){ + x1= i+n; + y1= j+m; + if (x1>0 && x1 < in->x && y1>0 && y1<in->y) { + if (do_float) { + dataF= in->rect_float + in->x * y1 * 4 + 4*x1; + outR+= dataF[0] * P(n-a) * P(b-m); + outG+= dataF[1] * P(n-a) * P(b-m); + outB+= dataF[2] * P(n-a) * P(b-m); + outA+= dataF[3] * P(n-a) * P(b-m); + } + if (do_rect) { + dataI= (unsigned char*)in->rect + in->x * y1 * 4 + 4*x1; + outR+= dataI[0] * P(n-a) * P(b-m); + outG+= dataI[1] * P(n-a) * P(b-m); + outB+= dataI[2] * P(n-a) * P(b-m); + outA+= dataI[3] * P(n-a) * P(b-m); + } + } + } + } + if (do_rect) { + outI= (unsigned char *)out->rect + out->x * yout * 4 + 4*xout; + outI[0]= (int)outR; + outI[1]= (int)outG; + outI[2]= (int)outB; + outI[3]= (int)outA; + } + if (do_float) { + outF= (float *)out->rect_float + out->x * yout * 4 + 4*xout; + outF[0]= outR; + outF[1]= outG; + outF[2]= outB; + outF[3]= outA; + } +} + +/* function assumes out to be zero'ed, only does RGBA */ +/* BILINEAR INTERPOLATION */ +void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout) +{ + float *row1, *row2, *row3, *row4, a, b, *outF; + unsigned char *row1I, *row2I, *row3I, *row4I, *outI; + float a_b, ma_b, a_mb, ma_mb; + float empty[4]= {0.0f, 0.0f, 0.0f, 0.0f}; + unsigned char emptyI[4]= {0, 0, 0, 0}; + int y1, y2, x1, x2; + int do_rect, do_float; + + if (in==NULL) return; + if (in->rect==NULL && in->rect_float==NULL) return; + + do_rect= (out->rect != NULL); + do_float= (out->rect_float != NULL); + + x1= (int)floor(u); + x2= (int)ceil(u); + y1= (int)floor(v); + y2= (int)ceil(v); + + // sample area entirely outside image? + if (x2<0 || x1>in->x-1 || y2<0 || y1>in->y-1) return; + + if (do_rect) + outI=(unsigned char *)out->rect + out->x * yout * 4 + 4*xout; + else + outI= NULL; + if (do_float) + outF=(float *)out->rect_float + out->x * yout * 4 + 4*xout; + else + outF= NULL; + + if (do_float) { + // sample including outside of edges of image + if (x1<0 || y1<0) row1= empty; + else row1= (float *)in->rect_float + in->x * y1 * 4 + 4*x1; + + if (x1<0 || y2>in->y-1) row2= empty; + else row2= (float *)in->rect_float + in->x * y2 * 4 + 4*x1; + + if (x2>in->x-1 || y1<0) row3= empty; + else row3= (float *)in->rect_float + in->x * y1 * 4 + 4*x2; + + if (x2>in->x-1 || y2>in->y-1) row4= empty; + else row4= (float *)in->rect_float + in->x * y2 * 4 + 4*x2; + + a= u-floor(u); + b= v-floor(v); + a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b); + + outF[0]= ma_mb*row1[0] + a_mb*row3[0] + ma_b*row2[0]+ a_b*row4[0]; + outF[1]= ma_mb*row1[1] + a_mb*row3[1] + ma_b*row2[1]+ a_b*row4[1]; + outF[2]= ma_mb*row1[2] + a_mb*row3[2] + ma_b*row2[2]+ a_b*row4[2]; + outF[3]= ma_mb*row1[3] + a_mb*row3[3] + ma_b*row2[3]+ a_b*row4[3]; + } + if (do_rect) { + // sample including outside of edges of image + if (x1<0 || y1<0) row1I= emptyI; + else row1I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1; + + if (x1<0 || y2>in->y-1) row2I= emptyI; + else row2I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x1; + + if (x2>in->x-1 || y1<0) row3I= emptyI; + else row3I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x2; + + if (x2>in->x-1 || y2>in->y-1) row4I= emptyI; + else row4I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x2; + + a= u-floor(u); + b= v-floor(v); + a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b); + + outI[0]= ma_mb*row1I[0] + a_mb*row3I[0] + ma_b*row2I[0]+ a_b*row4I[0]; + outI[1]= ma_mb*row1I[1] + a_mb*row3I[1] + ma_b*row2I[1]+ a_b*row4I[1]; + outI[2]= ma_mb*row1I[2] + a_mb*row3I[2] + ma_b*row2I[2]+ a_b*row4I[2]; + outI[3]= ma_mb*row1I[3] + a_mb*row3I[3] + ma_b*row2I[3]+ a_b*row4I[3]; + } +} + +/* function assumes out to be zero'ed, only does RGBA */ +/* NEAREST INTERPOLATION */ +void neareast_interpolation(ImBuf *in, ImBuf *out, float u, float v,int xout, int yout) +{ + float *outF,*dataF; + unsigned char *dataI,*outI; + int y1, x1; + int do_rect, do_float; + + if (in==NULL) return; + if (in->rect==NULL && in->rect_float==NULL) return; + + do_rect= (out->rect != NULL); + do_float= (out->rect_float != NULL); + + x1= (int)(u); + y1= (int)(v); + + if (do_rect) + outI=(unsigned char *)out->rect + out->x * yout * 4 + 4*xout; + else + outI= NULL; + if (do_float) + outF=(float *)out->rect_float + out->x * yout * 4 + 4*xout; + else + outF= NULL; + + // sample area entirely outside image? + if (x1<0 || x1>in->x-1 || y1<0 || y1>in->y-1) return; + + // sample including outside of edges of image + if (x1<0 || y1<0) { + if (do_rect) { + outI[0]= 0; + outI[1]= 0; + outI[2]= 0; + outI[3]= 0; + } + if (do_float) { + outF[0]= 0.0f; + outF[1]= 0.0f; + outF[2]= 0.0f; + outF[3]= 0.0f; + } + } else { + dataI= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1; + if (do_rect) { + outI[0]= dataI[0]; + outI[1]= dataI[1]; + outI[2]= dataI[2]; + outI[3]= dataI[3]; + } + dataF= in->rect_float + in->x * y1 * 4 + 4*x1; + if (do_float) { + outF[0]= dataF[0]; + outF[1]= dataF[1]; + outF[2]= dataF[2]; + outF[3]= dataF[3]; + } + } +} diff --git a/source/blender/imbuf/intern/imginfo.c b/source/blender/imbuf/intern/imginfo.c new file mode 100644 index 00000000000..37bde9e5ac3 --- /dev/null +++ b/source/blender/imbuf/intern/imginfo.c @@ -0,0 +1,158 @@ +/** + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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) 2005 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Austin Benesh. Ton Roosendaal. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <string.h> + +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_imginfo.h" + + + +void IMB_imginfo_free(struct ImBuf* img) +{ + ImgInfo *info; + + if (!img) + return; + if (!img->img_info) { + return; + } + info = img->img_info; + while (info) { + ImgInfo* next = info->next; + MEM_freeN(info->key); + MEM_freeN(info->value); + MEM_freeN(info); + info = next; + } +} + +int IMB_imginfo_get_field(struct ImBuf* img, const char* key, char* field, int len) +{ + ImgInfo *info; + int retval = 0; + + if (!img) + return 0; + if (!img->img_info) { + return 0; + } + info = img->img_info; + while (info) { + if (strcmp(key, info->key) == 0) { + BLI_strncpy(field, info->value, len); + retval = 1; + break; + } + info = info->next; + } + return retval; +} + +int IMB_imginfo_add_field(struct ImBuf* img, const char* key, const char* field) +{ + ImgInfo *info; + ImgInfo *last; + + if (!img) + return 0; + + if (!img->img_info) { + img->img_info = MEM_callocN(sizeof(ImgInfo), "ImgInfo"); + info = img->img_info; + } else { + info = img->img_info; + last = info; + while (info) { + last = info; + info = info->next; + } + info = MEM_callocN(sizeof(ImgInfo), "ImgInfo"); + last->next = info; + } + info->key = BLI_strdup(key); + info->value = BLI_strdup(field); + return 1; +} + +int IMB_imginfo_del_field(struct ImBuf *img, const char *key) +{ + ImgInfo *p, *p1; + + if ((!img) || (!img->img_info)) + return (0); + + p = img->img_info; + p1 = NULL; + while (p) { + if (!strcmp (key, p->key)) { + if (p1) + p1->next = p->next; + else + img->img_info = p->next; + + MEM_freeN(p->key); + MEM_freeN(p->value); + MEM_freeN(p); + return (1); + } + p1 = p; + p = p->next; + } + return (0); +} + +int IMB_imginfo_change_field(struct ImBuf *img, const char *key, const char *field) +{ + ImgInfo *p; + + if (!img) + return (0); + + if (!img->img_info) + return (IMB_imginfo_add_field (img, key, field)); + + p = img->img_info; + while (p) { + if (!strcmp (key, p->key)) { + MEM_freeN (p->value); + p->value = BLI_strdup (field); + return (1); + } + p = p->next; + } + + return (IMB_imginfo_add_field (img, key, field)); +} diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index cd90adda27a..eab07c19265 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -41,6 +41,7 @@ #include "imbuf_patch.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "IMB_imginfo.h" #include "IMB_jpeg.h" #include "jpeglib.h" @@ -244,11 +245,14 @@ static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int f int x, y, depth, r, g, b, k; struct ImBuf * ibuf = 0; uchar * rect; + jpeg_saved_marker_ptr marker; + char *str, *key, *value; /* install own app1 handler */ ibuf_ftype = 0; jpeg_set_marker_processor(cinfo, 0xe1, handle_app1); cinfo->dct_method = JDCT_FLOAT; + jpeg_save_markers(cinfo, JPEG_COM, 0xffff); if (jpeg_read_header(cinfo, FALSE) == JPEG_HEADER_OK) { x = cinfo->image_width; @@ -335,6 +339,64 @@ static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int f } } } + + marker= cinfo->marker_list; + while(marker) { + if(marker->marker != JPEG_COM) + goto next_stamp_marker; + + /* + * Because JPEG format don't support the + * pair "key/value" like PNG, we store the + * stampinfo in a single "encode" string: + * "Blender:key:value" + * + * That is why we need split it to the + * common key/value here. + */ + if(strncmp((char *) marker->data, "Blender", 7)) { + /* + * Maybe the file have text that + * we don't know "what it's", in that + * case we keep the text (with a + * key "None"). + * This is only for don't "lose" + * the information when we write + * it back to disk. + */ + IMB_imginfo_add_field(ibuf, "None", (char *) marker->data); + ibuf->flags |= IB_imginfo; + goto next_stamp_marker; + } + + str = BLI_strdup ((char *) marker->data); + key = strchr (str, ':'); + /* + * A little paranoid, but the file maybe + * is broken... and a "extra" check is better + * that a segfaul ;) + */ + if (!key) { + MEM_freeN(str); + goto next_stamp_marker; + } + + key++; + value = strchr (key, ':'); + if (!value) { + MEM_freeN(str); + goto next_stamp_marker; + } + + *value = '\0'; /* need finish the key string */ + value++; + IMB_imginfo_add_field(ibuf, key, value); + ibuf->flags |= IB_imginfo; + MEM_freeN(str); +next_stamp_marker: + marker= marker->next; + } + jpeg_finish_decompress(cinfo); } @@ -345,7 +407,7 @@ static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int f return(ibuf); } -ImBuf * imb_ibJpegImageFromFilename (char * filename, int flags) +ImBuf * imb_ibJpegImageFromFilename (const char * filename, int flags) { struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo; struct jpeg_error_mgr jerr; @@ -391,7 +453,8 @@ static void write_jpeg(struct jpeg_compress_struct * cinfo, struct ImBuf * ibuf) uchar * rect; int x, y; char neogeo[128]; - + ImgInfo *iptr; + char *text; jpeg_start_compress(cinfo, TRUE); @@ -401,6 +464,33 @@ static void write_jpeg(struct jpeg_compress_struct * cinfo, struct ImBuf * ibuf) memcpy(neogeo + 6, &ibuf_ftype, 4); jpeg_write_marker(cinfo, 0xe1, (JOCTET*) neogeo, 10); + if(ibuf->img_info) { + /* key + max value + "Blender" */ + text= MEM_mallocN(530, "stamp info read"); + iptr= ibuf->img_info; + while(iptr) { + if (!strcmp (iptr->key, "None")) { + jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) iptr->value, strlen (iptr->value) + 1); + goto next_stamp_info; + } + + /* + * The JPEG format don't support a pair "key/value" + * like PNG, so we "encode" the stamp in a + * single string: + * "Blender:key:value" + * + * The first "Blender" is a simple identify to help + * in the read process. + */ + sprintf (text, "Blender:%s:%s", iptr->key, iptr->value); + jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) text, strlen (text)+1); +next_stamp_info: + iptr = iptr->next; + } + MEM_freeN(text); + } + row_pointer[0] = mallocstruct(JSAMPLE, cinfo->input_components * diff --git a/source/blender/imbuf/intern/md5.c b/source/blender/imbuf/intern/md5.c new file mode 100644 index 00000000000..a3165467b53 --- /dev/null +++ b/source/blender/imbuf/intern/md5.c @@ -0,0 +1,361 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995 Software Foundation, Inc. + + 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, or (at your option) + any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/types.h> + +# include <stdlib.h> +# include <string.h> + +#include "md5.h" + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (ctx) + struct md5_ctx *ctx; +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result must + be in little endian byte order. */ +void * +md5_read_ctx (ctx, resbuf) + const struct md5_ctx *ctx; + void *resbuf; +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (stream, resblock) + FILE *stream; + void *resblock; +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + md5_uint32 len[2]; + char buffer[BLOCKSIZE + 72]; + size_t pad, sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + len[0] = 0; + len[1] = 0; + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* RFC 1321 specifies the possible length of the file up to 2^64 bits. + Here we only compute the number of bytes. Do a double word + increment. */ + len[0] += sum; + if (len[0] < sum) + ++len[1]; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* We can copy 64 byte because the buffer is always big enough. FILLBUF + contains the needed bits. */ + memcpy (&buffer[sum], fillbuf, 64); + + /* Compute amount of padding bytes needed. Alignment is done to + (N + PAD) % 64 == 56 + There is always at least one byte padded. I.e. even the alignment + is correctly aligned 64 padding bytes are added. */ + pad = sum & 63; + pad = pad >= 56 ? 64 + 56 - pad : 56 - pad; + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &buffer[sum + pad] = SWAP (len[0] << 3); + *(md5_uint32 *) &buffer[sum + pad + 4] = SWAP ((len[1] << 3) + | (len[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (buffer, sum + pad + 8, &ctx); + + /* Construct result in desired memory. */ + md5_read_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (buffer, len, resblock) + const char *buffer; + size_t len; + void *resblock; +{ + struct md5_ctx ctx; + char restbuf[64 + 72]; + size_t blocks = len & ~63; + size_t pad, rest; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_block (buffer, blocks, &ctx); + + /* REST bytes are not processed yet. */ + rest = len - blocks; + /* Copy to own buffer. */ + memcpy (restbuf, &buffer[blocks], rest); + /* Append needed fill bytes at end of buffer. We can copy 64 byte + because the buffer is always big enough. */ + memcpy (&restbuf[rest], fillbuf, 64); + + /* PAD bytes are used for padding to correct alignment. Note that + always at least one byte is padded. */ + pad = rest >= 56 ? 64 + 56 - rest : 56 - rest; + + /* Put length of buffer in *bits* in last eight bytes. */ + *(md5_uint32 *) &restbuf[rest + pad] = (md5_uint32) SWAP (len << 3); + *(md5_uint32 *) &restbuf[rest + pad + 4] = (md5_uint32) SWAP (len >> 29); + + /* Process last bytes. */ + md5_process_block (restbuf, rest + pad + 8, &ctx); + + /* Put result in desired memory area. */ + return md5_read_ctx (&ctx, resblock); +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} + diff --git a/source/blender/imbuf/intern/md5.h b/source/blender/imbuf/intern/md5.h new file mode 100644 index 00000000000..8b0d946430e --- /dev/null +++ b/source/blender/imbuf/intern/md5.h @@ -0,0 +1,116 @@ +/* md5.h - Declaration of functions and data types used for MD5 sum + computing library functions. + Copyright (C) 1995 Free Software Foundation, Inc. + +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, or (at your option) +any later version. + +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. */ + +#ifndef _MD5_H +#define _MD5_H + +#include <stdio.h> + +#if defined HAVE_LIMITS_H || _LIBC +# include <limits.h> +#endif + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + doing that would require that the configure script compile and *run* + the resulting executable. Locally running cross-compiled executables + is usually not possible. */ + +#if defined __STDC__ && __STDC__ +# define UINT_MAX_32_BITS 4294967295U +#else +# define UINT_MAX_32_BITS 0xFFFFFFFF +#endif + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have <limits.h>) have 64+-bit integral types. */ + +#ifndef UINT_MAX +# define UINT_MAX UINT_MAX_32_BITS +#endif + +#if UINT_MAX == UINT_MAX_32_BITS + typedef unsigned int md5_uint32; +#else +# if USHRT_MAX == UINT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +#endif + +#undef __P +#if defined (__STDC__) && __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void md5_init_ctx __P ((struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialzation function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +void md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int md5_stream __P ((FILE *stream, void *resblock)); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); + +#endif + diff --git a/source/blender/imbuf/intern/openexr/Makefile b/source/blender/imbuf/intern/openexr/Makefile index 65b9a058e01..a3b79c951dd 100644 --- a/source/blender/imbuf/intern/openexr/Makefile +++ b/source/blender/imbuf/intern/openexr/Makefile @@ -36,10 +36,6 @@ DIR = $(OCGDIR)/blender/imbuf/openexr include nan_compile.mk -ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris windows")) - CFLAGS += -funsigned-char -endif - CFLAGS += $(LEVEL_1_C_WARNINGS) CPPFLAGS += -I../../../makesdna diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 3cbada812b9..8f94c2cec3d 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -362,6 +362,7 @@ typedef struct ExrHandle { OutputFile *ofile; int tilex, tiley; int width, height; + int mipmap; ListBase channels; /* flattened out, ExrChannel */ ListBase layers; /* hierarchical, pointing in end to ExrChannel */ @@ -450,7 +451,7 @@ void IMB_exr_begin_write(void *handle, char *filename, int width, int height, in data->ofile = new OutputFile(filename, header); } -void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height, int tilex, int tiley) +void IMB_exrtile_begin_write(void *handle, char *filename, int mipmap, int width, int height, int tilex, int tiley) { ExrHandle *data= (ExrHandle *)handle; Header header (width, height); @@ -460,11 +461,12 @@ void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height data->tiley= tiley; data->width= width; data->height= height; + data->mipmap= mipmap; for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) header.channels().insert (echan->name, Channel (FLOAT)); - header.setTileDescription (TileDescription (tilex, tiley, ONE_LEVEL)); + header.setTileDescription (TileDescription (tilex, tiley, (mipmap)? MIPMAP_LEVELS: ONE_LEVEL)); header.lineOrder() = RANDOM_Y; header.compression() = RLE_COMPRESSION; @@ -478,7 +480,7 @@ int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height) { ExrHandle *data= (ExrHandle *)handle; - if(BLI_exists(filename)) { + if(BLI_exists(filename) && BLI_filepathsize(filename)>32) { /* 32 is arbitrary, but zero length files crashes exr */ data->ifile = new InputFile(filename); if(data->ifile) { Box2i dw = data->ifile->header().dataWindow(); @@ -533,7 +535,7 @@ void IMB_exrtile_clear_channels(void *handle) BLI_freelistN(&data->channels); } -void IMB_exrtile_write_channels(void *handle, int partx, int party) +void IMB_exrtile_write_channels(void *handle, int partx, int party, int level) { ExrHandle *data= (ExrHandle *)handle; FrameBuffer frameBuffer; @@ -547,9 +549,14 @@ void IMB_exrtile_write_channels(void *handle, int partx, int party) } data->tofile->setFrameBuffer (frameBuffer); - // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley); - data->tofile->writeTile (partx/data->tilex, party/data->tiley); - + + try { + // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley); + data->tofile->writeTile (partx/data->tilex, party/data->tiley, level); + } + catch (const std::exception &exc) { + std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl; + } } void IMB_exr_write_channels(void *handle) @@ -615,7 +622,6 @@ void IMB_exr_multilayer_convert(void *handle, void *base, void IMB_exr_close(void *handle) { ExrHandle *data= (ExrHandle *)handle; - ExrChannel *echan; ExrLayer *lay; ExrPass *pass; @@ -778,28 +784,28 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height) /* we can have RGB(A), XYZ(W), UVA */ if(pass->totchan==3 || pass->totchan==4) { if(pass->chan[0]->chan_id=='B' || pass->chan[1]->chan_id=='B' || pass->chan[2]->chan_id=='B') { - lookup['R']= 0; - lookup['G']= 1; - lookup['B']= 2; - lookup['A']= 3; + lookup[(unsigned int)'R']= 0; + lookup[(unsigned int)'G']= 1; + lookup[(unsigned int)'B']= 2; + lookup[(unsigned int)'A']= 3; } else if(pass->chan[0]->chan_id=='Y' || pass->chan[1]->chan_id=='Y' || pass->chan[2]->chan_id=='Y') { - lookup['X']= 0; - lookup['Y']= 1; - lookup['Z']= 2; - lookup['W']= 3; + lookup[(unsigned int)'X']= 0; + lookup[(unsigned int)'Y']= 1; + lookup[(unsigned int)'Z']= 2; + lookup[(unsigned int)'W']= 3; } else { - lookup['U']= 0; - lookup['V']= 1; - lookup['A']= 2; + lookup[(unsigned int)'U']= 0; + lookup[(unsigned int)'V']= 1; + lookup[(unsigned int)'A']= 2; } for(a=0; a<pass->totchan; a++) { echan= pass->chan[a]; - echan->rect= pass->rect + lookup[echan->chan_id]; + echan->rect= pass->rect + lookup[(unsigned int)echan->chan_id]; echan->xstride= pass->totchan; echan->ystride= width*pass->totchan; - pass->chan_id[ lookup[echan->chan_id] ]= echan->chan_id; + pass->chan_id[ (unsigned int)lookup[(unsigned int)echan->chan_id] ]= echan->chan_id; } } else { /* unknown */ @@ -831,6 +837,7 @@ typedef struct RGBA } RGBA; +#if 0 static void exr_print_filecontents(InputFile *file) { const ChannelList &channels = file->header().channels(); @@ -841,6 +848,7 @@ static void exr_print_filecontents(InputFile *file) printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type); } } +#endif static int exr_has_zbuffer(InputFile *file) { @@ -848,7 +856,6 @@ static int exr_has_zbuffer(InputFile *file) for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) { - const Channel &channel = i.channel(); if(strcmp("Z", i.name())==0) return 1; } diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h index ca4f7405f44..be4d1314a80 100644 --- a/source/blender/imbuf/intern/openexr/openexr_multi.h +++ b/source/blender/imbuf/intern/openexr/openexr_multi.h @@ -46,13 +46,13 @@ void IMB_exr_add_channel (void *handle, const char *layname, const char *passn int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height); void IMB_exr_begin_write (void *handle, char *filename, int width, int height, int compress); -void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley); +void IMB_exrtile_begin_write (void *handle, char *filename, int mipmap, int width, int height, int tilex, int tiley); void IMB_exr_set_channel (void *handle, char *layname, char *passname, int xstride, int ystride, float *rect); void IMB_exr_read_channels (void *handle); void IMB_exr_write_channels (void *handle); -void IMB_exrtile_write_channels (void *handle, int partx, int party); +void IMB_exrtile_write_channels (void *handle, int partx, int party, int level); void IMB_exrtile_clear_channels (void *handle); void IMB_exr_multilayer_convert (void *handle, void *base, @@ -71,13 +71,13 @@ void IMB_exr_add_channel (void *handle, const char *layname, const char *chann int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height) {return 0;} void IMB_exr_begin_write (void *handle, char *filename, int width, int height, int compress) {} -void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley) {} +void IMB_exrtile_begin_write (void *handle, char *filename, int mipmap, int width, int height, int tilex, int tiley) {} void IMB_exr_set_channel (void *handle, char *layname, char *channame, int xstride, int ystride, float *rect) {} void IMB_exr_read_channels (void *handle) {} void IMB_exr_write_channels (void *handle) {} -void IMB_exrtile_write_channels (void *handle, int partx, int party) {} +void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) {} void IMB_exrtile_clear_channels (void *handle) {} void IMB_exr_multilayer_convert (void *handle, void *base, diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 46c5232a61a..c77ff7ea56f 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -43,6 +43,7 @@ #include "IMB_allocimbuf.h" #include "IMB_cmap.h" +#include "IMB_imginfo.h" #include "IMB_png.h" typedef struct PNGReadStruct { @@ -100,6 +101,7 @@ short imb_savepng(struct ImBuf *ibuf, char *name, int flags) { png_structp png_ptr; png_infop info_ptr; + unsigned char *pixels = 0; unsigned char *from, *to; png_bytepp row_pointers = 0; @@ -219,6 +221,34 @@ short imb_savepng(struct ImBuf *ibuf, char *name, int flags) PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + /* image text info */ + if (ibuf->img_info) { + png_text* imginfo; + ImgInfo* iptr; + int num_text = 0; + iptr = ibuf->img_info; + while (iptr) { + num_text++; + iptr = iptr->next; + } + + imginfo = MEM_callocN(num_text*sizeof(png_text), "png_imginfo"); + iptr = ibuf->img_info; + num_text = 0; + while (iptr) { + + imginfo[num_text].compression = PNG_TEXT_COMPRESSION_NONE; + imginfo[num_text].key = iptr->key; + imginfo[num_text].text = iptr->value; + num_text++; + iptr = iptr->next; + } + + png_set_text(png_ptr, info_ptr, imginfo, num_text); + MEM_freeN(imginfo); + + } + // write the file header information png_write_info(png_ptr, info_ptr); @@ -409,6 +439,15 @@ struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags) break; } + if (flags & IB_imginfo) { + png_text* text_chunks; + int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); + for(i = 0; i < count; i++) { + IMB_imginfo_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); + ibuf->flags |= IB_imginfo; + } + } + png_read_end(png_ptr, info_ptr); } diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index 75be790a4cc..3cb9ca79ffc 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -161,8 +161,10 @@ static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe) int imb_is_a_hdr(void *buf) { - /* For recognition, Blender only loades first 32 bytes, so use #?RADIANCE id instead */ - if (strstr((char*)buf, "#?RADIANCE")) return 1; + // For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead + // update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part + //if (strstr((char*)buf, "#?RADIANCE")) return 1; + if (strstr((char*)buf, "#?")) return 1; // if (strstr((char*)buf, "32-bit_rle_rgbe")) return 1; return 0; } @@ -176,7 +178,6 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags) int found=0; int width=0, height=0; int x, y; - int ir, ig, ib; unsigned char* ptr; unsigned char* rect; char oriY[80], oriX[80]; @@ -225,18 +226,14 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags) *rect_float++ = fcol[GRN]; *rect_float++ = fcol[BLU]; *rect_float++ = 1.0f; - /* Also old oldstyle for the rest of blender which is not using floats yet */ -/* very weird mapping! (ton) */ - fcol[RED] = 1.f-exp(fcol[RED]*-1.414213562f); - fcol[GRN] = 1.f-exp(fcol[GRN]*-1.414213562f); - fcol[BLU] = 1.f-exp(fcol[BLU]*-1.414213562f); - ir = (int)(255.f*pow(fcol[RED], 0.45454545f)); - ig = (int)(255.f*pow(fcol[GRN], 0.45454545f)); - ib = (int)(255.f*pow(fcol[BLU], 0.45454545f)); - *rect++ = (unsigned char)((ir<0) ? 0 : ((ir>255) ? 255 : ir)); - *rect++ = (unsigned char)((ig<0) ? 0 : ((ig>255) ? 255 : ig)); - *rect++ = (unsigned char)((ib<0) ? 0 : ((ib>255) ? 255 : ib)); + // e: changed to simpler tonemapping, previous code was rather slow (is this actually still relevant at all?) + fcol[RED] = fcol[RED]/(1.f + fcol[RED]); + fcol[GRN] = fcol[GRN]/(1.f + fcol[GRN]); + fcol[BLU] = fcol[BLU]/(1.f + fcol[BLU]); + *rect++ = (unsigned char)((fcol[RED] < 0.f) ? 0 : ((fcol[RED] > 1.f) ? 255 : (255.f*fcol[RED]))); + *rect++ = (unsigned char)((fcol[GRN] < 0.f) ? 0 : ((fcol[GRN] > 1.f) ? 255 : (255.f*fcol[GRN]))); + *rect++ = (unsigned char)((fcol[BLU] < 0.f) ? 0 : ((fcol[BLU] > 1.f) ? 255 : (255.f*fcol[BLU]))); *rect++ = 255; } } @@ -328,10 +325,10 @@ static void writeHeader(FILE *file, int width, int height) fputc(10, file); fprintf(file, "# %s", "Created with Blender"); fputc(10, file); - fprintf(file, "FORMAT=32-bit_rle_rgbe"); - fputc(10, file); fprintf(file, "EXPOSURE=%25.13f", 1.0); fputc(10, file); + fprintf(file, "FORMAT=32-bit_rle_rgbe"); + fputc(10, file); fputc(10, file); fprintf(file, "-Y %d +X %d", height, width); fputc(10, file); diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index bfa6200d23b..ec0f17a8c2b 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__) @@ -259,7 +268,7 @@ struct ImBuf *IMB_loadifffile(int file, int flags) { } -struct ImBuf *IMB_loadiffname(char *naam, int flags) { +struct ImBuf *IMB_loadiffname(const char *naam, int flags) { int file; struct ImBuf *ibuf; int buf[1]; diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 85c5e07bb8e..5a907e71258 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -517,3 +517,87 @@ void IMB_rectfill(struct ImBuf *drect, float col[4]) } } +/* maybe we should use BKE_utildefines.h */ +#define FTOCHAR(val) (val<=0.0f ? 0: (val>=1.0f ? 255: (char)(255.99f*val))) +#define CLAMP(a, b, c) if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c) +#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } + +void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2) +{ + int i, j; + float a; /* alpha */ + float ai; /* alpha inverted */ + float aich; /* alpha, inverted, ai/255.0 - Convert char to float at the same time */ + if ((!rect && !rectf) || (!col) || col[3]==0.0) + return; + + /* sanity checks for coords */ + CLAMP(x1, 0, width); + CLAMP(x2, 0, width); + CLAMP(y1, 0, height); + CLAMP(y2, 0, height); + + if (x1>x2) SWAP(int,x1,x2); + if (y1>y2) SWAP(int,y1,y2); + if (x1==x2 || y1==y2) return; + + a = col[3]; + ai = 1-a; + aich = ai/255.0f; + + if (rect) { + unsigned char *pixel; + unsigned char chr=0, chg=0, chb=0; + float fr=0, fg=0, fb=0; + + if (a == 1.0) { + chr = FTOCHAR(col[0]); + chg = FTOCHAR(col[1]); + chb = FTOCHAR(col[2]); + } else { + fr = col[0]*a; + fg = col[1]*a; + fb = col[2]*a; + } + for (j = 0; j < y2-y1; j++) { + for (i = 0; i < x2-x1; i++) { + pixel = rect + 4 * (((y1 + j) * width) + (x1 + i)); + if (pixel >= rect && pixel < rect+ (4 * (width * height))) { + if (a == 1.0) { + pixel[0] = chr; + pixel[1] = chg; + pixel[2] = chb; + } else { + pixel[0] = (char)((fr + ((float)pixel[0]*aich))*255.0f); + pixel[1] = (char)((fg + ((float)pixel[1]*aich))*255.0f); + pixel[2] = (char)((fb + ((float)pixel[2]*aich))*255.0f); + } + } + } + } + } + + if (rectf) { + float *pixel; + for (j = 0; j < y2-y1; j++) { + for (i = 0; i < x2-x1; i++) { + pixel = rectf + 4 * (((y1 + j) * width) + (x1 + i)); + if (a == 1.0) { + pixel[0] = col[0]; + pixel[1] = col[1]; + pixel[2] = col[2]; + } else { + pixel[0] = (col[0]*a) + (pixel[0]*ai); + pixel[1] = (col[1]*a) + (pixel[1]*ai); + pixel[2] = (col[2]*a) + (pixel[2]*ai); + } + } + } + } +} + +void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2) +{ + if (!ibuf) return; + buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, x1, y1, x2, y2); +} diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c index 13edfbf0a33..8f5fb39d956 100644 --- a/source/blender/imbuf/intern/rotate.c +++ b/source/blender/imbuf/intern/rotate.c @@ -43,46 +43,85 @@ void IMB_flipy(struct ImBuf * ibuf) { - short x, y; - unsigned int *top, *bottom, do_float=0, *line; - float *topf=NULL, *bottomf=NULL, *linef=NULL; + int x, y; if (ibuf == NULL) return; - if (ibuf->rect == NULL) return; - - if (ibuf->rect_float) do_float =1; - x = ibuf->x; - y = ibuf->y; + if (ibuf->rect) { + unsigned int *top, *bottom, *line; + + x = ibuf->x; + y = ibuf->y; - top = ibuf->rect; - bottom = top + ((y-1) * x); - line= MEM_mallocN(x*sizeof(int), "linebuf"); + top = ibuf->rect; + bottom = top + ((y-1) * x); + line= MEM_mallocN(x*sizeof(int), "linebuf"); - if (do_float) { + y >>= 1; + + for(;y>0;y--) { + memcpy(line, top, x*sizeof(int)); + memcpy(top, bottom, x*sizeof(int)); + memcpy(bottom, line, x*sizeof(int)); + bottom -= x; + top+= x; + } + + MEM_freeN(line); + } + + if (ibuf->rect_float) { + float *topf=NULL, *bottomf=NULL, *linef=NULL; + + x = ibuf->x; + y = ibuf->y; + topf= ibuf->rect_float; bottomf = topf + 4*((y-1) * x); linef= MEM_mallocN(4*x*sizeof(float), "linebuff"); - } - y >>= 1; - - for(;y>0;y--) { - - memcpy(line, top, x*sizeof(int)); - memcpy(top, bottom, x*sizeof(int)); - memcpy(bottom, line, x*sizeof(int)); - bottom -= x; - top+= x; - - if(do_float) { + + y >>= 1; + + for(;y>0;y--) { memcpy(linef, topf, 4*x*sizeof(float)); memcpy(topf, bottomf, 4*x*sizeof(float)); memcpy(bottomf, linef, 4*x*sizeof(float)); bottomf -= 4*x; topf+= 4*x; } + + MEM_freeN(linef); + } +} + +void IMB_flipx(struct ImBuf * ibuf) +{ + short x, y, xr, xl, yi; + unsigned int px; + float px_f[4]; + + if (ibuf == NULL) return; + + x = ibuf->x; + y = ibuf->y; + + if (ibuf->rect) { + for(yi=y-1;yi>=0;yi--) { + for(xr=x-1, xl=0; xr>=xl; xr--, xl++) { + px = ibuf->rect[(x*yi)+xr]; + ibuf->rect[(x*yi)+xr] = ibuf->rect[(x*yi)+xl]; + ibuf->rect[(x*yi)+xl] = px; + } + } } - MEM_freeN(line); - if(linef) MEM_freeN(linef); + if (ibuf->rect_float) { + for(yi=y-1;yi>=0;yi--) { + for(xr=x-1, xl=0; xr>=xl; xr--, xl++) { + memcpy(&px_f, &ibuf->rect_float[((x*yi)+xr)*4], 4*sizeof(float)); + memcpy(&ibuf->rect_float[((x*yi)+xr)*4], &ibuf->rect_float[((x*yi)+xl)*4], 4*sizeof(float)); + memcpy(&ibuf->rect_float[((x*yi)+xl)*4], &px_f, 4*sizeof(float)); + } + } + } } diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index cd933cb0767..80731213140 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -483,6 +483,468 @@ struct ImBuf *IMB_halflace(struct ImBuf *ibuf1) return (ibuf2); } +/* q_scale_linear_interpolation helper functions */ + +static void enlarge_picture_byte( + unsigned char* src, unsigned char* dst, int src_width, + int src_height, int dst_width, int dst_height) +{ + double ratiox = (double) (dst_width - 1.0) + / (double) (src_width - 1.001); + double ratioy = (double) (dst_height - 1.0) + / (double) (src_height - 1.001); + unsigned long x_src, dx_src, x_dst; + unsigned long y_src, dy_src, y_dst; + + dx_src = 65536.0 / ratiox; + dy_src = 65536.0 / ratioy; + + y_src = 0; + for (y_dst = 0; y_dst < dst_height; y_dst++) { + unsigned char* line1 = src + (y_src >> 16) * 4 * src_width; + unsigned char* line2 = line1 + 4 * src_width; + unsigned long weight1y = 65536 - (y_src & 0xffff); + unsigned long weight2y = 65536 - weight1y; + + if ((y_src >> 16) == src_height - 1) { + line2 = line1; + } + + x_src = 0; + for (x_dst = 0; x_dst < dst_width; x_dst++) { + unsigned long weight1x = 65536 - (x_src & 0xffff); + unsigned long weight2x = 65536 - weight1x; + + unsigned long x = (x_src >> 16) * 4; + + *dst++ = ((((line1[x] * weight1y) >> 16) + * weight1x) >> 16) + + ((((line2[x] * weight2y) >> 16) + * weight1x) >> 16) + + ((((line1[4 + x] * weight1y) >> 16) + * weight2x) >> 16) + + ((((line2[4 + x] * weight2y) >> 16) + * weight2x) >> 16); + + *dst++ = ((((line1[x + 1] * weight1y) >> 16) + * weight1x) >> 16) + + ((((line2[x + 1] * weight2y) >> 16) + * weight1x) >> 16) + + ((((line1[4 + x + 1] * weight1y) >> 16) + * weight2x) >> 16) + + ((((line2[4 + x + 1] * weight2y) >> 16) + * weight2x) >> 16); + + *dst++ = ((((line1[x + 2] * weight1y) >> 16) + * weight1x) >> 16) + + ((((line2[x + 2] * weight2y) >> 16) + * weight1x) >> 16) + + ((((line1[4 + x + 2] * weight1y) >> 16) + * weight2x) >> 16) + + ((((line2[4 + x + 2] * weight2y) >> 16) + * weight2x) >> 16); + + *dst++ = ((((line1[x + 3] * weight1y) >> 16) + * weight1x) >> 16) + + ((((line2[x + 3] * weight2y) >> 16) + * weight1x) >> 16) + + ((((line1[4 + x + 3] * weight1y) >> 16) + * weight2x) >> 16) + + ((((line2[4 + x + 3] * weight2y) >> 16) + * weight2x) >> 16); + + x_src += dx_src; + } + y_src += dy_src; + } +} + +struct scale_outpix_byte { + unsigned long r; + unsigned long g; + unsigned long b; + unsigned long a; + + unsigned long weight; +}; + +static void shrink_picture_byte( + unsigned char* src, unsigned char* dst, int src_width, + int src_height, int dst_width, int dst_height) +{ + double ratiox = (double) (dst_width) / (double) (src_width); + double ratioy = (double) (dst_height) / (double) (src_height); + unsigned long x_src, dx_dst, x_dst; + unsigned long y_src, dy_dst, y_dst; + long y_counter; + unsigned char * dst_begin = dst; + + struct scale_outpix_byte * dst_line1 = NULL; + struct scale_outpix_byte * dst_line2 = NULL; + + dst_line1 = (struct scale_outpix_byte*) MEM_callocN( + (dst_width + 1) * sizeof(struct scale_outpix_byte), + "shrink_picture_byte 1"); + dst_line2 = (struct scale_outpix_byte*) MEM_callocN( + (dst_width + 1) * sizeof(struct scale_outpix_byte), + "shrink_picture_byte 2"); + + dx_dst = 65536.0 * ratiox; + dy_dst = 65536.0 * ratioy; + + y_dst = 0; + y_counter = 65536; + for (y_src = 0; y_src < src_height; y_src++) { + unsigned char* line = src + y_src * 4 * src_width; + unsigned long weight1y = 65536 - (y_dst & 0xffff); + unsigned long weight2y = 65536 - weight1y; + x_dst = 0; + for (x_src = 0; x_src < src_width; x_src++) { + unsigned long weight1x = 65536 - (x_dst & 0xffff); + unsigned long weight2x = 65536 - weight1x; + + unsigned long x = x_dst >> 16; + + unsigned long w; + + w = (weight1y * weight1x) >> 16; + + dst_line1[x].r += (line[0] * w) >> 16; + dst_line1[x].g += (line[1] * w) >> 16; + dst_line1[x].b += (line[2] * w) >> 16; + dst_line1[x].a += (line[3] * w) >> 16; + dst_line1[x].weight += w; + + w = (weight2y * weight1x) >> 16; + + dst_line2[x].r += (line[0] * w) >> 16; + dst_line2[x].g += (line[1] * w) >> 16; + dst_line2[x].b += (line[2] * w) >> 16; + dst_line2[x].a += (line[3] * w) >> 16; + dst_line2[x].weight += w; + + w = (weight1y * weight2x) >> 16; + + dst_line1[x+1].r += (line[0] * w) >> 16; + dst_line1[x+1].g += (line[1] * w) >> 16; + dst_line1[x+1].b += (line[2] * w) >> 16; + dst_line1[x+1].a += (line[3] * w) >> 16; + dst_line1[x+1].weight += w; + + w = (weight2y * weight2x) >> 16; + + dst_line2[x+1].r += (line[0] * w) >> 16; + dst_line2[x+1].g += (line[1] * w) >> 16; + dst_line2[x+1].b += (line[2] * w) >> 16; + dst_line2[x+1].a += (line[3] * w) >> 16; + dst_line2[x+1].weight += w; + + x_dst += dx_dst; + line += 4; + } + + y_dst += dy_dst; + y_counter -= dy_dst; + if (y_counter < 0) { + unsigned long x; + struct scale_outpix_byte * temp; + + y_counter += 65536; + + for (x=0; x < dst_width; x++) { + unsigned long f = 0x80000000UL + / dst_line1[x].weight; + *dst++ = (dst_line1[x].r * f) >> 15; + *dst++ = (dst_line1[x].g * f) >> 15; + *dst++ = (dst_line1[x].b * f) >> 15; + *dst++ = (dst_line1[x].a * f) >> 15; + } + memset(dst_line1, 0, dst_width * + sizeof(struct scale_outpix_byte)); + temp = dst_line1; + dst_line1 = dst_line2; + dst_line2 = temp; + } + } + if (dst - dst_begin < dst_width * dst_height * 4) { + unsigned long x; + for (x = 0; x < dst_width; x++) { + unsigned long f = 0x80000000UL / dst_line1[x].weight; + *dst++ = (dst_line1[x].r * f) >> 15; + *dst++ = (dst_line1[x].g * f) >> 15; + *dst++ = (dst_line1[x].b * f) >> 15; + *dst++ = (dst_line1[x].a * f) >> 15; + } + } + MEM_freeN(dst_line1); + MEM_freeN(dst_line2); +} + + +static void q_scale_byte(unsigned char* in, unsigned char* out, int in_width, + int in_height, int dst_width, int dst_height) +{ + if (dst_width > in_width && dst_height > in_height) { + enlarge_picture_byte(in, out, in_width, in_height, + dst_width, dst_height); + } else if (dst_width < in_width && dst_height < in_height) { + shrink_picture_byte(in, out, in_width, in_height, + dst_width, dst_height); + } +} + +static void enlarge_picture_float( + float* src, float* dst, int src_width, + int src_height, int dst_width, int dst_height) +{ + double ratiox = (double) (dst_width - 1.0) + / (double) (src_width - 1.001); + double ratioy = (double) (dst_height - 1.0) + / (double) (src_height - 1.001); + unsigned long x_dst; + unsigned long y_dst; + double x_src, dx_src; + double y_src, dy_src; + + dx_src = 1.0 / ratiox; + dy_src = 1.0 / ratioy; + + y_src = 0; + for (y_dst = 0; y_dst < dst_height; y_dst++) { + float* line1 = src + ((int) y_src) * 4 * src_width; + float* line2 = line1 + 4 * src_width; + float weight1y = 1.0 - (y_src - (int) y_src); + float weight2y = 1.0 - weight1y; + + if ((int) y_src == src_height - 1) { + line2 = line1; + } + + x_src = 0; + for (x_dst = 0; x_dst < dst_width; x_dst++) { + float weight1x = 1.0 - (x_src - (int) x_src); + float weight2x = 1.0 - weight1x; + + float w11 = weight1y * weight1x; + float w21 = weight2y * weight1x; + float w12 = weight1y * weight2x; + float w22 = weight2y * weight2x; + + unsigned long x = ((int) x_src) * 4; + + *dst++ = line1[x] * w11 + + line2[x] * w21 + + line1[4 + x] * w12 + + line2[4 + x] * w22; + + *dst++ = line1[x + 1] * w11 + + line2[x + 1] * w21 + + line1[4 + x + 1] * w12 + + line2[4 + x + 1] * w22; + + *dst++ = line1[x + 2] * w11 + + line2[x + 2] * w21 + + line1[4 + x + 2] * w12 + + line2[4 + x + 2] * w22; + + *dst++ = line1[x + 3] * w11 + + line2[x + 3] * w21 + + line1[4 + x + 3] * w12 + + line2[4 + x + 3] * w22; + + x_src += dx_src; + } + y_src += dy_src; + } +} + +struct scale_outpix_float { + float r; + float g; + float b; + float a; + + float weight; +}; + +static void shrink_picture_float( + float* src, float* dst, int src_width, + int src_height, int dst_width, int dst_height) +{ + double ratiox = (double) (dst_width) / (double) (src_width); + double ratioy = (double) (dst_height) / (double) (src_height); + unsigned long x_src; + unsigned long y_src; + float dx_dst, x_dst; + float dy_dst, y_dst; + float y_counter; + float * dst_begin = dst; + + struct scale_outpix_float * dst_line1; + struct scale_outpix_float * dst_line2; + + dst_line1 = (struct scale_outpix_float*) MEM_callocN( + (dst_width + 1) * sizeof(struct scale_outpix_float), + "shrink_picture_float 1"); + dst_line2 = (struct scale_outpix_float*) MEM_callocN( + (dst_width + 1) * sizeof(struct scale_outpix_float), + "shrink_picture_float 2"); + + dx_dst = ratiox; + dy_dst = ratioy; + + y_dst = 0; + y_counter = 1.0; + for (y_src = 0; y_src < src_height; y_src++) { + float* line = src + y_src * 4 * src_width; + unsigned long weight1y = 1.0 - (y_dst - (int) y_dst); + unsigned long weight2y = 1.0 - weight1y; + x_dst = 0; + for (x_src = 0; x_src < src_width; x_src++) { + unsigned long weight1x = 1.0 - (x_dst - (int) x_dst); + unsigned long weight2x = 1.0 - weight1x; + + unsigned long x = (int) x_dst; + + float w; + + w = weight1y * weight1x; + + dst_line1[x].r += line[0] * w; + dst_line1[x].g += line[1] * w; + dst_line1[x].b += line[2] * w; + dst_line1[x].a += line[3] * w; + dst_line1[x].weight += w; + + w = weight2y * weight1x; + + dst_line2[x].r += line[0] * w; + dst_line2[x].g += line[1] * w; + dst_line2[x].b += line[2] * w; + dst_line2[x].a += line[3] * w; + dst_line2[x].weight += w; + + w = weight1y * weight2x; + + dst_line1[x+1].r += line[0] * w; + dst_line1[x+1].g += line[1] * w; + dst_line1[x+1].b += line[2] * w; + dst_line1[x+1].a += line[3] * w; + dst_line1[x+1].weight += w; + + w = weight2y * weight2x; + + dst_line2[x+1].r += line[0] * w; + dst_line2[x+1].g += line[1] * w; + dst_line2[x+1].b += line[2] * w; + dst_line2[x+1].a += line[3] * w; + dst_line2[x+1].weight += w; + + x_dst += dx_dst; + line += 4; + } + + y_dst += dy_dst; + y_counter -= dy_dst; + if (y_counter < 0) { + unsigned long x; + struct scale_outpix_float * temp; + + y_counter += 1.0; + + for (x=0; x < dst_width; x++) { + float f = 1.0 / dst_line1[x].weight; + *dst++ = dst_line1[x].r * f; + *dst++ = dst_line1[x].g * f; + *dst++ = dst_line1[x].b * f; + *dst++ = dst_line1[x].a * f; + } + memset(dst_line1, 0, dst_width * + sizeof(struct scale_outpix_float)); + temp = dst_line1; + dst_line1 = dst_line2; + dst_line2 = temp; + } + } + if (dst - dst_begin < dst_width * dst_height * 4) { + unsigned long x; + for (x = 0; x < dst_width; x++) { + float f = 1.0 / dst_line1[x].weight; + *dst++ = dst_line1[x].r * f; + *dst++ = dst_line1[x].g * f; + *dst++ = dst_line1[x].b * f; + *dst++ = dst_line1[x].a * f; + } + } + MEM_freeN(dst_line1); + MEM_freeN(dst_line2); +} + + +static void q_scale_float(float* in, float* out, int in_width, + int in_height, int dst_width, int dst_height) +{ + if (dst_width > in_width && dst_height > in_height) { + enlarge_picture_float(in, out, in_width, in_height, + dst_width, dst_height); + } else if (dst_width < in_width && dst_height < in_height) { + shrink_picture_float(in, out, in_width, in_height, + dst_width, dst_height); + } +} + +/* q_scale_linear_interpolation (derived from ppmqscale, http://libdv.sf.net) + + q stands for quick _and_ quality :) + + only handles common cases when we either + + scale both, x and y or + shrink both, x and y + + but that is pretty fast: + * does only blit once instead of two passes like the old code + (fewer cache misses) + * uses fixed point integer arithmetic for byte buffers + * doesn't branch in tight loops + + Should be comparable in speed to the ImBuf ..._fast functions at least + for byte-buffers. + +*/ +static int q_scale_linear_interpolation( + struct ImBuf *ibuf, int newx, int newy) +{ + if ((newx > ibuf->x && newy < ibuf->y) || + (newx < ibuf->x && newy > ibuf->y)) { + return FALSE; + } + + if (ibuf->rect) { + unsigned char * newrect = + MEM_mallocN(newx * newy * sizeof(int), "q_scale rect"); + q_scale_byte((unsigned char *)ibuf->rect, newrect, ibuf->x, ibuf->y, + newx, newy); + + imb_freerectImBuf(ibuf); + ibuf->mall |= IB_rect; + ibuf->rect = (unsigned int *) newrect; + } + if (ibuf->rect_float) { + float * newrect = + MEM_mallocN(newx * newy * 4 *sizeof(float), + "q_scale rectfloat"); + q_scale_float(ibuf->rect_float, newrect, ibuf->x, ibuf->y, + newx, newy); + imb_freerectfloatImBuf(ibuf); + ibuf->mall |= IB_rectfloat; + ibuf->rect_float = newrect; + } + ibuf->x = newx; + ibuf->y = newy; + + return TRUE; +} static struct ImBuf *scaledownx(struct ImBuf *ibuf, int newx) { @@ -1113,11 +1575,18 @@ struct ImBuf *IMB_scaleImBuf(struct ImBuf * ibuf, short newx, short newy) { if (ibuf==NULL) return (0); if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf); + + if (newx == ibuf->x && newy == ibuf->y) { return ibuf; } - // scaleup / scaledown functions below change ibuf->x and ibuf->y - // so we first scale the Z-buffer (if any) + /* scaleup / scaledown functions below change ibuf->x and ibuf->y + so we first scale the Z-buffer (if any) */ scalefast_Z_ImBuf(ibuf, newx, newy); + /* try to scale common cases in a fast way */ + if (q_scale_linear_interpolation(ibuf, newx, newy)) { + return ibuf; + } + if (newx < ibuf->x) if (newx) scaledownx(ibuf,newx); if (newy < ibuf->y) if (newy) scaledowny(ibuf,newy); if (newx > ibuf->x) if (newx) scaleupx(ibuf,newx); diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c new file mode 100644 index 00000000000..718b0537b48 --- /dev/null +++ b/source/blender/imbuf/intern/thumbs.c @@ -0,0 +1,459 @@ +/** + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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) 2007 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Andrea Weikert. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* also defined in BKE_utildefines, repeated here to avoid dependency */ +#define FILE_MAX 240 + +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_thumbs.h" +#include "IMB_imginfo.h" + + +#include "md5.h" + +#ifdef WIN32 +#include <windows.h> /* need to include windows.h so _WIN32_IE is defined */ +#ifndef _WIN32_IE +#define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */ +#endif +#include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */ +#include "BLI_winstuff.h" +#include <process.h> /* getpid */ +#include <direct.h> /* chdir */ +#else +#include <unistd.h> +#endif + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> + +#define URI_MAX FILE_MAX*3 + 8 + +static int get_thumb_dir( char* dir , ThumbSize size) +{ +#ifdef WIN32 + /* yes, applications shouldn't store data there, but so does GIMP :)*/ + SHGetSpecialFolderPath(0, dir, CSIDL_PROFILE, 0); +#else + char* home = getenv("HOME"); + if (!home) return 0; + BLI_strncpy(dir, home, FILE_MAX); +#endif + switch(size) { + case THB_NORMAL: + strcat(dir, "/.thumbnails/normal/"); + break; + case THB_LARGE: + strcat(dir, "/.thumbnails/large/"); + break; + case THB_FAIL: + strcat(dir, "/.thumbnails/fail/blender/"); + break; + default: + return 0; /* unknown size */ + } + return 1; +} + +/** ----- begin of adapted code from glib --- + * The following code is adapted from function g_escape_uri_string from the gnome glib + * Source: http://svn.gnome.org/viewcvs/glib/trunk/glib/gconvert.c?view=markup + * released under the Gnu General Public License. + */ +typedef enum { + UNSAFE_ALL = 0x1, /* Escape all unsafe characters */ + UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */ + UNSAFE_PATH = 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */ + UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */ + UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */ +} UnsafeCharacterSet; + +static const unsigned char acceptable[96] = { + /* A table of the ASCII chars from space (32) to DEL (127) */ + /* ! " # $ % & ' ( ) * + , - . / */ + 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C, + /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20, + /* @ A B C D E F G H I J K L M N O */ + 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + /* P Q R S T U V W X Y Z [ \ ] ^ _ */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, + /* ` a b c d e f g h i j k l m n o */ + 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + /* p q r s t u v w x y z { | } ~ DEL */ + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20 +}; + +static const char hex[17] = "0123456789abcdef"; + +/* Note: This escape function works on file: URIs, but if you want to + * escape something else, please read RFC-2396 */ +void escape_uri_string (const char *string, char* escaped_string, int len,UnsafeCharacterSet mask) +{ +#define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) + + const char *p; + char *q; + int c; + UnsafeCharacterSet use_mask; + use_mask = mask; + + for (q = escaped_string, p = string; (*p != '\0') && len; p++) { + c = (unsigned char) *p; + len--; + + if (!ACCEPTABLE (c)) { + *q++ = '%'; /* means hex coming */ + *q++ = hex[c >> 4]; + *q++ = hex[c & 15]; + } else { + *q++ = *p; + } + } + + *q = '\0'; +} + +void to_hex_char(char* hexbytes, const unsigned char* bytes, int len) +{ + const unsigned char *p; + char *q; + + for (q = hexbytes, p = bytes; len; p++) { + const unsigned char c = (unsigned char) *p; + len--; + *q++ = hex[c >> 4]; + *q++ = hex[c & 15]; + } +} + +/** ----- end of adapted code from glib --- */ + +static int uri_from_filename( const char *dir, const char *file, char *uri ) +{ + char orig_uri[URI_MAX]; + const char* dirstart = dir; + +#ifdef WIN32 + { + char vol[3]; + + BLI_strncpy(orig_uri, "file:///", FILE_MAX); + if (strlen(dir) < 2 && dir[1] != ':') { + /* not a correct absolute path */ + return 0; + } + /* on windows, using always uppercase drive/volume letter in uri */ + vol[0] = (unsigned char)toupper(dir[0]); + vol[1] = ':'; + vol[2] = '\0'; + strcat(orig_uri, vol); + dirstart += 2; + } +#else + BLI_strncpy(orig_uri, "file://", FILE_MAX); +#endif + strcat(orig_uri, dirstart); + strcat(orig_uri, file); + BLI_char_switch(orig_uri, '\\', '/'); + +#ifdef WITH_ICONV + { + char uri_utf8[FILE_MAX*3+8]; + escape_uri_string(orig_uri, uri_utf8, FILE_MAX*3+8, UNSAFE_PATH); + BLI_string_to_utf8(uri_utf8, uri, NULL); + } +#else + escape_uri_string(orig_uri, uri, FILE_MAX*3+8, UNSAFE_PATH); +#endif + return 1; +} + +static void thumbname_from_uri(const char* uri, char* thumb) +{ + char hexdigest[33]; + unsigned char digest[16]; + + md5_buffer( uri, strlen(uri), digest); + hexdigest[0] = '\0'; + to_hex_char(hexdigest, digest, 16); + hexdigest[32] = '\0'; + sprintf(thumb, "%s.png", hexdigest); +} + +static int thumbpath_from_uri(const char* uri, char* path, ThumbSize size) +{ + char tmppath[FILE_MAX]; + int rv = 0; + + if (get_thumb_dir(tmppath, size)) { + char thumb[40]; + thumbname_from_uri(uri, thumb); + BLI_snprintf(path, FILE_MAX, "%s%s", tmppath, thumb); + rv = 1; + } + return rv; +} + + +/* create thumbnail for file and returns new imbuf for thumbnail */ +ImBuf* IMB_thumb_create(const char* dir, const char* file, ThumbSize size, ThumbSource source) +{ + ImBuf *img = 0; + char uri[URI_MAX]; + char desc[URI_MAX+22]; + char tpath[FILE_MAX]; + char tdir[FILE_MAX]; + char wdir[FILE_MAX]; + char temp[FILE_MAX]; + char mtime[40]; + char cwidth[40]; + char cheight[40]; + char thumb[40]; + short tsize = 128; + short ex, ey; + float scaledx, scaledy; + struct stat info; + + switch(size) { + case THB_NORMAL: + tsize = 128; + break; + case THB_LARGE: + tsize = 256; + break; + case THB_FAIL: + tsize = 0; + break; + default: + return 0; /* unknown size */ + } + + uri_from_filename(dir, file,uri); + thumbname_from_uri(uri, thumb); + if (get_thumb_dir(tdir, size)) { + BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb); + thumb[8] = '\0'; /* shorten for tempname, not needed anymore */ + BLI_snprintf(temp, FILE_MAX, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb); + if (strncmp(thumb, dir, strlen(dir)) == 0) { + return NULL; + } + if (size == THB_FAIL) { + img = IMB_allocImBuf(0,0,32, IB_rect | IB_imginfo, 0); + if (!img) return 0; + } else { + if (THB_SOURCE_IMAGE == source) { + BLI_getwdN(wdir); + chdir(dir); + img = IMB_loadiffname(file, IB_rect | IB_imginfo); + if (img != NULL) { + stat(file, &info); + sprintf(mtime, "%ld", info.st_mtime); + sprintf(cwidth, "%d", img->x); + sprintf(cheight, "%d", img->y); + chdir(wdir); + } + } else if (THB_SOURCE_MOVIE == source) { + struct anim * anim = NULL; + BLI_getwdN(wdir); + chdir(dir); + anim = IMB_open_anim(file, IB_rect | IB_imginfo); + if (anim != NULL) { + img = IMB_anim_absolute(anim, 0); + if (img == NULL) { + printf("not an anim; %s\n", file); + } else { + IMB_freeImBuf(img); + img = IMB_anim_previewframe(anim); + } + IMB_free_anim(anim); + } + stat(file, &info); + sprintf(mtime, "%ld", info.st_mtime); + chdir(wdir); + } + if (!img) return 0; + + if (img->x > img->y) { + scaledx = (float)tsize; + scaledy = ( (float)img->y/(float)img->x )*tsize; + } + else { + scaledy = (float)tsize; + scaledx = ( (float)img->x/(float)img->y )*tsize; + } + ex = (short)scaledx; + ey = (short)scaledy; + + IMB_scaleImBuf(img, ex, ey); + } + sprintf(desc, "Thumbnail for %s", uri); + IMB_imginfo_change_field(img, "Description", desc); + IMB_imginfo_change_field(img, "Software", "Blender"); + IMB_imginfo_change_field(img, "Thumb::URI", uri); + IMB_imginfo_change_field(img, "Thumb::MTime", mtime); + if (THB_SOURCE_IMAGE == source) { + IMB_imginfo_change_field(img, "Thumb::Image::Width", cwidth); + IMB_imginfo_change_field(img, "Thumb::Image::Height", cheight); + } + img->ftype = PNG; + img->depth = 32; + if (IMB_saveiff(img, temp, IB_rect | IB_imginfo)) { +#ifndef WIN32 + chmod(temp, S_IRUSR | S_IWUSR); +#endif + BLI_rename(temp, tpath); + } + + return img; + } + return img; +} + +/* read thumbnail for file and returns new imbuf for thumbnail */ +ImBuf* IMB_thumb_read(const char* dir, const char* file, ThumbSize size) +{ + char thumb[FILE_MAX]; + char uri[FILE_MAX*3+8]; + ImBuf *img = 0; + + if (!uri_from_filename(dir, file,uri)) { + return NULL; + } + if (thumbpath_from_uri(uri, thumb, size)) { + img = IMB_loadiffname(thumb, IB_rect | IB_imginfo); + } + + return img; +} + +/* delete all thumbs for the file */ +void IMB_thumb_delete(const char* dir, const char* file, ThumbSize size) +{ + char thumb[FILE_MAX]; + char uri[FILE_MAX*3+8]; + + if (!uri_from_filename(dir, file,uri)) { + return; + } + if (thumbpath_from_uri(uri, thumb, size)) { + if (strncmp(thumb, dir, strlen(dir)) == 0) { + return; + } + if (BLI_exists(thumb)) { + BLI_delete(thumb, 0, 0); + } + } +} + + +/* create the thumb if necessary and manage failed and old thumbs */ +ImBuf* IMB_thumb_manage(const char* dir, const char* file, ThumbSize size, ThumbSource source) +{ + char path[FILE_MAX]; + char thumb[FILE_MAX]; + char uri[FILE_MAX*3+8]; + struct stat st; + ImBuf* img = NULL; + + BLI_join_dirfile(path, dir, file); + if (stat(path, &st)) { + return NULL; + } + if (!uri_from_filename(dir, file,uri)) { + return NULL; + } + if (thumbpath_from_uri(uri, thumb, THB_FAIL)) { + /* failure thumb exists, don't try recreating */ + if (BLI_exists(thumb)) { + return NULL; + } + } + + if (thumbpath_from_uri(uri, thumb, size)) { + if (strncmp(thumb, dir, strlen(dir)) == 0) { + img = IMB_loadiffname(path, IB_rect); + } else { + img = IMB_loadiffname(thumb, IB_rect | IB_imginfo); + if (img) { + char mtime[40]; + if (!IMB_imginfo_get_field(img, "Thumb::MTime", mtime, 40)) { + /* illegal thumb, forget it! */ + IMB_freeImBuf(img); + img = 0; + } else { + time_t t = atol(mtime); + if (st.st_mtime != t) { + /* recreate all thumbs */ + IMB_freeImBuf(img); + img = 0; + IMB_thumb_delete(dir, file, THB_NORMAL); + IMB_thumb_delete(dir, file, THB_LARGE); + IMB_thumb_delete(dir, file, THB_FAIL); + img = IMB_thumb_create(dir, file, size, source); + if(!img){ + /* thumb creation failed, write fail thumb */ + img = IMB_thumb_create(dir, file, THB_FAIL, source); + if (img) { + /* we don't need failed thumb anymore */ + IMB_freeImBuf(img); + img = 0; + } + } + } + } + } else { + img = IMB_thumb_create(dir, file, size, source); + if(!img){ + /* thumb creation failed, write fail thumb */ + img = IMB_thumb_create(dir, file, THB_FAIL, source); + if (img) { + /* we don't need failed thumb anymore */ + IMB_freeImBuf(img); + img = 0; + } + } + } + } + } + + return img; +} + + diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 6fc5fb99f8b..dfa4e5831ba 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -43,7 +43,6 @@ * used to compress images. */ -#include <assert.h> #include <string.h> #include "imbuf.h" @@ -108,7 +107,6 @@ int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) * * @return: Number of bytes actually read. * 0 = EOF. - * -1 = Error (never returned). */ tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) { @@ -118,8 +116,10 @@ tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - assert(mfile != NULL); - assert(mfile->mem != NULL); + if (!mfile || !mfile->mem) { + fprintf(stderr, "imb_tiff_ReadProc: !mfile || !mfile->mem!\n"); + return 0; + } /* find the actual number of bytes to read (copy) */ nCopy = n; @@ -136,7 +136,6 @@ tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) return (0); /* all set -> do the read (copy) */ - assert(sizeof(unsigned char) == 1); srcAddr = (void*)(&(mfile->mem[mfile->offset])); memcpy((void*)data, srcAddr, nCopy); mfile->offset += nCopy; /* advance file ptr by copied bytes */ @@ -180,8 +179,10 @@ toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - assert(mfile != NULL); - assert(mfile->mem != NULL); + if (!mfile || !mfile->mem) { + fprintf(stderr, "imb_tiff_SeekProc: !mfile || !mfile->mem!\n"); + return (-1); + } /* find the location we plan to seek to */ switch (whence) { @@ -193,7 +194,9 @@ toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) break; default: /* no other types are supported - return an error */ - printf("Unsupported TIFF SEEK type.\n"); + fprintf(stderr, + "imb_tiff_SeekProc: " + "Unsupported TIFF SEEK type.\n"); return (-1); } @@ -222,8 +225,10 @@ int imb_tiff_CloseProc(thandle_t handle) /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - assert(mfile != NULL); - assert(mfile->mem != NULL); /* the file has not been closed yet */ + if (!mfile || !mfile->mem) { + fprintf(stderr,"imb_tiff_CloseProc: !mfile || !mfile->mem!\n"); + return (0); + } /* virtually close the file */ mfile->mem = NULL; @@ -246,8 +251,10 @@ toff_t imb_tiff_SizeProc(thandle_t handle) /* get the pointer to the in-memory file */ mfile = IMB_TIFF_GET_MEMFILE(handle); - assert(mfile != NULL); - assert(mfile->mem != NULL); + if (!mfile || !mfile->mem) { + fprintf(stderr,"imb_tiff_SizeProc: !mfile || !mfile->mem!\n"); + return (0); + } /* return the size */ return (toff_t)(mfile->size); @@ -305,7 +312,7 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) struct ImBuf *ibuf = NULL; struct ImbTIFFMemFile memFile; uint32 width, height; - int bytesperpixel; + int bytesperpixel, bitspersample; int success; unsigned int pixel_i, byte_i; uint32 *raster = NULL; @@ -317,7 +324,10 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) memFile.size = size; /* check whether or not we have a TIFF file */ - assert(size >= IMB_TIFF_NCB); + if (size < IMB_TIFF_NCB) { + fprintf(stderr, "imb_loadtiff: size < IMB_TIFF_NCB\n"); + return NULL; + } if (imb_is_a_tiff(mem) == 0) return NULL; @@ -336,11 +346,13 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) bytesperpixel = 4; /* 1 byte per channel, 4 channels */ libtiff_TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); libtiff_TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); + libtiff_TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bitspersample); ibuf = IMB_allocImBuf(width, height, 8*bytesperpixel, 0, 0); if (ibuf) { ibuf->ftype = TIF; } else { - printf("imb_loadtiff: could not allocate memory for TIFF " \ + fprintf(stderr, + "imb_loadtiff: could not allocate memory for TIFF " \ "image.\n"); libtiff_TIFFClose(image); return NULL; @@ -362,7 +374,8 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) success = libtiff_TIFFReadRGBAImage( image, width, height, raster, 0); if (!success) { - printf("imb_loadtiff: This TIFF format is not " \ + fprintf(stderr, + "imb_loadtiff: This TIFF format is not " "currently supported by Blender.\n"); libtiff__TIFFfree(raster); libtiff_TIFFClose(image); @@ -378,7 +391,8 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) /* this may not be entirely necessary, but is put here * in case sizeof(unsigned int) is not a 32-bit * quantity */ - printf("imb_loadtiff: using (slower) component-wise " \ + fprintf(stderr, + "imb_loadtiff: using (slower) component-wise " "buffer copy.\n"); to = (unsigned char*)ibuf->rect; for (pixel_i=0; pixel_i < width*height; pixel_i++) @@ -405,8 +419,6 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) return (ibuf); } - - /** * Saves a TIFF file. * @@ -422,14 +434,19 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags) * * @return: 1 if the function is successful, 0 on failure. */ + +#define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f)) + short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) { TIFF *image = NULL; - uint16 samplesperpixel; + uint16 samplesperpixel, bitspersample; size_t npixels; unsigned char *pixels = NULL; unsigned char *from = NULL, *to = NULL; - int x, y, from_i, to_i; + unsigned short *pixels16 = NULL, *to16 = NULL; + float *fromf = NULL; + int x, y, from_i, to_i, i; int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA }; /* check for a valid number of bytes per pixel. Like the PNG writer, @@ -437,15 +454,22 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) * to gray, RGB, RGBA respectively. */ samplesperpixel = (uint16)((ibuf->depth + 7) >> 3); if ((samplesperpixel > 4) || (samplesperpixel == 2)) { - printf("imb_savetiff: unsupported number of bytes per " \ + fprintf(stderr, + "imb_savetiff: unsupported number of bytes per " "pixel: %d\n", samplesperpixel); return (0); } + if((ibuf->ftype & TIF_16BIT) && ibuf->rect_float) + bitspersample = 16; + else + bitspersample = 8; + /* open TIFF file for writing */ if (flags & IB_mem) { /* bork at the creation of a TIFF in memory */ - printf("imb_savetiff: creation of in-memory TIFF files is " \ + fprintf(stderr, + "imb_savetiff: creation of in-memory TIFF files is " "not yet supported.\n"); return (0); } else { @@ -453,72 +477,74 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) image = libtiff_TIFFOpen(name, "w"); } if (image == NULL) { - printf("imb_savetiff: could not open TIFF for writing.\n"); + fprintf(stderr, + "imb_savetiff: could not open TIFF for writing.\n"); return (0); } /* allocate array for pixel data */ npixels = ibuf->x * ibuf->y; - pixels = (unsigned char*)libtiff__TIFFmalloc(npixels * - samplesperpixel * sizeof(unsigned char)); - if (pixels == NULL) { - printf("imb_savetiff: could not allocate pixels array.\n"); + if(ibuf->ftype & TIF_16BIT) + pixels16 = (unsigned short*)libtiff__TIFFmalloc(npixels * + samplesperpixel * sizeof(unsigned short)); + else + pixels = (unsigned char*)libtiff__TIFFmalloc(npixels * + samplesperpixel * sizeof(unsigned char)); + + if (pixels == NULL && pixels16 == NULL) { + fprintf(stderr, + "imb_savetiff: could not allocate pixels array.\n"); libtiff_TIFFClose(image); return (0); } - /* copy pixel data. While copying, we flip the image - * vertically. */ - from = (unsigned char*)ibuf->rect; - to = pixels; + /* setup pointers */ + if(ibuf->ftype & TIF_16BIT) { + fromf = ibuf->rect_float; + to16 = pixels16; + } + else { + from = (unsigned char*)ibuf->rect; + to = pixels; + } + + /* setup samples per pixel */ + libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample); libtiff_TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); - switch (samplesperpixel) { - case 4: /* RGBA images, 8 bits per channel */ - libtiff_TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, - extraSampleTypes); - libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8); - libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, - PHOTOMETRIC_RGB); - for (x = 0; x < ibuf->x; x++) { - for (y = 0; y < ibuf->y; y++) { - from_i = 4*(y*ibuf->x+x); - to_i = 4*((ibuf->y-y-1)*ibuf->x+x); - - to[to_i++] = from[from_i++]; - to[to_i++] = from[from_i++]; - to[to_i++] = from[from_i++]; - to[to_i] = from[from_i]; - } - } - break; - case 3: /* RGB images, 8 bits per channel */ - libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8); - libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, - PHOTOMETRIC_RGB); - for (x = 0; x < ibuf->x; x++) { - for (y = 0; y < ibuf->y; y++) { - from_i = 4*(y*ibuf->x+x); - to_i = 3*((ibuf->y-y-1)*ibuf->x+x); - - to[to_i++] = from[from_i++]; - to[to_i++] = from[from_i++]; - to[to_i] = from[from_i]; - } - } - break; - case 1: /* greyscale images, 1 channel with 8 bits */ - libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8); - libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, - PHOTOMETRIC_MINISBLACK); - for (x = 0; x < ibuf->x; x++) { - for (y = 0; y < ibuf->y; y++) { - from_i = 4*(y*ibuf->x+x); - to_i = 1*((ibuf->y-y-1)*ibuf->x+x); + if(samplesperpixel == 4) { + /* RGBA images */ + libtiff_TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, + extraSampleTypes); + libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + PHOTOMETRIC_RGB); + } + else if(samplesperpixel == 3) { + /* RGB images */ + libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + PHOTOMETRIC_RGB); + } + else if(samplesperpixel == 1) { + /* greyscale images, 1 channel */ + libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC, + PHOTOMETRIC_MINISBLACK); + } + + /* copy pixel data. While copying, we flip the image vertically. */ + for (x = 0; x < ibuf->x; x++) { + for (y = 0; y < ibuf->y; y++) { + from_i = 4*(y*ibuf->x+x); + to_i = samplesperpixel*((ibuf->y-y-1)*ibuf->x+x); + + if(pixels16) { + for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) + to16[to_i] = FTOUSHORT(fromf[from_i]); + } + else { + for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) to[to_i] = from[from_i]; - } } - break; + } } /* write the actual TIFF file */ @@ -531,17 +557,21 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags) libtiff_TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0); libtiff_TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0); libtiff_TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - if (libtiff_TIFFWriteEncodedStrip(image, 0, pixels, - ibuf->x*ibuf->y*samplesperpixel) == -1) { - printf("imb_savetiff: Could not write encoded TIFF.\n"); + if (libtiff_TIFFWriteEncodedStrip(image, 0, + (bitspersample == 16)? (unsigned char*)pixels16: pixels, + ibuf->x*ibuf->y*samplesperpixel*bitspersample/8) == -1) { + fprintf(stderr, + "imb_savetiff: Could not write encoded TIFF.\n"); libtiff_TIFFClose(image); - libtiff__TIFFfree(pixels); + if(pixels) libtiff__TIFFfree(pixels); + if(pixels16) libtiff__TIFFfree(pixels16); return (1); } /* close the TIFF file */ libtiff_TIFFClose(image); - libtiff__TIFFfree(pixels); + if(pixels) libtiff__TIFFfree(pixels); + if(pixels16) libtiff__TIFFfree(pixels16); return (1); } diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 69390951a25..acf15c04ed9 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") || @@ -274,8 +289,9 @@ static int isffmpeg (char *filename) { /* Find the first video stream */ videoStream=-1; for(i=0; i<pFormatCtx->nb_streams; i++) - if(get_codec_from_stream(pFormatCtx->streams[i]) - ->codec_type==CODEC_TYPE_VIDEO) + if(pFormatCtx->streams[i] && + get_codec_from_stream(pFormatCtx->streams[i]) && + (get_codec_from_stream(pFormatCtx->streams[i])->codec_type==CODEC_TYPE_VIDEO)) { videoStream=i; break; 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); |