1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup blenloader
22 */
23
24 /**
25 *
26 * FILE FORMAT
27 * ===========
28 *
29 * IFF-style structure (but not IFF compatible!)
30 *
31 * Start file:
32 * <pre>
33 * `BLENDER_V100` `12` bytes (version 1.00 is just an example).
34 * `V` = big endian, `v` = little endian.
35 * `_` = 4 byte pointer, `-` = 8 byte pointer.
36 * </pre>
37 *
38 * data-blocks: (also see struct #BHead).
39 * <pre>
40 * `bh.code` `char[4]` see `BLO_blend_defs.h` for a list of known types.
41 * `bh.len` `int32` length data after #BHead in bytes.
42 * `bh.old` `void *` old pointer (the address at the time of writing the file).
43 * `bh.SDNAnr` `int32` struct index of structs stored in #DNA1 data.
44 * `bh.nr` `int32` in case of array: number of structs.
45 * data
46 * ...
47 * ...
48 * </pre>
49 *
50 * Almost all data in Blender are structures. Each struct saved
51 * gets a BHead header. With BHead the struct can be linked again
52 * and compared with #StructDNA.
53
54 * WRITE
55 * =====
56 *
57 * Preferred writing order: (not really a must, but why would you do it random?)
58 * Any case: direct data is ALWAYS after the lib block.
59 *
60 * (Local file data)
61 * - for each LibBlock
62 * - write LibBlock
63 * - write associated direct data
64 * (External file data)
65 * - per library
66 * - write library block
67 * - per LibBlock
68 * - write the ID of LibBlock
69 * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
70 * - write #GLOB (#FileGlobal struct) (some global vars).
71 * - write #DNA1 (#SDNA struct)
72 * - write #USER (#UserDef struct) if filename is ``~/.config/blender/X.XX/config/startup.blend``.
73 */
74
75 #include <fcntl.h>
76 #include <limits.h>
77 #include <math.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81
82 #ifdef WIN32
83 # include "BLI_winstuff.h"
84 # include "winsock2.h"
85 # include <io.h>
86 # include <zlib.h> /* odd include order-issue */
87 #else
88 # include <unistd.h> /* FreeBSD, for write() and close(). */
89 #endif
90
91 #include "BLI_utildefines.h"
92
93 /* allow writefile to use deprecated functionality (for forward compatibility code) */
94 #define DNA_DEPRECATED_ALLOW
95
96 #include "DNA_anim_types.h"
97 #include "DNA_armature_types.h"
98 #include "DNA_cachefile_types.h"
99 #include "DNA_cloth_types.h"
100 #include "DNA_collection_types.h"
101 #include "DNA_constraint_types.h"
102 #include "DNA_curveprofile_types.h"
103 #include "DNA_dynamicpaint_types.h"
104 #include "DNA_fileglobal_types.h"
105 #include "DNA_fluid_types.h"
106 #include "DNA_genfile.h"
107 #include "DNA_lightprobe_types.h"
108 #include "DNA_meshdata_types.h"
109 #include "DNA_movieclip_types.h"
110 #include "DNA_object_force_types.h"
111 #include "DNA_object_types.h"
112 #include "DNA_particle_types.h"
113 #include "DNA_pointcache_types.h"
114 #include "DNA_rigidbody_types.h"
115 #include "DNA_scene_types.h"
116 #include "DNA_screen_types.h"
117 #include "DNA_sdna_types.h"
118 #include "DNA_sequence_types.h"
119 #include "DNA_shader_fx_types.h"
120 #include "DNA_space_types.h"
121 #include "DNA_view3d_types.h"
122 #include "DNA_windowmanager_types.h"
123 #include "DNA_workspace_types.h"
124
125 #include "BLI_bitmap.h"
126 #include "BLI_blenlib.h"
127 #include "BLI_mempool.h"
128 #include "MEM_guardedalloc.h" /* MEM_freeN */
129
130 #include "BKE_action.h"
131 #include "BKE_anim_data.h"
132 #include "BKE_animsys.h"
133 #include "BKE_armature.h"
134 #include "BKE_blender_version.h"
135 #include "BKE_bpath.h"
136 #include "BKE_collection.h"
137 #include "BKE_colortools.h"
138 #include "BKE_constraint.h"
139 #include "BKE_curveprofile.h"
140 #include "BKE_deform.h"
141 #include "BKE_fcurve.h"
142 #include "BKE_fcurve_driver.h"
143 #include "BKE_global.h" /* for G */
144 #include "BKE_gpencil_modifier.h"
145 #include "BKE_icons.h"
146 #include "BKE_idprop.h"
147 #include "BKE_idtype.h"
148 #include "BKE_layer.h"
149 #include "BKE_lib_id.h"
150 #include "BKE_lib_override.h"
151 #include "BKE_main.h"
152 #include "BKE_modifier.h"
153 #include "BKE_node.h"
154 #include "BKE_object.h"
155 #include "BKE_packedFile.h"
156 #include "BKE_pointcache.h"
157 #include "BKE_report.h"
158 #include "BKE_sequencer.h"
159 #include "BKE_shader_fx.h"
160 #include "BKE_subsurf.h"
161 #include "BKE_workspace.h"
162
163 #include "BLO_blend_defs.h"
164 #include "BLO_blend_validate.h"
165 #include "BLO_read_write.h"
166 #include "BLO_readfile.h"
167 #include "BLO_undofile.h"
168 #include "BLO_writefile.h"
169
170 #include "readfile.h"
171
172 #include <errno.h>
173
174 /* Make preferences read-only. */
175 #define U (*((const UserDef *)&U))
176
177 /* ********* my write, buffered writing with minimum size chunks ************ */
178
179 /* Use optimal allocation since blocks of this size are kept in memory for undo. */
180 #define MYWRITE_BUFFER_SIZE (MEM_SIZE_OPTIMAL(1 << 17)) /* 128kb */
181 #define MYWRITE_MAX_CHUNK (MEM_SIZE_OPTIMAL(1 << 15)) /* ~32kb */
182
183 /** Use if we want to store how many bytes have been written to the file. */
184 // #define USE_WRITE_DATA_LEN
185
186 /* -------------------------------------------------------------------- */
187 /** \name Internal Write Wrapper's (Abstracts Compression)
188 * \{ */
189
190 typedef enum {
191 WW_WRAP_NONE = 1,
192 WW_WRAP_ZLIB,
193 } eWriteWrapType;
194
195 typedef struct WriteWrap WriteWrap;
196 struct WriteWrap {
197 /* callbacks */
198 bool (*open)(WriteWrap *ww, const char *filepath);
199 bool (*close)(WriteWrap *ww);
200 size_t (*write)(WriteWrap *ww, const char *data, size_t data_len);
201
202 /* Buffer output (we only want when output isn't already buffered). */
203 bool use_buf;
204
205 /* internal */
206 union {
207 int file_handle;
208 gzFile gz_handle;
209 } _user_data;
210 };
211
212 /* none */
213 #define FILE_HANDLE(ww) (ww)->_user_data.file_handle
214
ww_open_none(WriteWrap * ww,const char * filepath)215 static bool ww_open_none(WriteWrap *ww, const char *filepath)
216 {
217 int file;
218
219 file = BLI_open(filepath, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
220
221 if (file != -1) {
222 FILE_HANDLE(ww) = file;
223 return true;
224 }
225
226 return false;
227 }
ww_close_none(WriteWrap * ww)228 static bool ww_close_none(WriteWrap *ww)
229 {
230 return (close(FILE_HANDLE(ww)) != -1);
231 }
ww_write_none(WriteWrap * ww,const char * buf,size_t buf_len)232 static size_t ww_write_none(WriteWrap *ww, const char *buf, size_t buf_len)
233 {
234 return write(FILE_HANDLE(ww), buf, buf_len);
235 }
236 #undef FILE_HANDLE
237
238 /* zlib */
239 #define FILE_HANDLE(ww) (ww)->_user_data.gz_handle
240
ww_open_zlib(WriteWrap * ww,const char * filepath)241 static bool ww_open_zlib(WriteWrap *ww, const char *filepath)
242 {
243 gzFile file;
244
245 file = BLI_gzopen(filepath, "wb1");
246
247 if (file != Z_NULL) {
248 FILE_HANDLE(ww) = file;
249 return true;
250 }
251
252 return false;
253 }
ww_close_zlib(WriteWrap * ww)254 static bool ww_close_zlib(WriteWrap *ww)
255 {
256 return (gzclose(FILE_HANDLE(ww)) == Z_OK);
257 }
ww_write_zlib(WriteWrap * ww,const char * buf,size_t buf_len)258 static size_t ww_write_zlib(WriteWrap *ww, const char *buf, size_t buf_len)
259 {
260 return gzwrite(FILE_HANDLE(ww), buf, buf_len);
261 }
262 #undef FILE_HANDLE
263
264 /* --- end compression types --- */
265
ww_handle_init(eWriteWrapType ww_type,WriteWrap * r_ww)266 static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww)
267 {
268 memset(r_ww, 0, sizeof(*r_ww));
269
270 switch (ww_type) {
271 case WW_WRAP_ZLIB: {
272 r_ww->open = ww_open_zlib;
273 r_ww->close = ww_close_zlib;
274 r_ww->write = ww_write_zlib;
275 r_ww->use_buf = false;
276 break;
277 }
278 default: {
279 r_ww->open = ww_open_none;
280 r_ww->close = ww_close_none;
281 r_ww->write = ww_write_none;
282 r_ww->use_buf = true;
283 break;
284 }
285 }
286 }
287
288 /** \} */
289
290 /* -------------------------------------------------------------------- */
291 /** \name Write Data Type & Functions
292 * \{ */
293
294 typedef struct {
295 const struct SDNA *sdna;
296
297 /** Use for file and memory writing (fixed size of #MYWRITE_BUFFER_SIZE). */
298 uchar *buf;
299 /** Number of bytes used in #WriteData.buf (flushed when exceeded). */
300 size_t buf_used_len;
301
302 #ifdef USE_WRITE_DATA_LEN
303 /** Total number of bytes written. */
304 size_t write_len;
305 #endif
306
307 /** Set on unlikely case of an error (ignores further file writing). */
308 bool error;
309
310 /** #MemFile writing (used for undo). */
311 MemFileWriteData mem;
312 /** When true, write to #WriteData.current, could also call 'is_undo'. */
313 bool use_memfile;
314
315 /**
316 * Wrap writing, so we can use zlib or
317 * other compression types later, see: G_FILE_COMPRESS
318 * Will be NULL for UNDO.
319 */
320 WriteWrap *ww;
321 } WriteData;
322
323 typedef struct BlendWriter {
324 WriteData *wd;
325 } BlendWriter;
326
writedata_new(WriteWrap * ww)327 static WriteData *writedata_new(WriteWrap *ww)
328 {
329 WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
330
331 wd->sdna = DNA_sdna_current_get();
332
333 wd->ww = ww;
334
335 if ((ww == NULL) || (ww->use_buf)) {
336 wd->buf = MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
337 }
338
339 return wd;
340 }
341
writedata_do_write(WriteData * wd,const void * mem,size_t memlen)342 static void writedata_do_write(WriteData *wd, const void *mem, size_t memlen)
343 {
344 if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) {
345 return;
346 }
347
348 if (memlen > INT_MAX) {
349 BLI_assert(!"Cannot write chunks bigger than INT_MAX.");
350 return;
351 }
352
353 if (UNLIKELY(wd->error)) {
354 return;
355 }
356
357 /* memory based save */
358 if (wd->use_memfile) {
359 BLO_memfile_chunk_add(&wd->mem, mem, memlen);
360 }
361 else {
362 if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
363 wd->error = true;
364 }
365 }
366 }
367
writedata_free(WriteData * wd)368 static void writedata_free(WriteData *wd)
369 {
370 if (wd->buf) {
371 MEM_freeN(wd->buf);
372 }
373 MEM_freeN(wd);
374 }
375
376 /** \} */
377
378 /* -------------------------------------------------------------------- */
379 /** \name Local Writing API 'mywrite'
380 * \{ */
381
382 /**
383 * Flush helps the de-duplicating memory for undo-save by logically segmenting data,
384 * so differences in one part of memory won't cause unrelated data to be duplicated.
385 */
mywrite_flush(WriteData * wd)386 static void mywrite_flush(WriteData *wd)
387 {
388 if (wd->buf_used_len != 0) {
389 writedata_do_write(wd, wd->buf, wd->buf_used_len);
390 wd->buf_used_len = 0;
391 }
392 }
393
394 /**
395 * Low level WRITE(2) wrapper that buffers data
396 * \param adr: Pointer to new chunk of data
397 * \param len: Length of new chunk of data
398 */
mywrite(WriteData * wd,const void * adr,size_t len)399 static void mywrite(WriteData *wd, const void *adr, size_t len)
400 {
401 if (UNLIKELY(wd->error)) {
402 return;
403 }
404
405 if (UNLIKELY(adr == NULL)) {
406 BLI_assert(0);
407 return;
408 }
409
410 #ifdef USE_WRITE_DATA_LEN
411 wd->write_len += len;
412 #endif
413
414 if (wd->buf == NULL) {
415 writedata_do_write(wd, adr, len);
416 }
417 else {
418 /* if we have a single big chunk, write existing data in
419 * buffer and write out big chunk in smaller pieces */
420 if (len > MYWRITE_MAX_CHUNK) {
421 if (wd->buf_used_len != 0) {
422 writedata_do_write(wd, wd->buf, wd->buf_used_len);
423 wd->buf_used_len = 0;
424 }
425
426 do {
427 size_t writelen = MIN2(len, MYWRITE_MAX_CHUNK);
428 writedata_do_write(wd, adr, writelen);
429 adr = (const char *)adr + writelen;
430 len -= writelen;
431 } while (len > 0);
432
433 return;
434 }
435
436 /* if data would overflow buffer, write out the buffer */
437 if (len + wd->buf_used_len > MYWRITE_BUFFER_SIZE - 1) {
438 writedata_do_write(wd, wd->buf, wd->buf_used_len);
439 wd->buf_used_len = 0;
440 }
441
442 /* append data at end of buffer */
443 memcpy(&wd->buf[wd->buf_used_len], adr, len);
444 wd->buf_used_len += len;
445 }
446 }
447
448 /**
449 * BeGiN initializer for mywrite
450 * \param ww: File write wrapper.
451 * \param compare: Previous memory file (can be NULL).
452 * \param current: The current memory file (can be NULL).
453 * \warning Talks to other functions with global parameters
454 */
mywrite_begin(WriteWrap * ww,MemFile * compare,MemFile * current)455 static WriteData *mywrite_begin(WriteWrap *ww, MemFile *compare, MemFile *current)
456 {
457 WriteData *wd = writedata_new(ww);
458
459 if (current != NULL) {
460 BLO_memfile_write_init(&wd->mem, current, compare);
461 wd->use_memfile = true;
462 }
463
464 return wd;
465 }
466
467 /**
468 * END the mywrite wrapper
469 * \return 1 if write failed
470 * \return unknown global variable otherwise
471 * \warning Talks to other functions with global parameters
472 */
mywrite_end(WriteData * wd)473 static bool mywrite_end(WriteData *wd)
474 {
475 if (wd->buf_used_len != 0) {
476 writedata_do_write(wd, wd->buf, wd->buf_used_len);
477 wd->buf_used_len = 0;
478 }
479
480 if (wd->use_memfile) {
481 BLO_memfile_write_finalize(&wd->mem);
482 }
483
484 const bool err = wd->error;
485 writedata_free(wd);
486
487 return err;
488 }
489
490 /**
491 * Start writing of data related to a single ID.
492 *
493 * Only does something when storing an undo step.
494 */
mywrite_id_begin(WriteData * wd,ID * id)495 static void mywrite_id_begin(WriteData *wd, ID *id)
496 {
497 if (wd->use_memfile) {
498 wd->mem.current_id_session_uuid = id->session_uuid;
499
500 /* If current next memchunk does not match the ID we are about to write, try to find the
501 * correct memchunk in the mapping using ID's session_uuid. */
502 if (wd->mem.id_session_uuid_mapping != NULL &&
503 (wd->mem.reference_current_chunk == NULL ||
504 wd->mem.reference_current_chunk->id_session_uuid != id->session_uuid)) {
505 void *ref = BLI_ghash_lookup(wd->mem.id_session_uuid_mapping,
506 POINTER_FROM_UINT(id->session_uuid));
507 if (ref != NULL) {
508 wd->mem.reference_current_chunk = ref;
509 }
510 /* Else, no existing memchunk found, i.e. this is supposed to be a new ID. */
511 }
512 /* Otherwise, we try with the current memchunk in any case, whether it is matching current
513 * ID's session_uuid or not. */
514 }
515 }
516
517 /**
518 * Start writing of data related to a single ID.
519 *
520 * Only does something when storing an undo step.
521 */
mywrite_id_end(WriteData * wd,ID * UNUSED (id))522 static void mywrite_id_end(WriteData *wd, ID *UNUSED(id))
523 {
524 if (wd->use_memfile) {
525 /* Very important to do it after every ID write now, otherwise we cannot know whether a
526 * specific ID changed or not. */
527 mywrite_flush(wd);
528 wd->mem.current_id_session_uuid = MAIN_ID_SESSION_UUID_UNSET;
529 }
530 }
531
532 /** \} */
533
534 /* -------------------------------------------------------------------- */
535 /** \name Generic DNA File Writing
536 * \{ */
537
writestruct_at_address_nr(WriteData * wd,int filecode,const int struct_nr,int nr,const void * adr,const void * data)538 static void writestruct_at_address_nr(
539 WriteData *wd, int filecode, const int struct_nr, int nr, const void *adr, const void *data)
540 {
541 BHead bh;
542
543 BLI_assert(struct_nr > 0 && struct_nr < SDNA_TYPE_MAX);
544
545 if (adr == NULL || data == NULL || nr == 0) {
546 return;
547 }
548
549 /* init BHead */
550 bh.code = filecode;
551 bh.old = adr;
552 bh.nr = nr;
553
554 bh.SDNAnr = struct_nr;
555 const SDNA_Struct *struct_info = wd->sdna->structs[bh.SDNAnr];
556
557 bh.len = nr * wd->sdna->types_size[struct_info->type];
558
559 if (bh.len == 0) {
560 return;
561 }
562
563 mywrite(wd, &bh, sizeof(BHead));
564 mywrite(wd, data, (size_t)bh.len);
565 }
566
writestruct_nr(WriteData * wd,int filecode,const int struct_nr,int nr,const void * adr)567 static void writestruct_nr(
568 WriteData *wd, int filecode, const int struct_nr, int nr, const void *adr)
569 {
570 writestruct_at_address_nr(wd, filecode, struct_nr, nr, adr, adr);
571 }
572
573 /* do not use for structs */
writedata(WriteData * wd,int filecode,size_t len,const void * adr)574 static void writedata(WriteData *wd, int filecode, size_t len, const void *adr)
575 {
576 BHead bh;
577
578 if (adr == NULL || len == 0) {
579 return;
580 }
581
582 if (len > INT_MAX) {
583 BLI_assert(!"Cannot write chunks bigger than INT_MAX.");
584 return;
585 }
586
587 /* align to 4 (writes uninitialized bytes in some cases) */
588 len = (len + 3) & ~((size_t)3);
589
590 /* init BHead */
591 bh.code = filecode;
592 bh.old = adr;
593 bh.nr = 1;
594 bh.SDNAnr = 0;
595 bh.len = (int)len;
596
597 mywrite(wd, &bh, sizeof(BHead));
598 mywrite(wd, adr, len);
599 }
600
601 /* use this to force writing of lists in same order as reading (using link_list) */
writelist_nr(WriteData * wd,int filecode,const int struct_nr,const ListBase * lb)602 static void writelist_nr(WriteData *wd, int filecode, const int struct_nr, const ListBase *lb)
603 {
604 const Link *link = lb->first;
605
606 while (link) {
607 writestruct_nr(wd, filecode, struct_nr, 1, link);
608 link = link->next;
609 }
610 }
611
612 #if 0
613 static void writelist_id(WriteData *wd, int filecode, const char *structname, const ListBase *lb)
614 {
615 const Link *link = lb->first;
616 if (link) {
617
618 const int struct_nr = DNA_struct_find_nr(wd->sdna, structname);
619 if (struct_nr == -1) {
620 printf("error: can't find SDNA code <%s>\n", structname);
621 return;
622 }
623
624 while (link) {
625 writestruct_nr(wd, filecode, struct_nr, 1, link);
626 link = link->next;
627 }
628 }
629 }
630 #endif
631
632 #define writestruct_at_address(wd, filecode, struct_id, nr, adr, data) \
633 writestruct_at_address_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr, data)
634
635 #define writestruct(wd, filecode, struct_id, nr, adr) \
636 writestruct_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr)
637
638 #define writelist(wd, filecode, struct_id, lb) \
639 writelist_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), lb)
640
641 /** \} */
642
643 /* -------------------------------------------------------------------- */
644 /** \name Typed DNA File Writing
645 *
646 * These functions are used by blender's .blend system for file saving/loading.
647 * \{ */
648
649 /**
650 * Take care using 'use_active_win', since we wont want the currently active window
651 * to change which scene renders (currently only used for undo).
652 */
current_screen_compat(Main * mainvar,bool use_active_win,bScreen ** r_screen,Scene ** r_scene,ViewLayer ** r_view_layer)653 static void current_screen_compat(Main *mainvar,
654 bool use_active_win,
655 bScreen **r_screen,
656 Scene **r_scene,
657 ViewLayer **r_view_layer)
658 {
659 wmWindowManager *wm;
660 wmWindow *window = NULL;
661
662 /* find a global current screen in the first open window, to have
663 * a reasonable default for reading in older versions */
664 wm = mainvar->wm.first;
665
666 if (wm) {
667 if (use_active_win) {
668 /* write the active window into the file, needed for multi-window undo T43424 */
669 for (window = wm->windows.first; window; window = window->next) {
670 if (window->active) {
671 break;
672 }
673 }
674
675 /* fallback */
676 if (window == NULL) {
677 window = wm->windows.first;
678 }
679 }
680 else {
681 window = wm->windows.first;
682 }
683 }
684
685 *r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL;
686 *r_scene = (window) ? window->scene : NULL;
687 *r_view_layer = (window && *r_scene) ? BKE_view_layer_find(*r_scene, window->view_layer_name) :
688 NULL;
689 }
690
691 typedef struct RenderInfo {
692 int sfra;
693 int efra;
694 char scene_name[MAX_ID_NAME - 2];
695 } RenderInfo;
696
697 /**
698 * This was originally added for the historic render-daemon feature,
699 * now write because it can be easily extracted without reading the whole blend file.
700 *
701 * See: `release/scripts/modules/blend_render_info.py`
702 */
write_renderinfo(WriteData * wd,Main * mainvar)703 static void write_renderinfo(WriteData *wd, Main *mainvar)
704 {
705 bScreen *curscreen;
706 Scene *curscene = NULL;
707 ViewLayer *view_layer;
708
709 /* XXX in future, handle multiple windows with multiple screens? */
710 current_screen_compat(mainvar, false, &curscreen, &curscene, &view_layer);
711
712 LISTBASE_FOREACH (Scene *, sce, &mainvar->scenes) {
713 if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
714 RenderInfo data;
715 data.sfra = sce->r.sfra;
716 data.efra = sce->r.efra;
717 memset(data.scene_name, 0, sizeof(data.scene_name));
718
719 BLI_strncpy(data.scene_name, sce->id.name + 2, sizeof(data.scene_name));
720
721 writedata(wd, REND, sizeof(data), &data);
722 }
723 }
724 }
725
write_keymapitem(BlendWriter * writer,const wmKeyMapItem * kmi)726 static void write_keymapitem(BlendWriter *writer, const wmKeyMapItem *kmi)
727 {
728 BLO_write_struct(writer, wmKeyMapItem, kmi);
729 if (kmi->properties) {
730 IDP_BlendWrite(writer, kmi->properties);
731 }
732 }
733
write_userdef(BlendWriter * writer,const UserDef * userdef)734 static void write_userdef(BlendWriter *writer, const UserDef *userdef)
735 {
736 writestruct(writer->wd, USER, UserDef, 1, userdef);
737
738 LISTBASE_FOREACH (const bTheme *, btheme, &userdef->themes) {
739 BLO_write_struct(writer, bTheme, btheme);
740 }
741
742 LISTBASE_FOREACH (const wmKeyMap *, keymap, &userdef->user_keymaps) {
743 BLO_write_struct(writer, wmKeyMap, keymap);
744
745 LISTBASE_FOREACH (const wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
746 BLO_write_struct(writer, wmKeyMapDiffItem, kmdi);
747 if (kmdi->remove_item) {
748 write_keymapitem(writer, kmdi->remove_item);
749 }
750 if (kmdi->add_item) {
751 write_keymapitem(writer, kmdi->add_item);
752 }
753 }
754
755 LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &keymap->items) {
756 write_keymapitem(writer, kmi);
757 }
758 }
759
760 LISTBASE_FOREACH (const wmKeyConfigPref *, kpt, &userdef->user_keyconfig_prefs) {
761 BLO_write_struct(writer, wmKeyConfigPref, kpt);
762 if (kpt->prop) {
763 IDP_BlendWrite(writer, kpt->prop);
764 }
765 }
766
767 LISTBASE_FOREACH (const bUserMenu *, um, &userdef->user_menus) {
768 BLO_write_struct(writer, bUserMenu, um);
769 LISTBASE_FOREACH (const bUserMenuItem *, umi, &um->items) {
770 if (umi->type == USER_MENU_TYPE_OPERATOR) {
771 const bUserMenuItem_Op *umi_op = (const bUserMenuItem_Op *)umi;
772 BLO_write_struct(writer, bUserMenuItem_Op, umi_op);
773 if (umi_op->prop) {
774 IDP_BlendWrite(writer, umi_op->prop);
775 }
776 }
777 else if (umi->type == USER_MENU_TYPE_MENU) {
778 const bUserMenuItem_Menu *umi_mt = (const bUserMenuItem_Menu *)umi;
779 BLO_write_struct(writer, bUserMenuItem_Menu, umi_mt);
780 }
781 else if (umi->type == USER_MENU_TYPE_PROP) {
782 const bUserMenuItem_Prop *umi_pr = (const bUserMenuItem_Prop *)umi;
783 BLO_write_struct(writer, bUserMenuItem_Prop, umi_pr);
784 }
785 else {
786 BLO_write_struct(writer, bUserMenuItem, umi);
787 }
788 }
789 }
790
791 LISTBASE_FOREACH (const bAddon *, bext, &userdef->addons) {
792 BLO_write_struct(writer, bAddon, bext);
793 if (bext->prop) {
794 IDP_BlendWrite(writer, bext->prop);
795 }
796 }
797
798 LISTBASE_FOREACH (const bPathCompare *, path_cmp, &userdef->autoexec_paths) {
799 BLO_write_struct(writer, bPathCompare, path_cmp);
800 }
801
802 LISTBASE_FOREACH (const uiStyle *, style, &userdef->uistyles) {
803 BLO_write_struct(writer, uiStyle, style);
804 }
805 }
806
write_boid_state(BlendWriter * writer,BoidState * state)807 static void write_boid_state(BlendWriter *writer, BoidState *state)
808 {
809 BLO_write_struct(writer, BoidState, state);
810
811 LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
812 switch (rule->type) {
813 case eBoidRuleType_Goal:
814 case eBoidRuleType_Avoid:
815 BLO_write_struct(writer, BoidRuleGoalAvoid, rule);
816 break;
817 case eBoidRuleType_AvoidCollision:
818 BLO_write_struct(writer, BoidRuleAvoidCollision, rule);
819 break;
820 case eBoidRuleType_FollowLeader:
821 BLO_write_struct(writer, BoidRuleFollowLeader, rule);
822 break;
823 case eBoidRuleType_AverageSpeed:
824 BLO_write_struct(writer, BoidRuleAverageSpeed, rule);
825 break;
826 case eBoidRuleType_Fight:
827 BLO_write_struct(writer, BoidRuleFight, rule);
828 break;
829 default:
830 BLO_write_struct(writer, BoidRule, rule);
831 break;
832 }
833 }
834 #if 0
835 BoidCondition *cond = state->conditions.first;
836 for (; cond; cond = cond->next) {
837 BLO_write_struct(writer, BoidCondition, cond);
838 }
839 #endif
840 }
841
842 /* update this also to readfile.c */
843 static const char *ptcache_data_struct[] = {
844 "", // BPHYS_DATA_INDEX
845 "", // BPHYS_DATA_LOCATION
846 "", // BPHYS_DATA_VELOCITY
847 "", // BPHYS_DATA_ROTATION
848 "", // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
849 "", // BPHYS_DATA_SIZE:
850 "", // BPHYS_DATA_TIMES:
851 "BoidData", // case BPHYS_DATA_BOIDS:
852 };
853 static const char *ptcache_extra_struct[] = {
854 "",
855 "ParticleSpring",
856 "vec3f",
857 };
write_pointcaches(BlendWriter * writer,ListBase * ptcaches)858 static void write_pointcaches(BlendWriter *writer, ListBase *ptcaches)
859 {
860 LISTBASE_FOREACH (PointCache *, cache, ptcaches) {
861 BLO_write_struct(writer, PointCache, cache);
862
863 if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
864 LISTBASE_FOREACH (PTCacheMem *, pm, &cache->mem_cache) {
865 BLO_write_struct(writer, PTCacheMem, pm);
866
867 for (int i = 0; i < BPHYS_TOT_DATA; i++) {
868 if (pm->data[i] && pm->data_types & (1 << i)) {
869 if (ptcache_data_struct[i][0] == '\0') {
870 BLO_write_raw(writer, MEM_allocN_len(pm->data[i]), pm->data[i]);
871 }
872 else {
873 BLO_write_struct_array_by_name(
874 writer, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
875 }
876 }
877 }
878
879 LISTBASE_FOREACH (PTCacheExtra *, extra, &pm->extradata) {
880 if (ptcache_extra_struct[extra->type][0] == '\0') {
881 continue;
882 }
883 BLO_write_struct(writer, PTCacheExtra, extra);
884 BLO_write_struct_array_by_name(
885 writer, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
886 }
887 }
888 }
889 }
890 }
891
write_particlesettings(BlendWriter * writer,ParticleSettings * part,const void * id_address)892 static void write_particlesettings(BlendWriter *writer,
893 ParticleSettings *part,
894 const void *id_address)
895 {
896 if (part->id.us > 0 || BLO_write_is_undo(writer)) {
897 /* write LibData */
898 BLO_write_id_struct(writer, ParticleSettings, id_address, &part->id);
899 BKE_id_blend_write(writer, &part->id);
900
901 if (part->adt) {
902 BKE_animdata_blend_write(writer, part->adt);
903 }
904 BLO_write_struct(writer, PartDeflect, part->pd);
905 BLO_write_struct(writer, PartDeflect, part->pd2);
906 BLO_write_struct(writer, EffectorWeights, part->effector_weights);
907
908 if (part->clumpcurve) {
909 BKE_curvemapping_blend_write(writer, part->clumpcurve);
910 }
911 if (part->roughcurve) {
912 BKE_curvemapping_blend_write(writer, part->roughcurve);
913 }
914 if (part->twistcurve) {
915 BKE_curvemapping_blend_write(writer, part->twistcurve);
916 }
917
918 LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
919 /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
920 if (dw->ob != NULL) {
921 dw->index = 0;
922 if (part->instance_collection) { /* can be NULL if lining fails or set to None */
923 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (part->instance_collection, object) {
924 if (object == dw->ob) {
925 break;
926 }
927 dw->index++;
928 }
929 FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
930 }
931 }
932 BLO_write_struct(writer, ParticleDupliWeight, dw);
933 }
934
935 if (part->boids && part->phystype == PART_PHYS_BOIDS) {
936 BLO_write_struct(writer, BoidSettings, part->boids);
937
938 LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
939 write_boid_state(writer, state);
940 }
941 }
942 if (part->fluid && part->phystype == PART_PHYS_FLUID) {
943 BLO_write_struct(writer, SPHFluidSettings, part->fluid);
944 }
945
946 for (int a = 0; a < MAX_MTEX; a++) {
947 if (part->mtex[a]) {
948 BLO_write_struct(writer, MTex, part->mtex[a]);
949 }
950 }
951 }
952 }
953
write_particlesystems(BlendWriter * writer,ListBase * particles)954 static void write_particlesystems(BlendWriter *writer, ListBase *particles)
955 {
956 LISTBASE_FOREACH (ParticleSystem *, psys, particles) {
957 BLO_write_struct(writer, ParticleSystem, psys);
958
959 if (psys->particles) {
960 BLO_write_struct_array(writer, ParticleData, psys->totpart, psys->particles);
961
962 if (psys->particles->hair) {
963 ParticleData *pa = psys->particles;
964
965 for (int a = 0; a < psys->totpart; a++, pa++) {
966 BLO_write_struct_array(writer, HairKey, pa->totkey, pa->hair);
967 }
968 }
969
970 if (psys->particles->boid && (psys->part->phystype == PART_PHYS_BOIDS)) {
971 BLO_write_struct_array(writer, BoidParticle, psys->totpart, psys->particles->boid);
972 }
973
974 if (psys->part->fluid && (psys->part->phystype == PART_PHYS_FLUID) &&
975 (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) {
976 BLO_write_struct_array(
977 writer, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs);
978 }
979 }
980 LISTBASE_FOREACH (ParticleTarget *, pt, &psys->targets) {
981 BLO_write_struct(writer, ParticleTarget, pt);
982 }
983
984 if (psys->child) {
985 BLO_write_struct_array(writer, ChildParticle, psys->totchild, psys->child);
986 }
987
988 if (psys->clmd) {
989 BLO_write_struct(writer, ClothModifierData, psys->clmd);
990 BLO_write_struct(writer, ClothSimSettings, psys->clmd->sim_parms);
991 BLO_write_struct(writer, ClothCollSettings, psys->clmd->coll_parms);
992 }
993
994 write_pointcaches(writer, &psys->ptcaches);
995 }
996 }
997
write_motionpath(BlendWriter * writer,bMotionPath * mpath)998 static void write_motionpath(BlendWriter *writer, bMotionPath *mpath)
999 {
1000 /* sanity checks */
1001 if (mpath == NULL) {
1002 return;
1003 }
1004
1005 /* firstly, just write the motionpath struct */
1006 BLO_write_struct(writer, bMotionPath, mpath);
1007
1008 /* now write the array of data */
1009 BLO_write_struct_array(writer, bMotionPathVert, mpath->length, mpath->points);
1010 }
1011
write_constraints(BlendWriter * writer,ListBase * conlist)1012 static void write_constraints(BlendWriter *writer, ListBase *conlist)
1013 {
1014 LISTBASE_FOREACH (bConstraint *, con, conlist) {
1015 const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
1016
1017 /* Write the specific data */
1018 if (cti && con->data) {
1019 /* firstly, just write the plain con->data struct */
1020 BLO_write_struct_by_name(writer, cti->structName, con->data);
1021
1022 /* do any constraint specific stuff */
1023 switch (con->type) {
1024 case CONSTRAINT_TYPE_PYTHON: {
1025 bPythonConstraint *data = con->data;
1026
1027 /* write targets */
1028 LISTBASE_FOREACH (bConstraintTarget *, ct, &data->targets) {
1029 BLO_write_struct(writer, bConstraintTarget, ct);
1030 }
1031
1032 /* Write ID Properties -- and copy this comment EXACTLY for easy finding
1033 * of library blocks that implement this.*/
1034 IDP_BlendWrite(writer, data->prop);
1035
1036 break;
1037 }
1038 case CONSTRAINT_TYPE_ARMATURE: {
1039 bArmatureConstraint *data = con->data;
1040
1041 /* write targets */
1042 LISTBASE_FOREACH (bConstraintTarget *, ct, &data->targets) {
1043 BLO_write_struct(writer, bConstraintTarget, ct);
1044 }
1045
1046 break;
1047 }
1048 case CONSTRAINT_TYPE_SPLINEIK: {
1049 bSplineIKConstraint *data = con->data;
1050
1051 /* write points array */
1052 BLO_write_float_array(writer, data->numpoints, data->points);
1053
1054 break;
1055 }
1056 }
1057 }
1058
1059 /* Write the constraint */
1060 BLO_write_struct(writer, bConstraint, con);
1061 }
1062 }
1063
write_pose(BlendWriter * writer,bPose * pose,bArmature * arm)1064 static void write_pose(BlendWriter *writer, bPose *pose, bArmature *arm)
1065 {
1066 /* Write each channel */
1067 if (pose == NULL) {
1068 return;
1069 }
1070
1071 BLI_assert(arm != NULL);
1072
1073 /* Write channels */
1074 LISTBASE_FOREACH (bPoseChannel *, chan, &pose->chanbase) {
1075 /* Write ID Properties -- and copy this comment EXACTLY for easy finding
1076 * of library blocks that implement this.*/
1077 if (chan->prop) {
1078 IDP_BlendWrite(writer, chan->prop);
1079 }
1080
1081 write_constraints(writer, &chan->constraints);
1082
1083 write_motionpath(writer, chan->mpath);
1084
1085 /* Prevent crashes with autosave,
1086 * when a bone duplicated in edit-mode has not yet been assigned to its pose-channel.
1087 * Also needed with memundo, in some cases we can store a step before pose has been
1088 * properly rebuilt from previous undo step. */
1089 Bone *bone = (pose->flag & POSE_RECALC) ? BKE_armature_find_bone_name(arm, chan->name) :
1090 chan->bone;
1091 if (bone != NULL) {
1092 /* gets restored on read, for library armatures */
1093 chan->selectflag = bone->flag & BONE_SELECTED;
1094 }
1095
1096 BLO_write_struct(writer, bPoseChannel, chan);
1097 }
1098
1099 /* Write groups */
1100 LISTBASE_FOREACH (bActionGroup *, grp, &pose->agroups) {
1101 BLO_write_struct(writer, bActionGroup, grp);
1102 }
1103
1104 /* write IK param */
1105 if (pose->ikparam) {
1106 const char *structname = BKE_pose_ikparam_get_name(pose);
1107 if (structname) {
1108 BLO_write_struct_by_name(writer, structname, pose->ikparam);
1109 }
1110 }
1111
1112 /* Write this pose */
1113 BLO_write_struct(writer, bPose, pose);
1114 }
1115
write_defgroups(BlendWriter * writer,ListBase * defbase)1116 static void write_defgroups(BlendWriter *writer, ListBase *defbase)
1117 {
1118 LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) {
1119 BLO_write_struct(writer, bDeformGroup, defgroup);
1120 }
1121 }
1122
write_fmaps(BlendWriter * writer,ListBase * fbase)1123 static void write_fmaps(BlendWriter *writer, ListBase *fbase)
1124 {
1125 LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
1126 BLO_write_struct(writer, bFaceMap, fmap);
1127 }
1128 }
1129
write_modifiers(BlendWriter * writer,ListBase * modbase)1130 static void write_modifiers(BlendWriter *writer, ListBase *modbase)
1131 {
1132 if (modbase == NULL) {
1133 return;
1134 }
1135
1136 LISTBASE_FOREACH (ModifierData *, md, modbase) {
1137 const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
1138 if (mti == NULL) {
1139 return;
1140 }
1141
1142 BLO_write_struct_by_name(writer, mti->structName, md);
1143
1144 if (md->type == eModifierType_Cloth) {
1145 ClothModifierData *clmd = (ClothModifierData *)md;
1146
1147 BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
1148 BLO_write_struct(writer, ClothCollSettings, clmd->coll_parms);
1149 BLO_write_struct(writer, EffectorWeights, clmd->sim_parms->effector_weights);
1150 write_pointcaches(writer, &clmd->ptcaches);
1151 }
1152 else if (md->type == eModifierType_Fluid) {
1153 FluidModifierData *fmd = (FluidModifierData *)md;
1154
1155 if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
1156 BLO_write_struct(writer, FluidDomainSettings, fmd->domain);
1157
1158 if (fmd->domain) {
1159 write_pointcaches(writer, &(fmd->domain->ptcaches[0]));
1160
1161 /* create fake pointcache so that old blender versions can read it */
1162 fmd->domain->point_cache[1] = BKE_ptcache_add(&fmd->domain->ptcaches[1]);
1163 fmd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
1164 fmd->domain->point_cache[1]->step = 1;
1165
1166 write_pointcaches(writer, &(fmd->domain->ptcaches[1]));
1167
1168 if (fmd->domain->coba) {
1169 BLO_write_struct(writer, ColorBand, fmd->domain->coba);
1170 }
1171
1172 /* cleanup the fake pointcache */
1173 BKE_ptcache_free_list(&fmd->domain->ptcaches[1]);
1174 fmd->domain->point_cache[1] = NULL;
1175
1176 BLO_write_struct(writer, EffectorWeights, fmd->domain->effector_weights);
1177 }
1178 }
1179 else if (fmd->type & MOD_FLUID_TYPE_FLOW) {
1180 BLO_write_struct(writer, FluidFlowSettings, fmd->flow);
1181 }
1182 else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
1183 BLO_write_struct(writer, FluidEffectorSettings, fmd->effector);
1184 }
1185 }
1186 else if (md->type == eModifierType_Fluidsim) {
1187 FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
1188
1189 BLO_write_struct(writer, FluidsimSettings, fluidmd->fss);
1190 }
1191 else if (md->type == eModifierType_DynamicPaint) {
1192 DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
1193
1194 if (pmd->canvas) {
1195 BLO_write_struct(writer, DynamicPaintCanvasSettings, pmd->canvas);
1196
1197 /* write surfaces */
1198 LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
1199 BLO_write_struct(writer, DynamicPaintSurface, surface);
1200 }
1201 /* write caches and effector weights */
1202 LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
1203 write_pointcaches(writer, &(surface->ptcaches));
1204
1205 BLO_write_struct(writer, EffectorWeights, surface->effector_weights);
1206 }
1207 }
1208 if (pmd->brush) {
1209 BLO_write_struct(writer, DynamicPaintBrushSettings, pmd->brush);
1210 BLO_write_struct(writer, ColorBand, pmd->brush->paint_ramp);
1211 BLO_write_struct(writer, ColorBand, pmd->brush->vel_ramp);
1212 }
1213 }
1214 else if (md->type == eModifierType_Collision) {
1215
1216 #if 0
1217 CollisionModifierData *collmd = (CollisionModifierData *)md;
1218 // TODO: CollisionModifier should use pointcache
1219 // + have proper reset events before enabling this
1220 writestruct(wd, DATA, MVert, collmd->numverts, collmd->x);
1221 writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew);
1222 writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
1223 #endif
1224 }
1225
1226 if (mti->blendWrite != NULL) {
1227 mti->blendWrite(writer, md);
1228 }
1229 }
1230 }
1231
write_gpencil_modifiers(BlendWriter * writer,ListBase * modbase)1232 static void write_gpencil_modifiers(BlendWriter *writer, ListBase *modbase)
1233 {
1234 if (modbase == NULL) {
1235 return;
1236 }
1237
1238 LISTBASE_FOREACH (GpencilModifierData *, md, modbase) {
1239 const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
1240 if (mti == NULL) {
1241 return;
1242 }
1243
1244 BLO_write_struct_by_name(writer, mti->struct_name, md);
1245
1246 if (md->type == eGpencilModifierType_Thick) {
1247 ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
1248
1249 if (gpmd->curve_thickness) {
1250 BKE_curvemapping_blend_write(writer, gpmd->curve_thickness);
1251 }
1252 }
1253 else if (md->type == eGpencilModifierType_Noise) {
1254 NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
1255
1256 if (gpmd->curve_intensity) {
1257 BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1258 }
1259 }
1260 else if (md->type == eGpencilModifierType_Hook) {
1261 HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
1262
1263 if (gpmd->curfalloff) {
1264 BKE_curvemapping_blend_write(writer, gpmd->curfalloff);
1265 }
1266 }
1267 else if (md->type == eGpencilModifierType_Tint) {
1268 TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
1269 if (gpmd->colorband) {
1270 BLO_write_struct(writer, ColorBand, gpmd->colorband);
1271 }
1272 if (gpmd->curve_intensity) {
1273 BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1274 }
1275 }
1276 else if (md->type == eGpencilModifierType_Smooth) {
1277 SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
1278 if (gpmd->curve_intensity) {
1279 BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1280 }
1281 }
1282 else if (md->type == eGpencilModifierType_Color) {
1283 ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
1284 if (gpmd->curve_intensity) {
1285 BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1286 }
1287 }
1288 else if (md->type == eGpencilModifierType_Opacity) {
1289 OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
1290 if (gpmd->curve_intensity) {
1291 BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1292 }
1293 }
1294 }
1295 }
1296
write_shaderfxs(BlendWriter * writer,ListBase * fxbase)1297 static void write_shaderfxs(BlendWriter *writer, ListBase *fxbase)
1298 {
1299 if (fxbase == NULL) {
1300 return;
1301 }
1302
1303 LISTBASE_FOREACH (ShaderFxData *, fx, fxbase) {
1304 const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
1305 if (fxi == NULL) {
1306 return;
1307 }
1308
1309 BLO_write_struct_by_name(writer, fxi->struct_name, fx);
1310 }
1311 }
1312
write_object(BlendWriter * writer,Object * ob,const void * id_address)1313 static void write_object(BlendWriter *writer, Object *ob, const void *id_address)
1314 {
1315 const bool is_undo = BLO_write_is_undo(writer);
1316 if (ob->id.us > 0 || is_undo) {
1317 /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
1318 BKE_object_runtime_reset(ob);
1319
1320 if (is_undo) {
1321 /* For undo we stay in object mode during undo presses, so keep edit-mode disabled on save as
1322 * well, can help reducing false detection of changed data-blocks. */
1323 ob->mode &= ~OB_MODE_EDIT;
1324 }
1325
1326 /* write LibData */
1327 BLO_write_id_struct(writer, Object, id_address, &ob->id);
1328 BKE_id_blend_write(writer, &ob->id);
1329
1330 if (ob->adt) {
1331 BKE_animdata_blend_write(writer, ob->adt);
1332 }
1333
1334 /* direct data */
1335 BLO_write_pointer_array(writer, ob->totcol, ob->mat);
1336 BLO_write_raw(writer, sizeof(char) * ob->totcol, ob->matbits);
1337
1338 bArmature *arm = NULL;
1339 if (ob->type == OB_ARMATURE) {
1340 arm = ob->data;
1341 if (arm && ob->pose && arm->act_bone) {
1342 BLI_strncpy(
1343 ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
1344 }
1345 }
1346
1347 write_pose(writer, ob->pose, arm);
1348 write_defgroups(writer, &ob->defbase);
1349 write_fmaps(writer, &ob->fmaps);
1350 write_constraints(writer, &ob->constraints);
1351 write_motionpath(writer, ob->mpath);
1352
1353 BLO_write_struct(writer, PartDeflect, ob->pd);
1354 if (ob->soft) {
1355 /* Set deprecated pointers to prevent crashes of older Blenders */
1356 ob->soft->pointcache = ob->soft->shared->pointcache;
1357 ob->soft->ptcaches = ob->soft->shared->ptcaches;
1358 BLO_write_struct(writer, SoftBody, ob->soft);
1359 BLO_write_struct(writer, SoftBody_Shared, ob->soft->shared);
1360 write_pointcaches(writer, &(ob->soft->shared->ptcaches));
1361 BLO_write_struct(writer, EffectorWeights, ob->soft->effector_weights);
1362 }
1363
1364 if (ob->rigidbody_object) {
1365 /* TODO: if any extra data is added to handle duplis, will need separate function then */
1366 BLO_write_struct(writer, RigidBodyOb, ob->rigidbody_object);
1367 }
1368 if (ob->rigidbody_constraint) {
1369 BLO_write_struct(writer, RigidBodyCon, ob->rigidbody_constraint);
1370 }
1371
1372 if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
1373 BLO_write_struct(writer, ImageUser, ob->iuser);
1374 }
1375
1376 write_particlesystems(writer, &ob->particlesystem);
1377 write_modifiers(writer, &ob->modifiers);
1378 write_gpencil_modifiers(writer, &ob->greasepencil_modifiers);
1379 write_shaderfxs(writer, &ob->shader_fx);
1380
1381 BLO_write_struct_list(writer, LinkData, &ob->pc_ids);
1382
1383 BKE_previewimg_blend_write(writer, ob->preview);
1384 }
1385 }
1386
write_collection_nolib(BlendWriter * writer,Collection * collection)1387 static void write_collection_nolib(BlendWriter *writer, Collection *collection)
1388 {
1389 /* Shared function for collection data-blocks and scene master collection. */
1390 BKE_previewimg_blend_write(writer, collection->preview);
1391
1392 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1393 BLO_write_struct(writer, CollectionObject, cob);
1394 }
1395
1396 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
1397 BLO_write_struct(writer, CollectionChild, child);
1398 }
1399 }
1400
write_collection(BlendWriter * writer,Collection * collection,const void * id_address)1401 static void write_collection(BlendWriter *writer, Collection *collection, const void *id_address)
1402 {
1403 if (collection->id.us > 0 || BLO_write_is_undo(writer)) {
1404 /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
1405 collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
1406 collection->tag = 0;
1407 BLI_listbase_clear(&collection->object_cache);
1408 BLI_listbase_clear(&collection->parents);
1409
1410 /* write LibData */
1411 BLO_write_id_struct(writer, Collection, id_address, &collection->id);
1412 BKE_id_blend_write(writer, &collection->id);
1413
1414 write_collection_nolib(writer, collection);
1415 }
1416 }
1417
write_sequence_modifiers(BlendWriter * writer,ListBase * modbase)1418 static void write_sequence_modifiers(BlendWriter *writer, ListBase *modbase)
1419 {
1420 LISTBASE_FOREACH (SequenceModifierData *, smd, modbase) {
1421 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
1422
1423 if (smti) {
1424 BLO_write_struct_by_name(writer, smti->struct_name, smd);
1425
1426 if (smd->type == seqModifierType_Curves) {
1427 CurvesModifierData *cmd = (CurvesModifierData *)smd;
1428
1429 BKE_curvemapping_blend_write(writer, &cmd->curve_mapping);
1430 }
1431 else if (smd->type == seqModifierType_HueCorrect) {
1432 HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
1433
1434 BKE_curvemapping_blend_write(writer, &hcmd->curve_mapping);
1435 }
1436 }
1437 else {
1438 BLO_write_struct(writer, SequenceModifierData, smd);
1439 }
1440 }
1441 }
1442
write_view_settings(BlendWriter * writer,ColorManagedViewSettings * view_settings)1443 static void write_view_settings(BlendWriter *writer, ColorManagedViewSettings *view_settings)
1444 {
1445 if (view_settings->curve_mapping) {
1446 BKE_curvemapping_blend_write(writer, view_settings->curve_mapping);
1447 }
1448 }
1449
write_view3dshading(BlendWriter * writer,View3DShading * shading)1450 static void write_view3dshading(BlendWriter *writer, View3DShading *shading)
1451 {
1452 if (shading->prop) {
1453 IDP_BlendWrite(writer, shading->prop);
1454 }
1455 }
1456
write_paint(BlendWriter * writer,Paint * p)1457 static void write_paint(BlendWriter *writer, Paint *p)
1458 {
1459 if (p->cavity_curve) {
1460 BKE_curvemapping_blend_write(writer, p->cavity_curve);
1461 }
1462 BLO_write_struct_array(writer, PaintToolSlot, p->tool_slots_len, p->tool_slots);
1463 }
1464
write_layer_collections(BlendWriter * writer,ListBase * lb)1465 static void write_layer_collections(BlendWriter *writer, ListBase *lb)
1466 {
1467 LISTBASE_FOREACH (LayerCollection *, lc, lb) {
1468 BLO_write_struct(writer, LayerCollection, lc);
1469
1470 write_layer_collections(writer, &lc->layer_collections);
1471 }
1472 }
1473
write_view_layer(BlendWriter * writer,ViewLayer * view_layer)1474 static void write_view_layer(BlendWriter *writer, ViewLayer *view_layer)
1475 {
1476 BLO_write_struct(writer, ViewLayer, view_layer);
1477 BLO_write_struct_list(writer, Base, &view_layer->object_bases);
1478
1479 if (view_layer->id_properties) {
1480 IDP_BlendWrite(writer, view_layer->id_properties);
1481 }
1482
1483 LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
1484 BLO_write_struct(writer, FreestyleModuleConfig, fmc);
1485 }
1486
1487 LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
1488 BLO_write_struct(writer, FreestyleLineSet, fls);
1489 }
1490 write_layer_collections(writer, &view_layer->layer_collections);
1491 }
1492
write_lightcache_texture(BlendWriter * writer,LightCacheTexture * tex)1493 static void write_lightcache_texture(BlendWriter *writer, LightCacheTexture *tex)
1494 {
1495 if (tex->data) {
1496 size_t data_size = tex->components * tex->tex_size[0] * tex->tex_size[1] * tex->tex_size[2];
1497 if (tex->data_type == LIGHTCACHETEX_FLOAT) {
1498 data_size *= sizeof(float);
1499 }
1500 else if (tex->data_type == LIGHTCACHETEX_UINT) {
1501 data_size *= sizeof(uint);
1502 }
1503
1504 /* FIXME: We can't save more than what 32bit systems can handle.
1505 * The solution would be to split the texture but it is too late for 2.90. (see T78529) */
1506 if (data_size < INT_MAX) {
1507 BLO_write_raw(writer, data_size, tex->data);
1508 }
1509 }
1510 }
1511
write_lightcache(BlendWriter * writer,LightCache * cache)1512 static void write_lightcache(BlendWriter *writer, LightCache *cache)
1513 {
1514 write_lightcache_texture(writer, &cache->grid_tx);
1515 write_lightcache_texture(writer, &cache->cube_tx);
1516
1517 if (cache->cube_mips) {
1518 BLO_write_struct_array(writer, LightCacheTexture, cache->mips_len, cache->cube_mips);
1519 for (int i = 0; i < cache->mips_len; i++) {
1520 write_lightcache_texture(writer, &cache->cube_mips[i]);
1521 }
1522 }
1523
1524 BLO_write_struct_array(writer, LightGridCache, cache->grid_len, cache->grid_data);
1525 BLO_write_struct_array(writer, LightProbeCache, cache->cube_len, cache->cube_data);
1526 }
1527
write_scene(BlendWriter * writer,Scene * sce,const void * id_address)1528 static void write_scene(BlendWriter *writer, Scene *sce, const void *id_address)
1529 {
1530 if (BLO_write_is_undo(writer)) {
1531 /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
1532 /* XXX This UI data should not be stored in Scene at all... */
1533 memset(&sce->cursor, 0, sizeof(sce->cursor));
1534 }
1535
1536 /* write LibData */
1537 BLO_write_id_struct(writer, Scene, id_address, &sce->id);
1538 BKE_id_blend_write(writer, &sce->id);
1539
1540 if (sce->adt) {
1541 BKE_animdata_blend_write(writer, sce->adt);
1542 }
1543 BKE_keyingsets_blend_write(writer, &sce->keyingsets);
1544
1545 /* direct data */
1546 ToolSettings *tos = sce->toolsettings;
1547 BLO_write_struct(writer, ToolSettings, tos);
1548 if (tos->vpaint) {
1549 BLO_write_struct(writer, VPaint, tos->vpaint);
1550 write_paint(writer, &tos->vpaint->paint);
1551 }
1552 if (tos->wpaint) {
1553 BLO_write_struct(writer, VPaint, tos->wpaint);
1554 write_paint(writer, &tos->wpaint->paint);
1555 }
1556 if (tos->sculpt) {
1557 BLO_write_struct(writer, Sculpt, tos->sculpt);
1558 write_paint(writer, &tos->sculpt->paint);
1559 }
1560 if (tos->uvsculpt) {
1561 BLO_write_struct(writer, UvSculpt, tos->uvsculpt);
1562 write_paint(writer, &tos->uvsculpt->paint);
1563 }
1564 if (tos->gp_paint) {
1565 BLO_write_struct(writer, GpPaint, tos->gp_paint);
1566 write_paint(writer, &tos->gp_paint->paint);
1567 }
1568 if (tos->gp_vertexpaint) {
1569 BLO_write_struct(writer, GpVertexPaint, tos->gp_vertexpaint);
1570 write_paint(writer, &tos->gp_vertexpaint->paint);
1571 }
1572 if (tos->gp_sculptpaint) {
1573 BLO_write_struct(writer, GpSculptPaint, tos->gp_sculptpaint);
1574 write_paint(writer, &tos->gp_sculptpaint->paint);
1575 }
1576 if (tos->gp_weightpaint) {
1577 BLO_write_struct(writer, GpWeightPaint, tos->gp_weightpaint);
1578 write_paint(writer, &tos->gp_weightpaint->paint);
1579 }
1580 /* write grease-pencil custom ipo curve to file */
1581 if (tos->gp_interpolate.custom_ipo) {
1582 BKE_curvemapping_blend_write(writer, tos->gp_interpolate.custom_ipo);
1583 }
1584 /* write grease-pencil multiframe falloff curve to file */
1585 if (tos->gp_sculpt.cur_falloff) {
1586 BKE_curvemapping_blend_write(writer, tos->gp_sculpt.cur_falloff);
1587 }
1588 /* write grease-pencil primitive curve to file */
1589 if (tos->gp_sculpt.cur_primitive) {
1590 BKE_curvemapping_blend_write(writer, tos->gp_sculpt.cur_primitive);
1591 }
1592 /* Write the curve profile to the file. */
1593 if (tos->custom_bevel_profile_preset) {
1594 BKE_curveprofile_blend_write(writer, tos->custom_bevel_profile_preset);
1595 }
1596
1597 write_paint(writer, &tos->imapaint.paint);
1598
1599 Editing *ed = sce->ed;
1600 if (ed) {
1601 Sequence *seq;
1602
1603 BLO_write_struct(writer, Editing, ed);
1604
1605 /* reset write flags too */
1606
1607 SEQ_ALL_BEGIN (ed, seq) {
1608 if (seq->strip) {
1609 seq->strip->done = false;
1610 }
1611 BLO_write_struct(writer, Sequence, seq);
1612 }
1613 SEQ_ALL_END;
1614
1615 SEQ_ALL_BEGIN (ed, seq) {
1616 if (seq->strip && seq->strip->done == 0) {
1617 /* write strip with 'done' at 0 because readfile */
1618
1619 if (seq->effectdata) {
1620 switch (seq->type) {
1621 case SEQ_TYPE_COLOR:
1622 BLO_write_struct(writer, SolidColorVars, seq->effectdata);
1623 break;
1624 case SEQ_TYPE_SPEED:
1625 BLO_write_struct(writer, SpeedControlVars, seq->effectdata);
1626 break;
1627 case SEQ_TYPE_WIPE:
1628 BLO_write_struct(writer, WipeVars, seq->effectdata);
1629 break;
1630 case SEQ_TYPE_GLOW:
1631 BLO_write_struct(writer, GlowVars, seq->effectdata);
1632 break;
1633 case SEQ_TYPE_TRANSFORM:
1634 BLO_write_struct(writer, TransformVars, seq->effectdata);
1635 break;
1636 case SEQ_TYPE_GAUSSIAN_BLUR:
1637 BLO_write_struct(writer, GaussianBlurVars, seq->effectdata);
1638 break;
1639 case SEQ_TYPE_TEXT:
1640 BLO_write_struct(writer, TextVars, seq->effectdata);
1641 break;
1642 case SEQ_TYPE_COLORMIX:
1643 BLO_write_struct(writer, ColorMixVars, seq->effectdata);
1644 break;
1645 }
1646 }
1647
1648 BLO_write_struct(writer, Stereo3dFormat, seq->stereo3d_format);
1649
1650 Strip *strip = seq->strip;
1651 BLO_write_struct(writer, Strip, strip);
1652 if (strip->crop) {
1653 BLO_write_struct(writer, StripCrop, strip->crop);
1654 }
1655 if (strip->transform) {
1656 BLO_write_struct(writer, StripTransform, strip->transform);
1657 }
1658 if (strip->proxy) {
1659 BLO_write_struct(writer, StripProxy, strip->proxy);
1660 }
1661 if (seq->type == SEQ_TYPE_IMAGE) {
1662 BLO_write_struct_array(writer,
1663 StripElem,
1664 MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem),
1665 strip->stripdata);
1666 }
1667 else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
1668 BLO_write_struct(writer, StripElem, strip->stripdata);
1669 }
1670
1671 strip->done = true;
1672 }
1673
1674 if (seq->prop) {
1675 IDP_BlendWrite(writer, seq->prop);
1676 }
1677
1678 write_sequence_modifiers(writer, &seq->modifiers);
1679 }
1680 SEQ_ALL_END;
1681
1682 /* new; meta stack too, even when its nasty restore code */
1683 LISTBASE_FOREACH (MetaStack *, ms, &ed->metastack) {
1684 BLO_write_struct(writer, MetaStack, ms);
1685 }
1686 }
1687
1688 if (sce->r.avicodecdata) {
1689 BLO_write_struct(writer, AviCodecData, sce->r.avicodecdata);
1690 if (sce->r.avicodecdata->lpFormat) {
1691 BLO_write_raw(writer, (size_t)sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
1692 }
1693 if (sce->r.avicodecdata->lpParms) {
1694 BLO_write_raw(writer, (size_t)sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
1695 }
1696 }
1697 if (sce->r.ffcodecdata.properties) {
1698 IDP_BlendWrite(writer, sce->r.ffcodecdata.properties);
1699 }
1700
1701 /* writing dynamic list of TimeMarkers to the blend file */
1702 LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) {
1703 BLO_write_struct(writer, TimeMarker, marker);
1704
1705 if (marker->prop != NULL) {
1706 IDP_BlendWrite(writer, marker->prop);
1707 }
1708 }
1709
1710 /* writing dynamic list of TransformOrientations to the blend file */
1711 LISTBASE_FOREACH (TransformOrientation *, ts, &sce->transform_spaces) {
1712 BLO_write_struct(writer, TransformOrientation, ts);
1713 }
1714
1715 /* writing MultiView to the blend file */
1716 LISTBASE_FOREACH (SceneRenderView *, srv, &sce->r.views) {
1717 BLO_write_struct(writer, SceneRenderView, srv);
1718 }
1719
1720 if (sce->nodetree) {
1721 BLO_write_struct(writer, bNodeTree, sce->nodetree);
1722 ntreeBlendWrite(writer, sce->nodetree);
1723 }
1724
1725 write_view_settings(writer, &sce->view_settings);
1726
1727 /* writing RigidBodyWorld data to the blend file */
1728 if (sce->rigidbody_world) {
1729 /* Set deprecated pointers to prevent crashes of older Blenders */
1730 sce->rigidbody_world->pointcache = sce->rigidbody_world->shared->pointcache;
1731 sce->rigidbody_world->ptcaches = sce->rigidbody_world->shared->ptcaches;
1732 BLO_write_struct(writer, RigidBodyWorld, sce->rigidbody_world);
1733
1734 BLO_write_struct(writer, RigidBodyWorld_Shared, sce->rigidbody_world->shared);
1735 BLO_write_struct(writer, EffectorWeights, sce->rigidbody_world->effector_weights);
1736 write_pointcaches(writer, &(sce->rigidbody_world->shared->ptcaches));
1737 }
1738
1739 BKE_previewimg_blend_write(writer, sce->preview);
1740 BKE_curvemapping_curves_blend_write(writer, &sce->r.mblur_shutter_curve);
1741
1742 LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) {
1743 write_view_layer(writer, view_layer);
1744 }
1745
1746 if (sce->master_collection) {
1747 BLO_write_struct(writer, Collection, sce->master_collection);
1748 write_collection_nolib(writer, sce->master_collection);
1749 }
1750
1751 /* Eevee Lightcache */
1752 if (sce->eevee.light_cache_data && !BLO_write_is_undo(writer)) {
1753 BLO_write_struct(writer, LightCache, sce->eevee.light_cache_data);
1754 write_lightcache(writer, sce->eevee.light_cache_data);
1755 }
1756
1757 write_view3dshading(writer, &sce->display.shading);
1758
1759 /* Freed on doversion. */
1760 BLI_assert(sce->layer_properties == NULL);
1761 }
1762
write_wm_xr_data(BlendWriter * writer,wmXrData * xr_data)1763 static void write_wm_xr_data(BlendWriter *writer, wmXrData *xr_data)
1764 {
1765 write_view3dshading(writer, &xr_data->session_settings.shading);
1766 }
1767
write_region(BlendWriter * writer,ARegion * region,int spacetype)1768 static void write_region(BlendWriter *writer, ARegion *region, int spacetype)
1769 {
1770 BLO_write_struct(writer, ARegion, region);
1771
1772 if (region->regiondata) {
1773 if (region->flag & RGN_FLAG_TEMP_REGIONDATA) {
1774 return;
1775 }
1776
1777 switch (spacetype) {
1778 case SPACE_VIEW3D:
1779 if (region->regiontype == RGN_TYPE_WINDOW) {
1780 RegionView3D *rv3d = region->regiondata;
1781 BLO_write_struct(writer, RegionView3D, rv3d);
1782
1783 if (rv3d->localvd) {
1784 BLO_write_struct(writer, RegionView3D, rv3d->localvd);
1785 }
1786 if (rv3d->clipbb) {
1787 BLO_write_struct(writer, BoundBox, rv3d->clipbb);
1788 }
1789 }
1790 else {
1791 printf("regiondata write missing!\n");
1792 }
1793 break;
1794 default:
1795 printf("regiondata write missing!\n");
1796 }
1797 }
1798 }
1799
write_uilist(BlendWriter * writer,uiList * ui_list)1800 static void write_uilist(BlendWriter *writer, uiList *ui_list)
1801 {
1802 BLO_write_struct(writer, uiList, ui_list);
1803
1804 if (ui_list->properties) {
1805 IDP_BlendWrite(writer, ui_list->properties);
1806 }
1807 }
1808
write_space_outliner(BlendWriter * writer,SpaceOutliner * space_outliner)1809 static void write_space_outliner(BlendWriter *writer, SpaceOutliner *space_outliner)
1810 {
1811 BLI_mempool *ts = space_outliner->treestore;
1812
1813 if (ts) {
1814 SpaceOutliner space_outliner_flat = *space_outliner;
1815
1816 int elems = BLI_mempool_len(ts);
1817 /* linearize mempool to array */
1818 TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL;
1819
1820 if (data) {
1821 /* In this block we use the memory location of the treestore
1822 * but _not_ its data, the addresses in this case are UUID's,
1823 * since we can't rely on malloc giving us different values each time.
1824 */
1825 TreeStore ts_flat = {0};
1826
1827 /* we know the treestore is at least as big as a pointer,
1828 * so offsetting works to give us a UUID. */
1829 void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *));
1830
1831 ts_flat.usedelem = elems;
1832 ts_flat.totelem = elems;
1833 ts_flat.data = data_addr;
1834
1835 BLO_write_struct(writer, SpaceOutliner, space_outliner);
1836
1837 BLO_write_struct_at_address(writer, TreeStore, ts, &ts_flat);
1838 BLO_write_struct_array_at_address(writer, TreeStoreElem, elems, data_addr, data);
1839
1840 MEM_freeN(data);
1841 }
1842 else {
1843 space_outliner_flat.treestore = NULL;
1844 BLO_write_struct_at_address(writer, SpaceOutliner, space_outliner, &space_outliner_flat);
1845 }
1846 }
1847 else {
1848 BLO_write_struct(writer, SpaceOutliner, space_outliner);
1849 }
1850 }
1851
write_panel_list(BlendWriter * writer,ListBase * lb)1852 static void write_panel_list(BlendWriter *writer, ListBase *lb)
1853 {
1854 LISTBASE_FOREACH (Panel *, panel, lb) {
1855 BLO_write_struct(writer, Panel, panel);
1856 write_panel_list(writer, &panel->children);
1857 }
1858 }
1859
write_area_regions(BlendWriter * writer,ScrArea * area)1860 static void write_area_regions(BlendWriter *writer, ScrArea *area)
1861 {
1862 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1863 write_region(writer, region, area->spacetype);
1864 write_panel_list(writer, ®ion->panels);
1865
1866 LISTBASE_FOREACH (PanelCategoryStack *, pc_act, ®ion->panels_category_active) {
1867 BLO_write_struct(writer, PanelCategoryStack, pc_act);
1868 }
1869
1870 LISTBASE_FOREACH (uiList *, ui_list, ®ion->ui_lists) {
1871 write_uilist(writer, ui_list);
1872 }
1873
1874 LISTBASE_FOREACH (uiPreview *, ui_preview, ®ion->ui_previews) {
1875 BLO_write_struct(writer, uiPreview, ui_preview);
1876 }
1877 }
1878
1879 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
1880 LISTBASE_FOREACH (ARegion *, region, &sl->regionbase) {
1881 write_region(writer, region, sl->spacetype);
1882 }
1883
1884 if (sl->spacetype == SPACE_VIEW3D) {
1885 View3D *v3d = (View3D *)sl;
1886 BLO_write_struct(writer, View3D, v3d);
1887
1888 if (v3d->localvd) {
1889 BLO_write_struct(writer, View3D, v3d->localvd);
1890 }
1891
1892 write_view3dshading(writer, &v3d->shading);
1893 }
1894 else if (sl->spacetype == SPACE_GRAPH) {
1895 SpaceGraph *sipo = (SpaceGraph *)sl;
1896 ListBase tmpGhosts = sipo->runtime.ghost_curves;
1897
1898 /* temporarily disable ghost curves when saving */
1899 BLI_listbase_clear(&sipo->runtime.ghost_curves);
1900
1901 BLO_write_struct(writer, SpaceGraph, sl);
1902 if (sipo->ads) {
1903 BLO_write_struct(writer, bDopeSheet, sipo->ads);
1904 }
1905
1906 /* reenable ghost curves */
1907 sipo->runtime.ghost_curves = tmpGhosts;
1908 }
1909 else if (sl->spacetype == SPACE_PROPERTIES) {
1910 BLO_write_struct(writer, SpaceProperties, sl);
1911 }
1912 else if (sl->spacetype == SPACE_FILE) {
1913 SpaceFile *sfile = (SpaceFile *)sl;
1914
1915 BLO_write_struct(writer, SpaceFile, sl);
1916 if (sfile->params) {
1917 BLO_write_struct(writer, FileSelectParams, sfile->params);
1918 }
1919 }
1920 else if (sl->spacetype == SPACE_SEQ) {
1921 BLO_write_struct(writer, SpaceSeq, sl);
1922 }
1923 else if (sl->spacetype == SPACE_OUTLINER) {
1924 SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
1925 write_space_outliner(writer, space_outliner);
1926 }
1927 else if (sl->spacetype == SPACE_IMAGE) {
1928 BLO_write_struct(writer, SpaceImage, sl);
1929 }
1930 else if (sl->spacetype == SPACE_TEXT) {
1931 BLO_write_struct(writer, SpaceText, sl);
1932 }
1933 else if (sl->spacetype == SPACE_SCRIPT) {
1934 SpaceScript *scr = (SpaceScript *)sl;
1935 scr->but_refs = NULL;
1936 BLO_write_struct(writer, SpaceScript, sl);
1937 }
1938 else if (sl->spacetype == SPACE_ACTION) {
1939 BLO_write_struct(writer, SpaceAction, sl);
1940 }
1941 else if (sl->spacetype == SPACE_NLA) {
1942 SpaceNla *snla = (SpaceNla *)sl;
1943
1944 BLO_write_struct(writer, SpaceNla, snla);
1945 if (snla->ads) {
1946 BLO_write_struct(writer, bDopeSheet, snla->ads);
1947 }
1948 }
1949 else if (sl->spacetype == SPACE_NODE) {
1950 SpaceNode *snode = (SpaceNode *)sl;
1951 BLO_write_struct(writer, SpaceNode, snode);
1952
1953 LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
1954 BLO_write_struct(writer, bNodeTreePath, path);
1955 }
1956 }
1957 else if (sl->spacetype == SPACE_CONSOLE) {
1958 SpaceConsole *con = (SpaceConsole *)sl;
1959
1960 LISTBASE_FOREACH (ConsoleLine *, cl, &con->history) {
1961 /* 'len_alloc' is invalid on write, set from 'len' on read */
1962 BLO_write_struct(writer, ConsoleLine, cl);
1963 BLO_write_raw(writer, (size_t)cl->len + 1, cl->line);
1964 }
1965 BLO_write_struct(writer, SpaceConsole, sl);
1966 }
1967 #ifdef WITH_GLOBAL_AREA_WRITING
1968 else if (sl->spacetype == SPACE_TOPBAR) {
1969 BLO_write_struct(writer, SpaceTopBar, sl);
1970 }
1971 else if (sl->spacetype == SPACE_STATUSBAR) {
1972 BLO_write_struct(writer, SpaceStatusBar, sl);
1973 }
1974 #endif
1975 else if (sl->spacetype == SPACE_USERPREF) {
1976 BLO_write_struct(writer, SpaceUserPref, sl);
1977 }
1978 else if (sl->spacetype == SPACE_CLIP) {
1979 BLO_write_struct(writer, SpaceClip, sl);
1980 }
1981 else if (sl->spacetype == SPACE_INFO) {
1982 BLO_write_struct(writer, SpaceInfo, sl);
1983 }
1984 }
1985 }
1986
write_area_map(BlendWriter * writer,ScrAreaMap * area_map)1987 static void write_area_map(BlendWriter *writer, ScrAreaMap *area_map)
1988 {
1989 BLO_write_struct_list(writer, ScrVert, &area_map->vertbase);
1990 BLO_write_struct_list(writer, ScrEdge, &area_map->edgebase);
1991 LISTBASE_FOREACH (ScrArea *, area, &area_map->areabase) {
1992 area->butspacetype = area->spacetype; /* Just for compatibility, will be reset below. */
1993
1994 BLO_write_struct(writer, ScrArea, area);
1995
1996 #ifdef WITH_GLOBAL_AREA_WRITING
1997 BLO_write_struct(writer, ScrGlobalAreaData, area->global);
1998 #endif
1999
2000 write_area_regions(writer, area);
2001
2002 area->butspacetype = SPACE_EMPTY; /* Unset again, was changed above. */
2003 }
2004 }
2005
write_windowmanager(BlendWriter * writer,wmWindowManager * wm,const void * id_address)2006 static void write_windowmanager(BlendWriter *writer, wmWindowManager *wm, const void *id_address)
2007 {
2008 BLO_write_id_struct(writer, wmWindowManager, id_address, &wm->id);
2009 BKE_id_blend_write(writer, &wm->id);
2010 write_wm_xr_data(writer, &wm->xr);
2011
2012 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2013 #ifndef WITH_GLOBAL_AREA_WRITING
2014 /* Don't write global areas yet, while we make changes to them. */
2015 ScrAreaMap global_areas = win->global_areas;
2016 memset(&win->global_areas, 0, sizeof(win->global_areas));
2017 #endif
2018
2019 /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
2020 win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
2021
2022 BLO_write_struct(writer, wmWindow, win);
2023 BLO_write_struct(writer, WorkSpaceInstanceHook, win->workspace_hook);
2024 BLO_write_struct(writer, Stereo3dFormat, win->stereo3d_format);
2025
2026 #ifdef WITH_GLOBAL_AREA_WRITING
2027 write_area_map(writer, &win->global_areas);
2028 #else
2029 win->global_areas = global_areas;
2030 #endif
2031
2032 /* data is written, clear deprecated data again */
2033 win->screen = NULL;
2034 }
2035 }
2036
write_screen(BlendWriter * writer,bScreen * screen,const void * id_address)2037 static void write_screen(BlendWriter *writer, bScreen *screen, const void *id_address)
2038 {
2039 /* Screens are reference counted, only saved if used by a workspace. */
2040 if (screen->id.us > 0 || BLO_write_is_undo(writer)) {
2041 /* write LibData */
2042 /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
2043 writestruct_at_address(writer->wd, ID_SCRN, bScreen, 1, id_address, screen);
2044 BKE_id_blend_write(writer, &screen->id);
2045
2046 BKE_previewimg_blend_write(writer, screen->preview);
2047
2048 /* direct data */
2049 write_area_map(writer, AREAMAP_FROM_SCREEN(screen));
2050 }
2051 }
2052
write_workspace(BlendWriter * writer,WorkSpace * workspace,const void * id_address)2053 static void write_workspace(BlendWriter *writer, WorkSpace *workspace, const void *id_address)
2054 {
2055 BLO_write_id_struct(writer, WorkSpace, id_address, &workspace->id);
2056 BKE_id_blend_write(writer, &workspace->id);
2057 BLO_write_struct_list(writer, WorkSpaceLayout, &workspace->layouts);
2058 BLO_write_struct_list(writer, WorkSpaceDataRelation, &workspace->hook_layout_relations);
2059 BLO_write_struct_list(writer, wmOwnerID, &workspace->owner_ids);
2060 BLO_write_struct_list(writer, bToolRef, &workspace->tools);
2061 LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
2062 if (tref->properties) {
2063 IDP_BlendWrite(writer, tref->properties);
2064 }
2065 }
2066 }
2067
2068 /* Keep it last of write_foodata functions. */
write_libraries(WriteData * wd,Main * main)2069 static void write_libraries(WriteData *wd, Main *main)
2070 {
2071 ListBase *lbarray[MAX_LIBARRAY];
2072 ID *id;
2073 int a, tot;
2074 bool found_one;
2075
2076 for (; main; main = main->next) {
2077 a = tot = set_listbasepointers(main, lbarray);
2078
2079 /* test: is lib being used */
2080 if (main->curlib && main->curlib->packedfile) {
2081 found_one = true;
2082 }
2083 else if (wd->use_memfile) {
2084 /* When writing undo step we always write all existing libraries, makes reading undo step
2085 * much easier when dealing with purely indirectly used libraries. */
2086 found_one = true;
2087 }
2088 else {
2089 found_one = false;
2090 while (!found_one && tot--) {
2091 for (id = lbarray[tot]->first; id; id = id->next) {
2092 if (id->us > 0 &&
2093 ((id->tag & LIB_TAG_EXTERN) ||
2094 ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
2095 found_one = true;
2096 break;
2097 }
2098 }
2099 }
2100 }
2101
2102 /* To be able to restore 'quit.blend' and temp saves,
2103 * the packed blend has to be in undo buffers... */
2104 /* XXX needs rethink, just like save UI in undo files now -
2105 * would be nice to append things only for the 'quit.blend' and temp saves. */
2106 if (found_one) {
2107 /* Not overridable. */
2108
2109 BlendWriter writer = {wd};
2110 writestruct(wd, ID_LI, Library, 1, main->curlib);
2111 BKE_id_blend_write(&writer, &main->curlib->id);
2112
2113 if (main->curlib->packedfile) {
2114 BKE_packedfile_blend_write(&writer, main->curlib->packedfile);
2115 if (wd->use_memfile == false) {
2116 printf("write packed .blend: %s\n", main->curlib->filepath);
2117 }
2118 }
2119
2120 /* Write link placeholders for all direct linked IDs. */
2121 while (a--) {
2122 for (id = lbarray[a]->first; id; id = id->next) {
2123 if (id->us > 0 &&
2124 ((id->tag & LIB_TAG_EXTERN) ||
2125 ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
2126 if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
2127 printf(
2128 "ERROR: write file: data-block '%s' from lib '%s' is not linkable "
2129 "but is flagged as directly linked",
2130 id->name,
2131 main->curlib->filepath_abs);
2132 BLI_assert(0);
2133 }
2134 writestruct(wd, ID_LINK_PLACEHOLDER, ID, 1, id);
2135 }
2136 }
2137 }
2138 }
2139 }
2140
2141 mywrite_flush(wd);
2142 }
2143
2144 /* context is usually defined by WM, two cases where no WM is available:
2145 * - for forward compatibility, curscreen has to be saved
2146 * - for undofile, curscene needs to be saved */
write_global(WriteData * wd,int fileflags,Main * mainvar)2147 static void write_global(WriteData *wd, int fileflags, Main *mainvar)
2148 {
2149 const bool is_undo = wd->use_memfile;
2150 FileGlobal fg;
2151 bScreen *screen;
2152 Scene *scene;
2153 ViewLayer *view_layer;
2154 char subvstr[8];
2155
2156 /* prevent mem checkers from complaining */
2157 memset(fg._pad, 0, sizeof(fg._pad));
2158 memset(fg.filename, 0, sizeof(fg.filename));
2159 memset(fg.build_hash, 0, sizeof(fg.build_hash));
2160 fg._pad1 = NULL;
2161
2162 current_screen_compat(mainvar, is_undo, &screen, &scene, &view_layer);
2163
2164 /* XXX still remap G */
2165 fg.curscreen = screen;
2166 fg.curscene = scene;
2167 fg.cur_view_layer = view_layer;
2168
2169 /* prevent to save this, is not good convention, and feature with concerns... */
2170 fg.fileflags = (fileflags & ~G_FILE_FLAG_ALL_RUNTIME);
2171
2172 fg.globalf = G.f;
2173 BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
2174 sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION);
2175 memcpy(fg.subvstr, subvstr, 4);
2176
2177 fg.subversion = BLENDER_FILE_SUBVERSION;
2178 fg.minversion = BLENDER_FILE_MIN_VERSION;
2179 fg.minsubversion = BLENDER_FILE_MIN_SUBVERSION;
2180 #ifdef WITH_BUILDINFO
2181 {
2182 extern unsigned long build_commit_timestamp;
2183 extern char build_hash[];
2184 /* TODO(sergey): Add branch name to file as well? */
2185 fg.build_commit_timestamp = build_commit_timestamp;
2186 BLI_strncpy(fg.build_hash, build_hash, sizeof(fg.build_hash));
2187 }
2188 #else
2189 fg.build_commit_timestamp = 0;
2190 BLI_strncpy(fg.build_hash, "unknown", sizeof(fg.build_hash));
2191 #endif
2192 writestruct(wd, GLOB, FileGlobal, 1, &fg);
2193 }
2194
2195 /* preview image, first 2 values are width and height
2196 * second are an RGBA image (uchar)
2197 * note, this uses 'TEST' since new types will segfault on file load for older blender versions.
2198 */
write_thumb(WriteData * wd,const BlendThumbnail * thumb)2199 static void write_thumb(WriteData *wd, const BlendThumbnail *thumb)
2200 {
2201 if (thumb) {
2202 writedata(wd, TEST, BLEN_THUMB_MEMSIZE_FILE(thumb->width, thumb->height), thumb);
2203 }
2204 }
2205
2206 /** \} */
2207
2208 /* -------------------------------------------------------------------- */
2209 /** \name File Writing (Private)
2210 * \{ */
2211
2212 /* if MemFile * there's filesave to memory */
write_file_handle(Main * mainvar,WriteWrap * ww,MemFile * compare,MemFile * current,int write_flags,bool use_userdef,const BlendThumbnail * thumb)2213 static bool write_file_handle(Main *mainvar,
2214 WriteWrap *ww,
2215 MemFile *compare,
2216 MemFile *current,
2217 int write_flags,
2218 bool use_userdef,
2219 const BlendThumbnail *thumb)
2220 {
2221 BHead bhead;
2222 ListBase mainlist;
2223 char buf[16];
2224 WriteData *wd;
2225
2226 blo_split_main(&mainlist, mainvar);
2227
2228 wd = mywrite_begin(ww, compare, current);
2229 BlendWriter writer = {wd};
2230
2231 sprintf(buf,
2232 "BLENDER%c%c%.3d",
2233 (sizeof(void *) == 8) ? '-' : '_',
2234 (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v',
2235 BLENDER_FILE_VERSION);
2236
2237 mywrite(wd, buf, 12);
2238
2239 write_renderinfo(wd, mainvar);
2240 write_thumb(wd, thumb);
2241 write_global(wd, write_flags, mainvar);
2242
2243 /* The windowmanager and screen often change,
2244 * avoid thumbnail detecting changes because of this. */
2245 mywrite_flush(wd);
2246
2247 OverrideLibraryStorage *override_storage = wd->use_memfile ?
2248 NULL :
2249 BKE_lib_override_library_operations_store_init();
2250
2251 #define ID_BUFFER_STATIC_SIZE 8192
2252 /* This outer loop allows to save first data-blocks from real mainvar,
2253 * then the temp ones from override process,
2254 * if needed, without duplicating whole code. */
2255 Main *bmain = mainvar;
2256 do {
2257 ListBase *lbarray[MAX_LIBARRAY];
2258 int a = set_listbasepointers(bmain, lbarray);
2259 while (a--) {
2260 ID *id = lbarray[a]->first;
2261
2262 if (id == NULL || GS(id->name) == ID_LI) {
2263 continue; /* Libraries are handled separately below. */
2264 }
2265
2266 char id_buffer_static[ID_BUFFER_STATIC_SIZE];
2267 void *id_buffer = id_buffer_static;
2268 const size_t idtype_struct_size = BKE_idtype_get_info_from_id(id)->struct_size;
2269 if (idtype_struct_size > ID_BUFFER_STATIC_SIZE) {
2270 BLI_assert(0);
2271 id_buffer = MEM_mallocN(idtype_struct_size, __func__);
2272 }
2273
2274 for (; id; id = id->next) {
2275 /* We should never attempt to write non-regular IDs
2276 * (i.e. all kind of temp/runtime ones). */
2277 BLI_assert(
2278 (id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0);
2279
2280 const bool do_override = !ELEM(override_storage, NULL, bmain) &&
2281 ID_IS_OVERRIDE_LIBRARY_REAL(id);
2282
2283 if (do_override) {
2284 BKE_lib_override_library_operations_store_start(bmain, override_storage, id);
2285 }
2286
2287 if (wd->use_memfile) {
2288 /* Record the changes that happened up to this undo push in
2289 * recalc_up_to_undo_push, and clear recalc_after_undo_push again
2290 * to start accumulating for the next undo push. */
2291 id->recalc_up_to_undo_push = id->recalc_after_undo_push;
2292 id->recalc_after_undo_push = 0;
2293
2294 bNodeTree *nodetree = ntreeFromID(id);
2295 if (nodetree != NULL) {
2296 nodetree->id.recalc_up_to_undo_push = nodetree->id.recalc_after_undo_push;
2297 nodetree->id.recalc_after_undo_push = 0;
2298 }
2299 if (GS(id->name) == ID_SCE) {
2300 Scene *scene = (Scene *)id;
2301 if (scene->master_collection != NULL) {
2302 scene->master_collection->id.recalc_up_to_undo_push =
2303 scene->master_collection->id.recalc_after_undo_push;
2304 scene->master_collection->id.recalc_after_undo_push = 0;
2305 }
2306 }
2307 }
2308
2309 mywrite_id_begin(wd, id);
2310
2311 memcpy(id_buffer, id, idtype_struct_size);
2312
2313 ((ID *)id_buffer)->tag = 0;
2314 /* Those listbase data change every time we add/remove an ID, and also often when
2315 * renaming one (due to re-sorting). This avoids generating a lot of false 'is changed'
2316 * detections between undo steps. */
2317 ((ID *)id_buffer)->prev = NULL;
2318 ((ID *)id_buffer)->next = NULL;
2319
2320 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2321 if (id_type->blend_write != NULL) {
2322 id_type->blend_write(&writer, (ID *)id_buffer, id);
2323 }
2324
2325 switch ((ID_Type)GS(id->name)) {
2326 case ID_WM:
2327 write_windowmanager(&writer, (wmWindowManager *)id_buffer, id);
2328 break;
2329 case ID_WS:
2330 write_workspace(&writer, (WorkSpace *)id_buffer, id);
2331 break;
2332 case ID_SCR:
2333 write_screen(&writer, (bScreen *)id_buffer, id);
2334 break;
2335 case ID_SCE:
2336 write_scene(&writer, (Scene *)id_buffer, id);
2337 break;
2338 case ID_GR:
2339 write_collection(&writer, (Collection *)id_buffer, id);
2340 break;
2341 case ID_OB:
2342 write_object(&writer, (Object *)id_buffer, id);
2343 break;
2344 case ID_PA:
2345 write_particlesettings(&writer, (ParticleSettings *)id_buffer, id);
2346 break;
2347 case ID_ME:
2348 case ID_LT:
2349 case ID_AC:
2350 case ID_NT:
2351 case ID_LS:
2352 case ID_TXT:
2353 case ID_VF:
2354 case ID_MC:
2355 case ID_PC:
2356 case ID_PAL:
2357 case ID_BR:
2358 case ID_IM:
2359 case ID_LA:
2360 case ID_MA:
2361 case ID_MB:
2362 case ID_CU:
2363 case ID_CA:
2364 case ID_WO:
2365 case ID_MSK:
2366 case ID_SPK:
2367 case ID_AR:
2368 case ID_LP:
2369 case ID_KE:
2370 case ID_TE:
2371 case ID_GD:
2372 case ID_HA:
2373 case ID_PT:
2374 case ID_VO:
2375 case ID_SIM:
2376 case ID_SO:
2377 case ID_CF:
2378 /* Do nothing, handled in IDTypeInfo callback. */
2379 break;
2380 case ID_LI:
2381 /* Do nothing, handled below - and should never be reached. */
2382 BLI_assert(0);
2383 break;
2384 case ID_IP:
2385 /* Do nothing, deprecated. */
2386 break;
2387 default:
2388 /* Should never be reached. */
2389 BLI_assert(0);
2390 break;
2391 }
2392
2393 if (do_override) {
2394 BKE_lib_override_library_operations_store_end(override_storage, id);
2395 }
2396
2397 mywrite_id_end(wd, id);
2398 }
2399
2400 if (id_buffer != id_buffer_static) {
2401 MEM_SAFE_FREE(id_buffer);
2402 }
2403
2404 mywrite_flush(wd);
2405 }
2406 } while ((bmain != override_storage) && (bmain = override_storage));
2407
2408 if (override_storage) {
2409 BKE_lib_override_library_operations_store_finalize(override_storage);
2410 override_storage = NULL;
2411 }
2412
2413 /* Special handling, operating over split Mains... */
2414 write_libraries(wd, mainvar->next);
2415
2416 /* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
2417 mywrite_flush(wd);
2418
2419 if (use_userdef) {
2420 write_userdef(&writer, &U);
2421 }
2422
2423 /* Write DNA last, because (to be implemented) test for which structs are written.
2424 *
2425 * Note that we *borrow* the pointer to 'DNAstr',
2426 * so writing each time uses the same address and doesn't cause unnecessary undo overhead. */
2427 writedata(wd, DNA1, (size_t)wd->sdna->data_len, wd->sdna->data);
2428
2429 /* end of file */
2430 memset(&bhead, 0, sizeof(BHead));
2431 bhead.code = ENDB;
2432 mywrite(wd, &bhead, sizeof(BHead));
2433
2434 blo_join_main(&mainlist);
2435
2436 return mywrite_end(wd);
2437 }
2438
2439 /* do reverse file history: .blend1 -> .blend2, .blend -> .blend1 */
2440 /* return: success(0), failure(1) */
do_history(const char * name,ReportList * reports)2441 static bool do_history(const char *name, ReportList *reports)
2442 {
2443 char tempname1[FILE_MAX], tempname2[FILE_MAX];
2444 int hisnr = U.versions;
2445
2446 if (U.versions == 0) {
2447 return 0;
2448 }
2449
2450 if (strlen(name) < 2) {
2451 BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short");
2452 return 1;
2453 }
2454
2455 while (hisnr > 1) {
2456 BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr - 1);
2457 if (BLI_exists(tempname1)) {
2458 BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr);
2459
2460 if (BLI_rename(tempname1, tempname2)) {
2461 BKE_report(reports, RPT_ERROR, "Unable to make version backup");
2462 return true;
2463 }
2464 }
2465 hisnr--;
2466 }
2467
2468 /* is needed when hisnr==1 */
2469 if (BLI_exists(name)) {
2470 BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr);
2471
2472 if (BLI_rename(name, tempname1)) {
2473 BKE_report(reports, RPT_ERROR, "Unable to make version backup");
2474 return true;
2475 }
2476 }
2477
2478 return 0;
2479 }
2480
2481 /** \} */
2482
2483 /* -------------------------------------------------------------------- */
2484 /** \name File Writing (Public)
2485 * \{ */
2486
2487 /**
2488 * \return Success.
2489 */
BLO_write_file(Main * mainvar,const char * filepath,const int write_flags,const struct BlendFileWriteParams * params,ReportList * reports)2490 bool BLO_write_file(Main *mainvar,
2491 const char *filepath,
2492 const int write_flags,
2493 const struct BlendFileWriteParams *params,
2494 ReportList *reports)
2495 {
2496 char tempname[FILE_MAX + 1];
2497 eWriteWrapType ww_type;
2498 WriteWrap ww;
2499
2500 eBLO_WritePathRemap remap_mode = params->remap_mode;
2501 const bool use_save_versions = params->use_save_versions;
2502 const bool use_save_as_copy = params->use_save_as_copy;
2503 const bool use_userdef = params->use_userdef;
2504 const BlendThumbnail *thumb = params->thumb;
2505
2506 /* path backup/restore */
2507 void *path_list_backup = NULL;
2508 const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
2509
2510 if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
2511 BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk");
2512 BLO_main_validate_libraries(mainvar, reports);
2513 BLO_main_validate_shapekeys(mainvar, reports);
2514 }
2515
2516 /* open temporary file, so we preserve the original in case we crash */
2517 BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath);
2518
2519 if (write_flags & G_FILE_COMPRESS) {
2520 ww_type = WW_WRAP_ZLIB;
2521 }
2522 else {
2523 ww_type = WW_WRAP_NONE;
2524 }
2525
2526 ww_handle_init(ww_type, &ww);
2527
2528 if (ww.open(&ww, tempname) == false) {
2529 BKE_reportf(
2530 reports, RPT_ERROR, "Cannot open file %s for writing: %s", tempname, strerror(errno));
2531 return 0;
2532 }
2533
2534 /* Remapping of relative paths to new file location. */
2535 if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
2536
2537 if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
2538 /* Make all relative as none of the existing paths can be relative in an unsaved document.
2539 */
2540 if (G.relbase_valid == false) {
2541 remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE_ALL;
2542 }
2543 }
2544
2545 char dir_src[FILE_MAX];
2546 char dir_dst[FILE_MAX];
2547 BLI_split_dir_part(mainvar->name, dir_src, sizeof(dir_src));
2548 BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
2549
2550 /* Just in case there is some subtle difference. */
2551 BLI_path_normalize(mainvar->name, dir_dst);
2552 BLI_path_normalize(mainvar->name, dir_src);
2553
2554 /* Only for relative, not relative-all, as this means making existing paths relative. */
2555 if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
2556 if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
2557 /* Saved to same path. Nothing to do. */
2558 remap_mode = BLO_WRITE_PATH_REMAP_NONE;
2559 }
2560 }
2561 else if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
2562 if (G.relbase_valid == false) {
2563 /* Unsaved, all paths are absolute.Even if the user manages to set a relative path,
2564 * there is no base-path that can be used to make it absolute. */
2565 remap_mode = BLO_WRITE_PATH_REMAP_NONE;
2566 }
2567 }
2568
2569 if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
2570 /* Check if we need to backup and restore paths. */
2571 if (UNLIKELY(use_save_as_copy)) {
2572 path_list_backup = BKE_bpath_list_backup(mainvar, path_list_flag);
2573 }
2574
2575 switch (remap_mode) {
2576 case BLO_WRITE_PATH_REMAP_RELATIVE:
2577 /* Saved, make relative paths relative to new location (if possible). */
2578 BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL);
2579 break;
2580 case BLO_WRITE_PATH_REMAP_RELATIVE_ALL:
2581 /* Make all relative (when requested or unsaved). */
2582 BKE_bpath_relative_convert(mainvar, dir_dst, NULL);
2583 break;
2584 case BLO_WRITE_PATH_REMAP_ABSOLUTE:
2585 /* Make all absolute (when requested or unsaved). */
2586 BKE_bpath_absolute_convert(mainvar, dir_src, NULL);
2587 break;
2588 case BLO_WRITE_PATH_REMAP_NONE:
2589 BLI_assert(0); /* Unreachable. */
2590 break;
2591 }
2592 }
2593 }
2594
2595 /* actual file writing */
2596 const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, use_userdef, thumb);
2597
2598 ww.close(&ww);
2599
2600 if (UNLIKELY(path_list_backup)) {
2601 BKE_bpath_list_restore(mainvar, path_list_flag, path_list_backup);
2602 BKE_bpath_list_free(path_list_backup);
2603 }
2604
2605 if (err) {
2606 BKE_report(reports, RPT_ERROR, strerror(errno));
2607 remove(tempname);
2608
2609 return 0;
2610 }
2611
2612 /* file save to temporary file was successful */
2613 /* now do reverse file history (move .blend1 -> .blend2, .blend -> .blend1) */
2614 if (use_save_versions) {
2615 const bool err_hist = do_history(filepath, reports);
2616 if (err_hist) {
2617 BKE_report(reports, RPT_ERROR, "Version backup failed (file saved with @)");
2618 return 0;
2619 }
2620 }
2621
2622 if (BLI_rename(tempname, filepath) != 0) {
2623 BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)");
2624 return 0;
2625 }
2626
2627 if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
2628 BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* save to disk");
2629 BLO_main_validate_libraries(mainvar, reports);
2630 }
2631
2632 return 1;
2633 }
2634
2635 /**
2636 * \return Success.
2637 */
BLO_write_file_mem(Main * mainvar,MemFile * compare,MemFile * current,int write_flags)2638 bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
2639 {
2640 bool use_userdef = false;
2641
2642 const bool err = write_file_handle(
2643 mainvar, NULL, compare, current, write_flags, use_userdef, NULL);
2644
2645 return (err == 0);
2646 }
2647
BLO_write_raw(BlendWriter * writer,size_t size_in_bytes,const void * data_ptr)2648 void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr)
2649 {
2650 writedata(writer->wd, DATA, size_in_bytes, data_ptr);
2651 }
2652
BLO_write_struct_by_name(BlendWriter * writer,const char * struct_name,const void * data_ptr)2653 void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
2654 {
2655 BLO_write_struct_array_by_name(writer, struct_name, 1, data_ptr);
2656 }
2657
BLO_write_struct_array_by_name(BlendWriter * writer,const char * struct_name,int array_size,const void * data_ptr)2658 void BLO_write_struct_array_by_name(BlendWriter *writer,
2659 const char *struct_name,
2660 int array_size,
2661 const void *data_ptr)
2662 {
2663 int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
2664 if (UNLIKELY(struct_id == -1)) {
2665 printf("error: can't find SDNA code <%s>\n", struct_name);
2666 return;
2667 }
2668 BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr);
2669 }
2670
BLO_write_struct_by_id(BlendWriter * writer,int struct_id,const void * data_ptr)2671 void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr)
2672 {
2673 writestruct_nr(writer->wd, DATA, struct_id, 1, data_ptr);
2674 }
2675
BLO_write_struct_at_address_by_id(BlendWriter * writer,int struct_id,const void * address,const void * data_ptr)2676 void BLO_write_struct_at_address_by_id(BlendWriter *writer,
2677 int struct_id,
2678 const void *address,
2679 const void *data_ptr)
2680 {
2681 writestruct_at_address_nr(writer->wd, DATA, struct_id, 1, address, data_ptr);
2682 }
2683
BLO_write_struct_array_by_id(BlendWriter * writer,int struct_id,int array_size,const void * data_ptr)2684 void BLO_write_struct_array_by_id(BlendWriter *writer,
2685 int struct_id,
2686 int array_size,
2687 const void *data_ptr)
2688 {
2689 writestruct_nr(writer->wd, DATA, struct_id, array_size, data_ptr);
2690 }
2691
BLO_write_struct_array_at_address_by_id(BlendWriter * writer,int struct_id,int array_size,const void * address,const void * data_ptr)2692 void BLO_write_struct_array_at_address_by_id(
2693 BlendWriter *writer, int struct_id, int array_size, const void *address, const void *data_ptr)
2694 {
2695 writestruct_at_address_nr(writer->wd, DATA, struct_id, array_size, address, data_ptr);
2696 }
2697
BLO_write_struct_list_by_id(BlendWriter * writer,int struct_id,ListBase * list)2698 void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, ListBase *list)
2699 {
2700 writelist_nr(writer->wd, DATA, struct_id, list);
2701 }
2702
BLO_write_struct_list_by_name(BlendWriter * writer,const char * struct_name,ListBase * list)2703 void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name, ListBase *list)
2704 {
2705 int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
2706 if (UNLIKELY(struct_id == -1)) {
2707 printf("error: can't find SDNA code <%s>\n", struct_name);
2708 return;
2709 }
2710 BLO_write_struct_list_by_id(writer, struct_id, list);
2711 }
2712
blo_write_id_struct(BlendWriter * writer,int struct_id,const void * id_address,const ID * id)2713 void blo_write_id_struct(BlendWriter *writer, int struct_id, const void *id_address, const ID *id)
2714 {
2715 writestruct_at_address_nr(writer->wd, GS(id->name), struct_id, 1, id_address, id);
2716 }
2717
BLO_get_struct_id_by_name(BlendWriter * writer,const char * struct_name)2718 int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name)
2719 {
2720 int struct_id = DNA_struct_find_nr(writer->wd->sdna, struct_name);
2721 return struct_id;
2722 }
2723
BLO_write_int32_array(BlendWriter * writer,uint num,const int32_t * data_ptr)2724 void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr)
2725 {
2726 BLO_write_raw(writer, sizeof(int32_t) * (size_t)num, data_ptr);
2727 }
2728
BLO_write_uint32_array(BlendWriter * writer,uint num,const uint32_t * data_ptr)2729 void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr)
2730 {
2731 BLO_write_raw(writer, sizeof(uint32_t) * (size_t)num, data_ptr);
2732 }
2733
BLO_write_float_array(BlendWriter * writer,uint num,const float * data_ptr)2734 void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
2735 {
2736 BLO_write_raw(writer, sizeof(float) * (size_t)num, data_ptr);
2737 }
2738
BLO_write_pointer_array(BlendWriter * writer,uint num,const void * data_ptr)2739 void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
2740 {
2741 BLO_write_raw(writer, sizeof(void *) * (size_t)num, data_ptr);
2742 }
2743
BLO_write_float3_array(BlendWriter * writer,uint num,const float * data_ptr)2744 void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr)
2745 {
2746 BLO_write_raw(writer, sizeof(float[3]) * (size_t)num, data_ptr);
2747 }
2748
2749 /**
2750 * Write a null terminated string.
2751 */
BLO_write_string(BlendWriter * writer,const char * data_ptr)2752 void BLO_write_string(BlendWriter *writer, const char *data_ptr)
2753 {
2754 if (data_ptr != NULL) {
2755 BLO_write_raw(writer, strlen(data_ptr) + 1, data_ptr);
2756 }
2757 }
2758
2759 /**
2760 * Sometimes different data is written depending on whether the file is saved to disk or used for
2761 * undo. This function returns true when the current file-writing is done for undo.
2762 */
BLO_write_is_undo(BlendWriter * writer)2763 bool BLO_write_is_undo(BlendWriter *writer)
2764 {
2765 return writer->wd->use_memfile;
2766 }
2767
2768 /** \} */
2769