1
/* vim:expandtab:ts=2 sw=2:
3
/* Grafx2 - The Ultimate 256-color bitmap paint program
5
Copyright 2008 Franck Charlet
6
Copyright 2007 Adrien Destugues
7
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
9
Grafx2 is free software; you can redistribute it and/or
10
modify it under the terms of the GNU General Public License
11
as published by the Free Software Foundation; version 2
14
Grafx2 is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with Grafx2; if not, see <http://www.gnu.org/licenses/>
22
********************************************************************************
24
Drawing functions and effects.
38
#include "sdlscreen.h"
53
#define __attribute__(x)
56
#if defined(__VBCC__)||defined(__GP2X__)
57
#define M_PI 3.141592653589793238462643
60
// Generic pixel-drawing function.
61
Func_pixel Pixel_figure;
63
// Fonction qui met � jour la zone de l'image donn�e en param�tre sur l'�cran.
64
// Tient compte du d�calage X et Y et du zoom, et fait tous les controles n�cessaires
65
void Update_part_of_screen(short x, short y, short width, short height)
67
short effective_w, effective_h;
72
// Premi�re �tape, si L ou H est n�gatif, on doit remettre la zone � l'endroit
85
// D'abord on met � jour dans la zone �cran normale
86
diff = x-Main_offset_X;
89
effective_w = width + diff;
97
diff = y-Main_offset_Y;
100
effective_h = height + diff;
105
effective_h = height;
109
// Normalement il ne faudrait pas updater au del� du split quand on est en mode loupe,
110
// mais personne ne devrait demander d'update en dehors de cette limite, m�me le fill est contraint
111
// a rester dans la zone visible de l'image
112
// ...Sauf l'affichage de brosse en preview - yr
113
if(Main_magnifier_mode && effective_X + effective_w > Main_separator_position)
114
effective_w = Main_separator_position - effective_X;
115
else if(effective_X + effective_w > Screen_width)
116
effective_w = Screen_width - effective_X;
118
if(effective_Y + effective_h > Menu_Y)
119
effective_h = Menu_Y - effective_Y;
127
SDL_FillRect(Screen_SDL,&r,3);
129
Update_rect(effective_X,effective_Y,effective_w,effective_h);
131
// Et ensuite dans la partie zoom�e
132
if(Main_magnifier_mode)
135
effective_X = (x-Main_magnifier_offset_X)*Main_magnifier_factor;
136
effective_Y = (y-Main_magnifier_offset_Y)*Main_magnifier_factor;
137
effective_w = width * Main_magnifier_factor;
138
effective_h = height * Main_magnifier_factor;
142
effective_w+=effective_X;
146
effective_X = Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X;
149
effective_X += Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X;
150
diff = effective_X+effective_w-Min(Screen_width, Main_X_zoom+(Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor);
162
effective_h+=effective_Y;
167
diff = effective_Y+effective_h-Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor);
176
// Tr�s utile pour le debug :)
182
SDL_FillRect(Screen_SDL,&r,3);*/
184
Redraw_grid(effective_X,effective_Y,effective_w,effective_h);
185
Update_rect(effective_X,effective_Y,effective_w,effective_h);
191
void Transform_point(short x, short y, float cos_a, float sin_a,
192
short * rx, short * ry)
194
*rx=Round(((float)x*cos_a)+((float)y*sin_a));
195
*ry=Round(((float)y*cos_a)-((float)x*sin_a));
199
//--------------------- Initialisation d'un mode vid�o -----------------------
201
int Init_mode_video(int width, int height, int fullscreen, int pix_ratio)
209
int absolute_mouse_x=Mouse_X*Pixel_width;
210
int absolute_mouse_y=Mouse_Y*Pixel_height;
211
static int Wrong_resize;
252
screen_changed = (Screen_width*Pixel_width!=width ||
253
Screen_height*Pixel_height!=height ||
254
Video_mode[Current_resolution].Fullscreen != fullscreen);
256
// Valeurs raisonnables: minimum 320x200
259
if (Wrong_resize>20 && (width < 320*pix_width || height < 200*pix_height))
261
if(pix_ratio != PIXEL_SIMPLE) {
262
pix_ratio = PIXEL_SIMPLE;
263
Verbose_message("Error!", "Your WM is forcing GrafX2 to resize to something "
264
"smaller than the minimal resolution.\n"
265
"GrafX2 switched to a smaller\npixel scaler to avoid problems ");
270
if (width > 320*pix_width && height > 200*pix_height)
273
if (width < 320*pix_width)
275
width = 320*pix_width;
279
if (height < 200*pix_height)
281
height = 200*pix_height;
285
Video_mode[0].Width = width;
286
Video_mode[0].Height = height;
291
if (width < 320*pix_width || height < 200*pix_height)
294
// La largeur doit �tre un multiple de 4
296
// On AmigaOS the systems adds some more constraints on that ...
297
width = (width + 15) & 0xFFFFFFF0;
299
//width = (width + 3 ) & 0xFFFFFFFC;
302
pixels_changed = (Pixel_ratio!=pix_ratio);
304
if (!screen_changed && !pixels_changed)
308
Set_mode_SDL(&width, &height,fullscreen);
311
if (screen_changed || pixels_changed)
313
Pixel_ratio=pix_ratio;
314
Pixel_width=pix_width;
315
Pixel_height=pix_height;
320
Pixel = Pixel_simple ;
321
Read_pixel= Read_pixel_simple ;
322
Display_screen = Display_part_of_screen_simple ;
323
Block = Block_simple ;
324
Pixel_preview_normal = Pixel_preview_normal_simple ;
325
Pixel_preview_magnifier = Pixel_preview_magnifier_simple ;
326
Horizontal_XOR_line = Horizontal_XOR_line_simple ;
327
Vertical_XOR_line = Vertical_XOR_line_simple ;
328
Display_brush_color = Display_brush_color_simple ;
329
Display_brush_mono = Display_brush_mono_simple ;
330
Clear_brush = Clear_brush_simple ;
331
Remap_screen = Remap_screen_simple ;
332
Display_line = Display_line_on_screen_simple ;
333
Display_line_fast = Display_line_on_screen_simple ;
334
Read_line = Read_line_screen_simple ;
335
Display_zoomed_screen = Display_part_of_screen_scaled_simple ;
336
Display_brush_color_zoom = Display_brush_color_zoom_simple ;
337
Display_brush_mono_zoom = Display_brush_mono_zoom_simple ;
338
Clear_brush_scaled = Clear_brush_scaled_simple ;
339
Display_brush = Display_brush_simple ;
343
Read_pixel= Read_pixel_tall;
344
Display_screen = Display_part_of_screen_tall;
346
Pixel_preview_normal = Pixel_preview_normal_tall;
347
Pixel_preview_magnifier = Pixel_preview_magnifier_tall;
348
Horizontal_XOR_line = Horizontal_XOR_line_tall;
349
Vertical_XOR_line = Vertical_XOR_line_tall;
350
Display_brush_color = Display_brush_color_tall;
351
Display_brush_mono = Display_brush_mono_tall;
352
Clear_brush = Clear_brush_tall;
353
Remap_screen = Remap_screen_tall;
354
Display_line = Display_line_on_screen_tall;
355
Display_line_fast = Display_line_on_screen_tall;
356
Read_line = Read_line_screen_tall;
357
Display_zoomed_screen = Display_part_of_screen_scaled_tall;
358
Display_brush_color_zoom = Display_brush_color_zoom_tall;
359
Display_brush_mono_zoom = Display_brush_mono_zoom_tall;
360
Clear_brush_scaled = Clear_brush_scaled_tall;
361
Display_brush = Display_brush_tall;
365
Read_pixel= Read_pixel_wide ;
366
Display_screen = Display_part_of_screen_wide ;
368
Pixel_preview_normal = Pixel_preview_normal_wide ;
369
Pixel_preview_magnifier = Pixel_preview_magnifier_wide ;
370
Horizontal_XOR_line = Horizontal_XOR_line_wide ;
371
Vertical_XOR_line = Vertical_XOR_line_wide ;
372
Display_brush_color = Display_brush_color_wide ;
373
Display_brush_mono = Display_brush_mono_wide ;
374
Clear_brush = Clear_brush_wide ;
375
Remap_screen = Remap_screen_wide ;
376
Display_line = Display_line_on_screen_wide ;
377
Display_line_fast = Display_line_on_screen_fast_wide ;
378
Read_line = Read_line_screen_wide ;
379
Display_zoomed_screen = Display_part_of_screen_scaled_wide ;
380
Display_brush_color_zoom = Display_brush_color_zoom_wide ;
381
Display_brush_mono_zoom = Display_brush_mono_zoom_wide ;
382
Clear_brush_scaled = Clear_brush_scaled_wide ;
383
Display_brush = Display_brush_wide ;
386
Pixel = Pixel_double ;
387
Read_pixel= Read_pixel_double ;
388
Display_screen = Display_part_of_screen_double ;
389
Block = Block_double ;
390
Pixel_preview_normal = Pixel_preview_normal_double ;
391
Pixel_preview_magnifier = Pixel_preview_magnifier_double ;
392
Horizontal_XOR_line = Horizontal_XOR_line_double ;
393
Vertical_XOR_line = Vertical_XOR_line_double ;
394
Display_brush_color = Display_brush_color_double ;
395
Display_brush_mono = Display_brush_mono_double ;
396
Clear_brush = Clear_brush_double ;
397
Remap_screen = Remap_screen_double ;
398
Display_line = Display_line_on_screen_double ;
399
Display_line_fast = Display_line_on_screen_fast_double ;
400
Read_line = Read_line_screen_double ;
401
Display_zoomed_screen = Display_part_of_screen_scaled_double ;
402
Display_brush_color_zoom = Display_brush_color_zoom_double ;
403
Display_brush_mono_zoom = Display_brush_mono_zoom_double ;
404
Clear_brush_scaled = Clear_brush_scaled_double ;
405
Display_brush = Display_brush_double ;
408
Pixel = Pixel_triple ;
409
Read_pixel= Read_pixel_triple ;
410
Display_screen = Display_part_of_screen_triple ;
411
Block = Block_triple ;
412
Pixel_preview_normal = Pixel_preview_normal_triple ;
413
Pixel_preview_magnifier = Pixel_preview_magnifier_triple ;
414
Horizontal_XOR_line = Horizontal_XOR_line_triple ;
415
Vertical_XOR_line = Vertical_XOR_line_triple ;
416
Display_brush_color = Display_brush_color_triple ;
417
Display_brush_mono = Display_brush_mono_triple ;
418
Clear_brush = Clear_brush_triple ;
419
Remap_screen = Remap_screen_triple ;
420
Display_line = Display_line_on_screen_triple ;
421
Display_line_fast = Display_line_on_screen_fast_triple ;
422
Read_line = Read_line_screen_triple ;
423
Display_zoomed_screen = Display_part_of_screen_scaled_triple ;
424
Display_brush_color_zoom = Display_brush_color_zoom_triple ;
425
Display_brush_mono_zoom = Display_brush_mono_zoom_triple ;
426
Clear_brush_scaled = Clear_brush_scaled_triple ;
427
Display_brush = Display_brush_triple ;
430
Pixel = Pixel_wide2 ;
431
Read_pixel= Read_pixel_wide2 ;
432
Display_screen = Display_part_of_screen_wide2 ;
433
Block = Block_wide2 ;
434
Pixel_preview_normal = Pixel_preview_normal_wide2 ;
435
Pixel_preview_magnifier = Pixel_preview_magnifier_wide2 ;
436
Horizontal_XOR_line = Horizontal_XOR_line_wide2 ;
437
Vertical_XOR_line = Vertical_XOR_line_wide2 ;
438
Display_brush_color = Display_brush_color_wide2 ;
439
Display_brush_mono = Display_brush_mono_wide2 ;
440
Clear_brush = Clear_brush_wide2 ;
441
Remap_screen = Remap_screen_wide2 ;
442
Display_line = Display_line_on_screen_wide2 ;
443
Display_line_fast = Display_line_on_screen_fast_wide2 ;
444
Read_line = Read_line_screen_wide2 ;
445
Display_zoomed_screen = Display_part_of_screen_scaled_wide2 ;
446
Display_brush_color_zoom = Display_brush_color_zoom_wide2 ;
447
Display_brush_mono_zoom = Display_brush_mono_zoom_wide2 ;
448
Clear_brush_scaled = Clear_brush_scaled_wide2 ;
449
Display_brush = Display_brush_wide2 ;
452
Pixel = Pixel_tall2 ;
453
Read_pixel= Read_pixel_tall2 ;
454
Display_screen = Display_part_of_screen_tall2 ;
455
Block = Block_tall2 ;
456
Pixel_preview_normal = Pixel_preview_normal_tall2 ;
457
Pixel_preview_magnifier = Pixel_preview_magnifier_tall2 ;
458
Horizontal_XOR_line = Horizontal_XOR_line_tall2 ;
459
Vertical_XOR_line = Vertical_XOR_line_tall2 ;
460
Display_brush_color = Display_brush_color_tall2 ;
461
Display_brush_mono = Display_brush_mono_tall2 ;
462
Clear_brush = Clear_brush_tall2 ;
463
Remap_screen = Remap_screen_tall2 ;
464
Display_line = Display_line_on_screen_tall2 ;
465
Display_line_fast = Display_line_on_screen_fast_tall2 ;
466
Read_line = Read_line_screen_tall2 ;
467
Display_zoomed_screen = Display_part_of_screen_scaled_tall2 ;
468
Display_brush_color_zoom = Display_brush_color_zoom_tall2 ;
469
Display_brush_mono_zoom = Display_brush_mono_zoom_tall2 ;
470
Clear_brush_scaled = Clear_brush_scaled_tall2 ;
471
Display_brush = Display_brush_tall2 ;
475
Read_pixel= Read_pixel_quad ;
476
Display_screen = Display_part_of_screen_quad ;
478
Pixel_preview_normal = Pixel_preview_normal_quad ;
479
Pixel_preview_magnifier = Pixel_preview_magnifier_quad ;
480
Horizontal_XOR_line = Horizontal_XOR_line_quad ;
481
Vertical_XOR_line = Vertical_XOR_line_quad ;
482
Display_brush_color = Display_brush_color_quad ;
483
Display_brush_mono = Display_brush_mono_quad ;
484
Clear_brush = Clear_brush_quad ;
485
Remap_screen = Remap_screen_quad ;
486
Display_line = Display_line_on_screen_quad ;
487
Display_line_fast = Display_line_on_screen_fast_quad ;
488
Read_line = Read_line_screen_quad ;
489
Display_zoomed_screen = Display_part_of_screen_scaled_quad ;
490
Display_brush_color_zoom = Display_brush_color_zoom_quad ;
491
Display_brush_mono_zoom = Display_brush_mono_zoom_quad ;
492
Clear_brush_scaled = Clear_brush_scaled_quad ;
493
Display_brush = Display_brush_quad ;
497
Screen_width = width/Pixel_width;
498
Screen_height = height/Pixel_height;
500
Clear_border(MC_Black); // Requires up-to-date Screen_* and Pixel_*
502
// Set menu size (software zoom)
503
if (Screen_width/320 > Screen_height/200)
504
factor=Screen_height/200;
506
factor=Screen_width/320;
508
switch (Config.Ratio)
510
case 1: // Always the biggest possible
511
Menu_factor_X=factor;
512
Menu_factor_Y=factor;
514
case 2: // Only keep the aspect ratio
515
Menu_factor_X=factor-1;
516
if (Menu_factor_X<1) Menu_factor_X=1;
517
Menu_factor_Y=factor-1;
518
if (Menu_factor_Y<1) Menu_factor_Y=1;
520
case 0: // Always smallest possible
524
default: // Stay below some reasonable size
525
Menu_factor_X=Min(factor,abs(Config.Ratio));
526
Menu_factor_Y=Min(factor,abs(Config.Ratio));
528
if (Pixel_height>Pixel_width && Screen_width>=Menu_factor_X*2*320)
530
else if (Pixel_width>Pixel_height && Screen_height>=Menu_factor_Y*2*200)
533
free(Horizontal_line_buffer);
534
Horizontal_line_buffer=(byte *)malloc(Pixel_width *
535
((Screen_width>Main_image_width)?Screen_width:Main_image_width));
537
Set_palette(Main_palette);
539
Current_resolution=0;
542
for (index=1; index<Nb_video_modes; index++)
544
if (Video_mode[index].Width/Pixel_width==Screen_width &&
545
Video_mode[index].Height/Pixel_height==Screen_height)
547
Current_resolution=index;
553
Change_palette_cells();
555
Menu_Y = Screen_height;
557
Menu_Y -= Menu_height * Menu_factor_Y;
558
Menu_status_Y = Screen_height-(Menu_factor_Y<<3);
560
Adjust_mouse_sensitivity(fullscreen);
562
Mouse_X=absolute_mouse_x/Pixel_width;
563
if (Mouse_X>=Screen_width)
564
Mouse_X=Screen_width-1;
565
Mouse_Y=absolute_mouse_y/Pixel_height;
566
if (Mouse_Y>=Screen_height)
567
Mouse_Y=Screen_height-1;
569
Set_mouse_position();
571
Spare_offset_X=0; // | Il faut penser � �viter les incoh�rences
572
Spare_offset_Y=0; // |- de d�calage du brouillon par rapport �
573
Spare_magnifier_mode=0; // | la r�solution.
575
if (Main_magnifier_mode)
577
Pixel_preview=Pixel_preview_magnifier;
581
Pixel_preview=Pixel_preview_normal;
582
// Recaler la vue (meme clipping que dans Scroll_screen())
583
if (Main_offset_X+Screen_width>Main_image_width)
584
Main_offset_X=Main_image_width-Screen_width;
587
if (Main_offset_Y+Menu_Y>Main_image_height)
588
Main_offset_Y=Main_image_height-Menu_Y;
593
Compute_magnifier_data();
594
if (Main_magnifier_mode)
595
Position_screen_according_to_zoom();
597
Compute_paintbrush_coordinates();
606
// -- Redimentionner l'image (nettoie l'�cran virtuel) --
608
void Resize_image(word chosen_width,word chosen_height)
610
word old_width=Main_image_width;
611
word old_height=Main_image_height;
615
// |C| | A+B+C = Ancienne image
617
// |B| | C = Nouvelle image
620
if (Backup_with_new_dimensions(1,Main_backups->Pages->Nb_layers,chosen_width,chosen_height))
622
// La nouvelle page a pu �tre allou�e, elle est pour l'instant pleine de
623
// 0s. Elle fait Main_image_width de large.
625
Main_image_is_modified=1;
627
// On copie donc maintenant la partie C dans la nouvelle image.
628
for (i=0; i<Main_backups->Pages->Nb_layers; i++)
630
Copy_part_of_image_to_another(
631
Main_backups->Pages->Next->Image[i],0,0,Min(old_width,Main_image_width),
632
Min(old_height,Main_image_height),old_width,
633
Main_backups->Pages->Image[i],0,0,Main_image_width);
635
Redraw_layered_image();
639
// Afficher un message d'erreur
641
Message_out_of_memory();
648
void Remap_spare(void)
650
short x_pos; // Variable de balayage de la brosse
651
short y_pos; // Variable de balayage de la brosse
652
byte used[256]; // Tableau de bool�ens "La couleur est utilis�e"
656
// On commence par initialiser le tableau de bool�ens � faux
657
for (color=0;color<=255;color++)
660
// On calcule la table d'utilisation des couleurs
661
for (layer=0; layer<Spare_backups->Pages->Nb_layers; layer++)
662
for (y_pos=0;y_pos<Spare_image_height;y_pos++)
663
for (x_pos=0;x_pos<Spare_image_width;x_pos++)
664
used[*(Spare_backups->Pages->Image[layer]+(y_pos*Spare_image_width+x_pos))]=1;
666
// On va maintenant se servir de la table "used" comme table de
667
// conversion: pour chaque indice, la table donne une couleur de
669
// Note : Seules les couleurs utilis�es on besoin d'�tres recalcul�es: les
670
// autres ne seront jamais consult�es dans la nouvelle table de
671
// conversion puisque elles n'existent pas dans l'image, donc elles
672
// ne seront pas utilis�es par Remap_general_lowlevel.
673
for (color=0;color<=255;color++)
675
used[color]=Best_color(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B);
677
// Maintenant qu'on a une super table de conversion qui n'a que le nom
678
// qui craint un peu, on peut faire l'�change dans la brosse de toutes les
680
for (layer=0; layer<Spare_backups->Pages->Nb_layers; layer++)
681
Remap_general_lowlevel(used,Spare_backups->Pages->Image[layer],Spare_image_width,Spare_image_height,Spare_image_width);
686
void Get_colors_from_brush(void)
688
short x_pos; // Variable de balayage de la brosse
689
short y_pos; // Variable de balayage de la brosse
690
byte used[256]; // Tableau de bool�ens "La couleur est utilis�e"
693
if (Confirmation_box("Modify current palette ?"))
695
// Backup with unchanged layers, only palette is modified
698
// On commence par initialiser le tableau de bool�en � faux
699
for (color=0;color<=255;color++)
702
// On calcule la table d'utilisation des couleurs
703
for (y_pos=0;y_pos<Brush_height;y_pos++)
704
for (x_pos=0;x_pos<Brush_width;x_pos++)
705
used[Read_pixel_from_brush(x_pos,y_pos)]=1;
707
// On recopie dans la palette principale les teintes des couleurs utilis�es
708
// dans la palette du brouillon
709
for (color=0;color<=255;color++)
712
Main_palette[color].R=Spare_palette[color].R;
713
Main_palette[color].G=Spare_palette[color].G;
714
Main_palette[color].B=Spare_palette[color].B;
717
Set_palette(Main_palette);
718
Compute_optimal_menu_colors(Main_palette);
720
Display_all_screen();
723
End_of_modification();
725
Main_image_is_modified=1;
731
//////////////////////////////////////////////////////////////////////////////
732
////////////////////////////// GESTION DU FILLER /////////////////////////////
733
//////////////////////////////////////////////////////////////////////////////
736
void Fill(short * top_reached , short * bottom_reached,
737
short * left_reached, short * right_reached)
739
// Cette fonction fait un remplissage classique d'une zone d�limit�e de
740
// l'image. Les limites employ�es sont Limit_top, Limit_bottom, Limit_left
741
// et Limit_right. Le point de d�part du remplissage est Paintbrush_X,Paintbrush_Y
742
// et s'effectue en th�orie sur la couleur 1 et emploie la couleur 2 pour le
743
// remplissage. Ces restrictions sont d�es � l'utilisation qu'on en fait dans
744
// la fonction principale "Fill_general", qui se charge de faire une gestion de
746
// Cette fonction ne doit pas �tre directement appel�e.
749
short x_pos; // Abscisse de balayage du segment, utilis�e lors de l'"affichage"
750
short line; // Ordonn�e de la ligne en cours de traitement
751
short start_x; // Abscisse de d�part du segment trait�
752
short end_x; // Abscisse de fin du segment trait�
753
int changes_made; // Bool�en "On a fait une modif dans le dernier passage"
754
int can_propagate; // Bool�en "On peut propager la couleur dans le segment"
755
short current_limit_bottom; // Intervalle vertical restreint
756
short current_limit_top;
757
int line_is_modified; // Bool�en "On a fait une modif dans la ligne"
760
current_limit_top=Paintbrush_Y;
761
current_limit_bottom =Min(Paintbrush_Y+1,Limit_bottom);
762
*left_reached=Paintbrush_X;
763
*right_reached=Paintbrush_X+1;
764
Pixel_in_current_layer(Paintbrush_X,Paintbrush_Y,2);
770
for (line=current_limit_top;line<=current_limit_bottom;line++)
773
// On va traiter le cas de la ligne n� line.
775
// On commence le traitement � la gauche de l'�cran
778
// Pour chaque segment de couleur 1 que peut contenir la ligne
779
while (start_x<=Limit_right)
781
// On cherche son d�but
782
while((start_x<=Limit_right) &&
783
(Read_pixel_from_current_layer(start_x,line)!=1))
786
if (start_x<=Limit_right)
788
// Un segment de couleur 1 existe et commence � la position start_x.
789
// On va donc en chercher la fin.
790
for (end_x=start_x+1;(end_x<=Limit_right) &&
791
(Read_pixel_from_current_layer(end_x,line)==1);end_x++);
793
// On sait qu'il existe un segment de couleur 1 qui commence en
794
// start_x et qui se termine en end_x-1.
796
// On va maintenant regarder si une couleur sur la p�riph�rie
797
// permet de colorier ce segment avec la couleur 2.
800
// Test de la pr�sence d'un point � gauche du segment
801
((start_x>Limit_left) &&
802
(Read_pixel_from_current_layer(start_x-1,line)==2)) ||
803
// Test de la pr�sence d'un point � droite du segment
804
((end_x-1<Limit_right) &&
805
(Read_pixel_from_current_layer(end_x ,line)==2))
808
// Test de la pr�sence d'un point en haut du segment
809
if (!can_propagate && (line>Limit_top))
810
for (x_pos=start_x;x_pos<end_x;x_pos++)
811
if (Read_pixel_from_current_layer(x_pos,line-1)==2)
819
if (start_x<*left_reached)
820
*left_reached=start_x;
821
if (end_x>*right_reached)
822
*right_reached=end_x;
823
// On remplit le segment de start_x � end_x-1.
824
for (x_pos=start_x;x_pos<end_x;x_pos++)
825
Pixel_in_current_layer(x_pos,line,2);
826
// On vient d'effectuer des modifications.
835
// Si on est en bas, et qu'on peut se propager vers le bas...
836
if ( (line==current_limit_bottom) &&
837
(line_is_modified) &&
838
(current_limit_bottom<Limit_bottom) )
839
current_limit_bottom++; // On descend cette limite vers le bas
842
// Pour le prochain balayage vers le haut, on va se permettre d'aller
843
// voir une ligne plus haut.
844
// Si on ne le fait pas, et que la premi�re ligne (current_limit_top)
845
// n'�tait pas modifi�e, alors cette limite ne serait pas remont�e, donc
846
// le filler ne progresserait pas vers le haut.
847
if (current_limit_top>Limit_top)
850
for (line=current_limit_bottom;line>=current_limit_top;line--)
853
// On va traiter le cas de la ligne n� line.
855
// On commence le traitement � la gauche de l'�cran
858
// Pour chaque segment de couleur 1 que peut contenir la ligne
859
while (start_x<=Limit_right)
861
// On cherche son d�but
862
for (;(start_x<=Limit_right) &&
863
(Read_pixel_from_current_layer(start_x,line)!=1);start_x++);
865
if (start_x<=Limit_right)
867
// Un segment de couleur 1 existe et commence � la position start_x.
868
// On va donc en chercher la fin.
869
for (end_x=start_x+1;(end_x<=Limit_right) &&
870
(Read_pixel_from_current_layer(end_x,line)==1);end_x++);
872
// On sait qu'il existe un segment de couleur 1 qui commence en
873
// start_x et qui se termine en end_x-1.
875
// On va maintenant regarder si une couleur sur la p�riph�rie
876
// permet de colorier ce segment avec la couleur 2.
879
// Test de la pr�sence d'un point � gauche du segment
880
((start_x>Limit_left) &&
881
(Read_pixel_from_current_layer(start_x-1,line)==2)) ||
882
// Test de la pr�sence d'un point � droite du segment
883
((end_x-1<Limit_right) &&
884
(Read_pixel_from_current_layer(end_x ,line)==2))
887
// Test de la pr�sence d'un point en bas du segment
888
if (!can_propagate && (line<Limit_bottom))
889
for (x_pos=start_x;x_pos<end_x;x_pos++)
890
if (Read_pixel_from_current_layer(x_pos,line+1)==2)
898
if (start_x<*left_reached)
899
*left_reached=start_x;
900
if (end_x>*right_reached)
901
*right_reached=end_x;
902
// On remplit le segment de start_x � end_x-1.
903
for (x_pos=start_x;x_pos<end_x;x_pos++)
904
Pixel_in_current_layer(x_pos,line,2);
905
// On vient d'effectuer des modifications.
914
// Si on est en haut, et qu'on peut se propager vers le haut...
915
if ( (line==current_limit_top) &&
916
(line_is_modified) &&
917
(current_limit_top>Limit_top) )
918
current_limit_top--; // On monte cette limite vers le haut
922
*top_reached=current_limit_top;
923
*bottom_reached =current_limit_bottom;
925
} // end de la routine de remplissage "Fill"
927
byte Read_pixel_from_backup_layer(word x,word y)
929
return *((y)*Main_image_width+(x)+Main_backups->Pages->Next->Image[Main_current_layer]);
932
void Fill_general(byte fill_color)
934
// Cette fonction fait un remplissage qui g�re tous les effets. Elle fait
938
byte cursor_shape_before_fill;
940
short top_reached ,bottom_reached;
941
short left_reached,right_reached;
942
byte replace_table[256];
945
// Avant toute chose, on v�rifie que l'on n'est pas en train de remplir
946
// en dehors de l'image:
948
if ( (Paintbrush_X>=Limit_left) &&
949
(Paintbrush_X<=Limit_right) &&
950
(Paintbrush_Y>=Limit_top) &&
951
(Paintbrush_Y<=Limit_bottom) )
953
// On suppose que le curseur est d�j� cach�.
956
// On va faire patienter l'utilisateur en lui affichant un joli petit
958
cursor_shape_before_fill=Cursor_shape;
959
Cursor_shape=CURSOR_SHAPE_HOURGLASS;
962
// On commence par effectuer un backup de l'image.
965
// On fait attention au Feedback qui DOIT se faire avec le backup.
966
Update_FX_feedback(0);
968
// On va maintenant "�purer" la zone visible de l'image:
969
memset(replace_table,0,256);
970
replace_table[Read_pixel_from_backup_layer(Paintbrush_X,Paintbrush_Y)]=1;
971
Replace_colors_within_limits(replace_table);
973
// On fait maintenant un remplissage classique de la couleur 1 avec la 2
974
Fill(&top_reached ,&bottom_reached,
975
&left_reached,&right_reached);
977
// On s'appr�te � faire des op�rations qui n�cessitent un affichage. Il
978
// faut donc retirer de l'�cran le curseur:
980
Cursor_shape=cursor_shape_before_fill;
982
// Il va maintenant falloir qu'on "turn" ce gros caca "into" un truc qui
983
// ressemble un peu plus � ce � quoi l'utilisateur peut s'attendre.
984
if (top_reached>Limit_top)
985
Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer], // source
986
Limit_left,Limit_top, // Pos X et Y dans source
987
(Limit_right-Limit_left)+1, // width copie
988
top_reached-Limit_top,// height copie
989
Main_image_width, // width de la source
990
Main_backups->Pages->Image[Main_current_layer], // Destination
991
Limit_left,Limit_top, // Pos X et Y destination
992
Main_image_width); // width destination
993
if (bottom_reached<Limit_bottom)
994
Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer],
995
Limit_left,bottom_reached+1,
996
(Limit_right-Limit_left)+1,
997
Limit_bottom-bottom_reached,
998
Main_image_width,Main_backups->Pages->Image[Main_current_layer],
999
Limit_left,bottom_reached+1,Main_image_width);
1000
if (left_reached>Limit_left)
1001
Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer],
1002
Limit_left,top_reached,
1003
left_reached-Limit_left,
1004
(bottom_reached-top_reached)+1,
1005
Main_image_width,Main_backups->Pages->Image[Main_current_layer],
1006
Limit_left,top_reached,Main_image_width);
1007
if (right_reached<Limit_right)
1008
Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer],
1009
right_reached+1,top_reached,
1010
Limit_right-right_reached,
1011
(bottom_reached-top_reached)+1,
1012
Main_image_width,Main_backups->Pages->Image[Main_current_layer],
1013
right_reached+1,top_reached,Main_image_width);
1015
for (y_pos=top_reached;y_pos<=bottom_reached;y_pos++)
1016
for (x_pos=left_reached;x_pos<=right_reached;x_pos++)
1017
if (Read_pixel_from_current_layer(x_pos,y_pos)==2)
1019
// Si le pixel en cours de traitement a �t� touch� par le Fill()
1020
// on se doit d'afficher le pixel modifi� par la couleur de
1023
// Ceci se fait en commen�ant par restaurer la couleur qu'il y avait
1024
// pr�c�demment (c'est important pour que les effets ne s'emm�lent
1026
Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0);
1028
// Enfin, on peut afficher le pixel, en le soumettant aux effets en
1030
Display_pixel(x_pos,y_pos,fill_color);
1033
Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0);
1035
// Restore original feedback value
1036
Update_FX_feedback(Config.FX_Feedback);
1038
// A la fin, on n'a pas besoin de r�afficher le curseur puisque c'est
1039
// l'appelant qui s'en charge, et on n'a pas besoin de rafficher l'image
1040
// puisque les seuls points qui ont chang� dans l'image ont �t� raffich�s
1041
// par l'utilisation de "Display_pixel()", et que les autres... eh bein
1042
// on n'y a jamais touch� � l'�cran les autres: ils sont donc corrects.
1043
if(Main_magnifier_mode)
1047
w=Min(Screen_width-Main_X_zoom, (Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor);
1048
h=Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor);
1050
Redraw_grid(Main_X_zoom,0,w,h);
1053
Update_rect(0,0,0,0);
1054
End_of_modification();
1060
//////////////////////////////////////////////////////////////////////////////
1061
////////////////// TRAC�S DE FIGURES G�OM�TRIQUES STANDARDS //////////////////
1062
////////////////////////// avec gestion de previews //////////////////////////
1063
//////////////////////////////////////////////////////////////////////////////
1065
// Data used by ::Init_permanent_draw() and ::Pixel_figure_permanent()
1066
static Uint32 Permanent_draw_next_refresh=0;
1067
static int Permanent_draw_count=0;
1069
void Init_permanent_draw(void)
1071
Permanent_draw_count = 0;
1072
Permanent_draw_next_refresh = SDL_GetTicks() + 100;
1075
// Affichage d'un point de fa�on d�finitive (utilisation du pinceau)
1076
void Pixel_figure_permanent(word x_pos,word y_pos,byte color)
1078
Display_paintbrush(x_pos,y_pos,color,0);
1079
Permanent_draw_count ++;
1081
// Check every 8 pixels
1082
if (! (Permanent_draw_count&7))
1084
Uint32 now = SDL_GetTicks();
1085
if (now>= Permanent_draw_next_refresh)
1087
Permanent_draw_next_refresh = now+100;
1093
// Affichage d'un point de fa�on d�finitive
1094
void Pixel_clipped(word x_pos,word y_pos,byte color)
1096
if ( (x_pos>=Limit_left) &&
1097
(x_pos<=Limit_right) &&
1098
(y_pos>=Limit_top) &&
1099
(y_pos<=Limit_bottom) )
1100
Display_pixel(x_pos,y_pos,color);
1103
// Affichage d'un point pour une preview
1104
void Pixel_figure_preview(word x_pos,word y_pos,byte color)
1106
if ( (x_pos>=Limit_left) &&
1107
(x_pos<=Limit_right) &&
1108
(y_pos>=Limit_top) &&
1109
(y_pos<=Limit_bottom) )
1110
Pixel_preview(x_pos,y_pos,color);
1112
// Affichage d'un point pour une preview, avec sa propre couleur
1113
void Pixel_figure_preview_auto(word x_pos,word y_pos)
1115
if ( (x_pos>=Limit_left) &&
1116
(x_pos<=Limit_right) &&
1117
(y_pos>=Limit_top) &&
1118
(y_pos<=Limit_bottom) )
1119
Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos));
1122
// Affichage d'un point pour une preview en xor
1123
void Pixel_figure_preview_xor(word x_pos,word y_pos,__attribute__((unused)) byte color)
1125
if ( (x_pos>=Limit_left) &&
1126
(x_pos<=Limit_right) &&
1127
(y_pos>=Limit_top) &&
1128
(y_pos<=Limit_bottom) )
1129
Pixel_preview(x_pos,y_pos,~Read_pixel(x_pos-Main_offset_X,
1130
y_pos-Main_offset_Y));
1133
// Affichage d'un point pour une preview en xor additif
1134
// (Il lit la couleur depuis la page backup)
1135
void Pixel_figure_preview_xorback(word x_pos,word y_pos,__attribute__((unused)) byte color)
1137
if ( (x_pos>=Limit_left) &&
1138
(x_pos<=Limit_right) &&
1139
(y_pos>=Limit_top) &&
1140
(y_pos<=Limit_bottom) )
1141
Pixel_preview(x_pos,y_pos,~Screen_backup[x_pos+y_pos*Main_image_width]);
1145
// Effacement d'un point de preview
1146
void Pixel_figure_clear_preview(word x_pos,word y_pos,__attribute__((unused)) byte color)
1148
if ( (x_pos>=Limit_left) &&
1149
(x_pos<=Limit_right) &&
1150
(y_pos>=Limit_top) &&
1151
(y_pos<=Limit_bottom) )
1152
Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos));
1155
// Affichage d'un point dans la brosse
1156
void Pixel_figure_in_brush(word x_pos,word y_pos,byte color)
1158
x_pos-=Brush_offset_X;
1159
y_pos-=Brush_offset_Y;
1160
if ( (x_pos<Brush_width) && // Les pos sont des word donc jamais < 0 ...
1161
(y_pos<Brush_height) )
1162
Pixel_in_brush(x_pos,y_pos,color);
1166
// -- Tracer g�n�ral d'un cercle vide -------------------------------------
1168
void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color)
1175
// Ensuite, on va parcourire le quart haut gauche du cercle
1176
start_x=center_x-radius;
1177
start_y=center_y-radius;
1179
// Affichage des extremit�es du cercle sur chaque quart du cercle:
1180
for (y_pos=start_y,Circle_cursor_Y=-radius;y_pos<center_y;y_pos++,Circle_cursor_Y++)
1181
for (x_pos=start_x,Circle_cursor_X=-radius;x_pos<center_x;x_pos++,Circle_cursor_X++)
1182
if (Pixel_in_circle())
1184
// On vient de tomber sur le premier point sur la ligne horizontale
1185
// qui fait partie du cercle.
1186
// Donc on peut l'afficher (lui et ses copains sym�triques)
1188
// Quart Haut-gauche
1189
Pixel_figure(x_pos,y_pos,color);
1190
// Quart Haut-droite
1191
Pixel_figure((center_x<<1)-x_pos,y_pos,color);
1193
Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
1195
Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
1197
// On peut ensuite afficher tous les points qui le suivent dont le
1198
// pixel voisin du haut n'appartient pas au cercle:
1199
for (Circle_cursor_Y--,x_pos++,Circle_cursor_X++;x_pos<center_x;x_pos++,Circle_cursor_X++)
1200
if (!Pixel_in_circle())
1202
// Quart Haut-gauche
1203
Pixel_figure(x_pos,y_pos,color);
1204
// Quart Haut-droite
1205
Pixel_figure((center_x<<1)-x_pos,y_pos,color);
1207
Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
1209
Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
1218
// On affiche � la fin les points cardinaux:
1219
Pixel_figure(center_x,center_y-radius,color); // Haut
1220
Pixel_figure(center_x-radius,center_y,color); // Gauche
1221
Pixel_figure(center_x+radius,center_y,color); // Droite
1222
Pixel_figure(center_x,center_y+radius,color); // Bas
1224
if(Main_magnifier_mode) Update_part_of_screen(center_x-radius,center_y-radius,2*radius+1,2*radius+1);
1227
// -- Trac� d�finitif d'un cercle vide --
1229
void Draw_empty_circle_permanent(short center_x,short center_y,short radius,byte color)
1231
Pixel_figure=Pixel_figure_permanent;
1232
Init_permanent_draw();
1233
Draw_empty_circle_general(center_x,center_y,radius,color);
1234
Update_part_of_screen(center_x - radius, center_y - radius, 2* radius+1, 2*radius+1);
1237
// -- Tracer la preview d'un cercle vide --
1239
void Draw_empty_circle_preview(short center_x,short center_y,short radius,byte color)
1241
Pixel_figure=Pixel_figure_preview;
1242
Draw_empty_circle_general(center_x,center_y,radius,color);
1243
Update_part_of_screen(center_x - radius, center_y - radius, 2* radius+1, 2*radius+1);
1246
// -- Effacer la preview d'un cercle vide --
1248
void Hide_empty_circle_preview(short center_x,short center_y,short radius)
1250
Pixel_figure=Pixel_figure_clear_preview;
1251
Draw_empty_circle_general(center_x,center_y,radius,0);
1252
Update_part_of_screen(center_x - radius, center_y - radius, 2* radius+1, 2*radius+1);
1255
// -- Tracer un cercle plein --
1257
void Draw_filled_circle(short center_x,short center_y,short radius,byte color)
1266
start_x=center_x-radius;
1267
start_y=center_y-radius;
1268
end_x=center_x+radius;
1269
end_y=center_y+radius;
1271
// Correction des bornes d'apr�s les limites
1272
if (start_y<Limit_top)
1274
if (end_y>Limit_bottom)
1276
if (start_x<Limit_left)
1278
if (end_x>Limit_right)
1281
// Affichage du cercle
1282
for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++)
1283
for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++)
1284
if (Pixel_in_circle())
1285
Display_pixel(x_pos,y_pos,color);
1287
Update_part_of_screen(start_x,start_y,end_x+1-start_x,end_y+1-start_y);
1291
// -- Tracer g�n�ral d'une ellipse vide -----------------------------------
1293
void Draw_empty_ellipse_general(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
1300
start_x=center_x-horizontal_radius;
1301
start_y=center_y-vertical_radius;
1303
// Calcul des limites de l'ellipse
1304
Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1);
1306
// Affichage des extremit�es de l'ellipse sur chaque quart de l'ellipse:
1307
for (y_pos=start_y,Ellipse_cursor_Y=-vertical_radius;y_pos<center_y;y_pos++,Ellipse_cursor_Y++)
1308
for (x_pos=start_x,Ellipse_cursor_X=-horizontal_radius;x_pos<center_x;x_pos++,Ellipse_cursor_X++)
1309
if (Pixel_in_ellipse())
1311
// On vient de tomber sur le premier point qui sur la ligne
1312
// horizontale fait partie de l'ellipse.
1314
// Donc on peut l'afficher (lui et ses copains sym�triques)
1316
// Quart Haut-gauche
1317
Pixel_figure(x_pos,y_pos,color);
1318
// Quart Haut-droite
1319
Pixel_figure((center_x<<1)-x_pos,y_pos,color);
1321
Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
1323
Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
1325
// On peut ensuite afficher tous les points qui le suivent dont le
1326
// pixel voisin du haut n'appartient pas � l'ellipse:
1327
for (Ellipse_cursor_Y--,x_pos++,Ellipse_cursor_X++;x_pos<center_x;x_pos++,Ellipse_cursor_X++)
1328
if (!Pixel_in_ellipse())
1330
// Quart Haut-gauche
1331
Pixel_figure(x_pos,y_pos,color);
1332
// Quart Haut-droite
1333
Pixel_figure((center_x<<1)-x_pos,y_pos,color);
1335
Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
1337
Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
1346
// On affiche � la fin les points cardinaux:
1348
// points verticaux:
1350
Ellipse_cursor_X=-1;
1351
for (y_pos=center_y+1-vertical_radius,Ellipse_cursor_Y=-vertical_radius+1;y_pos<center_y+vertical_radius;y_pos++,Ellipse_cursor_Y++)
1352
if (!Pixel_in_ellipse())
1353
Pixel_figure(x_pos,y_pos,color);
1355
// points horizontaux:
1357
Ellipse_cursor_Y=-1;
1358
for (x_pos=center_x+1-horizontal_radius,Ellipse_cursor_X=-horizontal_radius+1;x_pos<center_x+horizontal_radius;x_pos++,Ellipse_cursor_X++)
1359
if (!Pixel_in_ellipse())
1360
Pixel_figure(x_pos,y_pos,color);
1362
Pixel_figure(center_x,center_y-vertical_radius,color); // Haut
1363
Pixel_figure(center_x-horizontal_radius,center_y,color); // Gauche
1364
Pixel_figure(center_x+horizontal_radius,center_y,color); // Droite
1365
Pixel_figure(center_x,center_y+vertical_radius,color); // Bas
1367
Update_part_of_screen(center_x-horizontal_radius,center_y-vertical_radius,2*horizontal_radius+1,2*vertical_radius+1);
1370
// -- Trac� d�finitif d'une ellipse vide --
1372
void Draw_empty_ellipse_permanent(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
1374
Pixel_figure=Pixel_figure_permanent;
1375
Init_permanent_draw();
1376
Draw_empty_ellipse_general(center_x,center_y,horizontal_radius,vertical_radius,color);
1377
Update_part_of_screen(center_x - horizontal_radius, center_y - vertical_radius, 2* horizontal_radius+1, 2*vertical_radius+1);
1380
// -- Tracer la preview d'une ellipse vide --
1382
void Draw_empty_ellipse_preview(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
1384
Pixel_figure=Pixel_figure_preview;
1385
Draw_empty_ellipse_general(center_x,center_y,horizontal_radius,vertical_radius,color);
1386
Update_part_of_screen(center_x - horizontal_radius, center_y - vertical_radius, 2* horizontal_radius+1, 2*vertical_radius +1);
1389
// -- Effacer la preview d'une ellipse vide --
1391
void Hide_empty_ellipse_preview(short center_x,short center_y,short horizontal_radius,short vertical_radius)
1393
Pixel_figure=Pixel_figure_clear_preview;
1394
Draw_empty_ellipse_general(center_x,center_y,horizontal_radius,vertical_radius,0);
1395
Update_part_of_screen(center_x - horizontal_radius, center_y - vertical_radius, 2* horizontal_radius+1, 2*vertical_radius+1);
1398
// -- Tracer une ellipse pleine --
1400
void Draw_filled_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
1409
start_x=center_x-horizontal_radius;
1410
start_y=center_y-vertical_radius;
1411
end_x=center_x+horizontal_radius;
1412
end_y=center_y+vertical_radius;
1414
// Calcul des limites de l'ellipse
1415
Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1);
1417
// Correction des bornes d'apr�s les limites
1418
if (start_y<Limit_top)
1420
if (end_y>Limit_bottom)
1422
if (start_x<Limit_left)
1424
if (end_x>Limit_right)
1427
// Affichage de l'ellipse
1428
for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++)
1429
for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++)
1430
if (Pixel_in_ellipse())
1431
Display_pixel(x_pos,y_pos,color);
1432
Update_part_of_screen(center_x-horizontal_radius,center_y-vertical_radius,2*horizontal_radius+1,2*vertical_radius+1);
1439
/// Alters bx and by so the (AX,AY)-(BX,BY) segment becomes either horizontal,
1440
/// vertical, 45degrees, or isometrical for pixelart (ie 2:1 ratio)
1441
void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by)
1449
// No mouse move: no need to clamp anything
1450
if (dx==0 || dy == 0) return;
1452
// Determine angle (heading)
1453
angle = atan2(dx, dy);
1455
// Get absolute values, useful from now on:
1460
if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0))
1465
// Iso close to negative Y
1466
else if (angle < M_PI*(-13.0/16.0))
1468
dy=dy | 1; // Round up to next odd number
1473
else if (angle < M_PI*(-11.0/16.0))
1475
*by = (*by + ay + dx)/2;
1476
*bx = ax - ay + *by;
1478
// Iso close to negative X
1479
else if (angle < M_PI*(-9.0/16.0))
1481
dx=dx | 1; // Round up to next odd number
1486
else if (angle < M_PI*(-7.0/16.0))
1491
// Iso close to negative X
1492
else if (angle < M_PI*(-5.0/16.0))
1494
dx=dx | 1; // Round up to next odd number
1499
else if (angle < M_PI*(-3.0/16.0))
1501
*by = (*by + ay - dx)/2;
1502
*bx = ax + ay - *by;
1504
// Iso close to positive Y
1505
else if (angle < M_PI*(-1.0/16.0))
1507
dy=dy | 1; // Round up to next odd number
1512
else if (angle < M_PI*(1.0/16.0))
1517
// Iso close to positive Y
1518
else if (angle < M_PI*(3.0/16.0))
1520
dy=dy | 1; // Round up to next odd number
1525
else if (angle < M_PI*(5.0/16.0))
1527
*by = (*by + ay + dx)/2;
1528
*bx = ax - ay + *by;
1530
// Iso close to positive X
1531
else if (angle < M_PI*(7.0/16.0))
1533
dx=dx | 1; // Round up to next odd number
1538
else if (angle < M_PI*(9.0/16.0))
1543
// Iso close to positive X
1544
else if (angle < M_PI*(11.0/16.0))
1546
dx=dx | 1; // Round up to next odd number
1551
else if (angle < M_PI*(13.0/16.0))
1553
*by = (*by + ay - dx)/2;
1554
*bx = ax + ay - *by;
1556
// Iso close to negative Y
1557
else //if (angle < M_PI*(15.0/16.0))
1559
dy=dy | 1; // Round up to next odd number
1567
// -- Tracer g�n�ral d'une ligne ------------------------------------------
1569
void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color)
1572
short incr_x,incr_y;
1574
short delta_x,delta_y;
1582
delta_x=end_x-start_x;
1587
delta_x=start_x-end_x;
1593
delta_y=end_y-start_y;
1598
delta_y=start_y-end_y;
1601
if (delta_y>delta_x)
1604
for (i=1; i<delta_y; i++)
1613
Pixel_figure(x_pos,y_pos,color);
1619
for (i=1; i<delta_x; i++)
1628
Pixel_figure(x_pos,y_pos,color);
1632
if ( (start_x!=end_x) || (start_y!=end_y) )
1633
Pixel_figure(end_x,end_y,color);
1637
// -- Tracer d�finitif d'une ligne --
1639
void Draw_line_permanent(short start_x,short start_y,short end_x,short end_y, byte color)
1642
int w = end_x-start_x, h = end_y - start_y;
1643
Pixel_figure=Pixel_figure_permanent;
1644
Init_permanent_draw();
1645
Draw_line_general(start_x,start_y,end_x,end_y,color);
1646
Update_part_of_screen((start_x<end_x)?start_x:end_x,(start_y<end_y)?start_y:end_y,abs(w)+1,abs(h)+1);
1649
// -- Tracer la preview d'une ligne --
1651
void Draw_line_preview(short start_x,short start_y,short end_x,short end_y,byte color)
1653
int w = end_x-start_x, h = end_y - start_y;
1654
Pixel_figure=Pixel_figure_preview;
1655
Draw_line_general(start_x,start_y,end_x,end_y,color);
1656
Update_part_of_screen((start_x<end_x)?start_x:end_x,(start_y<end_y)?start_y:end_y,abs(w)+1,abs(h)+1);
1659
// -- Tracer la preview d'une ligne en xor --
1661
void Draw_line_preview_xor(short start_x,short start_y,short end_x,short end_y,byte color)
1664
Pixel_figure=Pixel_figure_preview_xor;
1665
Draw_line_general(start_x,start_y,end_x,end_y,color);
1676
Update_part_of_screen((start_x<end_x)?start_x:end_x,(start_y<end_y)?start_y:end_y,abs(w)+1,abs(h)+1);
1679
// -- Tracer la preview d'une ligne en xor additif --
1681
void Draw_line_preview_xorback(short start_x,short start_y,short end_x,short end_y,byte color)
1683
int w = end_x-start_x, h = end_y - start_y;
1684
Pixel_figure=Pixel_figure_preview_xorback;
1685
Draw_line_general(start_x,start_y,end_x,end_y,color);
1686
Update_part_of_screen((start_x<end_x)?start_x:end_x,(start_y<end_y)?start_y:end_y,abs(w)+1,abs(h)+1);
1689
// -- Effacer la preview d'une ligne --
1691
void Hide_line_preview(short start_x,short start_y,short end_x,short end_y)
1693
int w = end_x-start_x, h = end_y - start_y;
1694
Pixel_figure=Pixel_figure_clear_preview;
1695
Draw_line_general(start_x,start_y,end_x,end_y,0);
1696
Update_part_of_screen((start_x<end_x)?start_x:end_x,(start_y<end_y)?start_y:end_y,abs(w)+1,abs(h)+1);
1700
// -- Tracer un rectangle vide --
1702
void Draw_empty_rectangle(short start_x,short start_y,short end_x,short end_y,byte color)
1709
// On v�rifie que les bornes soient dans le bon sens:
1723
// On trace le rectangle:
1724
Init_permanent_draw();
1726
for (x_pos=start_x;x_pos<=end_x;x_pos++)
1728
Pixel_figure_permanent(x_pos,start_y,color);
1729
Pixel_figure_permanent(x_pos, end_y,color);
1732
for (y_pos=start_y+1;y_pos<end_y;y_pos++)
1734
Pixel_figure_permanent(start_x,y_pos,color);
1735
Pixel_figure_permanent( end_x,y_pos,color);
1738
#if defined(__macosx__) || defined(__FreeBSD__)
1739
Update_part_of_screen(start_x,end_x,end_x-start_x,end_y-start_y);
1743
// -- Tracer un rectangle plein --
1745
void Draw_filled_rectangle(short start_x,short start_y,short end_x,short end_y,byte color)
1752
// On v�rifie que les bornes sont dans le bon sens:
1766
// Correction en cas de d�passement des limites de l'image
1767
if (end_x>Limit_right)
1769
if (end_y>Limit_bottom)
1772
// On trace le rectangle:
1773
for (y_pos=start_y;y_pos<=end_y;y_pos++)
1774
for (x_pos=start_x;x_pos<=end_x;x_pos++)
1775
// Display_pixel traite chaque pixel avec tous les effets ! (smear, ...)
1776
// Donc on ne peut pas otimiser en tra�ant ligne par ligne avec memset :(
1777
Display_pixel(x_pos,y_pos,color);
1778
Update_part_of_screen(start_x,start_y,end_x-start_x,end_y-start_y);
1785
// -- Tracer une courbe de B�zier --
1787
void Draw_curve_general(short x1, short y1,
1793
float delta,t,t2,t3;
1794
short x,y,old_x,old_y;
1799
// Calcul des vecteurs de coefficients
1800
cx[0]= - x1 + 3*x2 - 3*x3 + x4;
1801
cx[1]= + 3*x1 - 6*x2 + 3*x3;
1802
cx[2]= - 3*x1 + 3*x2;
1804
cy[0]= - y1 + 3*y2 - 3*y3 + y4;
1805
cy[1]= + 3*y1 - 6*y2 + 3*y3;
1806
cy[2]= - 3*y1 + 3*y2;
1809
// Tra�age de la courbe
1812
Pixel_figure(old_x,old_y,color);
1813
delta=0.05; // 1.0/20
1815
for (i=1; i<=20; i++)
1817
t=t+delta; t2=t*t; t3=t2*t;
1818
x=Round(t3*cx[0] + t2*cx[1] + t*cx[2] + cx[3]);
1819
y=Round(t3*cy[0] + t2*cy[1] + t*cy[2] + cy[3]);
1820
Draw_line_general(old_x,old_y,x,y,color);
1825
x = Min(Min(x1,x2),Min(x3,x4));
1826
y = Min(Min(y1,y2),Min(y3,y4));
1827
old_x = Max(Max(x1,x2),Max(x3,x4)) - x;
1828
old_y = Max(Max(y1,y2),Max(y3,y4)) - y;
1829
Update_part_of_screen(x,y,old_x+1,old_y+1);
1832
// -- Tracer une courbe de B�zier d�finitivement --
1834
void Draw_curve_permanent(short x1, short y1,
1840
Pixel_figure=Pixel_figure_permanent;
1841
Init_permanent_draw();
1842
Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color);
1845
// -- Tracer la preview d'une courbe de B�zier --
1847
void Draw_curve_preview(short x1, short y1,
1853
Pixel_figure=Pixel_figure_preview;
1854
Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color);
1857
// -- Effacer la preview d'une courbe de B�zier --
1859
void Hide_curve_preview(short x1, short y1,
1865
Pixel_figure=Pixel_figure_clear_preview;
1866
Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color);
1872
// -- Spray : un petit coup de Pschiitt! --
1874
void Airbrush(short clicked_button)
1877
short radius=Airbrush_size>>1;
1878
long radius_squared=(long)radius*radius;
1888
for (count=1; count<=Airbrush_mono_flow; count++)
1890
x_pos=(rand()%Airbrush_size)-radius;
1891
y_pos=(rand()%Airbrush_size)-radius;
1892
if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared )
1894
x_pos+=Paintbrush_X;
1895
y_pos+=Paintbrush_Y;
1896
if (clicked_button==1)
1897
Display_paintbrush(x_pos,y_pos,Fore_color,0);
1899
Display_paintbrush(x_pos,y_pos,Back_color,0);
1905
// On essaye de se balader dans la table des flux de fa�on � ce que ce
1906
// ne soit pas toujours la derni�re couleur qui soit affich�e en dernier
1907
// Pour �a, on part d'une couleur au pif dans une direction al�atoire.
1909
for (index=0,color_index=rand()/*%256*/; index<256; index++)
1911
for (count=1; count<=Airbrush_multi_flow[color_index]; count++)
1913
x_pos=(rand()%Airbrush_size)-radius;
1914
y_pos=(rand()%Airbrush_size)-radius;
1915
if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared )
1917
x_pos+=Paintbrush_X;
1918
y_pos+=Paintbrush_Y;
1919
if (clicked_button==LEFT_SIDE)
1920
Display_paintbrush(x_pos,y_pos,color_index,0);
1922
Display_paintbrush(x_pos,y_pos,Back_color,0);
1937
//////////////////////////////////////////////////////////////////////////
1938
////////////////////////// GESTION DES DEGRADES //////////////////////////
1939
//////////////////////////////////////////////////////////////////////////
1942
// -- Gestion d'un d�grad� de base (le plus moche) --
1944
void Gradient_basic(long index,short x_pos,short y_pos)
1948
// On fait un premier calcul partiel
1949
position=(index*Gradient_bounds_range);
1951
// On g�re un d�placement au hasard
1952
position+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6;
1953
position-=(Gradient_total_range*Gradient_random_factor) >>7;
1955
position/=Gradient_total_range;
1957
// On va v�rifier que nos petites idioties n'ont pas �ject� la valeur hors
1958
// des valeurs autoris�es par le d�grad� d�fini par l'utilisateur.
1962
else if (position>=Gradient_bounds_range)
1963
position=Gradient_bounds_range-1;
1965
// On ram�ne ensuite la position dans le d�grad� vers un num�ro de couleur
1966
if (Gradient_is_inverted)
1967
Gradient_pixel(x_pos,y_pos,Gradient_upper_bound-position);
1969
Gradient_pixel(x_pos,y_pos,Gradient_lower_bound+position);
1973
// -- Gestion d'un d�grad� par trames simples --
1975
void Gradient_dithered(long index,short x_pos,short y_pos)
1977
long position_in_gradient;
1978
long position_in_segment;
1981
// But de l'op�ration: en plus de calculer la position de base (d�sign�e
1982
// dans cette proc�dure par "position_in_gradient", on calcule la position
1983
// de l'indice dans le sch�ma suivant:
1985
// | Les indices qui tra�nent de ce c�t� du segment se voient subir
1986
// | une incr�mentation conditionnelle � leur position dans l'�cran.
1988
// |---|---|---|---- - - -
1990
// |_ Les indices qui tra�nent de ce c�t� du segment se voient subir une
1991
// d�cr�mentation conditionnelle � leur position dans l'�cran.
1993
// On fait d'abord un premier calcul partiel
1994
position_in_gradient=(index*Gradient_bounds_range);
1996
// On g�re un d�placement au hasard...
1997
position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6;
1998
position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7;
2000
if (position_in_gradient<0)
2001
position_in_gradient=0;
2003
// ... qui nous permet de calculer la position dans le segment
2004
position_in_segment=((position_in_gradient<<2)/Gradient_total_range)&3;
2006
// On peut ensuite terminer le calcul de l'indice dans le d�grad�
2007
position_in_gradient/=Gradient_total_range;
2009
// On va pouvoir discuter de la valeur de position_in_gradient en fonction
2010
// de la position dans l'�cran et de la position_in_segment.
2012
switch (position_in_segment)
2014
case 0 : // On est sur la gauche du segment
2015
if (((x_pos+y_pos)&1)==0)
2016
position_in_gradient--;
2019
// On n'a pas � traiter les cas 1 et 2 car ils repr�sentent des valeurs
2020
// suffisament au centre du segment pour ne pas avoir � subir la trame
2022
case 3 : // On est sur la droite du segment
2023
if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 c�t�s de la trame.
2024
position_in_gradient++;
2027
// On va v�rifier que nos petites idioties n'ont pas �ject� la valeur hors
2028
// des valeurs autoris�es par le d�grad� d�fini par l'utilisateur.
2030
if (position_in_gradient<0)
2031
position_in_gradient=0;
2032
else if (position_in_gradient>=Gradient_bounds_range)
2033
position_in_gradient=Gradient_bounds_range-1;
2035
// On ram�ne ensuite la position dans le d�grad� vers un num�ro de couleur
2036
if (Gradient_is_inverted)
2037
position_in_gradient=Gradient_upper_bound-position_in_gradient;
2039
position_in_gradient=Gradient_lower_bound+position_in_gradient;
2041
Gradient_pixel(x_pos,y_pos,position_in_gradient);
2045
// -- Gestion d'un d�grad� par trames �tendues --
2047
void Gradient_extra_dithered(long index,short x_pos,short y_pos)
2049
long position_in_gradient;
2050
long position_in_segment;
2053
// But de l'op�ration: en plus de calculer la position de base (d�sign�e
2054
// dans cette proc�dure par "position_in_gradient", on calcule la position
2055
// de l'indice dans le sch�ma suivant:
2057
// | Les indices qui tra�nent de ce c�t� du segment se voient subir
2058
// | une incr�mentation conditionnelle � leur position dans l'�cran.
2060
// |---|---|---|---- - - -
2062
// |_ Les indices qui tra�nent de ce c�t� du segment se voient subir une
2063
// d�cr�mentation conditionnelle � leur position dans l'�cran.
2065
// On fait d'abord un premier calcul partiel
2066
position_in_gradient=(index*Gradient_bounds_range);
2068
// On g�re un d�placement au hasard
2069
position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6;
2070
position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7;
2072
if (position_in_gradient<0)
2073
position_in_gradient=0;
2075
// Qui nous permet de calculer la position dans le segment
2076
position_in_segment=((position_in_gradient<<3)/Gradient_total_range)&7;
2078
// On peut ensuite terminer le calcul de l'indice dans le d�grad�
2079
position_in_gradient/=Gradient_total_range;
2081
// On va pouvoir discuter de la valeur de position_in_gradient en fonction
2082
// de la position dans l'�cran et de la position_in_segment.
2084
switch (position_in_segment)
2086
case 0 : // On est sur l'extr�me gauche du segment
2087
if (((x_pos+y_pos)&1)==0)
2088
position_in_gradient--;
2091
case 1 : // On est sur la gauche du segment
2092
case 2 : // On est sur la gauche du segment
2093
if (((x_pos & 1)==0) && ((y_pos & 1)==0))
2094
position_in_gradient--;
2097
// On n'a pas � traiter les cas 3 et 4 car ils repr�sentent des valeurs
2098
// suffisament au centre du segment pour ne pas avoir � subir la trame
2100
case 5 : // On est sur la droite du segment
2101
case 6 : // On est sur la droite du segment
2102
if (((x_pos & 1)==0) && ((y_pos & 1)!=0))
2103
position_in_gradient++;
2106
case 7 : // On est sur l'extreme droite du segment
2107
if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 c�t�s de la trame.
2108
position_in_gradient++;
2111
// On va v�rifier que nos petites idioties n'ont pas �ject� la valeur hors
2112
// des valeurs autoris�es par le d�grad� d�fini par l'utilisateur.
2114
if (position_in_gradient<0)
2115
position_in_gradient=0;
2116
else if (position_in_gradient>=Gradient_bounds_range)
2117
position_in_gradient=Gradient_bounds_range-1;
2119
// On ram�ne ensuite la position dans le d�grad� vers un num�ro de couleur
2120
if (Gradient_is_inverted)
2121
position_in_gradient=Gradient_upper_bound-position_in_gradient;
2123
position_in_gradient=Gradient_lower_bound+position_in_gradient;
2125
Gradient_pixel(x_pos,y_pos,position_in_gradient);
2130
// -- Tracer un cercle degrad� (une sph�re) --
2132
void Draw_grad_circle(short center_x,short center_y,short radius,short spot_x,short spot_y)
2140
long distance_x; // Distance (au carr�) sur les X du point en cours au centre d'�clairage
2141
long distance_y; // Distance (au carr�) sur les Y du point en cours au centre d'�clairage
2143
start_x=center_x-radius;
2144
start_y=center_y-radius;
2145
end_x=center_x+radius;
2146
end_y=center_y+radius;
2148
// Correction des bornes d'apr�s les limites
2149
if (start_y<Limit_top)
2151
if (end_y>Limit_bottom)
2153
if (start_x<Limit_left)
2155
if (end_x>Limit_right)
2158
Gradient_total_range=Circle_limit+
2159
((center_x-spot_x)*(center_x-spot_x))+
2160
((center_y-spot_y)*(center_y-spot_y))+
2162
((center_x-spot_x)*(center_x-spot_x))+
2163
((center_y-spot_y)*(center_y-spot_y))));
2165
if (Gradient_total_range==0)
2166
Gradient_total_range=1;
2168
// Affichage du cercle
2169
for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++)
2171
distance_y =(y_pos-spot_y);
2172
distance_y*=distance_y;
2173
for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++)
2174
if (Pixel_in_circle())
2176
distance_x =(x_pos-spot_x);
2177
distance_x*=distance_x;
2178
Gradient_function(distance_x+distance_y,x_pos,y_pos);
2182
Update_part_of_screen(center_x-radius,center_y-radius,2*radius+1,2*radius+1);
2186
// -- Tracer une ellipse degrad�e --
2188
void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y)
2196
long distance_x; // Distance (au carr�) sur les X du point en cours au centre d'�clairage
2197
long distance_y; // Distance (au carr�) sur les Y du point en cours au centre d'�clairage
2200
start_x=center_x-horizontal_radius;
2201
start_y=center_y-vertical_radius;
2202
end_x=center_x+horizontal_radius;
2203
end_y=center_y+vertical_radius;
2205
// Calcul des limites de l'ellipse
2206
Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1);
2208
// On calcule la distance maximale:
2209
Gradient_total_range=(horizontal_radius*horizontal_radius)+
2210
(vertical_radius*vertical_radius)+
2211
((center_x-spot_x)*(center_x-spot_x))+
2212
((center_y-spot_y)*(center_y-spot_y))+
2215
(horizontal_radius*horizontal_radius)+
2216
(vertical_radius *vertical_radius ))
2218
((center_x-spot_x)*(center_x-spot_x))+
2219
((center_y-spot_y)*(center_y-spot_y))));
2221
if (Gradient_total_range==0)
2222
Gradient_total_range=1;
2224
// Correction des bornes d'apr�s les limites
2225
if (start_y<Limit_top)
2227
if (end_y>Limit_bottom)
2229
if (start_x<Limit_left)
2231
if (end_x>Limit_right)
2234
// Affichage de l'ellipse
2235
for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++)
2237
distance_y =(y_pos-spot_y);
2238
distance_y*=distance_y;
2239
for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++)
2240
if (Pixel_in_ellipse())
2242
distance_x =(x_pos-spot_x);
2243
distance_x*=distance_x;
2244
Gradient_function(distance_x+distance_y,x_pos,y_pos);
2248
Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1);
2252
// Trac� d'un rectangle (rax ray - rbx rby) d�grad� selon le vecteur (vax vay - vbx - vby)
2253
void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short vay, short vbx, short vby)
2257
// On commence par s'assurer que le rectangle est � l'endroit
2272
// Correction des bornes d'apr�s les limites
2275
if (rby>Limit_bottom)
2279
if (rbx>Limit_right)
2284
// Le vecteur est vertical, donc on �vite la partie en dessous qui foirerait avec une division par 0...
2285
if (vby == vay) return; // L'utilisateur fait n'importe quoi
2286
Gradient_total_range = abs(vby - vay);
2287
for(y_pos=ray;y_pos<=rby;y_pos++)
2288
for(x_pos=rax;x_pos<=rbx;x_pos++)
2289
Gradient_function(abs(vby - y_pos),x_pos,y_pos);
2296
float distance_x, distance_y;
2298
Gradient_total_range = sqrt(pow(vby - vay,2)+pow(vbx - vax,2));
2299
a = (float)(vby - vay)/(float)(vbx - vax);
2302
for (y_pos=ray;y_pos<=rby;y_pos++)
2303
for (x_pos = rax;x_pos<=rbx;x_pos++)
2305
// On calcule ou on en est dans le d�grad�
2306
distance_x = pow((y_pos - vay),2)+pow((x_pos - vax),2);
2307
distance_y = pow((-a * x_pos + y_pos - b),2)/(a*a+1);
2309
Gradient_function((int)sqrt(distance_x - distance_y),x_pos,y_pos);
2312
Update_part_of_screen(rax,ray,rbx,rby);
2318
// -- Tracer un polyg�ne plein --
2320
typedef struct T_Polygon_edge /* an active edge */
2322
short top; /* top y position */
2323
short bottom; /* bottom y position */
2324
float x, dx; /* floating point x position and gradient */
2325
float w; /* width of line segment */
2326
struct T_Polygon_edge *prev; /* doubly linked list */
2327
struct T_Polygon_edge *next;
2332
/* Fill_edge_structure:
2333
* Polygon helper function: initialises an edge structure for the 2d
2336
void Fill_edge_structure(T_Polygon_edge *edge, short *i1, short *i2)
2348
edge->bottom = i2[1] - 1;
2349
edge->dx = ((float) i2[0] - (float) i1[0]) / ((float) i2[1] - (float) i1[1]);
2350
edge->x = i1[0] + 0.4999999;
2354
if (edge->dx+1 < 0.0)
2355
edge->x += edge->dx+1;
2357
if (edge->dx >= 0.0)
2360
edge->w = -(edge->dx);
2362
if (edge->w-1.0<0.0)
2365
edge->w = edge->w-1;
2371
* Adds an edge structure to a linked list, returning the new head pointer.
2373
T_Polygon_edge * Add_edge(T_Polygon_edge *list, T_Polygon_edge *edge, int sort_by_x)
2375
T_Polygon_edge *pos = list;
2376
T_Polygon_edge *prev = NULL;
2380
while ( (pos) && ((pos->x+((pos->w+pos->dx)/2)) < (edge->x+((edge->w+edge->dx)/2))) )
2388
while ((pos) && (pos->top < edge->top))
2413
* Removes an edge structure from a list, returning the new head pointer.
2415
T_Polygon_edge * Remove_edge(T_Polygon_edge *list, T_Polygon_edge *edge)
2418
edge->next->prev = edge->prev;
2422
edge->prev->next = edge->next;
2432
* Draws a filled polygon with an arbitrary number of corners. Pass the
2433
* number of vertices, then an array containing a series of x, y points
2434
* (a total of vertices*2 values).
2436
void Polyfill_general(int vertices, short * points, int color)
2443
T_Polygon_edge *edge, *next_edge, *initial_edge;
2444
T_Polygon_edge *active_edges = NULL;
2445
T_Polygon_edge *inactive_edges = NULL;
2447
/* allocate some space and fill the edge table */
2448
initial_edge=edge=(T_Polygon_edge *) malloc(sizeof(T_Polygon_edge) * vertices);
2451
i2 = points + ((vertices-1)<<1);
2453
for (c=0; c<vertices; c++)
2457
Fill_edge_structure(edge, i1, i2);
2459
if (edge->bottom >= edge->top)
2461
if (edge->top < top)
2464
if (edge->bottom > bottom)
2465
bottom = edge->bottom;
2467
inactive_edges = Add_edge(inactive_edges, edge, 0);
2475
/* for each scanline in the polygon... */
2476
for (c=top; c<=bottom; c++)
2478
/* check for newly active edges */
2479
edge = inactive_edges;
2480
while ((edge) && (edge->top == c))
2482
next_edge = edge->next;
2483
inactive_edges = Remove_edge(inactive_edges, edge);
2484
active_edges = Add_edge(active_edges, edge, 1);
2488
/* draw horizontal line segments */
2489
if ((c>=Limit_top) && (c<=Limit_bottom))
2491
edge = active_edges;
2492
while ((edge) && (edge->next))
2494
x_pos=/*Round*/(edge->x);
2495
end_x=/*Round*/(edge->next->x+edge->next->w);
2496
if (x_pos<Limit_left)
2498
if (end_x>Limit_right)
2500
for (; x_pos<=end_x; x_pos++)
2501
Pixel_figure(x_pos,c,color);
2502
edge = edge->next->next;
2506
/* update edges, sorting and removing dead ones */
2507
edge = active_edges;
2510
next_edge = edge->next;
2511
if (c >= edge->bottom)
2512
active_edges = Remove_edge(active_edges, edge);
2515
edge->x += edge->dx;
2516
while ((edge->prev) && ( (edge->x+(edge->w/2)) < (edge->prev->x+(edge->prev->w/2))) )
2519
edge->next->prev = edge->prev;
2520
edge->prev->next = edge->next;
2521
edge->next = edge->prev;
2522
edge->prev = edge->prev->prev;
2523
edge->next->prev = edge;
2525
edge->prev->next = edge;
2527
active_edges = edge;
2535
initial_edge = NULL;
2537
// On ne connait pas simplement les xmin et xmax ici, mais de toutes fa�on ce n'est pas utilis� en preview
2538
Update_part_of_screen(0,top,Main_image_width,bottom-top+1);
2542
void Polyfill(int vertices, short * points, int color)
2546
Pixel_clipped(points[0],points[1],color);
2549
Update_part_of_screen(points[0],points[1],1,1);
2553
// Comme pour le Fill, cette operation fait un peu d'"overdraw"
2554
// (pixels dessin�s plus d'une fois) alors on force le FX Feedback � OFF
2555
Update_FX_feedback(0);
2557
Pixel_figure=Pixel_clipped;
2558
Polyfill_general(vertices,points,color);
2560
// Remarque: pour dessiner la bordure avec la brosse en cours au lieu
2561
// d'un pixel de couleur premier-plan, il suffit de mettre ici:
2562
// Pixel_figure=Pixel_figure_permanent;
2564
// Dessin du contour
2565
for (index=0; index<vertices-1;index+=1)
2566
Draw_line_general(points[index*2],points[index*2+1],points[index*2+2],points[index*2+3],color);
2567
Draw_line_general(points[0],points[1],points[index*2],points[index*2+1],color);
2569
// Restore original feedback value
2570
Update_FX_feedback(Config.FX_Feedback);
2576
//------------ Remplacement de la couleur point�e par une autre --------------
2578
void Replace(byte New_color)
2582
if ((Paintbrush_X<Main_image_width)
2583
&& (Paintbrush_Y<Main_image_height))
2585
old_color=Read_pixel_from_current_layer(Paintbrush_X,Paintbrush_Y);
2586
if ( (old_color!=New_color)
2587
&& ((!Stencil_mode) || (!Stencil[old_color])) )
2589
Replace_a_color(old_color,New_color);
2590
Display_all_screen();
2597
/******************************************************************************/
2598
/********************************** SHADES ************************************/
2600
// Transformer une liste de shade en deux tables de conversion
2601
void Shade_list_to_lookup_tables(word * list,short step,byte mode,byte * table_inc,byte * table_dec)
2610
// On initialise les deux tables de conversion en Identit�
2611
for (index=0;index<256;index++)
2613
table_inc[index]=index;
2614
table_dec[index]=index;
2617
// On s'appr�te � examiner l'ensemble de la liste
2618
for (index=0;index<512;index++)
2620
// On recherche la premi�re case de la liste non vide (et non inhib�e)
2621
while ((index<512) && (list[index]>255))
2624
// On note la position de la premi�re case de la s�quence
2627
// On recherche la position de la derni�re case de la s�quence
2628
for (last=first;list[last+1]<256;last++);
2630
// Pour toutes les cases non vides (et non inhib�es) qui suivent
2633
case SHADE_MODE_NORMAL :
2634
for (;(index<512) && (list[index]<256);index++)
2635
{ // On met � jour les tables de conversion
2637
table_inc[color]=list[(index+step<=last)?index+step:last];
2638
table_dec[color]=list[(index-step>=first)?index-step:first];
2641
case SHADE_MODE_LOOP :
2643
for (;(index<512) && (list[index]<256);index++)
2644
{ // On met � jour les tables de conversion
2646
table_inc[color]=list[first+((step+index-first)%temp)];
2647
table_dec[color]=list[first+(((temp-step)+index-first)%temp)];
2650
default : // SHADE_MODE_NOSAT
2651
for (;(index<512) && (list[index]<256);index++)
2652
{ // On met � jour les tables de conversion
2654
if (index+step<=last)
2655
table_inc[color]=list[index+step];
2656
if (index-step>=first)
2657
table_dec[color]=list[index-step];
2665
// -- Interface avec l'image, affect�e par le facteur de grossissement -------
2667
// fonction d'affichage "Pixel" utilis�e pour les op�rations d�finitivement
2668
// Ne doit � aucune condition �tre appel�e en dehors de la partie visible
2669
// de l'image dans l'�cran (�a pourrait �tre grave)
2670
void Display_pixel(word x,word y,byte color)
2671
// x & y sont la position d'un point dans l'IMAGE
2672
// color est la couleur du point
2673
// Le Stencil est g�r�.
2674
// Les effets sont g�r�s par appel � Effect_function().
2675
// La Loupe est g�r�e par appel � Pixel_preview().
2677
if ( ( (!Sieve_mode) || (Effect_sieve(x,y)) )
2678
&& (!((Stencil_mode) && (Stencil[Read_pixel_from_current_layer(x,y)])))
2679
&& (!((Mask_mode) && (Mask_table[Read_pixel_from_spare_screen(x,y)]))) )
2681
color=Effect_function(x,y,color);
2682
Pixel_in_current_screen(x,y,color,1);
2688
// -- Calcul des diff�rents effets -------------------------------------------
2690
// -- Aucun effet en cours --
2692
byte No_effect(__attribute__((unused)) word x,__attribute__((unused)) word y,byte color)
2697
// -- Effet de Shading --
2699
byte Effect_shade(word x,word y,__attribute__((unused)) byte color)
2701
return Shade_table[Read_pixel_from_feedback_screen(x,y)];
2704
byte Effect_quick_shade(word x,word y,byte color)
2706
int c=color=Read_pixel_from_feedback_screen(x,y);
2707
int direction=(Fore_color<=Back_color);
2722
if ((c>=start) && (c<=end) && (start!=end))
2726
if ( ((Shade_table==Shade_table_left) && direction) || ((Shade_table==Shade_table_right) && (!direction)) )
2727
c-=Quick_shade_step%width;
2729
c+=Quick_shade_step%width;
2732
switch (Quick_shade_loop)
2734
case SHADE_MODE_NORMAL : return start;
2735
case SHADE_MODE_LOOP : return (width+c);
2736
default : return color;
2740
switch (Quick_shade_loop)
2742
case SHADE_MODE_NORMAL : return end;
2743
case SHADE_MODE_LOOP : return (c-width);
2744
default : return color;
2751
// -- Effet de Tiling --
2753
byte Effect_tiling(word x,word y,__attribute__((unused)) byte color)
2755
return Read_pixel_from_brush((x+Brush_width-Tiling_offset_X)%Brush_width,
2756
(y+Brush_height-Tiling_offset_Y)%Brush_height);
2759
// -- Effet de Smooth --
2761
byte Effect_smooth(word x,word y,__attribute__((unused)) byte color)
2765
int weight,total_weight;
2766
byte x2=((x+1)<Main_image_width);
2767
byte y2=((y+1)<Main_image_height);
2769
// On commence par le pixel central
2770
c=Read_pixel_from_feedback_screen(x,y);
2771
total_weight=Smooth_matrix[1][1];
2772
r=total_weight*Main_palette[c].R;
2773
g=total_weight*Main_palette[c].G;
2774
b=total_weight*Main_palette[c].B;
2778
c=Read_pixel_from_feedback_screen(x-1,y);
2779
total_weight+=(weight=Smooth_matrix[0][1]);
2780
r+=weight*Main_palette[c].R;
2781
g+=weight*Main_palette[c].G;
2782
b+=weight*Main_palette[c].B;
2786
c=Read_pixel_from_feedback_screen(x-1,y-1);
2787
total_weight+=(weight=Smooth_matrix[0][0]);
2788
r+=weight*Main_palette[c].R;
2789
g+=weight*Main_palette[c].G;
2790
b+=weight*Main_palette[c].B;
2794
c=Read_pixel_from_feedback_screen(x-1,y+1);
2795
total_weight+=(weight=Smooth_matrix[0][2]);
2796
r+=weight*Main_palette[c].R;
2797
g+=weight*Main_palette[c].G;
2798
b+=weight*Main_palette[c].B;
2805
c=Read_pixel_from_feedback_screen(x+1,y);
2806
total_weight+=(weight=Smooth_matrix[2][1]);
2807
r+=weight*Main_palette[c].R;
2808
g+=weight*Main_palette[c].G;
2809
b+=weight*Main_palette[c].B;
2813
c=Read_pixel_from_feedback_screen(x+1,y-1);
2814
total_weight+=(weight=Smooth_matrix[2][0]);
2815
r+=weight*Main_palette[c].R;
2816
g+=weight*Main_palette[c].G;
2817
b+=weight*Main_palette[c].B;
2821
c=Read_pixel_from_feedback_screen(x+1,y+1);
2822
total_weight+=(weight=Smooth_matrix[2][2]);
2823
r+=weight*Main_palette[c].R;
2824
g+=weight*Main_palette[c].G;
2825
b+=weight*Main_palette[c].B;
2832
c=Read_pixel_from_feedback_screen(x,y-1);
2833
total_weight+=(weight=Smooth_matrix[1][0]);
2834
r+=weight*Main_palette[c].R;
2835
g+=weight*Main_palette[c].G;
2836
b+=weight*Main_palette[c].B;
2841
c=Read_pixel_from_feedback_screen(x,y+1);
2842
total_weight+=(weight=Smooth_matrix[1][2]);
2843
r+=weight*Main_palette[c].R;
2844
g+=weight*Main_palette[c].G;
2845
b+=weight*Main_palette[c].B;
2848
return (total_weight)? // On regarde s'il faut �viter le 0/0.
2849
Best_color(Round_div(r,total_weight),
2850
Round_div(g,total_weight),
2851
Round_div(b,total_weight)):
2852
Read_pixel_from_current_screen(x,y); // C'est bien l'�cran courant et pas
2853
// l'�cran feedback car il s'agit de ne
2854
} // pas modifier l'�cran courant.
2856
void Horizontal_grid_line(word x_pos,word y_pos,word width)
2860
for (x=!(x_pos&1);x<width;x+=2)
2861
Pixel(x_pos+x, y_pos, *((y_pos-1)*Pixel_height*VIDEO_LINE_WIDTH+x_pos*Pixel_width+Screen_pixels+x*Pixel_width)^Config.Grid_XOR_color);
2864
void Vertical_grid_line(word x_pos,word y_pos,word height)
2868
for (y=!(y_pos&1);y<height;y+=2)
2869
Pixel(x_pos, y_pos+y, *(Screen_pixels+(x_pos*Pixel_width-1)+(y_pos*Pixel_height+y*Pixel_height)*VIDEO_LINE_WIDTH)^Config.Grid_XOR_color);
2873
void Redraw_grid(short x, short y, unsigned short w, unsigned short h)
2879
row=y+((Snap_height*1000-(y-0)/Main_magnifier_factor-Main_magnifier_offset_Y+Snap_offset_Y-1)%Snap_height)*Main_magnifier_factor+Main_magnifier_factor-1;
2882
Horizontal_grid_line(x, row, w);
2883
row+= Snap_height*Main_magnifier_factor;
2886
col=x+((Snap_width*1000-(x-Main_X_zoom)/Main_magnifier_factor-Main_magnifier_offset_X+Snap_offset_X-1)%Snap_width)*Main_magnifier_factor+Main_magnifier_factor-1;
2889
Vertical_grid_line(col, y, h);
2890
col+= Snap_width*Main_magnifier_factor;
2894
byte Read_pixel_from_current_screen (word x,word y)
2899
color = *(Main_screen+y*Main_image_width+x);
2900
if (color != Main_backups->Pages->Transparent_color) // transparent color
2903
depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width);
2904
return *(Main_backups->Pages->Image[depth] + x+y*Main_image_width);
2906
return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]);
2910
void Pixel_in_current_screen (word x,word y,byte color,int with_preview)
2913
byte depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width);
2914
*(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color;
2915
if ( depth <= Main_current_layer)
2917
if (color == Main_backups->Pages->Transparent_color) // transparent color
2918
// fetch pixel color from the topmost visible layer
2919
color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width);
2921
*(x+y*Main_image_width+Main_screen)=color;
2924
Pixel_preview(x,y,color);
2927
*((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color;
2929
Pixel_preview(x,y,color);
2933
void Pixel_in_current_layer(word x,word y, byte color)
2935
*((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color;
2938
byte Read_pixel_from_current_layer(word x,word y)
2940
return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]);