363e515f6e2486656e6aaf42b00b0ddac75be349
[blender.git] / source / blender / blenkernel / intern / btex.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_fileops.h"
30 #include "BLI_string.h"
31
32 #include "BKE_btex.h"
33 #include "BKE_global.h"
34 #include "BKE_utildefines.h"
35
36 /************************* File Format Definitions ***************************/
37
38 #define BTEX_ENDIAN_LITTLE      0
39 #define BTEX_ENDIAN_BIG         1
40
41 #define BTEX_DATA_FLOAT 0
42
43 typedef struct BTexHeader {
44         char ID[4];                                     /* "BTEX" */
45         char endian;                            /* little, big */
46         char version;                           /* non-compatible versions */
47         char subversion;                        /* compatible sub versions */
48         char pad;                                       /* padding */
49
50         int structbytes;                        /* size of this struct in bytes */
51         int type;                                       /* image, mesh */
52         int totlayer;                           /* number of layers in the file */
53 } BTexHeader;
54
55 typedef struct BTexImageHeader {
56         int structbytes;                        /* size of this struct in bytes */
57         int width;                                      /* image width */
58         int height;                                     /* image height */
59         int tile_size;                          /* tile size (required power of 2) */
60 } BTexImageHeader;
61
62 typedef struct BTexMeshHeader {
63         int structbytes;                        /* size of this struct in bytes */
64         int totgrid;                            /* number of grids */
65         int gridsize;                           /* width of grids */
66 } BTexMeshHeader;
67
68 struct BTexLayer {
69         int structbytes;                                /* size of this struct in bytes */
70         int datatype;                                   /* only float for now */
71         int datasize;                                   /* size of data in layer */
72         int type;                                               /* layer type */
73         char name[BTEX_LAYER_NAME_MAX]; /* layer name */
74 };
75
76 /**************************** Other Definitions ******************************/
77
78 #define BTEX_VERSION            0
79 #define BTEX_SUBVERSION         0
80 #define BTEX_TILE_SIZE          64
81
82 struct BTex {
83         int type;
84
85         BTexHeader header;
86         union {
87                 BTexImageHeader image;
88                 BTexMeshHeader mesh;
89         } btype;
90
91         BTexLayer *layer;
92         int totlayer;
93
94         FILE *readf;
95         FILE *writef;
96         int switchendian;
97         size_t dataoffset;
98 };
99
100 /********************************* Create/Free *******************************/
101
102 static int btex_endian(void)
103 {
104         if(ENDIAN_ORDER == L_ENDIAN)
105                 return BTEX_ENDIAN_LITTLE;
106         else
107                 return BTEX_ENDIAN_BIG;
108 }
109
110 /*static int btex_data_type_size(int datatype)
111 {
112         if(datatype == BTEX_DATA_FLOAT)
113                 return sizeof(float);
114         
115         return 0;
116 }*/
117
118 BTex *btex_create(int type)
119 {
120         BTex *btex= MEM_callocN(sizeof(BTex), "BTex");
121
122         btex->type= type;
123
124         return btex;
125 }
126
127 void btex_free(BTex *btex)
128 {
129         btex_read_close(btex);
130         btex_write_close(btex);
131
132         if(btex->layer)
133                 MEM_freeN(btex->layer);
134
135         MEM_freeN(btex);
136 }
137
138 /********************************* Read/Write ********************************/
139
140 static int btex_read_header(BTex *btex)
141 {
142         BTexHeader *header;
143         BTexImageHeader *image;
144         BTexMeshHeader *mesh;
145         BTexLayer *layer;
146         FILE *f= btex->readf;
147         size_t offset = 0;
148         int a;
149
150         header= &btex->header;
151
152         if(!fread(header, sizeof(BTexHeader), 1, btex->readf))
153                 return 0;
154         
155         if(memcmp(header->ID, "BTEX", sizeof(header->ID)) != 0)
156                 return 0;
157         if(header->version > BTEX_VERSION)
158                 return 0;
159
160         btex->switchendian= header->endian != btex_endian();
161         header->endian= btex_endian();
162
163         if(btex->switchendian) {
164                 SWITCH_INT(header->type);
165                 SWITCH_INT(header->totlayer);
166                 SWITCH_INT(header->structbytes);
167         }
168
169         if(!ELEM(header->type, BTEX_TYPE_IMAGE, BTEX_TYPE_MESH))
170                 return 0;
171
172         offset += header->structbytes;
173         header->structbytes= sizeof(BTexHeader);
174
175         if(fseek(f, offset, SEEK_SET) != 0)
176                 return 0;
177         
178         if(header->type == BTEX_TYPE_IMAGE) {
179                 image= &btex->btype.image;
180                 if(!fread(image, sizeof(BTexImageHeader), 1, f))
181                         return 0;
182
183                 if(btex->switchendian) {
184                         SWITCH_INT(image->width);
185                         SWITCH_INT(image->height);
186                         SWITCH_INT(image->tile_size);
187                         SWITCH_INT(image->structbytes);
188                 }
189
190                 offset += image->structbytes;
191                 image->structbytes= sizeof(BTexImageHeader);
192         }
193         else if(header->type == BTEX_TYPE_MESH) {
194                 mesh= &btex->btype.mesh;
195                 if(!fread(mesh, sizeof(BTexMeshHeader), 1, f))
196                         return 0;
197
198                 if(btex->switchendian) {
199                         SWITCH_INT(mesh->totgrid);
200                         SWITCH_INT(mesh->gridsize);
201                         SWITCH_INT(mesh->structbytes);
202                 }
203
204                 offset += mesh->structbytes;
205                 mesh->structbytes= sizeof(BTexMeshHeader);
206         }
207
208         if(fseek(f, offset, SEEK_SET) != 0)
209                 return 0;
210
211         btex->layer= MEM_callocN(sizeof(BTexLayer)*header->totlayer, "BTexLayer");
212         btex->totlayer= header->totlayer;
213
214         for(a=0; a<header->totlayer; a++) {
215                 layer= &btex->layer[a];
216
217                 if(!fread(layer, sizeof(BTexLayer), 1, f))
218                         return 0;
219
220                 if(btex->switchendian) {
221                         SWITCH_INT(layer->type);
222                         SWITCH_INT(layer->datatype);
223                         SWITCH_INT(layer->datasize);
224                         SWITCH_INT(layer->structbytes);
225                 }
226
227                 if(layer->datatype != BTEX_DATA_FLOAT)
228                         return 0;
229
230                 offset += layer->structbytes;
231                 layer->structbytes= sizeof(BTexLayer);
232
233                 if(fseek(f, offset, SEEK_SET) != 0)
234                         return 0;
235         }
236
237         btex->dataoffset= offset;
238
239         return 1;
240 }
241
242 static int btex_write_header(BTex *btex)
243 {
244         BTexHeader *header;
245         BTexImageHeader *image;
246         BTexMeshHeader *mesh;
247         BTexLayer *layer;
248         FILE *f= btex->writef;
249         int a;
250
251         header= &btex->header;
252
253         if(!fwrite(header, sizeof(BTexHeader), 1, f))
254                 return 0;
255         
256         if(header->type == BTEX_TYPE_IMAGE) {
257                 image= &btex->btype.image;
258                 if(!fwrite(image, sizeof(BTexImageHeader), 1, f))
259                         return 0;
260         }
261         else if(header->type == BTEX_TYPE_MESH) {
262                 mesh= &btex->btype.mesh;
263                 if(!fwrite(mesh, sizeof(BTexMeshHeader), 1, f))
264                         return 0;
265         }
266
267         for(a=0; a<header->totlayer; a++) {
268                 layer= &btex->layer[a];
269
270                 if(!fwrite(layer, sizeof(BTexLayer), 1, f))
271                         return 0;
272         }
273
274         return 1;
275 }
276
277 int btex_read_open(BTex *btex, char *filename)
278 {
279         FILE *f;
280
281         f= fopen(filename, "rb");
282         if(!f)
283                 return 0;
284         
285         btex->readf= f;
286
287         if(!btex_read_header(btex)) {
288                 btex_read_close(btex);
289                 return 0;
290         }
291
292         if(btex->header.type != btex->type) {
293                 btex_read_close(btex);
294                 return 0;
295         }
296
297         return 1;
298 }
299
300 int btex_read_layer(BTex *btex, BTexLayer *blay)
301 {
302         size_t offset;
303         int a;
304
305         /* seek to right location in file */
306         offset= btex->dataoffset;
307         for(a=0; a<btex->totlayer; a++) {
308                 if(&btex->layer[a] == blay)
309                         break;
310                 else
311                         offset += btex->layer[a].datasize;
312         }
313
314         return (fseek(btex->readf, offset, SEEK_SET) == 0);
315 }
316
317 int btex_read_data(BTex *btex, int size, void *data)
318 {
319         float *fdata;
320         int a;
321         
322         /* read data */
323         if(!fread(data, size, 1, btex->readf))
324                 return 0;
325
326         /* switch endian if necessary */
327         if(btex->switchendian) {
328                 fdata= data;
329
330                 for(a=0; a<size/sizeof(float); a++)
331                         SWITCH_INT(fdata[a])
332         }
333
334         return 1;
335 }
336
337 void btex_read_close(BTex *btex)
338 {
339         if(btex->readf) {
340                 fclose(btex->readf);
341                 btex->readf= NULL;
342         }
343 }
344
345 int btex_write_open(BTex *btex, char *filename)
346 {
347         BTexHeader *header;
348         BTexImageHeader *image;
349         BTexMeshHeader *mesh;
350         FILE *f;
351
352         f= fopen(filename, "wb");
353         if(!f)
354                 return 0;
355         
356         btex->writef= f;
357
358         /* fill header */
359         header= &btex->header;
360         strcpy(header->ID, "BTEX");
361         header->endian= btex_endian();
362         header->version= BTEX_VERSION;
363         header->subversion= BTEX_SUBVERSION;
364
365         header->structbytes= sizeof(BTexHeader);
366         header->type= btex->type;
367         header->totlayer= btex->totlayer;
368
369         if(btex->type == BTEX_TYPE_IMAGE) {
370                 /* fill image header */
371                 image= &btex->btype.image;
372                 image->structbytes= sizeof(BTexImageHeader);
373                 image->tile_size= BTEX_TILE_SIZE;
374         }
375         else if(btex->type == BTEX_TYPE_MESH) {
376                 /* fill mesh header */
377                 mesh= &btex->btype.mesh;
378                 mesh->structbytes= sizeof(BTexMeshHeader);
379         }
380
381         btex_write_header(btex);
382
383         return 1;
384 }
385
386 int btex_write_layer(BTex *btex, BTexLayer *blay)
387 {
388         return 1;
389 }
390
391 int btex_write_data(BTex *btex, int size, void *data)
392 {
393         /* write data */
394         if(!fwrite(data, size, 1, btex->writef))
395                 return 0;
396
397         return 1;
398 }
399
400 void btex_write_close(BTex *btex)
401 {
402         if(btex->writef) {
403                 fclose(btex->writef);
404                 btex->writef= NULL;
405         }
406 }
407
408 void btex_remove(char *filename)
409 {
410         BLI_delete(filename, 0, 0);
411 }
412
413 /********************************** Layers ***********************************/
414
415 BTexLayer *btex_layer_find(BTex *btex, int type, char *name)
416 {
417         BTexLayer *layer;
418         int a;
419
420         for(a=0; a<btex->totlayer; a++) {
421                 layer= &btex->layer[a];
422
423                 if(layer->type == type && strcmp(layer->name, name) == 0)
424                         return layer;
425         }
426         
427         return NULL;
428 }
429
430 BTexLayer *btex_layer_add(BTex *btex, int type, char *name)
431 {
432         BTexLayer *newlayer, *layer;
433
434         /* expand array */
435         newlayer= MEM_callocN(sizeof(BTexLayer)*(btex->totlayer+1), "BTexLayer");
436         memcpy(newlayer, btex->layer, sizeof(BTexLayer)*btex->totlayer);
437         btex->layer= newlayer;
438
439         btex->totlayer++;
440
441         /* fill in new layer */
442         layer= &btex->layer[btex->totlayer-1];
443         layer->structbytes= sizeof(BTexLayer);
444         layer->datatype= BTEX_DATA_FLOAT;
445         layer->type= type;
446         BLI_strncpy(layer->name, name, BTEX_LAYER_NAME_MAX);
447
448         return layer;
449 }
450
451 void btex_layer_remove(BTex *btex, BTexLayer *layer)
452 {
453         BTexLayer *newlayer;
454         int index= layer - btex->layer;
455
456         /* expand array */
457         newlayer= MEM_callocN(sizeof(BTexLayer)*(btex->totlayer-1), "BTexLayer");
458         if(index > 0)
459                 memcpy(newlayer, btex->layer, sizeof(BTexLayer)*index);
460         if(index+1 < btex->totlayer)
461                 memcpy(newlayer+index, btex->layer+index+1, sizeof(BTexLayer)*(btex->totlayer-(index+1)));
462         btex->layer= newlayer;
463
464         btex->totlayer--;
465 }
466
467 /********************************* Mesh **************************************/
468
469 void btex_mesh_set_grids(BTex *btex, int totgrid, int gridsize, int datasize)
470 {
471         BTexLayer *layer;
472         int a;
473
474         btex->btype.mesh.totgrid= totgrid;
475         btex->btype.mesh.gridsize= gridsize;
476
477         for(a=0; a<btex->totlayer; a++) {
478                 layer= &btex->layer[a];
479                 layer->datasize= datasize;
480         }
481 }
482