12e03f554507132e38a5872a8068dfb1123787fe
[blender-staging.git] / source / blender / imbuf / intern / dds / dds_api.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributors: Amorilia (amorilia@users.sourceforge.net)
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/imbuf/intern/dds/dds_api.cpp
24  *  \ingroup imbdds
25  */
26
27
28 extern "C" {
29 #include "BLI_utildefines.h"
30 }
31
32 #include <stddef.h>
33 #include <dds_api.h>
34 #include <Stream.h>
35 #include <DirectDrawSurface.h>
36 #include <FlipDXT.h>
37 #include <stdio.h> // printf
38 #include <fstream>
39
40 #if defined (WIN32) && !defined(FREE_WINDOWS)
41 #include "utfconv.h"
42 #endif
43
44 extern "C" {
45
46 #include "imbuf.h"
47 #include "IMB_imbuf_types.h"
48 #include "IMB_imbuf.h"
49 #include "IMB_allocimbuf.h"
50
51 #include "IMB_colormanagement.h"
52 #include "IMB_colormanagement_intern.h"
53
54 int imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/)
55 {
56         return(0); /* todo: finish this function */
57
58         /* check image buffer */
59         if (ibuf == 0) return (0);
60         if (ibuf->rect == 0) return (0);
61
62         /* open file for writing */
63         std::ofstream fildes;
64
65 #if defined (WIN32) && !defined(FREE_WINDOWS)
66         wchar_t *wname = alloc_utf16_from_8(name, 0);
67         fildes.open(wname);
68         free(wname);
69 #else
70         fildes.open(name);
71 #endif
72
73         /* write header */
74         fildes << "DDS ";
75         fildes.close();
76
77         return(1);
78 }
79
80 int imb_is_a_dds(const unsigned char *mem) // note: use at most first 32 bytes
81 {
82         /* heuristic check to see if mem contains a DDS file */
83         /* header.fourcc == FOURCC_DDS */
84         if ((mem[0] != 'D') || (mem[1] != 'D') || (mem[2] != 'S') || (mem[3] != ' ')) return(0);
85         /* header.size == 124 */
86         if ((mem[4] != 124) || mem[5] || mem[6] || mem[7]) return(0);
87         return(1);
88 }
89
90 struct ImBuf *imb_load_dds(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
91 {
92         struct ImBuf *ibuf = NULL;
93         DirectDrawSurface dds((unsigned char *)mem, size); /* reads header */
94         unsigned char bits_per_pixel;
95         unsigned int *rect;
96         Image img;
97         unsigned int numpixels = 0;
98         int col;
99         unsigned char *cp = (unsigned char *) &col;
100         Color32 pixel;
101         Color32 *pixels = 0;
102
103         /* OCIO_TODO: never was able to save DDS, so can't test loading
104          *            but profile used to be set to sRGB and can't see rect_float here, so
105          *            default byte space should work fine
106          */
107         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
108
109         if (!imb_is_a_dds(mem))
110                 return (0);
111
112         /* check if DDS is valid and supported */
113         if (!dds.isValid()) {
114                 /* no need to print error here, just testing if it is a DDS */
115                 if (flags & IB_test)
116                         return (0);
117
118                 printf("DDS: not valid; header follows\n");
119                 dds.printInfo();
120                 return(0);
121         }
122         if (!dds.isSupported()) {
123                 printf("DDS: format not supported\n");
124                 return(0);
125         }
126         if ((dds.width() > 65535) || (dds.height() > 65535)) {
127                 printf("DDS: dimensions too large\n");
128                 return(0);
129         }
130
131         /* convert DDS into ImBuf */
132         dds.mipmap(&img, 0, 0); /* load first face, first mipmap */
133         pixels = img.pixels();
134         numpixels = dds.width() * dds.height();
135         bits_per_pixel = 24;
136         if (img.format() == Image::Format_ARGB) {
137                 /* check that there is effectively an alpha channel */
138                 for (unsigned int i = 0; i < numpixels; i++) {
139                         pixel = pixels[i];
140                         if (pixel.a != 255) {
141                                 bits_per_pixel = 32;
142                                 break;
143                         }
144                 }
145         }
146         ibuf = IMB_allocImBuf(dds.width(), dds.height(), bits_per_pixel, 0); 
147         if (ibuf == 0) return(0); /* memory allocation failed */
148
149         ibuf->ftype = IMB_FTYPE_DDS;
150         ibuf->dds_data.fourcc = dds.fourCC();
151         ibuf->dds_data.nummipmaps = dds.mipmapCount();
152
153         if ((flags & IB_test) == 0) {
154                 if (!imb_addrectImBuf(ibuf)) return(ibuf);
155                 if (ibuf->rect == 0) return(ibuf);
156
157                 rect = ibuf->rect;
158                 cp[3] = 0xff; /* default alpha if alpha channel is not present */
159
160                 for (unsigned int i = 0; i < numpixels; i++) {
161                         pixel = pixels[i];
162                         cp[0] = pixel.r; /* set R component of col */
163                         cp[1] = pixel.g; /* set G component of col */
164                         cp[2] = pixel.b; /* set B component of col */
165                         if (dds.hasAlpha())
166                                 cp[3] = pixel.a; /* set A component of col */
167                         rect[i] = col;
168                 }
169
170                 if (ibuf->dds_data.fourcc != FOURCC_DDS) {
171                         ibuf->dds_data.data = (unsigned char *)dds.readData(ibuf->dds_data.size);
172
173                         /* flip compressed texture */
174                         FlipDXTCImage(dds.width(), dds.height(), dds.mipmapCount(), dds.fourCC(), ibuf->dds_data.data);
175                 }
176                 else {
177                         ibuf->dds_data.data = NULL;
178                         ibuf->dds_data.size = 0;
179                 }
180
181                 /* flip uncompressed texture */
182                 IMB_flipy(ibuf);
183         }
184
185         return(ibuf);
186 }
187
188 } // extern "C"