1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /* Grafx2 - The Ultimate 256-color bitmap paint program
4
5 Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6
7 Grafx2 is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2
10 of the License.
11
12 Grafx2 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 //////////////////////////////////////////////////////////////////////////
21 /////////////////////////// GESTION DU BACKUP ////////////////////////////
22 //////////////////////////////////////////////////////////////////////////
23
24 #include <stddef.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #ifdef _MSC_VER
28 #define strdup _strdup
29 #endif
30
31 #include "gfx2mem.h"
32 #include "global.h"
33 #include "pages.h"
34 #include "errors.h"
35 #include "loadsave.h"
36 #include "misc.h"
37 #include "windows.h"
38 #include "tiles.h"
39 #include "graph.h"
40 #include "layers.h"
41 #include "unicode.h"
42
43 // -- Layers data
44
45 /// Array of two images, that contains the "flattened" version of the visible layers.
46 //T_Bitmap Main_visible_image;
47 T_Bitmap Main_visible_image_backup;
48 T_Bitmap Main_visible_image_depth_buffer;
49 //T_Bitmap Spare_visible_image;
50
51 ///
52 /// GESTION DES PAGES
53 ///
54
55 /// Bitfield which records which layers are backed up in Page 0.
56 static dword Last_backed_up_layers=0;
57
58 /// Total number of unique bitmaps (layers, animation frames, backups)
59 long Stats_pages_number=0;
60 /// Total memory used by bitmaps (layers, animation frames, backups)
61 long long Stats_pages_memory=0;
62
63 /// Allocate and initialize a new page.
New_page(int nb_layers)64 T_Page * New_page(int nb_layers)
65 {
66 T_Page * page;
67
68 page = (T_Page *)GFX2_malloc(sizeof(T_Page)+nb_layers*sizeof(T_Image));
69 if (page!=NULL)
70 {
71 int i;
72 for (i=0; i<nb_layers; i++)
73 {
74 page->Image[i].Pixels = NULL;
75 page->Image[i].Duration = 100;
76 }
77 page->Width=0;
78 page->Height=0;
79 page->Image_mode = IMAGE_MODE_LAYERED;
80 memset(page->Palette, 0, sizeof(T_Palette));
81 page->Comment[0] = '\0';
82 page->File_directory = NULL;
83 page->Filename = NULL;
84 page->Filename_unicode = NULL;
85 page->File_format = DEFAULT_FILEFORMAT;
86 page->Nb_layers = nb_layers;
87 page->Gradients = NULL;
88 page->Transparent_color = 0; // Default transparent color
89 page->Background_transparent = 0;
90 page->Next = page->Prev = NULL;
91 }
92 return page;
93 }
94
95 // ==============================================================
96 // Layers allocation functions.
97 //
98 // Layers are made of a "number of users" (short), followed by
99 // the actual pixel data (a large number of bytes).
100 // Every time a layer is 'duplicated' as a reference, the number
101 // of users is incremented.
102 // Every time a layer is freed, the number of users is decreased,
103 // and only when it reaches zero the pixel data is freed.
104 // ==============================================================
105
106 /// Allocate a new layer
New_layer(long pixel_size)107 byte * New_layer(long pixel_size)
108 {
109 short * ptr = GFX2_malloc(sizeof(short)+pixel_size);
110 if (ptr==NULL)
111 return NULL;
112
113 // Stats
114 Stats_pages_number++;
115 Stats_pages_memory+=pixel_size;
116
117 *ptr = 1;
118 return (byte *)(ptr+1);
119 }
120
121 /// Free a layer
Free_layer(T_Page * page,int layer)122 void Free_layer(T_Page * page, int layer)
123 {
124 short * ptr;
125 if (page->Image[layer].Pixels==NULL)
126 return;
127
128 ptr = (short *)(page->Image[layer].Pixels);
129 if (-- (*(ptr-1))) // Users--
130 return;
131 else {
132 free(ptr-1);
133 }
134
135 // Stats
136 Stats_pages_number--;
137 Stats_pages_memory-=page->Width * page->Height;
138 }
139
140 /// Duplicate a layer (new reference)
Dup_layer(byte * layer)141 byte * Dup_layer(byte * layer)
142 {
143 short * ptr = (short *)(layer);
144
145 if (layer==NULL)
146 return NULL;
147
148 (*(ptr-1)) ++; // Users ++
149 return layer;
150 }
151
152 // ==============================================================
153
154 /// Adds a shared reference to the gradient data of another page. Pass NULL for new.
Dup_gradient(T_Page * page)155 T_Gradient_array *Dup_gradient(T_Page * page)
156 {
157 // new
158 if (page==NULL || page->Gradients==NULL)
159 {
160 T_Gradient_array *array;
161 array=(T_Gradient_array *)calloc(1, sizeof(T_Gradient_array));
162 if (!array)
163 return NULL;
164 array->Used=1;
165 return array;
166 }
167 // shared
168 page->Gradients->Used++;
169 return page->Gradients;
170 }
171
Download_infos_page_main(T_Page * page)172 void Download_infos_page_main(T_Page * page)
173 // Affiche la page à l'écran
174 {
175 //int factor_index;
176 int size_is_modified;
177
178 if (page!=NULL)
179 {
180 size_is_modified=(Main.image_width!=page->Width) ||
181 (Main.image_height!=page->Height);
182
183 Main.image_width=page->Width;
184 Main.image_height=page->Height;
185 memcpy(Main.palette,page->Palette,sizeof(T_Palette));
186 Main.fileformat=page->File_format;
187
188 if (size_is_modified)
189 {
190 Main.magnifier_mode=0;
191 Main.offset_X=0;
192 Main.offset_Y=0;
193 Pixel_preview=Pixel_preview_normal;
194 Compute_limits();
195 Compute_paintbrush_coordinates();
196 }
197
198 }
199 //Update_buffers( page->Width, page->Height);
200 //memcpy(Main_screen, page->Image[Main.current_layer].Pixels, page->Width*page->Height);
201
202 }
203
Redraw_layered_image(void)204 void Redraw_layered_image(void)
205 {
206 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
207 {
208 // Re-construct the image with the visible layers
209 byte layer=0;
210 // First layer
211 if ((Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5
212 || Main.backups->Pages->Image_mode == IMAGE_MODE_RASTER) && Main.layers_visible & (1<<4))
213 {
214 // The raster result layer is visible: start there
215 // Copy it in Main_visible_image
216 int i;
217 for (i=0; i< Main.image_width*Main.image_height; i++)
218 {
219 layer = *(Main.backups->Pages->Image[4].Pixels+i);
220 if (Main.layers_visible & (1 << layer))
221 Main.visible_image.Image[i]=*(Main.backups->Pages->Image[layer].Pixels+i);
222 else
223 Main.visible_image.Image[i] = layer;
224 }
225
226 // Copy it to the depth buffer
227 memcpy(Main_visible_image_depth_buffer.Image,
228 Main.backups->Pages->Image[4].Pixels,
229 Main.image_width*Main.image_height);
230
231 // Next
232 layer= (1<<4)+1;
233 }
234 else
235 {
236 for (layer=0; layer<Main.backups->Pages->Nb_layers; layer++)
237 {
238 if ((1<<layer) & Main.layers_visible)
239 {
240 // Copy it in Main_visible_image
241 memcpy(Main.visible_image.Image,
242 Main.backups->Pages->Image[layer].Pixels,
243 Main.image_width*Main.image_height);
244
245 // Initialize the depth buffer
246 memset(Main_visible_image_depth_buffer.Image,
247 layer,
248 Main.image_width*Main.image_height);
249
250 // skip all other layers
251 layer++;
252 break;
253 }
254 }
255 }
256 // subsequent layer(s)
257 for (; layer<Main.backups->Pages->Nb_layers; layer++)
258 {
259 if ((1<<layer) & Main.layers_visible)
260 {
261 int i;
262 for (i=0; i<Main.image_width*Main.image_height; i++)
263 {
264 byte color = *(Main.backups->Pages->Image[layer].Pixels+i);
265 if (color != Main.backups->Pages->Transparent_color) // transparent color
266 {
267 *(Main.visible_image.Image+i) = color;
268 if (layer != Main.current_layer)
269 *(Main_visible_image_depth_buffer.Image+i) = layer;
270 }
271 }
272 }
273 }
274 }
275 else
276 {
277 Update_screen_targets();
278 }
279 Update_FX_feedback(Config.FX_Feedback);
280 }
281
Update_depth_buffer(void)282 void Update_depth_buffer(void)
283 {
284 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
285 {
286 // Re-construct the depth buffer with the visible layers.
287 // This function doesn't touch the visible buffer, it assumes
288 // that it was already up-to-date. (Ex. user only changed active layer)
289
290 int layer;
291 // First layer
292 for (layer=0; layer<Main.backups->Pages->Nb_layers; layer++)
293 {
294 if ((1<<layer) & Main.layers_visible)
295 {
296 // Initialize the depth buffer
297 memset(Main_visible_image_depth_buffer.Image,
298 layer,
299 Main.image_width*Main.image_height);
300
301 // skip all other layers
302 layer++;
303 break;
304 }
305 }
306 // subsequent layer(s)
307 for (; layer<Main.backups->Pages->Nb_layers; layer++)
308 {
309 // skip the current layer, whenever we reach it
310 if (layer == Main.current_layer)
311 continue;
312
313 if ((1<<layer) & Main.layers_visible)
314 {
315 int i;
316 for (i=0; i<Main.image_width*Main.image_height; i++)
317 {
318 byte color = *(Main.backups->Pages->Image[layer].Pixels+i);
319 if (color != Main.backups->Pages->Transparent_color) // transparent color
320 {
321 *(Main_visible_image_depth_buffer.Image+i) = layer;
322 }
323 }
324 }
325 }
326 }
327 Update_FX_feedback(Config.FX_Feedback);
328 }
329
Redraw_spare_image(void)330 void Redraw_spare_image(void)
331 {
332 if (Spare.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
333 {
334 // Re-construct the image with the visible layers
335 byte layer;
336 // First layer
337 for (layer=0; layer<Spare.backups->Pages->Nb_layers; layer++)
338 {
339 if ((1<<layer) & Spare.layers_visible)
340 {
341 // Copy it in Spare_visible_image
342 memcpy(Spare.visible_image.Image,
343 Spare.backups->Pages->Image[layer].Pixels,
344 Spare.image_width*Spare.image_height);
345
346 // No depth buffer in the spare
347 //memset(Spare_visible_image_depth_buffer.Image,
348 // layer,
349 // Spare.image_width*Spare.image_height);
350
351 // skip all other layers
352 layer++;
353 break;
354 }
355 }
356 // subsequent layer(s)
357 for (; layer<Spare.backups->Pages->Nb_layers; layer++)
358 {
359 if ((1<<layer) & Spare.layers_visible)
360 {
361 int i;
362 for (i=0; i<Spare.image_width*Spare.image_height; i++)
363 {
364 byte color = *(Spare.backups->Pages->Image[layer].Pixels+i);
365 if (color != Spare.backups->Pages->Transparent_color) // transparent color
366 {
367 *(Spare.visible_image.Image+i) = color;
368 //if (layer != Spare.current_layer)
369 // *(Spare_visible_image_depth_buffer.Image+i) = layer;
370 }
371 }
372 }
373 }
374 }
375 }
376
Redraw_current_layer(void)377 void Redraw_current_layer(void)
378 {
379 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
380 {
381 int i;
382 for (i=0; i<Main.image_width*Main.image_height; i++)
383 {
384 byte depth = *(Main_visible_image_depth_buffer.Image+i);
385 if (depth<=Main.current_layer)
386 {
387 byte color = *(Main.backups->Pages->Image[Main.current_layer].Pixels+i);
388 if (color != Main.backups->Pages->Transparent_color) // transparent color
389 {
390 *(Main.visible_image.Image+i) = color;
391 }
392 else
393 {
394 *(Main.visible_image.Image+i) = *(Main.backups->Pages->Image[depth].Pixels+i);
395 }
396 }
397 }
398 }
399 }
400
Upload_infos_page(T_Document * doc)401 void Upload_infos_page(T_Document * doc)
402 // Sauve l'écran courant dans la page
403 {
404 if (doc->backups->Pages != NULL)
405 {
406 doc->backups->Pages->Width = doc->image_width;
407 doc->backups->Pages->Height = doc->image_height;
408 memcpy(doc->backups->Pages->Palette, doc->palette, sizeof(T_Palette));
409 doc->backups->Pages->File_format = doc->fileformat;
410 }
411 }
412
Download_infos_page_spare(T_Page * page)413 void Download_infos_page_spare(T_Page * page)
414 {
415 if (page!=NULL)
416 {
417 Spare.image_width=page->Width;
418 Spare.image_height=page->Height;
419 memcpy(Spare.palette,page->Palette,sizeof(T_Palette));
420 Spare.fileformat=page->File_format;
421 }
422 }
423
424 byte * FX_feedback_screen;
425
Update_FX_feedback(byte with_feedback)426 void Update_FX_feedback(byte with_feedback)
427 {
428
429 if (with_feedback)
430 FX_feedback_screen=Main.backups->Pages->Image[Main.current_layer].Pixels;
431 else
432 FX_feedback_screen=Main.backups->Pages->Next->Image[Main.current_layer].Pixels;
433 }
434
Clear_page(T_Page * page)435 void Clear_page(T_Page * page)
436 {
437 // On peut appeler cette fonction sur une page non allouée.
438 int i;
439 for (i=0; i<page->Nb_layers; i++)
440 {
441 Free_layer(page, i);
442 page->Image[i].Pixels=NULL;
443 page->Image[i].Duration=0;
444 }
445
446 // Free_gradient() : This data is reference-counted
447 if (page->Gradients)
448 {
449 page->Gradients->Used--;
450 if (page->Gradients->Used==0)
451 free(page->Gradients);
452 page->Gradients=NULL;
453 }
454
455 page->Width=0;
456 page->Height=0;
457 // On ne se préoccupe pas de ce que deviens le reste des infos de l'image.
458 }
459
Copy_S_page(T_Page * dest,T_Page * source)460 void Copy_S_page(T_Page * dest, T_Page * source)
461 {
462 *dest = *source;
463 dest->Gradients = Dup_gradient(source);
464 if (source->File_directory != NULL)
465 dest->File_directory = strdup(source->File_directory);
466 if (source->Filename != NULL)
467 dest->Filename = strdup(source->Filename);
468 if (source->Filename_unicode != NULL)
469 dest->Filename_unicode = Unicode_strdup(source->Filename_unicode);
470 }
471
472
473 ///
474 /// GESTION DES LISTES DE PAGES
475 ///
476
Init_list_of_pages(T_List_of_pages * list)477 void Init_list_of_pages(T_List_of_pages * list)
478 {
479 // Important: appeler cette fonction sur toute nouvelle structure
480 // T_List_of_pages!
481
482 list->List_size=0;
483 list->Pages=NULL;
484 }
485
Allocate_list_of_pages(T_List_of_pages * list)486 int Allocate_list_of_pages(T_List_of_pages * list)
487 {
488 // Important: la T_List_of_pages ne doit pas déjà désigner une liste de
489 // pages allouée auquel cas celle-ci serait perdue.
490 T_Page * page;
491
492 // On initialise chacune des nouvelles pages
493 page=New_page(1);
494 if (!page)
495 return 0;
496
497 // Set as first page of the list
498 page->Next = page;
499 page->Prev = page;
500 list->Pages = page;
501
502 list->List_size=1;
503
504 page->Gradients = Dup_gradient(NULL);
505 if (!page->Gradients)
506 return 0;
507
508 return 1; // Succès
509 }
510
511
Backward_in_list_of_pages(T_List_of_pages * list)512 void Backward_in_list_of_pages(T_List_of_pages * list)
513 {
514 // Cette fonction fait l'équivalent d'un "Undo" dans la liste de pages.
515 // Elle effectue une sorte de ROL (Rotation Left) sur la liste:
516 // +---+-+-+-+-+-+-+-+-+-+ |
517 // ¦0¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦ |
518 // +---+-+-+-+-+-+-+-+-+-+ | 0=page courante
519 // ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ |_ A=page la plus ancienne
520 // v v v v v v v v v v v | 1=DerniÞre page (1er backup)
521 // +---+-+-+-+-+-+-+-+-+-+ |
522 // ¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦0¦ |
523 // +---+-+-+-+-+-+-+-+-+-+ |
524
525 // Pour simuler un véritable Undo, l'appelant doit mettre la structure
526 // de page courante à jour avant l'appel, puis en réextraire les infos en
527 // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère
528 // page de la liste).
529
530 if (Last_backed_up_layers)
531 {
532 // First page contains a ready-made backup of its ->Next.
533 // We have swap the first two pages, so the original page 0
534 // will end up in position 0 again, and then overwrite it with a backup
535 // of the 'new' page1.
536 T_Page * page0;
537 T_Page * page1;
538
539 page0 = list->Pages;
540 page1 = list->Pages->Next;
541
542 page0->Next = page1->Next;
543 page1->Prev = page0->Prev;
544 page0->Prev = page1;
545 page1->Next = page0;
546 list->Pages = page0;
547 return;
548 }
549 list->Pages = list->Pages->Next;
550 }
551
Advance_in_list_of_pages(T_List_of_pages * list)552 void Advance_in_list_of_pages(T_List_of_pages * list)
553 {
554 // Cette fonction fait l'équivalent d'un "Redo" dans la liste de pages.
555 // Elle effectue une sorte de ROR (Rotation Right) sur la liste:
556 // +-+-+-+-+-+-+-+-+-+-+-+ |
557 // |0|1|2|3|4|5|6|7|8|9|A| |
558 // +-+-+-+-+-+-+-+-+-+-+-+ | 0=page courante
559 // | | | | | | | | | | | |_ A=page la plus ancienne
560 // v v v v v v v v v v v | 1=Dernière page (1er backup)
561 // +-+-+-+-+-+-+-+-+-+-+-+ |
562 // |A|0|1|2|3|4|5|6|7|8|9| |
563 // +-+-+-+-+-+-+-+-+-+-+-+ |
564
565 // Pour simuler un véritable Redo, l'appelant doit mettre la structure
566 // de page courante à jour avant l'appel, puis en réextraire les infos en
567 // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère
568 // page de la liste).
569 if (Last_backed_up_layers)
570 {
571 // First page contains a ready-made backup of its ->Next.
572 // We have swap the first two pages, so the original page 0
573 // will end up in position -1 again, and then overwrite it with a backup
574 // of the 'new' page1.
575 T_Page * page0;
576 T_Page * page1;
577
578 page0 = list->Pages;
579 page1 = list->Pages->Prev;
580
581 page0->Prev = page1->Prev;
582 page1->Next = page0->Next;
583 page0->Next = page1;
584 page1->Prev = page0;
585 list->Pages = page1;
586 return;
587 }
588 list->Pages = list->Pages->Prev;
589 }
590
Free_last_page_of_list(T_List_of_pages * list)591 void Free_last_page_of_list(T_List_of_pages * list)
592 {
593 if (list!=NULL)
594 {
595 if (list->List_size>0)
596 {
597 T_Page * page;
598 // The last page is the one before first
599 page = list->Pages->Prev;
600
601 page->Next->Prev = page->Prev;
602 page->Prev->Next = page->Next;
603 Clear_page(page);
604 free(page->File_directory);
605 free(page->Filename);
606 free(page->Filename_unicode);
607 free(page);
608 page = NULL;
609 list->List_size--;
610 }
611 }
612 }
613
614 // layer tells which layers have to be fresh copies instead of references :
615 // it's a layer number (>=0) or LAYER_NONE or LAYER_ALL
Create_new_page(T_Page * new_page,T_List_of_pages * list,int layer)616 int Create_new_page(T_Page * new_page, T_List_of_pages * list, int layer)
617 {
618
619 // This function fills the "Image" field of a new Page,
620 // based on the pages's attributes (width,height,...)
621 // then pushes it on front of a Page list.
622
623 if (list->List_size >= (Config.Max_undo_pages+1))
624 {
625 // List is full.
626 // If some other memory-limit was to be implemented, here would
627 // be the right place to do it.
628 // For example, we could rely on Stats_pages_memory,
629 // because it's the sum of all bitmaps in use (in bytes).
630
631 // Destroy the latest page
632 Free_last_page_of_list(list);
633 }
634 {
635 int i;
636 for (i=0; i<new_page->Nb_layers; i++)
637 {
638 if (layer == LAYER_ALL || i == layer)
639 new_page->Image[i].Pixels=New_layer(new_page->Height*new_page->Width);
640 else
641 new_page->Image[i].Pixels=Dup_layer(list->Pages->Image[i].Pixels);
642 new_page->Image[i].Duration=list->Pages->Image[i].Duration;
643 }
644 }
645
646
647 // Insert as first
648 new_page->Next = list->Pages;
649 new_page->Prev = list->Pages->Prev;
650 list->Pages->Prev->Next = new_page;
651 list->Pages->Prev = new_page;
652 list->Pages = new_page;
653 list->List_size++;
654
655 return 1;
656 }
657
Change_page_number_of_list(T_List_of_pages * list,int number)658 void Change_page_number_of_list(T_List_of_pages * list,int number)
659 {
660 // Truncate the list if larger than requested
661 while(list->List_size > number)
662 {
663 Free_last_page_of_list(list);
664 }
665 }
666
Free_page_of_a_list(T_List_of_pages * list)667 void Free_page_of_a_list(T_List_of_pages * list)
668 {
669 // On ne peut pas détruire la page courante de la liste si après
670 // destruction il ne reste pas encore au moins une page.
671 if (list->List_size>1)
672 {
673 // On fait faire un undo à la liste, comme ça, la nouvelle page courante
674 // est la page précédente
675 Backward_in_list_of_pages(Main.backups);
676
677 // Puis on détruit la dernière page, qui est l'ancienne page courante
678 Free_last_page_of_list(list);
679 }
680 }
681
Update_screen_targets(void)682 void Update_screen_targets(void)
683 {
684 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
685 {
686 Main_screen=Main.visible_image.Image;
687 Screen_backup=Main_visible_image_backup.Image;
688 }
689 else
690 {
691 Main_screen=Main.backups->Pages->Image[Main.current_layer].Pixels;
692 // Sometimes this function will be called in situations where the
693 // current history step and previous one don't have as many layers.
694 // I don't like the idea of letting Screen_backup NULL or dangling,
695 // so in case Screen_backup was queried, it will point to a valid
696 // readable bitmap of correct size : current image.
697 if (Main.backups->Pages->Nb_layers != Main.backups->Pages->Next->Nb_layers
698 || Main.backups->Pages->Width != Main.backups->Pages->Next->Width
699 || Main.backups->Pages->Height != Main.backups->Pages->Next->Height)
700 Screen_backup=Main_screen;
701 else
702 Screen_backup=Main.backups->Pages->Next->Image[Main.current_layer].Pixels;
703 }
704 Update_pixel_renderer();
705 }
706
707 /// Update all the special image buffers, if necessary.
Update_buffers(int width,int height)708 int Update_buffers(int width, int height)
709 {
710 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
711 {
712 // At least one dimension is different
713 if (Main.visible_image.Width*Main.visible_image.Height != width*height)
714 {
715 // Current image
716 free(Main.visible_image.Image);
717 Main.visible_image.Image = (byte *)GFX2_malloc(width * height);
718 if (Main.visible_image.Image == NULL)
719 return 0;
720 }
721 Main.visible_image.Width = width;
722 Main.visible_image.Height = height;
723
724 if (Main_visible_image_backup.Width*Main_visible_image_backup.Height != width*height)
725 {
726 // Previous image
727 free(Main_visible_image_backup.Image);
728 Main_visible_image_backup.Image = (byte *)GFX2_malloc(width * height);
729 if (Main_visible_image_backup.Image == NULL)
730 return 0;
731 }
732 Main_visible_image_backup.Width = width;
733 Main_visible_image_backup.Height = height;
734
735 if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height)
736 {
737 // Depth buffer
738 free(Main_visible_image_depth_buffer.Image);
739 Main_visible_image_depth_buffer.Image = (byte *)GFX2_malloc(width * height);
740 if (Main_visible_image_depth_buffer.Image == NULL)
741 return 0;
742 }
743 Main_visible_image_depth_buffer.Width = width;
744 Main_visible_image_depth_buffer.Height = height;
745 }
746 Update_screen_targets();
747 return 1;
748 }
749 /// Update all the special image buffers of the spare page, if necessary.
Update_spare_buffers(int width,int height)750 int Update_spare_buffers(int width, int height)
751 {
752 if (Spare.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
753 {
754 // At least one dimension is different
755 if (Spare.visible_image.Width*Spare.visible_image.Height != width*height)
756 {
757 // Current image
758 free(Spare.visible_image.Image);
759 Spare.visible_image.Image = (byte *)GFX2_malloc(width * height);
760 if (Spare.visible_image.Image == NULL)
761 return 0;
762 }
763 Spare.visible_image.Width = width;
764 Spare.visible_image.Height = height;
765
766 }
767 return 1;
768 }
769
770 ///
771 /// GESTION DES BACKUPS
772 ///
773
Init_all_backup_lists(enum IMAGE_MODES image_mode,int width,int height)774 int Init_all_backup_lists(enum IMAGE_MODES image_mode, int width, int height)
775 {
776 // width et height correspondent à la dimension des images de départ.
777 int i;
778
779 if (! Allocate_list_of_pages(Main.backups) ||
780 ! Allocate_list_of_pages(Spare.backups))
781 return 0;
782 // On a réussi à allouer deux listes de pages dont la taille correspond à
783 // celle demandée par l'utilisateur.
784
785 // On crée un descripteur de page correspondant à la page principale
786 Upload_infos_page(&Main);
787 // On y met les infos sur la dimension de démarrage
788 Main.backups->Pages->Width = width;
789 Main.backups->Pages->Height = height;
790 Main.backups->Pages->File_directory = strdup(Main.selector.Directory);
791 Main.backups->Pages->Filename = strdup("NO_NAME.GIF");
792 Main.backups->Pages->Filename_unicode = NULL;
793
794
795 for (i=0; i<Main.backups->Pages->Nb_layers; i++)
796 {
797 Main.backups->Pages->Image[i].Pixels=New_layer(width*height);
798 if (! Main.backups->Pages->Image[i].Pixels)
799 return 0;
800 memset(Main.backups->Pages->Image[i].Pixels, 0, width*height);
801 }
802 Main.visible_image.Width = 0;
803 Main.visible_image.Height = 0;
804 Main.visible_image.Image = NULL;
805 Main_visible_image_backup.Image = NULL;
806 Main_visible_image_depth_buffer.Image = NULL;
807 Main.backups->Pages->Image_mode = image_mode;
808 Spare.visible_image.Width = 0;
809 Spare.visible_image.Height = 0;
810 Spare.visible_image.Image = NULL;
811 Spare.backups->Pages->Image_mode = image_mode;
812
813 if (!Update_buffers(width, height))
814 return 0;
815 if (!Update_spare_buffers(width, height))
816 return 0;
817
818 // For speed, instead of Redraw_layered_image() we'll directly set the buffers.
819 if (Main.visible_image.Image != NULL)
820 {
821 memset(Main.visible_image.Image, 0, width*height);
822 memset(Main_visible_image_backup.Image, 0, width*height);
823 memset(Main_visible_image_depth_buffer.Image, 0, width*height);
824 }
825 if (Spare.visible_image.Image != NULL)
826 memset(Spare.visible_image.Image, 0, width*height);
827
828 Download_infos_page_main(Main.backups->Pages);
829 Update_FX_feedback(Config.FX_Feedback);
830
831 // Default values for spare page
832 Spare.backups->Pages->Width = width;
833 Spare.backups->Pages->Height = height;
834 memcpy(Spare.backups->Pages->Palette,Main.palette,sizeof(T_Palette));
835 strcpy(Spare.backups->Pages->Comment,"");
836 Spare.backups->Pages->File_directory = strdup(Main.selector.Directory);
837 Spare.backups->Pages->Filename = strdup("NO_NAME2.GIF");
838 Spare.backups->Pages->Filename_unicode = NULL;
839
840 Spare.backups->Pages->File_format=DEFAULT_FILEFORMAT;
841 // Copy this informations in the global Spare_ variables
842 Download_infos_page_spare(Spare.backups->Pages);
843
844 // Clear the initial Visible buffer
845 //memset(Main_screen,0,Main.image_width*Main.image_height);
846
847 // Spare
848 for (i=0; i<NB_LAYERS; i++)
849 {
850 Spare.backups->Pages->Image[i].Pixels=New_layer(width*height);
851 if (! Spare.backups->Pages->Image[i].Pixels)
852 return 0;
853 memset(Spare.backups->Pages->Image[i].Pixels, 0, width*height);
854
855 }
856 //memset(Spare_screen,0,Spare.image_width*Spare.image_height);
857
858 End_of_modification();
859 return 1;
860 }
861
Set_number_of_backups(int nb_backups)862 void Set_number_of_backups(int nb_backups)
863 {
864 Change_page_number_of_list(Main.backups,nb_backups+1);
865 Change_page_number_of_list(Spare.backups,nb_backups+1);
866
867 // Le +1 vient du fait que dans chaque liste, en 1ère position on retrouve
868 // les infos de la page courante sur le brouillon et la page principale.
869 // (nb_backups = Nombre de backups, sans compter les pages courantes)
870 }
871
Backup_new_image(int layers,int width,int height)872 int Backup_new_image(int layers,int width,int height)
873 {
874 // Retourne 1 si une nouvelle page est disponible et 0 sinon
875 T_Page * new_page;
876
877 // On crée un descripteur pour la nouvelle page courante
878 new_page=New_page(layers);
879 if (!new_page)
880 {
881 Error(0);
882 return 0;
883 }
884 new_page->Width=width;
885 new_page->Height=height;
886 new_page->Transparent_color=0;
887 new_page->Gradients = Dup_gradient(NULL);
888 if (!Create_new_page(new_page,Main.backups,LAYER_ALL))
889 {
890 Error(0);
891 return 0;
892 }
893
894 Update_buffers(width, height);
895 memset(Main_visible_image_depth_buffer.Image, 0, width*height);
896
897 Download_infos_page_main(Main.backups->Pages);
898
899 return 1;
900 }
901
902
Backup_with_new_dimensions(int width,int height)903 int Backup_with_new_dimensions(int width,int height)
904 {
905 // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et
906 // 0 sinon.
907
908 T_Page * new_page;
909 int i;
910
911 // On crée un descripteur pour la nouvelle page courante
912 new_page=New_page(Main.backups->Pages->Nb_layers);
913 if (!new_page)
914 {
915 Error(0);
916 return 0;
917 }
918 new_page->Width=width;
919 new_page->Height=height;
920 new_page->Transparent_color=0;
921 if (!Create_new_page(new_page,Main.backups,LAYER_ALL))
922 {
923 Error(0);
924 return 0;
925 }
926
927 // Copy data from previous history step
928 memcpy(Main.backups->Pages->Palette, Main.backups->Pages->Next->Palette, sizeof(T_Palette));
929 strcpy(Main.backups->Pages->Comment ,Main.backups->Pages->Next->Comment);
930 Main.backups->Pages->File_format = Main.backups->Pages->Next->File_format;
931 Main.backups->Pages->Filename = strdup(Main.backups->Pages->Next->Filename);
932 Main.backups->Pages->Filename_unicode = Unicode_strdup(Main.backups->Pages->Next->Filename_unicode);
933 Main.backups->Pages->File_directory = strdup(Main.backups->Pages->Next->File_directory);
934 Main.backups->Pages->Gradients = Dup_gradient(Main.backups->Pages->Next);
935 Main.backups->Pages->Background_transparent = Main.backups->Pages->Next->Background_transparent;
936 Main.backups->Pages->Transparent_color = Main.backups->Pages->Next->Transparent_color;
937 Main.backups->Pages->Image_mode = Main.backups->Pages->Next->Image_mode;
938
939 // Fill with transparent color
940 for (i=0; i<Main.backups->Pages->Nb_layers;i++)
941 {
942 memset(Main.backups->Pages->Image[i].Pixels, Main.backups->Pages->Transparent_color, width*height);
943 }
944
945 Update_buffers(width, height);
946
947 Download_infos_page_main(Main.backups->Pages);
948
949 // Same code as in End_of_modification(),
950 // Without saving a safety backup:
951 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
952 {
953 memcpy(Main_visible_image_backup.Image,
954 Main.visible_image.Image,
955 Main.image_width*Main.image_height);
956 }
957 else
958 {
959 Update_screen_targets();
960 }
961 Update_FX_feedback(Config.FX_Feedback);
962 // --
963
964 return 1;
965 }
966
967 ///
968 /// Resizes a backup step in-place (doesn't add a Undo/Redo step).
969 /// Should only be called after an actual backup, because it loses the current.
970 /// pixels. This function is meant to be used from within Lua scripts.
Backup_in_place(int width,int height)971 int Backup_in_place(int width,int height)
972 {
973 // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et
974 // 0 sinon.
975
976 int i;
977 byte ** new_layer;
978
979 // Perform all allocations first
980
981 new_layer=calloc(Main.backups->Pages->Nb_layers,sizeof(byte *));
982 if (!new_layer)
983 return 0;
984
985 for (i=0; i<Main.backups->Pages->Nb_layers; i++)
986 {
987 new_layer[i]=New_layer(height*width);
988 if (!new_layer[i])
989 {
990 // Allocation error
991 for (; i>0; i--)
992 free(new_layer[i]);
993 free(new_layer);
994 return 0;
995 }
996 }
997
998 // Now ok to proceed
999
1000 for (i=0; i<Main.backups->Pages->Nb_layers; i++)
1001 {
1002 // Replace layers
1003 Free_layer(Main.backups->Pages,i);
1004 Main.backups->Pages->Image[i].Pixels=new_layer[i];
1005
1006 // Fill with transparency
1007 memset(Main.backups->Pages->Image[i].Pixels, Main.backups->Pages->Transparent_color, width*height);
1008 }
1009
1010 Main.backups->Pages->Width=width;
1011 Main.backups->Pages->Height=height;
1012
1013 Download_infos_page_main(Main.backups->Pages);
1014
1015 // The following is part of Update_buffers()
1016 // (without changing the backup buffer)
1017 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
1018 {
1019 // At least one dimension is different
1020 if (Main.visible_image.Width*Main.visible_image.Height != width*height)
1021 {
1022 // Current image
1023 free(Main.visible_image.Image);
1024 Main.visible_image.Image = (byte *)GFX2_malloc(width * height);
1025 if (Main.visible_image.Image == NULL)
1026 return 0;
1027 }
1028 Main.visible_image.Width = width;
1029 Main.visible_image.Height = height;
1030
1031 if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height)
1032 {
1033 // Depth buffer
1034 free(Main_visible_image_depth_buffer.Image);
1035 Main_visible_image_depth_buffer.Image = (byte *)GFX2_malloc(width * height);
1036 if (Main_visible_image_depth_buffer.Image == NULL)
1037 return 0;
1038 }
1039 Main_visible_image_depth_buffer.Width = width;
1040 Main_visible_image_depth_buffer.Height = height;
1041
1042 }
1043 Update_screen_targets();
1044
1045 return 1;
1046 }
1047
Backup_and_resize_the_spare(int width,int height)1048 int Backup_and_resize_the_spare(int width,int height)
1049 {
1050 // Retourne 1 si la page de dimension souhaitee est disponible en brouillon
1051 // et 0 sinon.
1052
1053 T_Page * new_page;
1054 int return_code=0;
1055 int nb_layers;
1056
1057 nb_layers=Spare.backups->Pages->Nb_layers;
1058 // On crée un descripteur pour la nouvelle page de brouillon
1059 new_page=New_page(nb_layers);
1060 if (!new_page)
1061 {
1062 Error(0);
1063 return 0;
1064 }
1065
1066 // Fill it with a copy of the latest history
1067 Copy_S_page(new_page,Spare.backups->Pages);
1068
1069 new_page->Width=width;
1070 new_page->Height=height;
1071 if (Create_new_page(new_page,Spare.backups,LAYER_ALL))
1072 {
1073 byte i;
1074
1075 for (i=0; i<nb_layers;i++)
1076 {
1077 memset(Spare.backups->Pages->Image[i].Pixels, Spare.backups->Pages->Transparent_color, width*height);
1078 }
1079
1080 // Update_buffers(width, height); // Not for spare
1081
1082 Download_infos_page_spare(Spare.backups->Pages);
1083
1084 // Light up the 'has unsaved changes' indicator
1085 Spare.image_is_modified=1;
1086
1087 return_code=1;
1088 }
1089 return return_code;
1090 }
1091
Backup(void)1092 void Backup(void)
1093 // Sauve la page courante comme première page de backup et crée une nouvelle page
1094 // pur continuer à dessiner. Utilisé par exemple pour le fill
1095 {
1096 Backup_layers(Main.current_layer);
1097 }
1098
Backup_layers(int layer)1099 void Backup_layers(int layer)
1100 {
1101 int i;
1102 T_Page *new_page;
1103
1104 /*
1105 if (Last_backed_up_layers == (1<<Main.current_layer))
1106 return; // Already done.
1107 */
1108
1109 // On remet à jour l'état des infos de la page courante (pour pouvoir les
1110 // retrouver plus tard)
1111 Upload_infos_page(&Main);
1112
1113 // Create a fresh Page descriptor
1114 new_page=New_page(Main.backups->Pages->Nb_layers);
1115 if (!new_page)
1116 {
1117 Error(0);
1118 return;
1119 }
1120
1121 // Fill it with a copy of the latest history
1122 Copy_S_page(new_page,Main.backups->Pages);
1123 Create_new_page(new_page,Main.backups,layer);
1124 Download_infos_page_main(new_page);
1125
1126 Update_FX_feedback(Config.FX_Feedback);
1127
1128 // Copy the actual pixels from the backup to the latest page
1129 if (layer != LAYER_NONE)
1130 {
1131 for (i=0; i<Main.backups->Pages->Nb_layers;i++)
1132 {
1133 if (layer == LAYER_ALL || i == layer)
1134 memcpy(Main.backups->Pages->Image[i].Pixels,
1135 Main.backups->Pages->Next->Image[i].Pixels,
1136 Main.image_width*Main.image_height);
1137 }
1138 }
1139 // Light up the 'has unsaved changes' indicator
1140 Main.image_is_modified=1;
1141
1142 /*
1143 Last_backed_up_layers = 1<<Main.current_layer;
1144 */
1145 }
1146
1147 /// Backs up a layer, unless it's already different from previous history step.
1148 // This function checks if a layer/frame shares the same
1149 // bitmap as its Undo history parent.
1150 // If this is the case, it instanciates a new copy, and returns true.
1151 // Otherwise, it returns false.
Dup_layer_if_shared(T_Page * page,int layer)1152 int Dup_layer_if_shared(T_Page * page, int layer)
1153 {
1154 if (page->Image[layer].Pixels == page->Next->Image[layer].Pixels)
1155 {
1156 Free_layer(page, layer);
1157 page->Image[layer].Pixels=New_layer(page->Height*page->Width);
1158 memcpy(
1159 page->Image[layer].Pixels,
1160 page->Next->Image[layer].Pixels,
1161 page->Width*page->Height);
1162 return 1;
1163 }
1164 return 0;
1165 }
1166
Backup_the_spare(int layer)1167 void Backup_the_spare(int layer)
1168 {
1169 int i;
1170 T_Page *new_page;
1171
1172 // Create a fresh Page descriptor
1173 new_page=New_page(Spare.backups->Pages->Nb_layers);
1174 if (!new_page)
1175 {
1176 Error(0);
1177 return;
1178 }
1179
1180 // Fill it with a copy of the latest history
1181 Copy_S_page(new_page,Spare.backups->Pages);
1182 Create_new_page(new_page,Spare.backups,layer);
1183
1184 // Copy the actual pixels from the backup to the latest page
1185 if (layer != LAYER_NONE)
1186 {
1187 for (i=0; i<Spare.backups->Pages->Nb_layers;i++)
1188 {
1189 if (layer == LAYER_ALL || i == layer)
1190 memcpy(Spare.backups->Pages->Image[i].Pixels,
1191 Spare.backups->Pages->Next->Image[i].Pixels,
1192 Spare.image_width*Spare.image_height);
1193 }
1194 }
1195 // Light up the 'has unsaved changes' indicator
1196 Spare.image_is_modified=1;
1197
1198 }
1199
Check_layers_limits()1200 void Check_layers_limits()
1201 {
1202 if (Main.current_layer > Main.backups->Pages->Nb_layers-1)
1203 {
1204 Main.current_layer = Main.backups->Pages->Nb_layers-1;
1205 Main.layers_visible |= 1<<Main.current_layer;
1206 }
1207 }
1208
Undo(void)1209 void Undo(void)
1210 {
1211 int width = Main.image_width;
1212 int height = Main.image_height;
1213
1214 if (Last_backed_up_layers)
1215 {
1216 Free_page_of_a_list(Main.backups);
1217 Last_backed_up_layers=0;
1218 }
1219
1220 // On remet à jour l'état des infos de la page courante (pour pouvoir les
1221 // retrouver plus tard)
1222 Upload_infos_page(&Main);
1223 // On fait faire un undo à la liste des backups de la page principale
1224 Backward_in_list_of_pages(Main.backups);
1225
1226 Update_buffers(Main.backups->Pages->Width, Main.backups->Pages->Height);
1227
1228 // On extrait ensuite les infos sur la nouvelle page courante
1229 Download_infos_page_main(Main.backups->Pages);
1230 // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même
1231 // palette que la page courante. Mais en temps normal, le backup
1232 // n'est pas utilisé à la suite d'un Undo. Donc ça ne devrait pas
1233 // poser de problèmes.
1234
1235 Check_layers_limits();
1236 Redraw_layered_image();
1237 End_of_modification();
1238
1239 if (width != Main.image_width || height != Main.image_height)
1240 Tilemap_update();
1241 }
1242
Redo(void)1243 void Redo(void)
1244 {
1245 int width = Main.image_width;
1246 int height = Main.image_height;
1247
1248 if (Last_backed_up_layers)
1249 {
1250 Free_page_of_a_list(Main.backups);
1251 Last_backed_up_layers=0;
1252 }
1253 // On remet à jour l'état des infos de la page courante (pour pouvoir les
1254 // retrouver plus tard)
1255 Upload_infos_page(&Main);
1256 // On fait faire un redo à la liste des backups de la page principale
1257 Advance_in_list_of_pages(Main.backups);
1258
1259 Update_buffers(Main.backups->Pages->Width, Main.backups->Pages->Height);
1260
1261 // On extrait ensuite les infos sur la nouvelle page courante
1262 Download_infos_page_main(Main.backups->Pages);
1263 // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même
1264 // palette que la page courante. Mais en temps normal, le backup
1265 // n'est pas utilisé à la suite d'un Redo. Donc ça ne devrait pas
1266 // poser de problèmes.
1267
1268 Check_layers_limits();
1269 Redraw_layered_image();
1270 End_of_modification();
1271
1272 if (width != Main.image_width || height != Main.image_height)
1273 Tilemap_update();
1274 }
1275
Free_current_page(void)1276 void Free_current_page(void)
1277 {
1278 // On détruit la page courante de la liste principale
1279 Free_page_of_a_list(Main.backups);
1280
1281 // On extrait ensuite les infos sur la nouvelle page courante
1282 Download_infos_page_main(Main.backups->Pages);
1283 // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même
1284 // palette que la page courante. Mais en temps normal, le backup
1285 // n'est pas utilisé à la suite d'une destruction de page. Donc ça ne
1286 // devrait pas poser de problèmes.
1287
1288 Update_buffers(Main.backups->Pages->Width, Main.backups->Pages->Height);
1289 Check_layers_limits();
1290 Redraw_layered_image();
1291 End_of_modification();
1292 }
1293
End_of_modification(void)1294 void End_of_modification(void)
1295 {
1296
1297 //Update_buffers(Main.image_width, Main.image_height);
1298
1299 if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
1300 {
1301 // Backup buffer can have "wrong" size if a Lua script
1302 // performs a resize.
1303 Update_buffers(Main.image_width, Main.image_height);
1304 //
1305
1306 memcpy(Main_visible_image_backup.Image,
1307 Main.visible_image.Image,
1308 Main.image_width*Main.image_height);
1309 }
1310 else
1311 {
1312 Update_screen_targets();
1313 }
1314 Update_FX_feedback(Config.FX_Feedback);
1315 /*
1316 Last_backed_up_layers = 0;
1317 Backup();
1318 */
1319 //
1320 // Processing safety backups
1321 //
1322 Main.edits_since_safety_backup++;
1323 Rotate_safety_backups();
1324 }
1325
1326 /// Add a new layer to latest page of a list. Returns 0 on success.
Add_layer(T_List_of_pages * list,int layer)1327 byte Add_layer(T_List_of_pages *list, int layer)
1328 {
1329 T_Page * source_page;
1330 T_Page * new_page;
1331 byte * new_image;
1332 int i;
1333 int duration;
1334
1335 source_page = list->Pages;
1336
1337 if (list->Pages->Nb_layers >= Layers_max(list->Pages->Image_mode)) // MAX_NB_LAYERS
1338 return 1;
1339
1340 // Keep the position reasonable
1341 if (layer > list->Pages->Nb_layers)
1342 layer = list->Pages->Nb_layers;
1343
1344 // Allocate the pixel data
1345 new_image = New_layer(list->Pages->Height*list->Pages->Width);
1346 if (! new_image)
1347 {
1348 Error(0);
1349 return 1;
1350 }
1351 // Re-allocate the page itself, with room for one more pointer
1352 new_page = realloc(source_page, sizeof(T_Page)+(list->Pages->Nb_layers+1)*sizeof(T_Image));
1353 if (!new_page)
1354 {
1355 Error(0);
1356 return 1;
1357 }
1358 if (new_page != source_page)
1359 {
1360 // Need some housekeeping because the page moved in memory.
1361 // Update all pointers that pointed to it:
1362 new_page->Prev->Next = new_page;
1363 new_page->Next->Prev = new_page;
1364 list->Pages = new_page;
1365 }
1366 list->Pages->Nb_layers++;
1367 // Move around the pointers. This part is going to be tricky when we
1368 // have 'animations x layers' in this vector.
1369 for (i=list->Pages->Nb_layers-1; i>layer ; i--)
1370 {
1371 new_page->Image[i]=new_page->Image[i-1];
1372 }
1373 new_page->Image[layer].Pixels=new_image;
1374 if (list->Pages->Nb_layers==0)
1375 duration=100;
1376 else if (layer>0)
1377 duration=new_page->Image[layer-1].Duration;
1378 else
1379 duration=new_page->Image[1].Duration;
1380 new_page->Image[layer].Duration=duration;
1381 // Fill with transparency, initially
1382 memset(new_image, Main.backups->Pages->Transparent_color, list->Pages->Height*list->Pages->Width); // transparent color
1383
1384 // Done. Note that the visible buffer is already ok since we
1385 // only inserted a transparent "slide" somewhere.
1386 // The depth buffer is all wrong though.
1387
1388 // Update the flags of visible layers.
1389 {
1390 dword layers_before;
1391 dword layers_after;
1392 dword *visible_layers_flag;
1393
1394 // Determine if we're modifying the spare or the main page.
1395 if (list == Main.backups)
1396 {
1397 visible_layers_flag = &Main.layers_visible;
1398 Main.current_layer = layer;
1399 }
1400 else
1401 {
1402 visible_layers_flag = &Spare.layers_visible;
1403 Spare.current_layer = layer;
1404 }
1405
1406 // Fun with binary!
1407 layers_before = ((1<<layer)-1) & *visible_layers_flag;
1408 layers_after = (*visible_layers_flag & (~layers_before))<<1;
1409 *visible_layers_flag = (1<<layer) | layers_before | layers_after;
1410 }
1411
1412 // All ok
1413 return 0;
1414 }
1415
1416 /// Delete a layer from the latest page of a list. Returns 0 on success.
Delete_layer(T_List_of_pages * list,int layer)1417 byte Delete_layer(T_List_of_pages *list, int layer)
1418 {
1419 int i;
1420
1421 // Keep the position reasonable
1422 if (layer >= list->Pages->Nb_layers)
1423 layer = list->Pages->Nb_layers - 1;
1424 if (list->Pages->Nb_layers == 1)
1425 return 1;
1426
1427 // For simplicity, we won't actually shrink the page in terms of allocation.
1428 // It would only save the size of a pointer, and anyway, as the user draws,
1429 // this page is going to fall off the end of the Undo-list
1430 // and so it will be cleared anyway.
1431
1432 // Smart freeing of the pixel data
1433 Free_layer(list->Pages, layer);
1434
1435 list->Pages->Nb_layers--;
1436 // Move around the pointers. This part is going to be tricky when we
1437 // have 'animations x layers' in this vector.
1438 for (i=layer; i < list->Pages->Nb_layers; i++)
1439 {
1440 list->Pages->Image[i]=list->Pages->Image[i+1];
1441 }
1442
1443 // Done. At this point the visible buffer and the depth buffer are
1444 // all wrong.
1445
1446 // Update the flags of visible layers.
1447 {
1448 dword layers_before;
1449 dword layers_after;
1450 dword *visible_layers_flag;
1451 byte new_current_layer;
1452
1453 // Determine if we're modifying the spare or the main page.
1454 if (list == Main.backups)
1455 {
1456 visible_layers_flag = &Main.layers_visible;
1457 if (Main.current_layer>=layer && Main.current_layer>0)
1458 Main.current_layer--;
1459 new_current_layer = Main.current_layer;
1460 }
1461 else
1462 {
1463 visible_layers_flag = &Spare.layers_visible;
1464 if (Spare.current_layer>=layer && Spare.current_layer>0)
1465 Spare.current_layer--;
1466 new_current_layer = Spare.current_layer;
1467 }
1468
1469 // Fun with binary!
1470 layers_before = ((1<<layer)-1) & *visible_layers_flag;
1471 layers_after = (*visible_layers_flag & (~layers_before))>>1;
1472 *visible_layers_flag = layers_before | layers_after;
1473 // Ensure the current layer is part what is shown.
1474 *visible_layers_flag |= 1<<new_current_layer;
1475 }
1476
1477 // All ok
1478 return 0;
1479 }
1480
1481
1482 /// Merges the current layer onto the one below it.
Merge_layer(void)1483 byte Merge_layer(void)
1484 {
1485 int i;
1486 for (i=0; i<Main.image_width*Main.image_height; i++)
1487 {
1488 byte color = *(Main.backups->Pages->Image[Main.current_layer].Pixels+i);
1489 if (color != Main.backups->Pages->Transparent_color) // transparent color
1490 *(Main.backups->Pages->Image[Main.current_layer-1].Pixels+i) = color;
1491 }
1492 return Delete_layer(Main.backups,Main.current_layer);
1493 }
1494
1495
Switch_layer_mode(enum IMAGE_MODES new_mode)1496 void Switch_layer_mode(enum IMAGE_MODES new_mode)
1497 {
1498 if (new_mode == Main.backups->Pages->Image_mode)
1499 return;
1500
1501 Main.backups->Pages->Image_mode = new_mode;
1502
1503 if (new_mode != IMAGE_MODE_ANIMATION)
1504 {
1505 Update_buffers(Main.image_width, Main.image_height);
1506 Redraw_layered_image();
1507 }
1508 // TODO Eventually, in animation mode we may clear the buffers to save a bit of memory...
1509
1510 Update_pixel_renderer();
1511 }
1512