Initial commit for new text object.
[blender.git] / source / blender / blenloader / intern / writefile.c
1 /* writefile.c
2  *
3  * .blend file writing
4  *
5  * $Id$
6  *
7  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version. The Blender
13  * Foundation also sells licenses for use in proprietary software under
14  * the Blender License.  See http://www.blender.org/BL/ for information
15  * about this.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
27  * All rights reserved.
28  *
29  * The Original Code is: all of this file.
30  *
31  * Contributor(s): none yet.
32  *
33  * ***** END GPL/BL DUAL LICENSE BLOCK *****
34  */
35
36 /*
37 FILEFORMAT: IFF-style structure  (but not IFF compatible!)
38
39 start file:
40         BLENDER_V100    12 bytes  (versie 1.00)
41                                         V = big endian, v = little endian
42                                         _ = 4 byte pointer, - = 8 byte pointer
43
44 datablocks:             also see struct BHead
45         <bh.code>                       4 chars
46         <bh.len>                        int,  len data after BHead
47         <bh.old>                        void,  old pointer
48         <bh.SDNAnr>                     int
49         <bh.nr>                         int, in case of array: amount of structs
50         data
51         ...
52         ...
53
54 Almost all data in Blender are structures. Each struct saved
55 gets a BHead header.  With BHead the struct can be linked again
56 and compared with StructDNA .
57
58 WRITE
59
60 Preferred writing order: (not really a must, but why would you do it random?)
61 Any case: direct data is ALWAYS after the lib block
62
63 (Local file data)
64 - for each LibBlock
65         - write LibBlock
66         - write associated direct data
67 (External file data)
68 - per library
69         - write library block
70         - per LibBlock
71                 - write the ID of LibBlock
72 - write FileGlobal (some global vars)
73 - write SDNA
74 - write USER if filename is ~/.B.blend
75 */
76
77 /* for version 2.2+
78 Important to know is that 'streaming' has been added to files, for Blender Publisher
79 */
80
81
82 #ifdef HAVE_CONFIG_H
83 #include <config.h>
84 #endif
85
86 #ifndef WIN32
87 #include <unistd.h>
88 #else
89 #include "winsock2.h"
90 #include "BLI_winstuff.h"
91 #include <io.h>
92 #include <process.h> // for getpid
93 #endif
94
95 #include <math.h>
96 #include <fcntl.h>
97 #include <stdio.h>
98 #include <string.h>
99 #include <stdlib.h>
100
101 #include "nla.h" //  __NLA is defined
102
103 #include "DNA_armature_types.h"
104 #include "DNA_action_types.h"
105 #include "DNA_actuator_types.h"
106 #include "DNA_controller_types.h"
107 #include "DNA_curve_types.h"
108 #include "DNA_constraint_types.h"
109 #include "DNA_camera_types.h"
110 #include "DNA_effect_types.h"
111 #include "DNA_group_types.h"
112 #include "DNA_image_types.h"
113 #include "DNA_ika_types.h"
114 #include "DNA_ipo_types.h"
115 #include "DNA_fileglobal_types.h"
116 #include "DNA_key_types.h"
117 #include "DNA_lattice_types.h"
118 #include "DNA_listBase.h" /* for Listbase, the type of samples, ...*/
119 #include "DNA_lamp_types.h"
120 #include "DNA_meta_types.h"
121 #include "DNA_mesh_types.h"
122 #include "DNA_meshdata_types.h"
123 #include "DNA_material_types.h"
124 #include "DNA_nla_types.h"
125 #include "DNA_object_types.h"
126 #include "DNA_object_force.h"
127 #include "DNA_oops_types.h"
128 #include "DNA_packedFile_types.h"
129 #include "DNA_property_types.h"
130 #include "DNA_scene_types.h"
131 #include "DNA_sdna_types.h"
132 #include "DNA_sequence_types.h"
133 #include "DNA_sensor_types.h"
134 #include "DNA_space_types.h"
135 #include "DNA_screen_types.h"
136 #include "DNA_sound_types.h"
137 #include "DNA_texture_types.h"
138 #include "DNA_text_types.h"
139 #include "DNA_view3d_types.h"
140 #include "DNA_vfont_types.h"
141 #include "DNA_userdef_types.h"
142
143 #include "MEM_guardedalloc.h" // MEM_freeN
144 #include "BLI_blenlib.h"
145 #include "BLI_linklist.h"
146
147 #include "BKE_action.h"
148 #include "BKE_bad_level_calls.h" // build_seqar (from WHILE_SEQ) free_oops error
149 #include "BKE_curve.h"
150 #include "BKE_constraint.h"
151 #include "BKE_global.h" // for G
152 #include "BKE_library.h" // for  set_listbasepointers
153 #include "BKE_main.h" // G.main
154 #include "BKE_packedFile.h" // for packAll
155 #include "BKE_screen.h" // for waitcursor
156 #include "BKE_scene.h" // for do_seq
157 #include "BKE_sound.h" /* ... and for samples */
158 #include "BKE_utildefines.h" // for defines
159
160 #include "GEN_messaging.h"
161
162 #include "BLO_writefile.h"
163 #include "BLO_readfile.h"
164 #include "BLO_undofile.h"
165
166 #include "readfile.h"
167 #include "genfile.h"
168
169
170 /* ********* my write, buffered writing with minimum 50k chunks ************ */
171
172 typedef struct {
173         struct SDNA *sdna;
174
175         int file;
176         unsigned char *buf;
177         MemFile *compare, *current;
178         
179         int tot, count, error, memsize;
180 } WriteData;
181
182 static WriteData *writedata_new(int file)
183 {
184         extern char DNAstr[];   /* DNA.c */
185         extern int DNAlen;
186
187         WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
188
189                 /* XXX, see note about this in readfile.c, remove
190                  * once we have an xp lock - zr
191                  */
192         wd->sdna= dna_sdna_from_data(DNAstr, DNAlen, 0);
193
194         wd->file= file;
195
196         wd->buf= MEM_mallocN(100000, "wd->buf");
197
198         return wd;
199 }
200
201 static void writedata_do_write(WriteData *wd, void *mem, int memlen)
202 {
203         if (wd->error) return;
204
205         /* memory based save */
206         if(wd->current) {
207                 add_memfilechunk(NULL, wd->current, mem, memlen);
208         }
209         else {
210                 if (write(wd->file, mem, memlen) != memlen)
211                         wd->error= 1;
212                 
213         }
214 }
215
216 static void writedata_free(WriteData *wd)
217 {
218         dna_freestructDNA(wd->sdna);
219
220         MEM_freeN(wd->buf);
221         MEM_freeN(wd);
222 }
223
224 /***/
225
226 int mywfile;
227
228 /**
229  * Low level WRITE(2) wrapper that buffers data
230  * @param adr Pointer to new chunk of data
231  * @param len Length of new chunk of data
232  * @warning Talks to other functions with global parameters
233  */
234  
235 #define MYWRITE_FLUSH   NULL
236
237 static void mywrite( WriteData *wd, void *adr, int len)
238 {
239         if (wd->error) return;
240
241         if(adr==MYWRITE_FLUSH) {
242                 if(wd->count) {
243                         writedata_do_write(wd, wd->buf, wd->count);
244                         wd->count= 0;
245                 }
246                 return;
247         }
248
249         wd->tot+= len;
250         
251         if(len>50000) {
252                 if(wd->count) {
253                         writedata_do_write(wd, wd->buf, wd->count);
254                         wd->count= 0;
255                 }
256                 writedata_do_write(wd, adr, len);
257                 return;
258         }
259         if(len+wd->count>99999) {
260                 writedata_do_write(wd, wd->buf, wd->count);
261                 wd->count= 0;
262         }
263         memcpy(&wd->buf[wd->count], adr, len);
264         wd->count+= len;
265
266 }
267
268 /**
269  * BeGiN initializer for mywrite
270  * @param file File descriptor
271  * @param write_flags Write parameters
272  * @warning Talks to other functions with global parameters
273  */
274 static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current, int write_flags)
275 {
276         WriteData *wd= writedata_new(file);
277
278         wd->compare= compare;
279         wd->current= current;
280         /* this inits comparing */
281         add_memfilechunk(compare, NULL, NULL, 0);
282         
283         return wd;
284 }
285
286 /**
287  * END the mywrite wrapper
288  * @return 1 if write failed
289  * @return unknown global variable otherwise
290  * @warning Talks to other functions with global parameters
291  */
292 static int endwrite(WriteData *wd)
293 {
294         int err;
295
296         if (wd->count) {
297                 writedata_do_write(wd, wd->buf, wd->count);
298                 wd->count= 0;
299         }
300         
301         err= wd->error;
302         writedata_free(wd);
303 /* blender gods may live forever but this parent pointer died in the statement above
304 if(wd->current) printf("undo size %d\n", wd->current->size);
305 */
306         return err;
307 }
308
309 /* ********** WRITE FILE ****************** */
310
311 static void writestruct(WriteData *wd, int filecode, char *structname, int nr, void *adr)
312 {
313         BHead bh;
314         short *sp;
315
316         if(adr==0 || nr==0) return;
317
318         /* init BHead */
319         bh.code= filecode;
320         bh.old= adr;
321         bh.nr= nr;
322
323         bh.SDNAnr= dna_findstruct_nr(wd->sdna, structname);
324         if(bh.SDNAnr== -1) {
325                 printf("error: can't find SDNA code %s\n", structname);
326                 return;
327         }
328         sp= wd->sdna->structs[bh.SDNAnr];
329
330         bh.len= nr*wd->sdna->typelens[sp[0]];
331
332         if(bh.len==0) return;
333
334         mywrite(wd, &bh, sizeof(BHead));
335         mywrite(wd, adr, bh.len);
336 }
337
338 static void writedata(WriteData *wd, int filecode, int len, void *adr)  /* do not use for structs */
339 {
340         BHead bh;
341
342         if(adr==0) return;
343         if(len==0) return;
344
345         len+= 3;
346         len-= ( len % 4);
347
348         /* init BHead */
349         bh.code= filecode;
350         bh.old= adr;
351         bh.nr= 1;
352         bh.SDNAnr= 0;
353         bh.len= len;
354
355         mywrite(wd, &bh, sizeof(BHead));
356         if(len) mywrite(wd, adr, len);
357 }
358
359 static void write_scriptlink(WriteData *wd, ScriptLink *slink)
360 {
361         writedata(wd, DATA, sizeof(void *)*slink->totscript, slink->scripts);
362         writedata(wd, DATA, sizeof(short)*slink->totscript, slink->flag);
363 }
364
365 static void write_renderinfo(WriteData *wd)             /* for renderdaemon */
366 {
367         Scene *sce;
368         int data[8];
369
370         sce= G.main->scene.first;
371         while(sce) {
372                 if(sce->id.lib==0  && ( sce==G.scene || (sce->r.scemode & R_BG_RENDER)) ) {
373                         data[0]= sce->r.sfra;
374                         data[1]= sce->r.efra;
375
376                         strncpy((char *)(data+2), sce->id.name+2, 23);
377
378                         writedata(wd, REND, 32, data);
379                 }
380                 sce= sce->id.next;
381         }
382 }
383
384 static void write_userdef(WriteData *wd)
385 {
386         bTheme *btheme;
387
388         writestruct(wd, USER, "UserDef", 1, &U);
389
390         btheme= U.themes.first;
391         while(btheme) {
392                 writestruct(wd, DATA, "bTheme", 1, btheme);
393                 btheme= btheme->next;
394         }
395 }
396
397 static void write_effects(WriteData *wd, ListBase *lb)
398 {
399         Effect *eff;
400
401         eff= lb->first;
402         while(eff) {
403
404                 switch(eff->type) {
405                 case EFF_BUILD:
406                         writestruct(wd, DATA, "BuildEff", 1, eff);
407                         break;
408                 case EFF_PARTICLE:
409                         writestruct(wd, DATA, "PartEff", 1, eff);
410                         break;
411                 case EFF_WAVE:
412                         writestruct(wd, DATA, "WaveEff", 1, eff);
413                         break;
414                 default:
415                         writedata(wd, DATA, MEM_allocN_len(eff), eff);
416                 }
417
418                 eff= eff->next;
419         }
420 }
421
422 static void write_properties(WriteData *wd, ListBase *lb)
423 {
424         bProperty *prop;
425
426         prop= lb->first;
427         while(prop) {
428                 writestruct(wd, DATA, "bProperty", 1, prop);
429
430                 if(prop->poin && prop->poin != &prop->data)
431                         writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin);
432
433                 prop= prop->next;
434         }
435 }
436
437 static void write_sensors(WriteData *wd, ListBase *lb)
438 {
439         bSensor *sens;
440
441         sens= lb->first;
442         while(sens) {
443                 writestruct(wd, DATA, "bSensor", 1, sens);
444
445                 writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links);
446
447                 switch(sens->type) {
448                 case SENS_NEAR:
449                         writestruct(wd, DATA, "bNearSensor", 1, sens->data);
450                         break;
451                 case SENS_MOUSE:
452                         writestruct(wd, DATA, "bMouseSensor", 1, sens->data);
453                         break;
454                 case SENS_TOUCH:
455                         writestruct(wd, DATA, "bTouchSensor", 1, sens->data);
456                         break;
457                 case SENS_KEYBOARD:
458                         writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data);
459                         break;
460                 case SENS_PROPERTY:
461                         writestruct(wd, DATA, "bPropertySensor", 1, sens->data);
462                         break;
463                 case SENS_COLLISION:
464                         writestruct(wd, DATA, "bCollisionSensor", 1, sens->data);
465                         break;
466                 case SENS_RADAR:
467                         writestruct(wd, DATA, "bRadarSensor", 1, sens->data);
468                         break;
469                 case SENS_RANDOM:
470                         writestruct(wd, DATA, "bRandomSensor", 1, sens->data);
471                         break;
472                 case SENS_RAY:
473                         writestruct(wd, DATA, "bRaySensor", 1, sens->data);
474                         break;
475                 case SENS_MESSAGE:
476                         writestruct(wd, DATA, "bMessageSensor", 1, sens->data);
477                         break;
478                 case SENS_JOYSTICK:
479                         writestruct(wd, DATA, "bJoystickSensor", 1, sens->data);
480                         break;
481                 default:
482                         ; /* error: don't know how to write this file */
483                 }
484
485                 sens= sens->next;
486         }
487 }
488
489 static void write_controllers(WriteData *wd, ListBase *lb)
490 {
491         bController *cont;
492
493         cont= lb->first;
494         while(cont) {
495                 writestruct(wd, DATA, "bController", 1, cont);
496
497                 writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links);
498
499                 switch(cont->type) {
500                 case CONT_EXPRESSION:
501                         writestruct(wd, DATA, "bExpressionCont", 1, cont->data);
502                         break;
503                 case CONT_PYTHON:
504                         writestruct(wd, DATA, "bPythonCont", 1, cont->data);
505                         break;
506                 default:
507                         ; /* error: don't know how to write this file */
508                 }
509
510                 cont= cont->next;
511         }
512 }
513
514 static void write_actuators(WriteData *wd, ListBase *lb)
515 {
516         bActuator *act;
517
518         act= lb->first;
519         while(act) {
520                 writestruct(wd, DATA, "bActuator", 1, act);
521
522                 switch(act->type) {
523                 case ACT_ACTION:
524                         writestruct(wd, DATA, "bActionActuator", 1, act->data);
525                         break;
526                 case ACT_SOUND:
527                         writestruct(wd, DATA, "bSoundActuator", 1, act->data);
528                         break;
529                 case ACT_CD:
530                         writestruct(wd, DATA, "bCDActuator", 1, act->data);
531                         break;
532                 case ACT_OBJECT:
533                         writestruct(wd, DATA, "bObjectActuator", 1, act->data);
534                         break;
535                 case ACT_IPO:
536                         writestruct(wd, DATA, "bIpoActuator", 1, act->data);
537                         break;
538                 case ACT_PROPERTY:
539                         writestruct(wd, DATA, "bPropertyActuator", 1, act->data);
540                         break;
541                 case ACT_CAMERA:
542                         writestruct(wd, DATA, "bCameraActuator", 1, act->data);
543                         break;
544                 case ACT_CONSTRAINT:
545                         writestruct(wd, DATA, "bConstraintActuator", 1, act->data);
546                         break;
547                 case ACT_EDIT_OBJECT:
548                         writestruct(wd, DATA, "bEditObjectActuator", 1, act->data);
549                         break;
550                 case ACT_SCENE:
551                         writestruct(wd, DATA, "bSceneActuator", 1, act->data);
552                         break;
553                 case ACT_GROUP:
554                         writestruct(wd, DATA, "bGroupActuator", 1, act->data);
555                         break;
556                 case ACT_RANDOM:
557                         writestruct(wd, DATA, "bRandomActuator", 1, act->data);
558                         break;
559                 case ACT_MESSAGE:
560                         writestruct(wd, DATA, "bMessageActuator", 1, act->data);
561                         break;
562                 case ACT_GAME:
563                         writestruct(wd, DATA, "bGameActuator", 1, act->data);
564                         break;
565                 case ACT_VISIBILITY:
566                         writestruct(wd, DATA, "bVisibilityActuator", 1, act->data);
567                         break;
568                 default:
569                         ; /* error: don't know how to write this file */
570                 }
571
572                 act= act->next;
573         }
574 }
575
576 static void write_nlastrips(WriteData *wd, ListBase *nlabase)
577 {
578         bActionStrip *strip;
579
580         for (strip=nlabase->first; strip; strip=strip->next)
581                 writestruct(wd, DATA, "bActionStrip", 1, strip);
582 }
583
584 static void write_constraints(WriteData *wd, ListBase *conlist)
585 {
586         bConstraint *con;
587
588         for (con=conlist->first; con; con=con->next) {
589                 /* Write the specific data */
590                 switch (con->type) {
591                 case CONSTRAINT_TYPE_NULL:
592                         break;
593                 case CONSTRAINT_TYPE_TRACKTO:
594                         writestruct(wd, DATA, "bTrackToConstraint", 1, con->data);
595                         break;
596                 case CONSTRAINT_TYPE_KINEMATIC:
597                         writestruct(wd, DATA, "bKinematicConstraint", 1, con->data);
598                         break;
599                 case CONSTRAINT_TYPE_ROTLIKE:
600                         writestruct(wd, DATA, "bRotateLikeConstraint", 1, con->data);
601                         break;
602                 case CONSTRAINT_TYPE_LOCLIKE:
603                         writestruct(wd, DATA, "bLocateLikeConstraint", 1, con->data);
604                         break;
605                 case CONSTRAINT_TYPE_ACTION:
606                         writestruct(wd, DATA, "bActionConstraint", 1, con->data);
607                         break;
608                 case CONSTRAINT_TYPE_LOCKTRACK:
609                         writestruct(wd, DATA, "bLockTrackConstraint", 1, con->data);
610                         break;
611                 case CONSTRAINT_TYPE_FOLLOWPATH:
612                         writestruct(wd, DATA, "bFollowPathConstraint", 1, con->data);
613                         break;
614                 case CONSTRAINT_TYPE_STRETCHTO:
615                         writestruct(wd, DATA, "bStretchToConstraint", 1, con->data);
616                         break;
617                 default:
618                         break;
619                 }
620                 /* Write the constraint */
621                 writestruct(wd, DATA, "bConstraint", 1, con);
622         }
623 }
624
625 static void write_pose(WriteData *wd, bPose *pose)
626 {
627         bPoseChannel    *chan;
628
629         /* Write each channel */
630
631         if (!pose)
632                 return;
633
634         // Write channels
635         for (chan=pose->chanbase.first; chan; chan=chan->next) {
636                 write_constraints(wd, &chan->constraints);
637                 writestruct(wd, DATA, "bPoseChannel", 1, chan);
638         }
639
640         // Write this pose
641         writestruct(wd, DATA, "bPose", 1, pose);
642 }
643
644 static void write_defgroups(WriteData *wd, ListBase *defbase)
645 {
646         bDeformGroup    *defgroup;
647
648         for (defgroup=defbase->first; defgroup; defgroup=defgroup->next)
649                 writestruct(wd, DATA, "bDeformGroup", 1, defgroup);
650 }
651
652 static void write_constraint_channels(WriteData *wd, ListBase *chanbase)
653 {
654         bConstraintChannel *chan;
655
656         for (chan = chanbase->first; chan; chan=chan->next)
657                 writestruct(wd, DATA, "bConstraintChannel", 1, chan);
658
659 }
660
661 static void write_objects(WriteData *wd, ListBase *idbase)
662 {
663         Object *ob;
664         ObHook *hook;
665         int a;
666         
667         ob= idbase->first;
668         while(ob) {
669                 if(ob->id.us>0 || wd->current) {
670                         /* write LibData */
671                         writestruct(wd, ID_OB, "Object", 1, ob);
672
673                         /* direct data */
674                         writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat);
675                         write_effects(wd, &ob->effect);
676                         write_properties(wd, &ob->prop);
677                         write_sensors(wd, &ob->sensors);
678                         write_controllers(wd, &ob->controllers);
679                         write_actuators(wd, &ob->actuators);
680                         write_scriptlink(wd, &ob->scriptlink);
681                         write_pose(wd, ob->pose);
682                         write_defgroups(wd, &ob->defbase);
683                         write_constraints(wd, &ob->constraints);
684                         write_constraint_channels(wd, &ob->constraintChannels);
685                         write_nlastrips(wd, &ob->nlastrips);
686                         
687                         writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
688                         writestruct(wd, DATA, "SoftBody", 1, ob->soft);
689                         if(ob->soft) {
690                                 SoftBody *sb= ob->soft;
691                                 if(sb->keys) {
692                                         writedata(wd, DATA, sizeof(void *)*sb->totkey, sb->keys);
693                                         for(a=0; a<sb->totkey; a++) {
694                                                 writestruct(wd, DATA, "SBVertex", sb->totpoint, sb->keys[a]);
695                                         }
696                                 }
697                         }
698                         
699                         for(hook= ob->hooks.first; hook; hook= hook->next) {
700                                 writestruct(wd, DATA, "ObHook", 1, hook);
701                                 writedata(wd, DATA, sizeof(int)*hook->totindex, hook->indexar);
702                         }
703                 }
704                 ob= ob->id.next;
705         }
706
707         /* flush helps the compression for undo-save */
708         mywrite(wd, MYWRITE_FLUSH, 0);
709 }
710
711
712 static void write_vfonts(WriteData *wd, ListBase *idbase)
713 {
714         VFont *vf;
715         PackedFile * pf;
716
717         vf= idbase->first;
718         while(vf) {
719                 if(vf->id.us>0 || wd->current) {
720                         /* write LibData */
721                         writestruct(wd, ID_VF, "VFont", 1, vf);
722
723                         /* direct data */
724
725                         if (vf->packedfile) {
726                                 pf = vf->packedfile;
727                                 writestruct(wd, DATA, "PackedFile", 1, pf);
728                                 writedata(wd, DATA, pf->size, pf->data);
729                         }
730                 }
731
732                 vf= vf->id.next;
733         }
734 }
735
736 static void write_ipos(WriteData *wd, ListBase *idbase)
737 {
738         Ipo *ipo;
739         IpoCurve *icu;
740
741         ipo= idbase->first;
742         while(ipo) {
743                 if(ipo->id.us>0 || wd->current) {
744                         /* write LibData */
745                         writestruct(wd, ID_IP, "Ipo", 1, ipo);
746
747                         /* direct data */
748                         icu= ipo->curve.first;
749                         while(icu) {
750                                 writestruct(wd, DATA, "IpoCurve", 1, icu);
751                                 icu= icu->next;
752                         }
753
754                         icu= ipo->curve.first;
755                         while(icu) {
756                                 if(icu->bezt)  writestruct(wd, DATA, "BezTriple", icu->totvert, icu->bezt);
757                                 if(icu->bp)  writestruct(wd, DATA, "BPoint", icu->totvert, icu->bp);
758                                 icu= icu->next;
759                         }
760                 }
761
762                 ipo= ipo->id.next;
763         }
764
765         /* flush helps the compression for undo-save */
766         mywrite(wd, MYWRITE_FLUSH, 0);
767 }
768
769 static void write_keys(WriteData *wd, ListBase *idbase)
770 {
771         Key *key;
772         KeyBlock *kb;
773
774         key= idbase->first;
775         while(key) {
776                 if(key->id.us>0 || wd->current) {
777                         /* write LibData */
778                         writestruct(wd, ID_KE, "Key", 1, key);
779
780                         /* direct data */
781                         kb= key->block.first;
782                         while(kb) {
783                                 writestruct(wd, DATA, "KeyBlock", 1, kb);
784                                 if(kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data);
785                                 kb= kb->next;
786                         }
787                 }
788
789                 key= key->id.next;
790         }
791         /* flush helps the compression for undo-save */
792         mywrite(wd, MYWRITE_FLUSH, 0);
793 }
794
795 static void write_cameras(WriteData *wd, ListBase *idbase)
796 {
797         Camera *cam;
798
799         cam= idbase->first;
800         while(cam) {
801                 if(cam->id.us>0 || wd->current) {
802                         /* write LibData */
803                         writestruct(wd, ID_CA, "Camera", 1, cam);
804
805                         /* direct data */
806                         write_scriptlink(wd, &cam->scriptlink);
807                 }
808
809                 cam= cam->id.next;
810         }
811 }
812
813 static void write_mballs(WriteData *wd, ListBase *idbase)
814 {
815         MetaBall *mb;
816         MetaElem *ml;
817
818         mb= idbase->first;
819         while(mb) {
820                 if(mb->id.us>0 || wd->current) {
821                         /* write LibData */
822                         writestruct(wd, ID_MB, "MetaBall", 1, mb);
823
824                         /* direct data */
825                         writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat);
826
827                         ml= mb->elems.first;
828                         while(ml) {
829                                 writestruct(wd, DATA, "MetaElem", 1, ml);
830                                 ml= ml->next;
831                         }
832                 }
833                 mb= mb->id.next;
834         }
835 }
836
837 static void write_curves(WriteData *wd, ListBase *idbase)
838 {
839         Curve *cu;
840         Nurb *nu;
841
842         cu= idbase->first;
843         while(cu) {
844                 if(cu->id.us>0 || wd->current) {
845                         /* write LibData */
846                         writestruct(wd, ID_CU, "Curve", 1, cu);
847
848                         /* direct data */
849                         writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat);
850
851                         if(cu->vfont) {
852                                 writedata(wd, DATA, cu->len+1, cu->str);
853                                 writestruct(wd, DATA, "CharInfo", cu->len, cu->strinfo);
854                                 writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);                           
855                         }
856                         else {
857                                 /* is also the order of reading */
858                                 nu= cu->nurb.first;
859                                 while(nu) {
860                                         writestruct(wd, DATA, "Nurb", 1, nu);
861                                         nu= nu->next;
862                                 }
863                                 nu= cu->nurb.first;
864                                 while(nu) {
865                                         if( (nu->type & 7)==CU_BEZIER)
866                                                 writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt);
867                                         else {
868                                                 writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp);
869                                                 if(nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu);
870                                                 if(nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv);
871                                         }
872                                         nu= nu->next;
873                                 }
874                         }
875                 }
876                 cu= cu->id.next;
877         }
878
879         /* flush helps the compression for undo-save */
880         mywrite(wd, MYWRITE_FLUSH, 0);
881 }
882
883 static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
884 {
885         int     i;
886
887         /* Write the dvert list */
888         writestruct(wd, DATA, "MDeformVert", count, dvlist);
889
890         /* Write deformation data for each dvert */
891         if (dvlist) {
892                 for (i=0; i<count; i++) {
893                         if (dvlist[i].dw)
894                                 writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw);
895                 }
896         }
897 }
898
899 static void write_meshs(WriteData *wd, ListBase *idbase)
900 {
901         Mesh *mesh;
902
903         mesh= idbase->first;
904         while(mesh) {
905                 if(mesh->id.us>0 || wd->current) {
906                         /* write LibData */
907                         writestruct(wd, ID_ME, "Mesh", 1, mesh);
908
909                         /* direct data */
910                         writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
911
912                         writestruct(wd, DATA, "MVert", mesh->totvert, mesh->mvert);
913                         writestruct(wd, DATA, "MEdge", mesh->totedge, mesh->medge);
914                         writestruct(wd, DATA, "MFace", mesh->totface, mesh->mface);
915                         writestruct(wd, DATA, "TFace", mesh->totface, mesh->tface);
916                         writestruct(wd, DATA, "MCol", 4*mesh->totface, mesh->mcol);
917                         writestruct(wd, DATA, "MSticky", mesh->totvert, mesh->msticky);
918
919                         write_dverts(wd, mesh->totvert, mesh->dvert);
920
921                 }
922                 mesh= mesh->id.next;
923         }
924 }
925
926 static void write_images(WriteData *wd, ListBase *idbase)
927 {
928         Image *ima;
929         PackedFile * pf;
930
931         ima= idbase->first;
932         while(ima) {
933                 if(ima->id.us>0 || wd->current) {
934                         /* write LibData */
935                         writestruct(wd, ID_IM, "Image", 1, ima);
936
937                         if (ima->packedfile) {
938                                 pf = ima->packedfile;
939                                 writestruct(wd, DATA, "PackedFile", 1, pf);
940                                 writedata(wd, DATA, pf->size, pf->data);
941                         }
942                 }
943                 ima= ima->id.next;
944         }
945         /* flush helps the compression for undo-save */
946         mywrite(wd, MYWRITE_FLUSH, 0);
947 }
948
949 static void write_textures(WriteData *wd, ListBase *idbase)
950 {
951         Tex *tex;
952
953         tex= idbase->first;
954         while(tex) {
955                 if(tex->id.us>0 || wd->current) {
956                         /* write LibData */
957                         writestruct(wd, ID_TE, "Tex", 1, tex);
958
959                         /* direct data */
960                         if(tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin);
961                         if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba);
962                         if(tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env);
963                 }
964                 tex= tex->id.next;
965         }
966
967         /* flush helps the compression for undo-save */
968         mywrite(wd, MYWRITE_FLUSH, 0);
969 }
970
971 static void write_materials(WriteData *wd, ListBase *idbase)
972 {
973         Material *ma;
974         int a;
975
976         ma= idbase->first;
977         while(ma) {
978                 if(ma->id.us>0 || wd->current) {
979                         /* write LibData */
980                         writestruct(wd, ID_MA, "Material", 1, ma);
981
982                         for(a=0; a<MAX_MTEX; a++) {
983                                 if(ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]);
984                         }
985                         
986                         if(ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col);
987                         if(ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec);
988                         
989                         write_scriptlink(wd, &ma->scriptlink);
990                 }
991                 ma= ma->id.next;
992         }
993 }
994
995 static void write_worlds(WriteData *wd, ListBase *idbase)
996 {
997         World *wrld;
998         int a;
999
1000         wrld= idbase->first;
1001         while(wrld) {
1002                 if(wrld->id.us>0 || wd->current) {
1003                         /* write LibData */
1004                         writestruct(wd, ID_WO, "World", 1, wrld);
1005
1006                         for(a=0; a<MAX_MTEX; a++) {
1007                                 if(wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]);
1008                         }
1009
1010                         write_scriptlink(wd, &wrld->scriptlink);
1011                 }
1012                 wrld= wrld->id.next;
1013         }
1014 }
1015
1016 static void write_lamps(WriteData *wd, ListBase *idbase)
1017 {
1018         Lamp *la;
1019         int a;
1020
1021         la= idbase->first;
1022         while(la) {
1023                 if(la->id.us>0 || wd->current) {
1024                         /* write LibData */
1025                         writestruct(wd, ID_LA, "Lamp", 1, la);
1026
1027                         /* direct data */
1028                         for(a=0; a<MAX_MTEX; a++) {
1029                                 if(la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]);
1030                         }
1031
1032                         write_scriptlink(wd, &la->scriptlink);
1033                 }
1034                 la= la->id.next;
1035         }
1036 }
1037
1038 static void write_lattices(WriteData *wd, ListBase *idbase)
1039 {
1040         Lattice *lt;
1041
1042         lt= idbase->first;
1043         while(lt) {
1044                 if(lt->id.us>0 || wd->current) {
1045                         /* write LibData */
1046                         writestruct(wd, ID_LT, "Lattice", 1, lt);
1047
1048                         /* direct data */
1049                         writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def);
1050                 }
1051                 lt= lt->id.next;
1052         }
1053 }
1054
1055 static void write_ikas(WriteData *wd, ListBase *idbase)
1056 {
1057         Ika *ika;
1058         Limb *li;
1059
1060         ika= idbase->first;
1061         while(ika) {
1062                 if(ika->id.us>0 || wd->current) {
1063                         /* write LibData */
1064                         writestruct(wd, ID_IK, "Ika", 1, ika);
1065
1066                         /* direct data */
1067                         li= ika->limbbase.first;
1068                         while(li) {
1069                                 writestruct(wd, DATA, "Limb", 1, li);
1070                                 li= li->next;
1071                         }
1072
1073                         writestruct(wd, DATA, "Deform", ika->totdef, ika->def);
1074                 }
1075                 ika= ika->id.next;
1076         }
1077 }
1078
1079 static void write_scenes(WriteData *wd, ListBase *scebase)
1080 {
1081         Scene *sce;
1082         Base *base;
1083         Editing *ed;
1084         Sequence *seq;
1085         MetaStack *ms;
1086         Strip *strip;
1087         TimeMarker *marker;
1088
1089         sce= scebase->first;
1090         while(sce) {
1091                 /* write LibData */
1092                 writestruct(wd, ID_SCE, "Scene", 1, sce);
1093
1094                 /* direct data */
1095                 base= sce->base.first;
1096                 while(base) {
1097                         writestruct(wd, DATA, "Base", 1, base);
1098                         base= base->next;
1099                 }
1100
1101                 writestruct(wd, DATA, "Radio", 1, sce->radio);
1102
1103                 ed= sce->ed;
1104                 if(ed) {
1105                         writestruct(wd, DATA, "Editing", 1, ed);
1106
1107                         /* reset write flags too */
1108                         WHILE_SEQ(&ed->seqbase) {
1109                                 if(seq->strip) seq->strip->done= 0;
1110                                 writestruct(wd, DATA, "Sequence", 1, seq);
1111                         }
1112                         END_SEQ
1113
1114                         WHILE_SEQ(&ed->seqbase) {
1115                                 if(seq->strip && seq->strip->done==0) {
1116                                         /* write strip with 'done' at 0 because readfile */
1117
1118                                         if(seq->plugin) writestruct(wd, DATA, "PluginSeq", 1, seq->plugin);
1119                                         if(seq->effectdata) {
1120                                                 switch(seq->type){
1121                                                         case SEQ_WIPE:
1122                                                                 writestruct(wd, DATA, "WipeVars", 1, seq->effectdata);
1123                                                                 break;
1124                                                         case SEQ_GLOW:
1125                                                                 writestruct(wd, DATA, "GlowVars", 1, seq->effectdata);
1126                                                                 break;
1127                                                 }
1128                                         }
1129
1130                                         strip= seq->strip;
1131                                         writestruct(wd, DATA, "Strip", 1, strip);
1132
1133                                         if(seq->type==SEQ_IMAGE)
1134                                                 writestruct(wd, DATA, "StripElem", strip->len, strip->stripdata);
1135                                         else if(seq->type==SEQ_MOVIE || seq->type==SEQ_SOUND)
1136                                                 writestruct(wd, DATA, "StripElem", 1, strip->stripdata);
1137
1138                                         strip->done= 1;
1139                                 }
1140                         }
1141                         END_SEQ
1142                                 
1143                         /* new; meta stack too, even when its nasty restore code */
1144                         for(ms= ed->metastack.first; ms; ms= ms->next) {
1145                                 writestruct(wd, DATA, "MetaStack", 1, ms);
1146                         }
1147                 }
1148
1149                 write_scriptlink(wd, &sce->scriptlink);
1150
1151                 if (sce->r.avicodecdata) {
1152                         writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata);
1153                         if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
1154                         if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
1155                 }
1156
1157                 if (sce->r.qtcodecdata) {
1158                         writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata);
1159                         if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
1160                 }
1161
1162                 /* writing dynamic list of TimeMarkers to the blend file */
1163                 marker= sce->markers.first;
1164                 while(marker){
1165                         writestruct(wd, DATA, "TimeMarker", 1, marker);
1166                         marker= marker->next;
1167                 }
1168                 
1169                 sce= sce->id.next;
1170         }
1171         /* flush helps the compression for undo-save */
1172         mywrite(wd, MYWRITE_FLUSH, 0);
1173 }
1174
1175 static void write_screens(WriteData *wd, ListBase *scrbase)
1176 {
1177         bScreen *sc;
1178         ScrArea *sa;
1179         ScrVert *sv;
1180         ScrEdge *se;
1181
1182         sc= scrbase->first;
1183         while(sc) {
1184                 /* write LibData */
1185                 writestruct(wd, ID_SCR, "Screen", 1, sc);
1186
1187                 /* direct data */
1188                 sv= sc->vertbase.first;
1189                 while(sv) {
1190                         writestruct(wd, DATA, "ScrVert", 1, sv);
1191                         sv= sv->next;
1192                 }
1193
1194                 se= sc->edgebase.first;
1195                 while(se) {
1196                         writestruct(wd, DATA, "ScrEdge", 1, se);
1197                         se= se->next;
1198                 }
1199
1200                 sa= sc->areabase.first;
1201                 while(sa) {
1202                         SpaceLink *sl;
1203                         Panel *pa;
1204
1205                         writestruct(wd, DATA, "ScrArea", 1, sa);
1206
1207                         pa= sa->panels.first;
1208                         while(pa) {
1209                                 writestruct(wd, DATA, "Panel", 1, pa);
1210                                 pa= pa->next;
1211                         }
1212
1213                         /* space handler scriptlinks */
1214                         write_scriptlink(wd, &sa->scriptlink);
1215
1216                         sl= sa->spacedata.first;
1217                         while(sl) {
1218                                 if(sl->spacetype==SPACE_VIEW3D) {
1219                                         View3D *v3d= (View3D*) sl;
1220                                         writestruct(wd, DATA, "View3D", 1, v3d);
1221                                         if(v3d->bgpic) writestruct(wd, DATA, "BGpic", 1, v3d->bgpic);
1222                                         if(v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd);
1223                                 }
1224                                 else if(sl->spacetype==SPACE_IPO) {
1225                                         writestruct(wd, DATA, "SpaceIpo", 1, sl);
1226                                 }
1227                                 else if(sl->spacetype==SPACE_BUTS) {
1228                                         writestruct(wd, DATA, "SpaceButs", 1, sl);
1229                                 }
1230                                 else if(sl->spacetype==SPACE_FILE) {
1231                                         writestruct(wd, DATA, "SpaceFile", 1, sl);
1232                                 }
1233                                 else if(sl->spacetype==SPACE_SEQ) {
1234                                         writestruct(wd, DATA, "SpaceSeq", 1, sl);
1235                                 }
1236                                 else if(sl->spacetype==SPACE_OOPS) {
1237                                         SpaceOops *so= (SpaceOops *)sl;
1238                                         Oops *oops;
1239
1240                                         /* cleanup */
1241                                         oops= so->oops.first;
1242                                         while(oops) {
1243                                                 Oops *oopsn= oops->next;
1244                                                 if(oops->id==0) {
1245                                                         BLI_remlink(&so->oops, oops);
1246                                                         free_oops(oops);
1247                                                 }
1248                                                 oops= oopsn;
1249                                         }
1250
1251                                         /* ater cleanup, because of listbase! */
1252                                         writestruct(wd, DATA, "SpaceOops", 1, so);
1253
1254                                         oops= so->oops.first;
1255                                         while(oops) {
1256                                                 writestruct(wd, DATA, "Oops", 1, oops);
1257                                                 oops= oops->next;
1258                                         }
1259                                         /* outliner */
1260                                         if(so->treestore) {
1261                                                 writestruct(wd, DATA, "TreeStore", 1, so->treestore);
1262                                                 if(so->treestore->data)
1263                                                         writestruct(wd, DATA, "TreeStoreElem", so->treestore->usedelem, so->treestore->data);
1264                                         }
1265                                 }
1266                                 else if(sl->spacetype==SPACE_IMAGE) {
1267                                         writestruct(wd, DATA, "SpaceImage", 1, sl);
1268                                 }
1269                                 else if(sl->spacetype==SPACE_IMASEL) {
1270                                         writestruct(wd, DATA, "SpaceImaSel", 1, sl);
1271                                 }
1272                                 else if(sl->spacetype==SPACE_TEXT) {
1273                                         writestruct(wd, DATA, "SpaceText", 1, sl);
1274                                 }
1275                                 else if(sl->spacetype==SPACE_SCRIPT) {
1276                                         writestruct(wd, DATA, "SpaceScript", 1, sl);
1277                                 }
1278                                 else if(sl->spacetype==SPACE_ACTION) {
1279                                         writestruct(wd, DATA, "SpaceAction", 1, sl);
1280                                 }
1281                                 else if(sl->spacetype==SPACE_SOUND) {
1282                                         writestruct(wd, DATA, "SpaceSound", 1, sl);
1283                                 }
1284                                 else if(sl->spacetype==SPACE_NLA){
1285                                         writestruct(wd, DATA, "SpaceNla", 1, sl);
1286                                 }
1287                                 else if(sl->spacetype==SPACE_TIME){
1288                                         writestruct(wd, DATA, "SpaceTime", 1, sl);
1289                                 }
1290                                 sl= sl->next;
1291                         }
1292
1293                         sa= sa->next;
1294                 }
1295
1296                 sc= sc->id.next;
1297         }
1298 }
1299
1300 static void write_libraries(WriteData *wd, Main *main)
1301 {
1302         ListBase *lbarray[30];
1303         ID *id;
1304         int a, tot, foundone;
1305
1306         while(main) {
1307
1308                 a=tot= set_listbasepointers(main, lbarray);
1309
1310                 /* test: is lib being used */
1311                 foundone= 0;
1312                 while(tot--) {
1313                         id= lbarray[tot]->first;
1314                         while(id) {
1315                                 if(id->us>0 && (id->flag & LIB_EXTERN)) {
1316                                         foundone= 1;
1317                                         break;
1318                                 }
1319                                 id= id->next;
1320                         }
1321                         if(foundone) break;
1322                 }
1323
1324                 if(foundone) {
1325                         writestruct(wd, ID_LI, "Library", 1, main->curlib);
1326
1327                         while(a--) {
1328                                 id= lbarray[a]->first;
1329                                 while(id) {
1330                                         if(id->us>0 && (id->flag & LIB_EXTERN)) {
1331
1332                                                 writestruct(wd, ID_ID, "ID", 1, id);
1333                                         }
1334                                         id= id->next;
1335                                 }
1336                         }
1337                 }
1338
1339                 main= main->next;
1340         }
1341 }
1342
1343 static void write_bone(WriteData *wd, Bone* bone)
1344 {
1345         Bone*   cbone;
1346
1347 //      write_constraints(wd, &bone->constraints);
1348
1349         // Write this bone
1350         writestruct(wd, DATA, "Bone", 1, bone);
1351
1352         // Write Children
1353         cbone= bone->childbase.first;
1354         while(cbone) {
1355                 write_bone(wd, cbone);
1356                 cbone= cbone->next;
1357         }
1358 }
1359
1360 static void write_armatures(WriteData *wd, ListBase *idbase)
1361 {
1362         bArmature       *arm;
1363         Bone            *bone;
1364
1365         arm=idbase->first;
1366         while (arm) {
1367                 if (arm->id.us>0 || wd->current) {
1368                         writestruct(wd, ID_AR, "bArmature", 1, arm);
1369
1370                         /* Direct data */
1371                         bone= arm->bonebase.first;
1372                         while(bone) {
1373                                 write_bone(wd, bone);
1374                                 bone=bone->next;
1375                         }
1376                 }
1377                 arm=arm->id.next;
1378         }
1379
1380         /* flush helps the compression for undo-save */
1381         mywrite(wd, MYWRITE_FLUSH, 0);
1382 }
1383
1384 static void write_actions(WriteData *wd, ListBase *idbase)
1385 {
1386         bAction                 *act;
1387         bActionChannel  *chan;
1388         act=idbase->first;
1389         while (act) {
1390                 if (act->id.us>0 || wd->current) {
1391                         writestruct(wd, ID_AC, "bAction", 1, act);
1392
1393                         for (chan=act->chanbase.first; chan; chan=chan->next) {
1394                                 writestruct(wd, DATA, "bActionChannel", 1, chan);
1395                                 write_constraint_channels(wd, &chan->constraintChannels);
1396                         }
1397                 }
1398                 act=act->id.next;
1399         }
1400 }
1401
1402 static void write_texts(WriteData *wd, ListBase *idbase)
1403 {
1404         Text *text;
1405         TextLine *tmp;
1406
1407         text= idbase->first;
1408         while(text) {
1409                 if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT;
1410
1411                 /* write LibData */
1412                 writestruct(wd, ID_TXT, "Text", 1, text);
1413                 if(text->name) writedata(wd, DATA, strlen(text->name)+1, text->name);
1414
1415                 if(!(text->flags & TXT_ISEXT)) {
1416                         /* now write the text data, in two steps for optimization in the readfunction */
1417                         tmp= text->lines.first;
1418                         while (tmp) {
1419                                 writestruct(wd, DATA, "TextLine", 1, tmp);
1420                                 tmp= tmp->next;
1421                         }
1422
1423                         tmp= text->lines.first;
1424                         while (tmp) {
1425                                 writedata(wd, DATA, tmp->len+1, tmp->line);
1426                                 tmp= tmp->next;
1427                         }
1428                 }
1429                 text= text->id.next;
1430         }
1431
1432         /* flush helps the compression for undo-save */
1433         mywrite(wd, MYWRITE_FLUSH, 0);
1434 }
1435
1436 static void write_sounds(WriteData *wd, ListBase *idbase)
1437 {
1438         bSound *sound;
1439         bSample *sample;
1440
1441         PackedFile * pf;
1442
1443         // set all samples to unsaved status
1444
1445         sample = samples->first;
1446         while (sample) {
1447                 sample->flags |= SAMPLE_NEEDS_SAVE;
1448                 sample = sample->id.next;
1449         }
1450
1451         sound= idbase->first;
1452         while(sound) {
1453                 if(sound->id.us>0 || wd->current) {
1454                         // do we need to save the packedfile as well ?
1455                         sample = sound->sample;
1456                         if (sample) {
1457                                 if (sample->flags & SAMPLE_NEEDS_SAVE) {
1458                                         sound->newpackedfile = sample->packedfile;
1459                                         sample->flags &= ~SAMPLE_NEEDS_SAVE;
1460                                 } else {
1461                                         sound->newpackedfile = NULL;
1462                                 }
1463                         }
1464
1465                         /* write LibData */
1466                         writestruct(wd, ID_SO, "bSound", 1, sound);
1467
1468                         if (sound->newpackedfile) {
1469                                 pf = sound->newpackedfile;
1470                                 writestruct(wd, DATA, "PackedFile", 1, pf);
1471                                 writedata(wd, DATA, pf->size, pf->data);
1472                         }
1473
1474                         if (sample) {
1475                                 sound->newpackedfile = sample->packedfile;
1476                         }
1477                 }
1478                 sound= sound->id.next;
1479         }
1480
1481         /* flush helps the compression for undo-save */
1482         mywrite(wd, MYWRITE_FLUSH, 0);
1483 }
1484
1485 static void write_groups(WriteData *wd, ListBase *idbase)
1486 {
1487         Group *group;
1488         GroupKey *gk;
1489         GroupObject *go;
1490         ObjectKey *ok;
1491
1492         group= idbase->first;
1493         while(group) {
1494                 if(group->id.us>0 || wd->current) {
1495                         /* write LibData */
1496                         writestruct(wd, ID_GR, "Group", 1, group);
1497
1498                         gk= group->gkey.first;
1499                         while(gk) {
1500                                 writestruct(wd, DATA, "GroupKey", 1, gk);
1501                                 gk= gk->next;
1502                         }
1503
1504                         go= group->gobject.first;
1505                         while(go) {
1506                                 writestruct(wd, DATA, "GroupObject", 1, go);
1507                                 go= go->next;
1508                         }
1509                         go= group->gobject.first;
1510                         while(go) {
1511                                 ok= go->okey.first;
1512                                 while(ok) {
1513                                         writestruct(wd, DATA, "ObjectKey", 1, ok);
1514                                         ok= ok->next;
1515                                 }
1516                                 go= go->next;
1517                         }
1518
1519                 }
1520                 group= group->id.next;
1521         }
1522 }
1523
1524 static void write_global(WriteData *wd)
1525 {
1526         FileGlobal fg;
1527
1528         fg.curscreen= G.curscreen;
1529         fg.curscene= G.scene;
1530         fg.displaymode= G.displaymode;
1531         fg.winpos= G.winpos;
1532         fg.fileflags= (G.fileflags & ~G_FILE_NO_UI);    // prevent to save this, is not good convention, and feature with concerns...
1533         fg.globalf= G.f;
1534
1535         writestruct(wd, GLOB, "FileGlobal", 1, &fg);
1536 }
1537
1538 /* if *mem there's filesave to memory */
1539 static int write_file_handle(int handle, MemFile *compare, MemFile *current, int write_user_block, int write_flags)
1540 {
1541         BHead bhead;
1542         ListBase mainlist;
1543         char buf[13];
1544         WriteData *wd;
1545 /*      int data; */ /*unused*/
1546
1547         mainlist.first= mainlist.last= G.main;
1548         G.main->next= NULL;
1549
1550         blo_split_main(&mainlist);
1551
1552         wd= bgnwrite(handle, compare, current, write_flags);
1553         
1554         sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (G.order==B_ENDIAN)?'V':'v', G.version);
1555         mywrite(wd, buf, 12);
1556
1557         write_renderinfo(wd);
1558         
1559         if(current==NULL)
1560                 write_screens  (wd, &G.main->screen);   // no UI save
1561         write_scenes   (wd, &G.main->scene);
1562         write_curves   (wd, &G.main->curve);
1563         write_mballs   (wd, &G.main->mball);
1564         write_images   (wd, &G.main->image);
1565         write_cameras  (wd, &G.main->camera);
1566         write_lamps    (wd, &G.main->lamp);
1567         write_lattices (wd, &G.main->latt);
1568         write_ikas     (wd, &G.main->ika);
1569         write_vfonts   (wd, &G.main->vfont);
1570         write_ipos     (wd, &G.main->ipo);
1571         write_keys     (wd, &G.main->key);
1572         write_worlds   (wd, &G.main->world);
1573         write_texts    (wd, &G.main->text);
1574         write_sounds   (wd, &G.main->sound);
1575         write_groups   (wd, &G.main->group);
1576         write_armatures(wd, &G.main->armature);
1577         write_actions  (wd, &G.main->action);
1578         write_objects  (wd, &G.main->object);
1579         write_materials(wd, &G.main->mat);
1580         write_textures (wd, &G.main->tex);
1581         write_meshs    (wd, &G.main->mesh);
1582         write_libraries(wd,  G.main->next);
1583
1584         write_global(wd);
1585         if (write_user_block) {
1586                 write_userdef(wd);
1587         }
1588
1589         /* dna as last, because (to be implemented) test for which structs are written */
1590         writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
1591
1592         /* end of file */
1593         memset(&bhead, 0, sizeof(BHead));
1594         bhead.code= ENDB;
1595         mywrite(wd, &bhead, sizeof(BHead));
1596
1597         blo_join_main(&mainlist);
1598         G.main= mainlist.first;
1599
1600         return endwrite(wd);
1601 }
1602
1603 /* return: success (1) */
1604 int BLO_write_file(char *dir, int write_flags, char **error_r)
1605 {
1606         char userfilename[FILE_MAXDIR+FILE_MAXFILE];
1607         char tempname[FILE_MAXDIR+FILE_MAXFILE];
1608         int file, fout, write_user_block;
1609
1610         sprintf(tempname, "%s@", dir);
1611
1612         file = open(tempname,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
1613         if(file == -1) {
1614                 *error_r= "Unable to open";
1615                 return 0;
1616         }
1617
1618         BLI_make_file_string(G.sce, userfilename, BLI_gethome(), ".B.blend");
1619
1620         write_user_block= BLI_streq(dir, userfilename);
1621
1622         fout= write_file_handle(file, NULL,NULL, write_user_block, write_flags);
1623         close(file);
1624
1625         if(!fout) {
1626                 if(BLI_rename(tempname, dir) < 0) {
1627                         *error_r= "Can't change old file. File saved with @";
1628                         return 0;
1629                 }
1630         } else {
1631                 remove(tempname);
1632
1633                 *error_r= "Not enough diskspace";
1634                 return 0;
1635         }
1636
1637         return 1;
1638 }
1639
1640 /* return: success (1) */
1641 int BLO_write_file_mem(MemFile *compare, MemFile *current, int write_flags, char **error_r)
1642 {
1643         int err;
1644
1645         err= write_file_handle(0, compare, current, 0, write_flags);
1646         
1647         if(err==0) return 1;
1648         return 0;
1649 }
1650
1651
1652         /* Runtime writing */
1653
1654 #ifdef WIN32
1655 #define PATHSEPERATOR           "\\"
1656 #else
1657 #define PATHSEPERATOR           "/"
1658 #endif
1659
1660 static char *get_install_dir(void) {
1661         extern char bprogname[];
1662         char *tmpname = BLI_strdup(bprogname);
1663         char *cut;
1664
1665 #ifdef __APPLE__
1666         cut = strstr(tmpname, ".app");
1667         if (cut) cut[0] = 0;
1668 #endif
1669
1670         cut = BLI_last_slash(tmpname);
1671
1672         if (cut) {
1673                 cut[0] = 0;
1674                 return tmpname;
1675         } else {
1676                 MEM_freeN(tmpname);
1677                 return NULL;
1678         }
1679 }
1680
1681 static char *get_runtime_path(char *exename) {
1682         char *installpath= get_install_dir();
1683
1684         if (!installpath) {
1685                 return NULL;
1686         } else {
1687                 char *path= MEM_mallocN(strlen(installpath)+strlen(PATHSEPERATOR)+strlen(exename)+1, "runtimepath");
1688                 strcpy(path, installpath);
1689                 strcat(path, PATHSEPERATOR);
1690                 strcat(path, exename);
1691
1692                 MEM_freeN(installpath);
1693
1694                 return path;
1695         }
1696 }
1697
1698 #ifdef __APPLE__
1699
1700 static int recursive_copy_runtime(char *outname, char *exename, char **cause_r) 
1701 {
1702         char *cause = NULL, *runtime = get_runtime_path(exename);
1703         char command[2 * (FILE_MAXDIR+FILE_MAXFILE) + 32];
1704         int progfd = -1;
1705
1706         if (!runtime) {
1707                 cause= "Unable to find runtime";
1708                 goto cleanup;
1709         }
1710         //printf("runtimepath %s\n", runtime);
1711                 
1712         progfd= open(runtime, O_BINARY|O_RDONLY, 0);
1713         if (progfd==-1) {
1714                 cause= "Unable to find runtime";
1715                 goto cleanup;
1716         }
1717
1718         sprintf(command, "/bin/cp -R \"%s\" \"%s\"", runtime, outname);
1719         //printf("command %s\n", command);
1720         if (system(command) == -1) {
1721                 cause = "Couldn't copy runtime";
1722         }
1723
1724 cleanup:
1725         if (progfd!=-1)
1726                 close(progfd);
1727         if (runtime)
1728                 MEM_freeN(runtime);
1729
1730         if (cause) {
1731                 *cause_r= cause;
1732                 return 0;
1733         } else
1734                 return 1;
1735 }
1736
1737 void BLO_write_runtime(char *file, char *exename) {
1738         char gamename[FILE_MAXDIR+FILE_MAXFILE];
1739         int outfd = -1;
1740         char *cause= NULL;
1741
1742         // remove existing file / bundle
1743         //printf("Delete file %s\n", file);
1744         BLI_delete(file, NULL, TRUE);
1745
1746         if (!recursive_copy_runtime(file, exename, &cause))
1747                 goto cleanup;
1748
1749         strcpy(gamename, file);
1750         strcat(gamename, "/Contents/Resources/game.blend");
1751         //printf("gamename %s\n", gamename);
1752         outfd= open(gamename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777);
1753         if (outfd != -1) {
1754
1755                 write_file_handle(outfd, NULL,NULL, 0, G.fileflags);
1756
1757                 if (write(outfd, " ", 1) != 1) {
1758                         cause= "Unable to write to output file";
1759                         goto cleanup;
1760                 }
1761         } else {
1762                 cause = "Unable to open blenderfile";
1763         }
1764
1765 cleanup:
1766         if (outfd!=-1)
1767                 close(outfd);
1768
1769         if (cause)
1770                 error("Unable to make runtime: %s", cause);
1771 }
1772
1773 #else /* !__APPLE__ */
1774
1775 static int handle_append_runtime(int handle, char *exename, char **cause_r) {
1776         char *cause= NULL, *runtime= get_runtime_path(exename);
1777         unsigned char buf[1024];
1778         int count, progfd= -1;
1779
1780         if (!runtime) {
1781                 cause= "Unable to find runtime";
1782                 goto cleanup;
1783         }
1784
1785         progfd= open(runtime, O_BINARY|O_RDONLY, 0);
1786         if (progfd==-1) {
1787                 cause= "Unable to find runtime";
1788                 goto cleanup;
1789         }
1790
1791         while ((count= read(progfd, buf, sizeof(buf)))>0) {
1792                 if (write(handle, buf, count)!=count) {
1793                         cause= "Unable to write to output file";
1794                         goto cleanup;
1795                 }
1796         }
1797
1798 cleanup:
1799         if (progfd!=-1)
1800                 close(progfd);
1801         if (runtime)
1802                 MEM_freeN(runtime);
1803
1804         if (cause) {
1805                 *cause_r= cause;
1806                 return 0;
1807         } else
1808                 return 1;
1809 }
1810
1811 static int handle_write_msb_int(int handle, int i) {
1812         unsigned char buf[4];
1813         buf[0]= (i>>24)&0xFF;
1814         buf[1]= (i>>16)&0xFF;
1815         buf[2]= (i>>8)&0xFF;
1816         buf[3]= (i>>0)&0xFF;
1817
1818         return (write(handle, buf, 4)==4);
1819 }
1820
1821 void BLO_write_runtime(char *file, char *exename) {
1822         int outfd= open(file, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777);
1823         char *cause= NULL;
1824         int datastart;
1825
1826         if (!outfd) {
1827                 cause= "Unable to open output file";
1828                 goto cleanup;
1829         }
1830         if (!handle_append_runtime(outfd, exename, &cause))
1831                 goto cleanup;
1832
1833         datastart= lseek(outfd, 0, SEEK_CUR);
1834
1835         write_file_handle(outfd, NULL,NULL, 0, G.fileflags);
1836
1837         if (!handle_write_msb_int(outfd, datastart) || (write(outfd, "BRUNTIME", 8)!=8)) {
1838                 cause= "Unable to write to output file";
1839                 goto cleanup;
1840         }
1841
1842 cleanup:
1843         if (outfd!=-1)
1844                 close(outfd);
1845
1846         if (cause)
1847                 error("Unable to make runtime: %s", cause);
1848 }
1849
1850 #endif /* !__APPLE__ */