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