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 #include <stdlib.h>
21 #include <string.h>
22 #include "const.h"
23 #include "struct.h"
24 #include "global.h"
25 #include "graph.h"
26 #include "engine.h"
27 #include "windows.h"
28 #include "special.h"
29 #include "pages.h"
30 #include "misc.h"
31 #include "osdep.h"
32 #include "buttons.h"
33
34
35
36
37
38 //---------------------- Modifier le pinceau spécial -------------------------
39
Set_paintbrush_size(int width,int height)40 void Set_paintbrush_size(int width, int height)
41 {
42 int x_pos,y_pos;
43 int x,y;
44 int radius2;
45
46 if (width<1) width=1;
47 if (height<1) height=1;
48 if (width>MAX_PAINTBRUSH_SIZE) width=MAX_PAINTBRUSH_SIZE;
49 if (height>MAX_PAINTBRUSH_SIZE) height=MAX_PAINTBRUSH_SIZE;
50 Paintbrush_width=width;
51 Paintbrush_height=height;
52 Paintbrush_offset_X=Paintbrush_width>>1;
53 Paintbrush_offset_Y=Paintbrush_height>>1;
54 switch (Paintbrush_shape)
55 {
56 case PAINTBRUSH_SHAPE_ROUND :
57 radius2=Circle_squared_diameter(Paintbrush_width);
58
59 for (y_pos=0, y=1-Paintbrush_height; y_pos<Paintbrush_height; y_pos++,y+=2)
60 for (x_pos=0, x=1-Paintbrush_width; x_pos<Paintbrush_width; x_pos++,x+=2)
61 {
62 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=( ((x*x)+(y*y)) <= radius2 );
63 }
64 break;
65 case PAINTBRUSH_SHAPE_SQUARE :
66 for (x_pos=0,y_pos=0; x_pos<Paintbrush_height; x_pos++,y_pos+=MAX_PAINTBRUSH_SIZE)
67 memset(Paintbrush_sprite+y_pos,1,Paintbrush_width);
68 break;
69 case PAINTBRUSH_SHAPE_SIEVE_ROUND :
70 {
71 int reminder=0;
72 if (Paintbrush_width==1)
73 reminder = 1;
74
75 radius2=Circle_squared_diameter(Paintbrush_width);
76
77 for (y_pos=0, y=1-Paintbrush_height; y_pos<Paintbrush_height; y_pos++,y+=2)
78 for (x_pos=0, x=1-Paintbrush_width; x_pos<Paintbrush_width; x_pos++,x+=2)
79 {
80 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=( ((x_pos+y_pos+reminder)&1) && (((x*x)+(y*y)) < radius2));
81 }
82 break;
83 }
84 case PAINTBRUSH_SHAPE_SIEVE_SQUARE:
85 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
86 for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
87 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=!((x_pos+y_pos)&1);
88 break;
89 case PAINTBRUSH_SHAPE_PLUS:
90 x=Paintbrush_width>>1;
91 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
92 for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
93 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=((x_pos==x) || (y_pos==x));
94 break;
95 case PAINTBRUSH_SHAPE_SLASH:
96 x=Paintbrush_width>>1;
97 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
98 for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
99 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=(x_pos==(Paintbrush_width-(y_pos+1)));
100 break;
101 case PAINTBRUSH_SHAPE_ANTISLASH:
102 x=Paintbrush_width>>1;
103 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
104 for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
105 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=(x_pos==y_pos);
106 break;
107 case PAINTBRUSH_SHAPE_HORIZONTAL_BAR:
108 memset(Paintbrush_sprite,1,Paintbrush_width);
109 break;
110 case PAINTBRUSH_SHAPE_VERTICAL_BAR:
111 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
112 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)]=1;
113 break;
114 case PAINTBRUSH_SHAPE_CROSS:
115 x=Paintbrush_width>>1;
116 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
117 for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
118 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=( (x_pos==y_pos) || (x_pos==(Paintbrush_height-(y_pos+1))) );
119 break;
120 case PAINTBRUSH_SHAPE_DIAMOND:
121 x=Paintbrush_width>>1;
122 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
123 for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
124 {
125 if (x_pos<=x)
126 y=x-x_pos;
127 else
128 y=x_pos-x;
129 if (y_pos<=x)
130 y+=x-y_pos;
131 else
132 y+=y_pos-x;
133 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=(y<=x);
134 }
135 break;
136 case PAINTBRUSH_SHAPE_RANDOM:
137 // Init with blank
138 for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
139 memset(Paintbrush_sprite+y_pos*MAX_PAINTBRUSH_SIZE,0,Paintbrush_width);
140
141 radius2=Circle_squared_diameter(Paintbrush_width);
142
143 for (y_pos=0, y=1-Paintbrush_height; y_pos<Paintbrush_height; y_pos++,y+=2)
144 for (x_pos=0, x=1-Paintbrush_width; x_pos<Paintbrush_width; x_pos++,x+=2)
145 {
146 if ((x*x)+(y*y) < radius2 && !(rand()&7))
147 {
148 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=1;
149 // This prevents having a pixels that touch each other.
150 if (x_pos>0)
151 Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos-1]=0;
152 if (y_pos>0)
153 Paintbrush_sprite[((y_pos-1)*MAX_PAINTBRUSH_SIZE)+x_pos]=0;
154 }
155 }
156 }
157 }
158
Smaller_paintbrush(void)159 void Smaller_paintbrush(void)
160 {
161 if ( (Paintbrush_shape<PAINTBRUSH_SHAPE_MISC)
162 && ( (Paintbrush_width>1)
163 || (Paintbrush_height>1) ) )
164 {
165 Hide_cursor();
166 switch (Paintbrush_shape)
167 {
168 case PAINTBRUSH_SHAPE_CROSS:
169 case PAINTBRUSH_SHAPE_PLUS:
170 case PAINTBRUSH_SHAPE_DIAMOND:
171 if (Paintbrush_width&1)
172 Set_paintbrush_size(Paintbrush_width-2,Paintbrush_height-2);
173 else
174 Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1);
175 break;
176 case PAINTBRUSH_SHAPE_SQUARE:
177 case PAINTBRUSH_SHAPE_SLASH:
178 case PAINTBRUSH_SHAPE_ANTISLASH:
179 case PAINTBRUSH_SHAPE_SIEVE_SQUARE:
180 case PAINTBRUSH_SHAPE_ROUND:
181 case PAINTBRUSH_SHAPE_SIEVE_ROUND:
182 case PAINTBRUSH_SHAPE_RANDOM:
183 Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1);
184 break;
185 case PAINTBRUSH_SHAPE_HORIZONTAL_BAR:
186 Set_paintbrush_size(Paintbrush_width-1,1);
187 break;
188 case PAINTBRUSH_SHAPE_VERTICAL_BAR:
189 Set_paintbrush_size(1,Paintbrush_height-1);
190 }
191 Display_paintbrush_in_menu();
192 Display_cursor();
193 }
194 }
195
Bigger_paintbrush(void)196 void Bigger_paintbrush(void)
197 {
198 if ( (Paintbrush_shape<PAINTBRUSH_SHAPE_MISC)
199 && ( (Paintbrush_width<MAX_PAINTBRUSH_SIZE)
200 || (Paintbrush_height<MAX_PAINTBRUSH_SIZE) ) )
201 {
202 Hide_cursor();
203 switch (Paintbrush_shape)
204 {
205 case PAINTBRUSH_SHAPE_CROSS:
206 case PAINTBRUSH_SHAPE_PLUS:
207 case PAINTBRUSH_SHAPE_DIAMOND:
208 if (Paintbrush_width&1)
209 Set_paintbrush_size(Paintbrush_width+2,Paintbrush_height+2);
210 else
211 Set_paintbrush_size(Paintbrush_width+1,Paintbrush_height+1);
212 break;
213 case PAINTBRUSH_SHAPE_SQUARE:
214 case PAINTBRUSH_SHAPE_SLASH:
215 case PAINTBRUSH_SHAPE_ANTISLASH:
216 case PAINTBRUSH_SHAPE_SIEVE_SQUARE:
217 case PAINTBRUSH_SHAPE_ROUND:
218 case PAINTBRUSH_SHAPE_SIEVE_ROUND:
219 case PAINTBRUSH_SHAPE_RANDOM:
220 Set_paintbrush_size(Paintbrush_width+1,Paintbrush_height+1);
221 break;
222 case PAINTBRUSH_SHAPE_HORIZONTAL_BAR:
223 Set_paintbrush_size(Paintbrush_width+1,1);
224 break;
225 case PAINTBRUSH_SHAPE_VERTICAL_BAR:
226 Set_paintbrush_size(1,Paintbrush_height+1);
227 }
228 Display_paintbrush_in_menu();
229 Display_cursor();
230 }
231 }
232
233
234 //--------------------- Increase the ForeColor -----------------------
Special_next_forecolor(void)235 void Special_next_forecolor(void)
236 {
237 Hide_cursor();
238 Set_fore_color(Fore_color+1);
239 Display_cursor();
240 }
241
242 //--------------------- Decrease the ForeColor -----------------------
Special_previous_forecolor(void)243 void Special_previous_forecolor(void)
244 {
245 Hide_cursor();
246 Set_fore_color(Fore_color-1);
247 Display_cursor();
248 }
249
250 //--------------------- Increase the BackColor -----------------------
Special_next_backcolor(void)251 void Special_next_backcolor(void)
252 {
253 Hide_cursor();
254 Set_back_color(Back_color+1);
255 Display_cursor();
256 }
257
258 //--------------------- Decrease the BackColor -----------------------
Special_previous_backcolor(void)259 void Special_previous_backcolor(void)
260 {
261 Hide_cursor();
262 Set_back_color(Back_color-1);
263 Display_cursor();
264 }
265
266 /// Picks the next foreground color, according to current shade table
Special_next_user_forecolor(void)267 void Special_next_user_forecolor(void)
268 {
269 Hide_cursor();
270 Set_fore_color(Shade_table_left[Fore_color]);
271 Display_cursor();
272 }
273
274 /// Picks the previous foreground color, according to current shade table
Special_previous_user_forecolor(void)275 void Special_previous_user_forecolor(void)
276 {
277 Hide_cursor();
278 Set_fore_color(Shade_table_right[Fore_color]);
279 Display_cursor();
280 }
281
282 /// Picks the next background color, according to current shade table
Special_next_user_backcolor(void)283 void Special_next_user_backcolor(void)
284 {
285 Hide_cursor();
286 Set_back_color(Shade_table_left[Back_color]);
287 Display_cursor();
288 }
289
290 /// Picks the previous background color, according to current shade table
Special_previous_user_backcolor(void)291 void Special_previous_user_backcolor(void)
292 {
293 Hide_cursor();
294 Set_back_color(Shade_table_right[Back_color]);
295 Display_cursor();
296 }
297
298 // ------------------- Scroller l'écran (pas en mode loupe) ------------------
Scroll_screen(short delta_x,short delta_y)299 void Scroll_screen(short delta_x,short delta_y)
300 {
301 short temp_x_offset;
302 short temp_y_offset;
303
304 temp_x_offset=Main.offset_X+delta_x;
305 temp_y_offset=Main.offset_Y+delta_y;
306
307 if (temp_x_offset+Screen_width>Main.image_width)
308 temp_x_offset=Main.image_width-Screen_width;
309 if (temp_y_offset+Menu_Y>Main.image_height)
310 temp_y_offset=Main.image_height-Menu_Y;
311 if (temp_x_offset<0)
312 temp_x_offset=0;
313 if (temp_y_offset<0)
314 temp_y_offset=0;
315
316 if ( (Main.offset_X!=temp_x_offset) ||
317 (Main.offset_Y!=temp_y_offset) )
318 {
319 Hide_cursor();
320 Main.offset_X=temp_x_offset;
321 Main.offset_Y=temp_y_offset;
322
323 Compute_limits();
324 Compute_paintbrush_coordinates();
325
326 Display_all_screen(); // <=> Display_screen + Display_image_limits
327 Display_cursor();
328 }
329 }
330
331
332 // ---------------------- Scroller la fenêtre de la loupe --------------------
Scroll_magnifier(short delta_x,short delta_y)333 void Scroll_magnifier(short delta_x,short delta_y)
334 {
335 short temp_x_offset;
336 short temp_y_offset;
337
338 temp_x_offset=Main.magnifier_offset_X+delta_x;
339 temp_y_offset=Main.magnifier_offset_Y+delta_y;
340
341 Clip_magnifier_offsets(&temp_x_offset, &temp_y_offset);
342
343 if ( (Main.magnifier_offset_X!=temp_x_offset) ||
344 (Main.magnifier_offset_Y!=temp_y_offset) )
345 {
346 Hide_cursor();
347 Main.magnifier_offset_X=temp_x_offset;
348 Main.magnifier_offset_Y=temp_y_offset;
349
350 Position_screen_according_to_zoom();
351
352 Compute_limits();
353 Compute_paintbrush_coordinates();
354
355 Display_all_screen();
356 Display_cursor();
357 }
358 }
359
360
361 // -------------- Changer le Zoom (grâce aux touches [+] et [-]) -------------
Zoom(short delta)362 void Zoom(short delta)
363 {
364 short index;
365 for (index=0; ZOOM_FACTOR[index]!=Main.magnifier_factor; index++);
366 index+=delta;
367
368 if ( (index>=0) && (index<NB_ZOOM_FACTORS) )
369 {
370 Hide_cursor();
371 Change_magnifier_factor(index,1);
372 if (Main.magnifier_mode)
373 Display_all_screen();
374 Display_cursor();
375 }
376 }
377
378 /**
379 Set zoom value. Negative value means no zoom.
380 */
Zoom_set(int index)381 void Zoom_set(int index)
382 {
383 Hide_cursor();
384 if (index<0)
385 {
386 /* Zoom 1:1 */
387 if (Main.magnifier_mode)
388 Unselect_button(BUTTON_MAGNIFIER);
389 }
390 else
391 {
392 Change_magnifier_factor(index,1);
393 if (!Main.magnifier_mode)
394 Select_button(BUTTON_MAGNIFIER,1);
395 Display_all_screen();
396 }
397 Display_cursor();
398 }
399
Transparency_set(byte amount)400 void Transparency_set(byte amount)
401 {
402 const int doubleclick_delay = Config.Double_key_speed;
403 static long time_click = 0;
404 long time_previous;
405
406 if (!Colorize_mode)
407 {
408 // Activate mode
409 switch(Colorize_current_mode)
410 {
411 case 0 :
412 Effect_function=Effect_interpolated_colorize;
413 break;
414 case 1 :
415 Effect_function=Effect_additive_colorize;
416 break;
417 case 2 :
418 Effect_function=Effect_substractive_colorize;
419 break;
420 case 3 :
421 Effect_function=Effect_alpha_colorize;
422 }
423 Shade_mode=0;
424 Quick_shade_mode=0;
425 Smooth_mode=0;
426 Tiling_mode=0;
427
428 Colorize_mode=1;
429 }
430
431 time_previous = time_click;
432 time_click = GFX2_GetTicks();
433
434 // Check if it's a quick re-press
435 if (time_click - time_previous < doubleclick_delay)
436 {
437 // Use the typed amount as units, keep the tens.
438 Colorize_opacity = ((Colorize_opacity%100) /10 *10) + amount;
439 if (Colorize_opacity == 0)
440 Colorize_opacity = 100;
441 }
442 else
443 {
444 // Use 10% units: "1"=10%, ... "0"=100%
445 if (amount == 0)
446 Colorize_opacity = 100;
447 else
448 Colorize_opacity = amount*10;
449 }
450 Compute_colorize_table();
451 }
452
453
454