migrated NDOF code from soc-2010-merwin, SpaceNavigator now works on Mac blender
[blender.git] / source / blender / blenkernel / intern / customdata_file.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/blenkernel/intern/customdata_file.c
24  *  \ingroup bke
25  */
26
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_fileops.h"
35 #include "BLI_string.h"
36 #include "BLI_utildefines.h"
37
38 #include "BKE_customdata_file.h"
39 #include "BKE_global.h"
40
41
42 /************************* File Format Definitions ***************************/
43
44 #define CDF_ENDIAN_LITTLE       0
45 #define CDF_ENDIAN_BIG          1
46
47 #define CDF_DATA_FLOAT  0
48
49 typedef struct CDataFileHeader {
50         char ID[4];                                     /* "BCDF" */
51         char endian;                            /* little, big */
52         char version;                           /* non-compatible versions */
53         char subversion;                        /* compatible sub versions */
54         char pad;                                       /* padding */
55
56         int structbytes;                        /* size of this struct in bytes */
57         int type;                                       /* image, mesh */
58         int totlayer;                           /* number of layers in the file */
59 } CDataFileHeader;
60
61 typedef struct CDataFileImageHeader {
62         int structbytes;                        /* size of this struct in bytes */
63         int width;                                      /* image width */
64         int height;                                     /* image height */
65         int tile_size;                          /* tile size (required power of 2) */
66 } CDataFileImageHeader;
67
68 typedef struct CDataFileMeshHeader {
69         int structbytes;                        /* size of this struct in bytes */
70 } CDataFileMeshHeader;
71
72 struct CDataFileLayer {
73         int structbytes;                                /* size of this struct in bytes */
74         int datatype;                                   /* only float for now */
75         uint64_t datasize;                              /* size of data in layer */
76         int type;                                               /* layer type */
77         char name[CDF_LAYER_NAME_MAX];  /* layer name */
78 };
79
80 /**************************** Other Definitions ******************************/
81
82 #define CDF_VERSION                     0
83 #define CDF_SUBVERSION          0
84 #define CDF_TILE_SIZE           64
85
86 struct CDataFile {
87         int type;
88
89         CDataFileHeader header;
90         union {
91                 CDataFileImageHeader image;
92                 CDataFileMeshHeader mesh;
93         } btype;
94
95         CDataFileLayer *layer;
96         int totlayer;
97
98         FILE *readf;
99         FILE *writef;
100         int switchendian;
101         size_t dataoffset;
102 };
103
104 /********************************* Create/Free *******************************/
105
106 static int cdf_endian(void)
107 {
108         if(ENDIAN_ORDER == L_ENDIAN)
109                 return CDF_ENDIAN_LITTLE;
110         else
111                 return CDF_ENDIAN_BIG;
112 }
113
114 /*static int cdf_data_type_size(int datatype)
115 {
116         if(datatype == CDF_DATA_FLOAT)
117                 return sizeof(float);
118         
119         return 0;
120 }*/
121
122 CDataFile *cdf_create(int type)
123 {
124         CDataFile *cdf= MEM_callocN(sizeof(CDataFile), "CDataFile");
125
126         cdf->type= type;
127
128         return cdf;
129 }
130
131 void cdf_free(CDataFile *cdf)
132 {
133         cdf_read_close(cdf);
134         cdf_write_close(cdf);
135
136         if(cdf->layer)
137                 MEM_freeN(cdf->layer);
138
139         MEM_freeN(cdf);
140 }
141
142 /********************************* Read/Write ********************************/
143
144 static int cdf_read_header(CDataFile *cdf)
145 {
146         CDataFileHeader *header;
147         CDataFileImageHeader *image;
148         CDataFileMeshHeader *mesh;
149         CDataFileLayer *layer;
150         FILE *f= cdf->readf;
151         size_t offset = 0;
152         int a;
153
154         header= &cdf->header;
155
156         if(!fread(header, sizeof(CDataFileHeader), 1, cdf->readf))
157                 return 0;
158         
159         if(memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0)
160                 return 0;
161         if(header->version > CDF_VERSION)
162                 return 0;
163
164         cdf->switchendian= header->endian != cdf_endian();
165         header->endian= cdf_endian();
166
167         if(cdf->switchendian) {
168                 SWITCH_INT(header->type);
169                 SWITCH_INT(header->totlayer);
170                 SWITCH_INT(header->structbytes);
171         }
172
173         if(!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH))
174                 return 0;
175
176         offset += header->structbytes;
177         header->structbytes= sizeof(CDataFileHeader);
178
179         if(fseek(f, offset, SEEK_SET) != 0)
180                 return 0;
181         
182         if(header->type == CDF_TYPE_IMAGE) {
183                 image= &cdf->btype.image;
184                 if(!fread(image, sizeof(CDataFileImageHeader), 1, f))
185                         return 0;
186
187                 if(cdf->switchendian) {
188                         SWITCH_INT(image->width);
189                         SWITCH_INT(image->height);
190                         SWITCH_INT(image->tile_size);
191                         SWITCH_INT(image->structbytes);
192                 }
193
194                 offset += image->structbytes;
195                 image->structbytes= sizeof(CDataFileImageHeader);
196         }
197         else if(header->type == CDF_TYPE_MESH) {
198                 mesh= &cdf->btype.mesh;
199                 if(!fread(mesh, sizeof(CDataFileMeshHeader), 1, f))
200                         return 0;
201
202                 if(cdf->switchendian)
203                         SWITCH_INT(mesh->structbytes);
204
205                 offset += mesh->structbytes;
206                 mesh->structbytes= sizeof(CDataFileMeshHeader);
207         }
208
209         if(fseek(f, offset, SEEK_SET) != 0)
210                 return 0;
211
212         cdf->layer= MEM_callocN(sizeof(CDataFileLayer)*header->totlayer, "CDataFileLayer");
213         cdf->totlayer= header->totlayer;
214
215         for(a=0; a<header->totlayer; a++) {
216                 layer= &cdf->layer[a];
217
218                 if(!fread(layer, sizeof(CDataFileLayer), 1, f))
219                         return 0;
220
221                 if(cdf->switchendian) {
222                         SWITCH_INT(layer->type);
223                         SWITCH_INT(layer->datatype);
224                         SWITCH_INT64(layer->datasize);
225                         SWITCH_INT(layer->structbytes);
226                 }
227
228                 if(layer->datatype != CDF_DATA_FLOAT)
229                         return 0;
230
231                 offset += layer->structbytes;
232                 layer->structbytes= sizeof(CDataFileLayer);
233
234                 if(fseek(f, offset, SEEK_SET) != 0)
235                         return 0;
236         }
237
238         cdf->dataoffset= offset;
239
240         return 1;
241 }
242
243 static int cdf_write_header(CDataFile *cdf)
244 {
245         CDataFileHeader *header;
246         CDataFileImageHeader *image;
247         CDataFileMeshHeader *mesh;
248         CDataFileLayer *layer;
249         FILE *f= cdf->writef;
250         int a;
251
252         header= &cdf->header;
253
254         if(!fwrite(header, sizeof(CDataFileHeader), 1, f))
255                 return 0;
256         
257         if(header->type == CDF_TYPE_IMAGE) {
258                 image= &cdf->btype.image;
259                 if(!fwrite(image, sizeof(CDataFileImageHeader), 1, f))
260                         return 0;
261         }
262         else if(header->type == CDF_TYPE_MESH) {
263                 mesh= &cdf->btype.mesh;
264                 if(!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f))
265                         return 0;
266         }
267
268         for(a=0; a<header->totlayer; a++) {
269                 layer= &cdf->layer[a];
270
271                 if(!fwrite(layer, sizeof(CDataFileLayer), 1, f))
272                         return 0;
273         }
274
275         return 1;
276 }
277
278 int cdf_read_open(CDataFile *cdf, char *filename)
279 {
280         FILE *f;
281
282         f= fopen(filename, "rb");
283         if(!f)
284                 return 0;
285         
286         cdf->readf= f;
287
288         if(!cdf_read_header(cdf)) {
289                 cdf_read_close(cdf);
290                 return 0;
291         }
292
293         if(cdf->header.type != cdf->type) {
294                 cdf_read_close(cdf);
295                 return 0;
296         }
297
298         return 1;
299 }
300
301 int cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
302 {
303         size_t offset;
304         int a;
305
306         /* seek to right location in file */
307         offset= cdf->dataoffset;
308         for(a=0; a<cdf->totlayer; a++) {
309                 if(&cdf->layer[a] == blay)
310                         break;
311                 else
312                         offset += cdf->layer[a].datasize;
313         }
314
315         return (fseek(cdf->readf, offset, SEEK_SET) == 0);
316 }
317
318 int cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
319 {
320         float *fdata;
321         unsigned int a;
322
323         /* read data */
324         if(!fread(data, size, 1, cdf->readf))
325                 return 0;
326
327         /* switch endian if necessary */
328         if(cdf->switchendian) {
329                 fdata= data;
330
331                 for(a=0; a<size/sizeof(float); a++)
332                         SWITCH_INT(fdata[a])
333         }
334
335         return 1;
336 }
337
338 void cdf_read_close(CDataFile *cdf)
339 {
340         if(cdf->readf) {
341                 fclose(cdf->readf);
342                 cdf->readf= NULL;
343         }
344 }
345
346 int cdf_write_open(CDataFile *cdf, char *filename)
347 {
348         CDataFileHeader *header;
349         CDataFileImageHeader *image;
350         CDataFileMeshHeader *mesh;
351         FILE *f;
352
353         f= fopen(filename, "wb");
354         if(!f)
355                 return 0;
356         
357         cdf->writef= f;
358
359         /* fill header */
360         header= &cdf->header;
361         /* strcpy(, "BCDF"); // terminator out of range */
362         header->ID[0]= 'B'; header->ID[1]= 'C'; header->ID[2]= 'D'; header->ID[3]= 'F';
363         header->endian= cdf_endian();
364         header->version= CDF_VERSION;
365         header->subversion= CDF_SUBVERSION;
366
367         header->structbytes= sizeof(CDataFileHeader);
368         header->type= cdf->type;
369         header->totlayer= cdf->totlayer;
370
371         if(cdf->type == CDF_TYPE_IMAGE) {
372                 /* fill image header */
373                 image= &cdf->btype.image;
374                 image->structbytes= sizeof(CDataFileImageHeader);
375                 image->tile_size= CDF_TILE_SIZE;
376         }
377         else if(cdf->type == CDF_TYPE_MESH) {
378                 /* fill mesh header */
379                 mesh= &cdf->btype.mesh;
380                 mesh->structbytes= sizeof(CDataFileMeshHeader);
381         }
382
383         cdf_write_header(cdf);
384
385         return 1;
386 }
387
388 int cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
389 {
390         return 1;
391 }
392
393 int cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
394 {
395         /* write data */
396         if(!fwrite(data, size, 1, cdf->writef))
397                 return 0;
398
399         return 1;
400 }
401
402 void cdf_write_close(CDataFile *cdf)
403 {
404         if(cdf->writef) {
405                 fclose(cdf->writef);
406                 cdf->writef= NULL;
407         }
408 }
409
410 void cdf_remove(char *filename)
411 {
412         BLI_delete(filename, 0, 0);
413 }
414
415 /********************************** Layers ***********************************/
416
417 CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, char *name)
418 {
419         CDataFileLayer *layer;
420         int a;
421
422         for(a=0; a<cdf->totlayer; a++) {
423                 layer= &cdf->layer[a];
424
425                 if(layer->type == type && strcmp(layer->name, name) == 0)
426                         return layer;
427         }
428         
429         return NULL;
430 }
431
432 CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, char *name, size_t datasize)
433 {
434         CDataFileLayer *newlayer, *layer;
435
436         /* expand array */
437         newlayer= MEM_callocN(sizeof(CDataFileLayer)*(cdf->totlayer+1), "CDataFileLayer");
438         memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer)*cdf->totlayer);
439         cdf->layer= newlayer;
440
441         cdf->totlayer++;
442
443         /* fill in new layer */
444         layer= &cdf->layer[cdf->totlayer-1];
445         layer->structbytes= sizeof(CDataFileLayer);
446         layer->datatype= CDF_DATA_FLOAT;
447         layer->datasize= datasize;
448         layer->type= type;
449         BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
450
451         return layer;
452 }
453