~ubuntu-branches/ubuntu/maverick/grafx2/maverick

« back to all changes in this revision

Viewing changes to src/graph.c

  • Committer: Bazaar Package Importer
  • Author(s): Gürkan Sengün
  • Date: 2010-03-22 12:07:47 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20100322120747-g0jel6vf6mjkc53s
Tags: 2.2-1
* New upstream version, fixes FTBFS with binutils-gold. (Closes: #554742)
* Bump standards version to 3.8.4.
* debian/control: Add liblua5.1-0-dev and pkg-config to build depends.
* debian/rules: Drop dh_desktop call.
* debian/copyright: Update years.
* Switch to dpkg-source format version 3.0 (quilt).
* debian/watch: Added.
* Added patch to fix spelling errors in source code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim:expandtab:ts=2 sw=2:
 
2
*/
 
3
/*  Grafx2 - The Ultimate 256-color bitmap paint program
 
4
 
 
5
    Copyright 2008 Franck Charlet
 
6
    Copyright 2007 Adrien Destugues
 
7
    Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
 
8
 
 
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
 
12
    of the License.
 
13
 
 
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.
 
18
 
 
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/>
 
21
 
 
22
********************************************************************************
 
23
 
 
24
    Drawing functions and effects.
 
25
 
 
26
*/
 
27
 
 
28
#include <string.h>
 
29
#include <stdlib.h>
 
30
#include <math.h>
 
31
 
 
32
#include "global.h"
 
33
#include "struct.h"
 
34
#include "engine.h"
 
35
#include "buttons.h"
 
36
#include "pages.h"
 
37
#include "errors.h"
 
38
#include "sdlscreen.h"
 
39
#include "graph.h"
 
40
#include "misc.h"
 
41
#include "pxsimple.h"
 
42
#include "pxtall.h"
 
43
#include "pxwide.h"
 
44
#include "pxdouble.h"
 
45
#include "pxtriple.h"
 
46
#include "pxwide2.h"
 
47
#include "pxtall2.h"
 
48
#include "pxquad.h"
 
49
#include "windows.h"
 
50
#include "input.h"
 
51
 
 
52
#ifdef __VBCC__
 
53
    #define __attribute__(x)
 
54
#endif
 
55
 
 
56
#if defined(__VBCC__)||defined(__GP2X__)
 
57
    #define M_PI 3.141592653589793238462643
 
58
#endif
 
59
 
 
60
// Generic pixel-drawing function.
 
61
Func_pixel Pixel_figure;
 
62
 
 
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)
 
66
{
 
67
  short effective_w, effective_h;
 
68
  short effective_X;
 
69
  short effective_Y;
 
70
  short diff;
 
71
 
 
72
  // Premi�re �tape, si L ou H est n�gatif, on doit remettre la zone � l'endroit
 
73
  if (width < 0)
 
74
  {
 
75
    x += width;
 
76
    width = - width;
 
77
  }
 
78
 
 
79
  if (height < 0)
 
80
  {
 
81
    y += height;
 
82
    height = - height;
 
83
  }
 
84
 
 
85
  // D'abord on met � jour dans la zone �cran normale
 
86
  diff = x-Main_offset_X;
 
87
  if (diff<0)
 
88
  {
 
89
    effective_w = width + diff;
 
90
    effective_X = 0;
 
91
  }
 
92
  else
 
93
  {
 
94
    effective_w = width;
 
95
    effective_X = diff;
 
96
  }
 
97
  diff = y-Main_offset_Y;
 
98
  if (diff<0)
 
99
  {
 
100
    effective_h = height + diff;
 
101
    effective_Y = 0;
 
102
  }
 
103
  else
 
104
  {
 
105
    effective_h = height;
 
106
    effective_Y = diff;
 
107
  }
 
108
 
 
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;
 
117
 
 
118
  if(effective_Y + effective_h > Menu_Y)
 
119
    effective_h = Menu_Y - effective_Y;
 
120
    
 
121
  /*
 
122
  SDL_Rect r;
 
123
  r.x=effective_X;
 
124
  r.y=effective_Y;
 
125
  r.h=effective_h;
 
126
  r.w=effective_w;
 
127
  SDL_FillRect(Screen_SDL,&r,3);
 
128
  */
 
129
  Update_rect(effective_X,effective_Y,effective_w,effective_h);
 
130
 
 
131
  // Et ensuite dans la partie zoom�e
 
132
  if(Main_magnifier_mode)
 
133
  {
 
134
    // Clipping en X
 
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;
 
139
 
 
140
    if (effective_X < 0)
 
141
    {
 
142
      effective_w+=effective_X;
 
143
      if (effective_w<0)
 
144
        return;
 
145
 
 
146
      effective_X = Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X;
 
147
    }
 
148
    else
 
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);
 
151
    if (diff>0)
 
152
    {
 
153
      effective_w -=diff;
 
154
      if (effective_w<0)
 
155
        return;
 
156
    }
 
157
 
 
158
 
 
159
    // Clipping en Y
 
160
    if (effective_Y < 0)
 
161
    {
 
162
      effective_h+=effective_Y;
 
163
      if (effective_h<0)
 
164
        return;
 
165
      effective_Y = 0;
 
166
    }
 
167
    diff = effective_Y+effective_h-Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor);
 
168
    if (diff>0)
 
169
    {
 
170
      effective_h -=diff;
 
171
      if (effective_h<0)
 
172
        return;
 
173
    }
 
174
 
 
175
 
 
176
 // Tr�s utile pour le debug :)
 
177
    /*SDL_Rect r;
 
178
    r.x=effective_X;
 
179
    r.y=effective_Y;
 
180
    r.h=effective_h;
 
181
    r.w=effective_w;
 
182
    SDL_FillRect(Screen_SDL,&r,3);*/
 
183
 
 
184
    Redraw_grid(effective_X,effective_Y,effective_w,effective_h);
 
185
    Update_rect(effective_X,effective_Y,effective_w,effective_h);
 
186
  }
 
187
}
 
188
 
 
189
 
 
190
 
 
191
void Transform_point(short x, short y, float cos_a, float sin_a,
 
192
                       short * rx, short * ry)
 
193
{
 
194
  *rx=Round(((float)x*cos_a)+((float)y*sin_a));
 
195
  *ry=Round(((float)y*cos_a)-((float)x*sin_a));
 
196
}
 
197
 
 
198
 
 
199
//--------------------- Initialisation d'un mode vid�o -----------------------
 
200
 
 
201
int Init_mode_video(int width, int height, int fullscreen, int pix_ratio)
 
202
{
 
203
  int index;
 
204
  int factor;
 
205
  int pix_width;
 
206
  int pix_height;
 
207
  byte screen_changed;
 
208
  byte pixels_changed;
 
209
  int absolute_mouse_x=Mouse_X*Pixel_width;
 
210
  int absolute_mouse_y=Mouse_Y*Pixel_height;
 
211
  static int Wrong_resize;
 
212
 
 
213
try_again:
 
214
  
 
215
  switch (pix_ratio)
 
216
  {
 
217
      default:
 
218
      case PIXEL_SIMPLE:
 
219
          pix_width=1;
 
220
          pix_height=1;
 
221
      break;
 
222
      case PIXEL_TALL:
 
223
          pix_width=1;
 
224
          pix_height=2;
 
225
      break;
 
226
      case PIXEL_WIDE:
 
227
          pix_width=2;
 
228
          pix_height=1;
 
229
      break;
 
230
      case PIXEL_DOUBLE:
 
231
          pix_width=2;
 
232
          pix_height=2;
 
233
      break;
 
234
      case PIXEL_TRIPLE:
 
235
          pix_width=3;
 
236
          pix_height=3;
 
237
      break;
 
238
      case PIXEL_WIDE2:
 
239
          pix_width=4;
 
240
          pix_height=2;
 
241
      break;
 
242
      case PIXEL_TALL2:
 
243
          pix_width=2;
 
244
          pix_height=4;
 
245
      break;
 
246
      case PIXEL_QUAD:
 
247
          pix_width=4;
 
248
          pix_height=4;
 
249
      break;
 
250
  }
 
251
 
 
252
  screen_changed = (Screen_width*Pixel_width!=width ||
 
253
                    Screen_height*Pixel_height!=height ||
 
254
                    Video_mode[Current_resolution].Fullscreen != fullscreen);
 
255
 
 
256
  // Valeurs raisonnables: minimum 320x200
 
257
  if (!fullscreen)
 
258
  {
 
259
    if (Wrong_resize>20 && (width < 320*pix_width || height < 200*pix_height))
 
260
    {
 
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                     ");
 
266
        goto try_again;
 
267
      }
 
268
    }
 
269
    
 
270
    if (width > 320*pix_width && height > 200*pix_height)
 
271
      Wrong_resize = 0;
 
272
 
 
273
    if (width < 320*pix_width)
 
274
    {
 
275
        width = 320*pix_width;
 
276
        screen_changed=1;
 
277
        Wrong_resize++;
 
278
    }
 
279
    if (height < 200*pix_height)
 
280
    {
 
281
        height = 200*pix_height;
 
282
        screen_changed=1;
 
283
        Wrong_resize++;
 
284
    }
 
285
    Video_mode[0].Width = width;
 
286
    Video_mode[0].Height = height;
 
287
 
 
288
  }
 
289
  else
 
290
  {
 
291
    if (width < 320*pix_width || height < 200*pix_height)
 
292
      return 1;
 
293
  }
 
294
  // La largeur doit �tre un multiple de 4
 
295
  #ifdef __amigaos4__
 
296
      // On AmigaOS the systems adds some more constraints on that ...
 
297
      width = (width + 15) & 0xFFFFFFF0;
 
298
  #else
 
299
      //width = (width + 3 ) & 0xFFFFFFFC;
 
300
  #endif  
 
301
 
 
302
  pixels_changed = (Pixel_ratio!=pix_ratio);
 
303
  
 
304
  if (!screen_changed && !pixels_changed)
 
305
    return 0;
 
306
  if (screen_changed)
 
307
  {
 
308
    Set_mode_SDL(&width, &height,fullscreen);
 
309
  }
 
310
  
 
311
  if (screen_changed || pixels_changed)
 
312
  {
 
313
    Pixel_ratio=pix_ratio;
 
314
    Pixel_width=pix_width;
 
315
    Pixel_height=pix_height;
 
316
    switch (Pixel_ratio)
 
317
    {
 
318
        default:
 
319
        case PIXEL_SIMPLE:
 
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 ;
 
340
        break;
 
341
        case PIXEL_TALL:
 
342
            Pixel = Pixel_tall;
 
343
            Read_pixel= Read_pixel_tall;
 
344
            Display_screen = Display_part_of_screen_tall;
 
345
            Block = Block_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;
 
362
        break;
 
363
        case PIXEL_WIDE:
 
364
            Pixel = Pixel_wide ;
 
365
            Read_pixel= Read_pixel_wide ;
 
366
            Display_screen = Display_part_of_screen_wide ;
 
367
            Block = Block_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 ;
 
384
        break;
 
385
        case PIXEL_DOUBLE:
 
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 ;
 
406
        break;
 
407
        case PIXEL_TRIPLE:
 
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 ;
 
428
        break;
 
429
        case PIXEL_WIDE2:
 
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 ;
 
450
        break;
 
451
        case PIXEL_TALL2:
 
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 ;
 
472
        break;
 
473
        case PIXEL_QUAD:
 
474
            Pixel = Pixel_quad ;
 
475
            Read_pixel= Read_pixel_quad ;
 
476
            Display_screen = Display_part_of_screen_quad ;
 
477
            Block = Block_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 ;
 
494
        break;
 
495
    }
 
496
  }
 
497
  Screen_width = width/Pixel_width;
 
498
  Screen_height = height/Pixel_height;
 
499
 
 
500
  Clear_border(MC_Black); // Requires up-to-date Screen_* and Pixel_*
 
501
 
 
502
  // Set menu size (software zoom)
 
503
  if (Screen_width/320 > Screen_height/200)
 
504
    factor=Screen_height/200;
 
505
  else
 
506
    factor=Screen_width/320;
 
507
 
 
508
  switch (Config.Ratio)
 
509
  {
 
510
    case 1: // Always the biggest possible
 
511
      Menu_factor_X=factor;
 
512
      Menu_factor_Y=factor;
 
513
      break;
 
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;
 
519
      break;
 
520
    case 0: // Always smallest possible
 
521
      Menu_factor_X=1;
 
522
      Menu_factor_Y=1;
 
523
      break;
 
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));
 
527
  }
 
528
  if (Pixel_height>Pixel_width && Screen_width>=Menu_factor_X*2*320)
 
529
    Menu_factor_X*=2;
 
530
  else if (Pixel_width>Pixel_height && Screen_height>=Menu_factor_Y*2*200)
 
531
    Menu_factor_Y*=2;
 
532
    
 
533
  free(Horizontal_line_buffer);
 
534
  Horizontal_line_buffer=(byte *)malloc(Pixel_width * 
 
535
    ((Screen_width>Main_image_width)?Screen_width:Main_image_width));
 
536
 
 
537
  Set_palette(Main_palette);
 
538
 
 
539
  Current_resolution=0;
 
540
  if (fullscreen)
 
541
  {
 
542
    for (index=1; index<Nb_video_modes; index++)
 
543
    {
 
544
      if (Video_mode[index].Width/Pixel_width==Screen_width &&
 
545
          Video_mode[index].Height/Pixel_height==Screen_height)
 
546
      {
 
547
        Current_resolution=index;
 
548
        break;
 
549
      }
 
550
    }
 
551
  }
 
552
 
 
553
  Change_palette_cells();
 
554
  
 
555
  Menu_Y = Screen_height;
 
556
  if (Menu_is_visible)
 
557
    Menu_Y -= Menu_height * Menu_factor_Y;
 
558
  Menu_status_Y = Screen_height-(Menu_factor_Y<<3);
 
559
 
 
560
  Adjust_mouse_sensitivity(fullscreen);
 
561
 
 
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;
 
568
  if (fullscreen)
 
569
    Set_mouse_position();
 
570
  
 
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.
 
574
 
 
575
  if (Main_magnifier_mode)
 
576
  {
 
577
    Pixel_preview=Pixel_preview_magnifier;
 
578
  }
 
579
  else
 
580
  {
 
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;
 
585
    if (Main_offset_X<0)
 
586
      Main_offset_X=0;
 
587
    if (Main_offset_Y+Menu_Y>Main_image_height)
 
588
      Main_offset_Y=Main_image_height-Menu_Y;
 
589
    if (Main_offset_Y<0)
 
590
      Main_offset_Y=0;
 
591
  }
 
592
 
 
593
  Compute_magnifier_data();
 
594
  if (Main_magnifier_mode)
 
595
    Position_screen_according_to_zoom();
 
596
  Compute_limits();
 
597
  Compute_paintbrush_coordinates();
 
598
  
 
599
  Resize_width=0;
 
600
  Resize_height=0;
 
601
  return 0;
 
602
}
 
603
 
 
604
 
 
605
 
 
606
  // -- Redimentionner l'image (nettoie l'�cran virtuel) --
 
607
 
 
608
void Resize_image(word chosen_width,word chosen_height)
 
609
{
 
610
  word old_width=Main_image_width;
 
611
  word old_height=Main_image_height;
 
612
  int i;
 
613
 
 
614
  // +-+-+
 
615
  // |C| |  A+B+C = Ancienne image
 
616
  // +-+A|
 
617
  // |B| |    C   = Nouvelle image
 
618
  // +-+-+
 
619
 
 
620
  if (Backup_with_new_dimensions(1,Main_backups->Pages->Nb_layers,chosen_width,chosen_height))
 
621
  {
 
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.
 
624
 
 
625
    Main_image_is_modified=1;
 
626
 
 
627
    // On copie donc maintenant la partie C dans la nouvelle image.
 
628
    for (i=0; i<Main_backups->Pages->Nb_layers; i++)
 
629
    {
 
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);
 
634
    }
 
635
    Redraw_layered_image();
 
636
  }
 
637
  else
 
638
  {
 
639
    // Afficher un message d'erreur
 
640
    Display_cursor();
 
641
    Message_out_of_memory();
 
642
    Hide_cursor();
 
643
  }
 
644
}
 
645
 
 
646
 
 
647
 
 
648
void Remap_spare(void)
 
649
{
 
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"
 
653
  int   color;
 
654
  byte layer;
 
655
 
 
656
  // On commence par initialiser le tableau de bool�ens � faux
 
657
  for (color=0;color<=255;color++)
 
658
    used[color]=0;
 
659
 
 
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;
 
665
 
 
666
  //   On va maintenant se servir de la table "used" comme table de
 
667
  // conversion: pour chaque indice, la table donne une couleur de
 
668
  // remplacement.
 
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++)
 
674
    if (used[color])
 
675
      used[color]=Best_color(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B);
 
676
 
 
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
 
679
  // teintes.
 
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);
 
682
}
 
683
 
 
684
 
 
685
 
 
686
void Get_colors_from_brush(void)
 
687
{
 
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"
 
691
  int   color;
 
692
 
 
693
  if (Confirmation_box("Modify current palette ?"))
 
694
  {
 
695
    // Backup with unchanged layers, only palette is modified
 
696
    Backup_layers(0);
 
697
 
 
698
    // On commence par initialiser le tableau de bool�en � faux
 
699
    for (color=0;color<=255;color++)
 
700
      used[color]=0;
 
701
 
 
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;
 
706
 
 
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++)
 
710
      if (used[color])
 
711
      {
 
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;
 
715
      }
 
716
 
 
717
    Set_palette(Main_palette);
 
718
    Compute_optimal_menu_colors(Main_palette);
 
719
    Hide_cursor();
 
720
    Display_all_screen();
 
721
    Display_menu();
 
722
    Display_cursor();
 
723
    End_of_modification();
 
724
 
 
725
    Main_image_is_modified=1;
 
726
  }
 
727
}
 
728
 
 
729
 
 
730
 
 
731
//////////////////////////////////////////////////////////////////////////////
 
732
////////////////////////////// GESTION DU FILLER /////////////////////////////
 
733
//////////////////////////////////////////////////////////////////////////////
 
734
 
 
735
 
 
736
void Fill(short * top_reached  , short * bottom_reached,
 
737
          short * left_reached, short * right_reached)
 
738
//
 
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
 
745
// tous les effets.
 
746
//   Cette fonction ne doit pas �tre directement appel�e.
 
747
//
 
748
{
 
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"
 
758
 
 
759
  changes_made=1;
 
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);
 
765
 
 
766
  while (changes_made)
 
767
  {
 
768
    changes_made=0;
 
769
 
 
770
    for (line=current_limit_top;line<=current_limit_bottom;line++)
 
771
    {
 
772
      line_is_modified=0;
 
773
      // On va traiter le cas de la ligne n� line.
 
774
 
 
775
      // On commence le traitement � la gauche de l'�cran
 
776
      start_x=Limit_left;
 
777
 
 
778
      // Pour chaque segment de couleur 1 que peut contenir la ligne
 
779
      while (start_x<=Limit_right)
 
780
      {
 
781
        // On cherche son d�but
 
782
        while((start_x<=Limit_right) &&
 
783
                (Read_pixel_from_current_layer(start_x,line)!=1))
 
784
             start_x++;
 
785
 
 
786
        if (start_x<=Limit_right)
 
787
        {
 
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++);
 
792
 
 
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.
 
795
 
 
796
          //   On va maintenant regarder si une couleur sur la p�riph�rie
 
797
          // permet de colorier ce segment avec la couleur 2.
 
798
 
 
799
          can_propagate=(
 
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))
 
806
                               );
 
807
 
 
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)
 
812
              {
 
813
                can_propagate=1;
 
814
                break;
 
815
              }
 
816
 
 
817
          if (can_propagate)
 
818
          {
 
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.
 
827
            changes_made=1;
 
828
            line_is_modified=1;
 
829
          }
 
830
 
 
831
          start_x=end_x+1;
 
832
        }
 
833
      }
 
834
 
 
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
 
840
    }
 
841
 
 
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)
 
848
      current_limit_top--;
 
849
 
 
850
    for (line=current_limit_bottom;line>=current_limit_top;line--)
 
851
    {
 
852
      line_is_modified=0;
 
853
      // On va traiter le cas de la ligne n� line.
 
854
 
 
855
      // On commence le traitement � la gauche de l'�cran
 
856
      start_x=Limit_left;
 
857
 
 
858
      // Pour chaque segment de couleur 1 que peut contenir la ligne
 
859
      while (start_x<=Limit_right)
 
860
      {
 
861
        // On cherche son d�but
 
862
        for (;(start_x<=Limit_right) &&
 
863
             (Read_pixel_from_current_layer(start_x,line)!=1);start_x++);
 
864
 
 
865
        if (start_x<=Limit_right)
 
866
        {
 
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++);
 
871
 
 
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.
 
874
 
 
875
          //   On va maintenant regarder si une couleur sur la p�riph�rie
 
876
          // permet de colorier ce segment avec la couleur 2.
 
877
 
 
878
          can_propagate=(
 
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))
 
885
                               );
 
886
 
 
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)
 
891
              {
 
892
                can_propagate=1;
 
893
                break;
 
894
              }
 
895
 
 
896
          if (can_propagate)
 
897
          {
 
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.
 
906
            changes_made=1;
 
907
            line_is_modified=1;
 
908
          }
 
909
 
 
910
          start_x=end_x+1;
 
911
        }
 
912
      }
 
913
 
 
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
 
919
    }
 
920
  }
 
921
 
 
922
  *top_reached=current_limit_top;
 
923
  *bottom_reached =current_limit_bottom;
 
924
  (*right_reached)--;
 
925
} // end de la routine de remplissage "Fill"
 
926
 
 
927
byte Read_pixel_from_backup_layer(word x,word y)
 
928
{
 
929
  return *((y)*Main_image_width+(x)+Main_backups->Pages->Next->Image[Main_current_layer]);
 
930
}
 
931
 
 
932
void Fill_general(byte fill_color)
 
933
//
 
934
//  Cette fonction fait un remplissage qui g�re tous les effets. Elle fait
 
935
// appel � "Fill()".
 
936
//
 
937
{
 
938
  byte   cursor_shape_before_fill;
 
939
  short  x_pos,y_pos;
 
940
  short  top_reached  ,bottom_reached;
 
941
  short  left_reached,right_reached;
 
942
  byte   replace_table[256];
 
943
 
 
944
 
 
945
  // Avant toute chose, on v�rifie que l'on n'est pas en train de remplir
 
946
  // en dehors de l'image:
 
947
 
 
948
  if ( (Paintbrush_X>=Limit_left) &&
 
949
       (Paintbrush_X<=Limit_right) &&
 
950
       (Paintbrush_Y>=Limit_top)   &&
 
951
       (Paintbrush_Y<=Limit_bottom) )
 
952
  {
 
953
    // On suppose que le curseur est d�j� cach�.
 
954
    // Hide_cursor();
 
955
 
 
956
    //   On va faire patienter l'utilisateur en lui affichant un joli petit
 
957
    // sablier:
 
958
    cursor_shape_before_fill=Cursor_shape;
 
959
    Cursor_shape=CURSOR_SHAPE_HOURGLASS;
 
960
    Display_cursor();
 
961
 
 
962
    // On commence par effectuer un backup de l'image.
 
963
    Backup();
 
964
 
 
965
    // On fait attention au Feedback qui DOIT se faire avec le backup.
 
966
    Update_FX_feedback(0);
 
967
 
 
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);
 
972
 
 
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);
 
976
 
 
977
    //  On s'appr�te � faire des op�rations qui n�cessitent un affichage. Il
 
978
    // faut donc retirer de l'�cran le curseur:
 
979
    Hide_cursor();
 
980
    Cursor_shape=cursor_shape_before_fill;
 
981
 
 
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);
 
1014
 
 
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)
 
1018
        {
 
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
 
1021
          // remplissage:
 
1022
 
 
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
 
1025
          // pas le pinceaux)
 
1026
          Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0);
 
1027
 
 
1028
          //  Enfin, on peut afficher le pixel, en le soumettant aux effets en
 
1029
          // cours:
 
1030
          Display_pixel(x_pos,y_pos,fill_color);
 
1031
        }
 
1032
        else
 
1033
          Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0);
 
1034
 
 
1035
    // Restore original feedback value
 
1036
    Update_FX_feedback(Config.FX_Feedback);
 
1037
 
 
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)
 
1044
    {
 
1045
      short w,h;
 
1046
      
 
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);
 
1049
 
 
1050
      Redraw_grid(Main_X_zoom,0,w,h);
 
1051
    }
 
1052
 
 
1053
    Update_rect(0,0,0,0);
 
1054
    End_of_modification();
 
1055
  }
 
1056
}
 
1057
 
 
1058
 
 
1059
 
 
1060
//////////////////////////////////////////////////////////////////////////////
 
1061
////////////////// TRAC�S DE FIGURES G�OM�TRIQUES STANDARDS //////////////////
 
1062
////////////////////////// avec gestion de previews //////////////////////////
 
1063
//////////////////////////////////////////////////////////////////////////////
 
1064
 
 
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;
 
1068
 
 
1069
  void Init_permanent_draw(void)
 
1070
  {
 
1071
    Permanent_draw_count = 0;
 
1072
    Permanent_draw_next_refresh = SDL_GetTicks() + 100;
 
1073
  }
 
1074
 
 
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)
 
1077
  {
 
1078
    Display_paintbrush(x_pos,y_pos,color,0);
 
1079
    Permanent_draw_count ++;
 
1080
    
 
1081
    // Check every 8 pixels
 
1082
    if (! (Permanent_draw_count&7))
 
1083
    {
 
1084
      Uint32 now = SDL_GetTicks();
 
1085
      if (now>= Permanent_draw_next_refresh)
 
1086
      {
 
1087
        Permanent_draw_next_refresh = now+100;
 
1088
        Flush_update();
 
1089
      }
 
1090
    }
 
1091
  }
 
1092
 
 
1093
  // Affichage d'un point de fa�on d�finitive
 
1094
  void Pixel_clipped(word x_pos,word y_pos,byte color)
 
1095
  {
 
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);
 
1101
  }
 
1102
  
 
1103
  // Affichage d'un point pour une preview
 
1104
  void Pixel_figure_preview(word x_pos,word y_pos,byte color)
 
1105
  {
 
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);
 
1111
  }
 
1112
  // Affichage d'un point pour une preview, avec sa propre couleur
 
1113
  void Pixel_figure_preview_auto(word x_pos,word y_pos)
 
1114
  {
 
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));
 
1120
  }
 
1121
 
 
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)
 
1124
  {
 
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));
 
1131
  }
 
1132
  
 
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)
 
1136
  {
 
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]);
 
1142
  }
 
1143
  
 
1144
 
 
1145
  // Effacement d'un point de preview
 
1146
  void Pixel_figure_clear_preview(word x_pos,word y_pos,__attribute__((unused)) byte color)
 
1147
  {
 
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));
 
1153
  }
 
1154
 
 
1155
  // Affichage d'un point dans la brosse
 
1156
  void Pixel_figure_in_brush(word x_pos,word y_pos,byte color)
 
1157
  {
 
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);
 
1163
  }
 
1164
 
 
1165
 
 
1166
  // -- Tracer g�n�ral d'un cercle vide -------------------------------------
 
1167
 
 
1168
void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color)
 
1169
{
 
1170
  short start_x;
 
1171
  short start_y;
 
1172
  short x_pos;
 
1173
  short y_pos;
 
1174
 
 
1175
  // Ensuite, on va parcourire le quart haut gauche du cercle
 
1176
  start_x=center_x-radius;
 
1177
  start_y=center_y-radius;
 
1178
 
 
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())
 
1183
      {
 
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)
 
1187
 
 
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);
 
1192
         // Quart Bas-droite
 
1193
        Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
 
1194
         // Quart Bas-gauche
 
1195
        Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
 
1196
 
 
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())
 
1201
          {
 
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);
 
1206
             // Quart Bas-gauche
 
1207
            Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
 
1208
             // Quart Bas-droite
 
1209
            Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
 
1210
          }
 
1211
          else
 
1212
            break;
 
1213
 
 
1214
        Circle_cursor_Y++;
 
1215
        break;
 
1216
      }
 
1217
 
 
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
 
1223
 
 
1224
  if(Main_magnifier_mode) Update_part_of_screen(center_x-radius,center_y-radius,2*radius+1,2*radius+1);
 
1225
}
 
1226
 
 
1227
  // -- Trac� d�finitif d'un cercle vide --
 
1228
 
 
1229
void Draw_empty_circle_permanent(short center_x,short center_y,short radius,byte color)
 
1230
{
 
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);
 
1235
}
 
1236
 
 
1237
  // -- Tracer la preview d'un cercle vide --
 
1238
 
 
1239
void Draw_empty_circle_preview(short center_x,short center_y,short radius,byte color)
 
1240
{
 
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);
 
1244
}
 
1245
 
 
1246
  // -- Effacer la preview d'un cercle vide --
 
1247
 
 
1248
void Hide_empty_circle_preview(short center_x,short center_y,short radius)
 
1249
{
 
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);
 
1253
}
 
1254
 
 
1255
  // -- Tracer un cercle plein --
 
1256
 
 
1257
void Draw_filled_circle(short center_x,short center_y,short radius,byte color)
 
1258
{
 
1259
  short start_x;
 
1260
  short start_y;
 
1261
  short x_pos;
 
1262
  short y_pos;
 
1263
  short end_x;
 
1264
  short end_y;
 
1265
 
 
1266
  start_x=center_x-radius;
 
1267
  start_y=center_y-radius;
 
1268
  end_x=center_x+radius;
 
1269
  end_y=center_y+radius;
 
1270
 
 
1271
  // Correction des bornes d'apr�s les limites
 
1272
  if (start_y<Limit_top)
 
1273
    start_y=Limit_top;
 
1274
  if (end_y>Limit_bottom)
 
1275
    end_y=Limit_bottom;
 
1276
  if (start_x<Limit_left)
 
1277
    start_x=Limit_left;
 
1278
  if (end_x>Limit_right)
 
1279
    end_x=Limit_right;
 
1280
 
 
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);
 
1286
 
 
1287
  Update_part_of_screen(start_x,start_y,end_x+1-start_x,end_y+1-start_y);
 
1288
}
 
1289
 
 
1290
 
 
1291
  // -- Tracer g�n�ral d'une ellipse vide -----------------------------------
 
1292
 
 
1293
void Draw_empty_ellipse_general(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
 
1294
{
 
1295
  short start_x;
 
1296
  short start_y;
 
1297
  short x_pos;
 
1298
  short y_pos;
 
1299
 
 
1300
  start_x=center_x-horizontal_radius;
 
1301
  start_y=center_y-vertical_radius;
 
1302
 
 
1303
  // Calcul des limites de l'ellipse
 
1304
  Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1);
 
1305
 
 
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())
 
1310
      {
 
1311
        // On vient de tomber sur le premier point qui sur la ligne
 
1312
        // horizontale fait partie de l'ellipse.
 
1313
 
 
1314
        // Donc on peut l'afficher (lui et ses copains sym�triques)
 
1315
 
 
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);
 
1320
         // Quart Bas-gauche
 
1321
        Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
 
1322
         // Quart Bas-droite
 
1323
        Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
 
1324
 
 
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())
 
1329
          {
 
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);
 
1334
             // Quart Bas-gauche
 
1335
            Pixel_figure(x_pos,(center_y<<1)-y_pos,color);
 
1336
             // Quart Bas-droite
 
1337
            Pixel_figure((center_x<<1)-x_pos,(center_y<<1)-y_pos,color);
 
1338
          }
 
1339
          else
 
1340
            break;
 
1341
 
 
1342
        Ellipse_cursor_Y++;
 
1343
        break;
 
1344
      }
 
1345
 
 
1346
  // On affiche � la fin les points cardinaux:
 
1347
 
 
1348
  // points verticaux:
 
1349
  x_pos=center_x;
 
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);
 
1354
 
 
1355
  // points horizontaux:
 
1356
  y_pos=center_y;
 
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);
 
1361
 
 
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
 
1366
 
 
1367
  Update_part_of_screen(center_x-horizontal_radius,center_y-vertical_radius,2*horizontal_radius+1,2*vertical_radius+1);
 
1368
}
 
1369
 
 
1370
  // -- Trac� d�finitif d'une ellipse vide --
 
1371
 
 
1372
void Draw_empty_ellipse_permanent(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
 
1373
{
 
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);
 
1378
}
 
1379
 
 
1380
  // -- Tracer la preview d'une ellipse vide --
 
1381
 
 
1382
void Draw_empty_ellipse_preview(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
 
1383
{
 
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);
 
1387
}
 
1388
 
 
1389
  // -- Effacer la preview d'une ellipse vide --
 
1390
 
 
1391
void Hide_empty_ellipse_preview(short center_x,short center_y,short horizontal_radius,short vertical_radius)
 
1392
{
 
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);
 
1396
}
 
1397
 
 
1398
  // -- Tracer une ellipse pleine --
 
1399
 
 
1400
void Draw_filled_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color)
 
1401
{
 
1402
  short start_x;
 
1403
  short start_y;
 
1404
  short x_pos;
 
1405
  short y_pos;
 
1406
  short end_x;
 
1407
  short end_y;
 
1408
 
 
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;
 
1413
 
 
1414
  // Calcul des limites de l'ellipse
 
1415
  Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1);
 
1416
 
 
1417
  // Correction des bornes d'apr�s les limites
 
1418
  if (start_y<Limit_top)
 
1419
    start_y=Limit_top;
 
1420
  if (end_y>Limit_bottom)
 
1421
    end_y=Limit_bottom;
 
1422
  if (start_x<Limit_left)
 
1423
    start_x=Limit_left;
 
1424
  if (end_x>Limit_right)
 
1425
    end_x=Limit_right;
 
1426
 
 
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);
 
1433
}
 
1434
 
 
1435
/******************
 
1436
* TRAC� DE LIGNES *
 
1437
******************/
 
1438
 
 
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)
 
1442
{
 
1443
  int dx, dy;
 
1444
  float angle;
 
1445
 
 
1446
  dx = *bx-ax;
 
1447
  dy = *by-ay; 
 
1448
 
 
1449
  // No mouse move: no need to clamp anything
 
1450
  if (dx==0 || dy == 0) return; 
 
1451
 
 
1452
  // Determine angle (heading)
 
1453
  angle = atan2(dx, dy);
 
1454
    
 
1455
  // Get absolute values, useful from now on:
 
1456
  //dx=abs(dx);
 
1457
  //dy=abs(dy);
 
1458
    
 
1459
  // Negative Y
 
1460
  if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0))
 
1461
  {
 
1462
    *bx=ax;
 
1463
    *by=ay + dy;
 
1464
  }
 
1465
  // Iso close to negative Y
 
1466
  else if (angle < M_PI*(-13.0/16.0))
 
1467
  {
 
1468
    dy=dy | 1; // Round up to next odd number
 
1469
    *bx=ax + dy/2;
 
1470
    *by=ay + dy;
 
1471
  }
 
1472
  // 45deg
 
1473
  else if (angle < M_PI*(-11.0/16.0))
 
1474
  {
 
1475
    *by = (*by + ay + dx)/2;
 
1476
    *bx = ax  - ay + *by;
 
1477
  }
 
1478
  // Iso close to negative X
 
1479
  else if (angle < M_PI*(-9.0/16.0))
 
1480
  {
 
1481
    dx=dx | 1; // Round up to next odd number
 
1482
    *bx=ax + dx;
 
1483
    *by=ay + dx/2;
 
1484
  }
 
1485
  // Negative X
 
1486
  else if (angle < M_PI*(-7.0/16.0))
 
1487
  {
 
1488
    *bx=ax + dx;
 
1489
    *by=ay;
 
1490
  }
 
1491
  // Iso close to negative X
 
1492
  else if (angle < M_PI*(-5.0/16.0))
 
1493
  {
 
1494
    dx=dx | 1; // Round up to next odd number
 
1495
    *bx=ax + dx;
 
1496
    *by=ay - dx/2;
 
1497
  }
 
1498
  // 45 degrees
 
1499
  else if (angle < M_PI*(-3.0/16.0))
 
1500
  {
 
1501
    *by = (*by + ay - dx)/2;
 
1502
    *bx = ax  + ay - *by;
 
1503
  }
 
1504
  // Iso close to positive Y
 
1505
  else if (angle < M_PI*(-1.0/16.0))
 
1506
  {
 
1507
    dy=dy | 1; // Round up to next odd number
 
1508
    *bx=ax - dy/2;
 
1509
    *by=ay + dy;
 
1510
  }
 
1511
  // Positive Y
 
1512
  else if (angle < M_PI*(1.0/16.0))
 
1513
  {
 
1514
    *bx=ax;
 
1515
    *by=ay + dy;
 
1516
  }
 
1517
  // Iso close to positive Y
 
1518
  else if (angle < M_PI*(3.0/16.0))
 
1519
  {
 
1520
    dy=dy | 1; // Round up to next odd number
 
1521
    *bx=ax + dy/2;
 
1522
    *by=ay + dy;
 
1523
  }
 
1524
  // 45 degrees
 
1525
  else if (angle < M_PI*(5.0/16.0))
 
1526
  {
 
1527
    *by = (*by + ay + dx)/2;
 
1528
    *bx = ax  - ay + *by;
 
1529
  }
 
1530
  // Iso close to positive X
 
1531
  else if (angle < M_PI*(7.0/16.0))
 
1532
  {
 
1533
    dx=dx | 1; // Round up to next odd number
 
1534
    *bx=ax + dx;
 
1535
    *by=ay + dx/2;
 
1536
  }
 
1537
  // Positive X
 
1538
  else if (angle < M_PI*(9.0/16.0))
 
1539
  {
 
1540
    *bx=ax + dx;
 
1541
    *by=ay;
 
1542
  }
 
1543
  // Iso close to positive X
 
1544
  else if (angle < M_PI*(11.0/16.0))
 
1545
  {
 
1546
    dx=dx | 1; // Round up to next odd number
 
1547
    *bx=ax + dx;
 
1548
    *by=ay - dx/2;
 
1549
  }
 
1550
  // 45 degrees
 
1551
  else if (angle < M_PI*(13.0/16.0))
 
1552
  {
 
1553
    *by = (*by + ay - dx)/2;
 
1554
    *bx = ax  + ay - *by;
 
1555
  }
 
1556
  // Iso close to negative Y
 
1557
  else //if (angle < M_PI*(15.0/16.0))
 
1558
  {
 
1559
    dy=dy | 1; // Round up to next odd number
 
1560
    *bx=ax - dy/2;
 
1561
    *by=ay + dy;
 
1562
  }
 
1563
 
 
1564
  return;
 
1565
}
 
1566
 
 
1567
  // -- Tracer g�n�ral d'une ligne ------------------------------------------
 
1568
 
 
1569
void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color)
 
1570
{
 
1571
  short x_pos,y_pos;
 
1572
  short incr_x,incr_y;
 
1573
  short i,cumul;
 
1574
  short delta_x,delta_y;
 
1575
  
 
1576
  x_pos=start_x;
 
1577
  y_pos=start_y;
 
1578
 
 
1579
  if (start_x<end_x)
 
1580
  {
 
1581
    incr_x=+1;
 
1582
    delta_x=end_x-start_x;
 
1583
  }
 
1584
  else
 
1585
  {
 
1586
    incr_x=-1;
 
1587
    delta_x=start_x-end_x;
 
1588
  }
 
1589
 
 
1590
  if (start_y<end_y)
 
1591
  {
 
1592
    incr_y=+1;
 
1593
    delta_y=end_y-start_y;
 
1594
  }
 
1595
  else
 
1596
  {
 
1597
    incr_y=-1;
 
1598
    delta_y=start_y-end_y;
 
1599
  }
 
1600
 
 
1601
  if (delta_y>delta_x)
 
1602
  {
 
1603
    cumul=delta_y>>1;
 
1604
    for (i=1; i<delta_y; i++)
 
1605
    {
 
1606
      y_pos+=incr_y;
 
1607
      cumul+=delta_x;
 
1608
      if (cumul>=delta_y)
 
1609
      {
 
1610
        cumul-=delta_y;
 
1611
        x_pos+=incr_x;
 
1612
      }
 
1613
      Pixel_figure(x_pos,y_pos,color);
 
1614
    }
 
1615
  }
 
1616
  else
 
1617
  {
 
1618
    cumul=delta_x>>1;
 
1619
    for (i=1; i<delta_x; i++)
 
1620
    {
 
1621
      x_pos+=incr_x;
 
1622
      cumul+=delta_y;
 
1623
      if (cumul>=delta_x)
 
1624
      {
 
1625
        cumul-=delta_x;
 
1626
        y_pos+=incr_y;
 
1627
      }
 
1628
      Pixel_figure(x_pos,y_pos,color);
 
1629
    }
 
1630
  }
 
1631
 
 
1632
  if ( (start_x!=end_x) || (start_y!=end_y) )
 
1633
    Pixel_figure(end_x,end_y,color);
 
1634
 
 
1635
}
 
1636
 
 
1637
  // -- Tracer d�finitif d'une ligne --
 
1638
 
 
1639
void Draw_line_permanent(short start_x,short start_y,short end_x,short end_y, byte color)
 
1640
{
 
1641
 
 
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);
 
1647
}
 
1648
 
 
1649
  // -- Tracer la preview d'une ligne --
 
1650
 
 
1651
void Draw_line_preview(short start_x,short start_y,short end_x,short end_y,byte color)
 
1652
{
 
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);
 
1657
}
 
1658
 
 
1659
  // -- Tracer la preview d'une ligne en xor --
 
1660
 
 
1661
void Draw_line_preview_xor(short start_x,short start_y,short end_x,short end_y,byte color)
 
1662
{
 
1663
  int w, h;
 
1664
  Pixel_figure=Pixel_figure_preview_xor;
 
1665
  Draw_line_general(start_x,start_y,end_x,end_y,color);
 
1666
  if (start_x<0)
 
1667
    start_x=0;
 
1668
  if (start_y<0)
 
1669
    start_y=0;
 
1670
  if (end_x<0)
 
1671
    end_x=0;
 
1672
  if (end_y<0)
 
1673
    end_y=0;
 
1674
  w = end_x-start_x;
 
1675
  h = end_y-start_y;
 
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);
 
1677
}
 
1678
 
 
1679
  // -- Tracer la preview d'une ligne en xor additif --
 
1680
 
 
1681
void Draw_line_preview_xorback(short start_x,short start_y,short end_x,short end_y,byte color)
 
1682
{
 
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);
 
1687
}
 
1688
 
 
1689
  // -- Effacer la preview d'une ligne --
 
1690
 
 
1691
void Hide_line_preview(short start_x,short start_y,short end_x,short end_y)
 
1692
{
 
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);
 
1697
}
 
1698
 
 
1699
 
 
1700
  // -- Tracer un rectangle vide --
 
1701
 
 
1702
void Draw_empty_rectangle(short start_x,short start_y,short end_x,short end_y,byte color)
 
1703
{
 
1704
  short temp;
 
1705
  short x_pos;
 
1706
  short y_pos;
 
1707
 
 
1708
 
 
1709
  // On v�rifie que les bornes soient dans le bon sens:
 
1710
  if (start_x>end_x)
 
1711
  {
 
1712
    temp=start_x;
 
1713
    start_x=end_x;
 
1714
    end_x=temp;
 
1715
  }
 
1716
  if (start_y>end_y)
 
1717
  {
 
1718
    temp=start_y;
 
1719
    start_y=end_y;
 
1720
    end_y=temp;
 
1721
  }
 
1722
 
 
1723
  // On trace le rectangle:
 
1724
  Init_permanent_draw();
 
1725
  
 
1726
  for (x_pos=start_x;x_pos<=end_x;x_pos++)
 
1727
  {
 
1728
    Pixel_figure_permanent(x_pos,start_y,color);
 
1729
    Pixel_figure_permanent(x_pos,  end_y,color);
 
1730
  }
 
1731
 
 
1732
  for (y_pos=start_y+1;y_pos<end_y;y_pos++)
 
1733
  {
 
1734
    Pixel_figure_permanent(start_x,y_pos,color);
 
1735
    Pixel_figure_permanent(  end_x,y_pos,color);
 
1736
  }
 
1737
    
 
1738
#if defined(__macosx__) || defined(__FreeBSD__)
 
1739
  Update_part_of_screen(start_x,end_x,end_x-start_x,end_y-start_y);
 
1740
#endif
 
1741
}
 
1742
 
 
1743
  // -- Tracer un rectangle plein --
 
1744
 
 
1745
void Draw_filled_rectangle(short start_x,short start_y,short end_x,short end_y,byte color)
 
1746
{
 
1747
  short temp;
 
1748
  short x_pos;
 
1749
  short y_pos;
 
1750
 
 
1751
 
 
1752
  // On v�rifie que les bornes sont dans le bon sens:
 
1753
  if (start_x>end_x)
 
1754
  {
 
1755
    temp=start_x;
 
1756
    start_x=end_x;
 
1757
    end_x=temp;
 
1758
  }
 
1759
  if (start_y>end_y)
 
1760
  {
 
1761
    temp=start_y;
 
1762
    start_y=end_y;
 
1763
    end_y=temp;
 
1764
  }
 
1765
 
 
1766
  // Correction en cas de d�passement des limites de l'image
 
1767
  if (end_x>Limit_right)
 
1768
    end_x=Limit_right;
 
1769
  if (end_y>Limit_bottom)
 
1770
    end_y=Limit_bottom;
 
1771
 
 
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);
 
1779
 
 
1780
}
 
1781
 
 
1782
 
 
1783
 
 
1784
 
 
1785
  // -- Tracer une courbe de B�zier --
 
1786
 
 
1787
void Draw_curve_general(short x1, short y1,
 
1788
                           short x2, short y2,
 
1789
                           short x3, short y3,
 
1790
                           short x4, short y4,
 
1791
                           byte color)
 
1792
{
 
1793
  float delta,t,t2,t3;
 
1794
  short x,y,old_x,old_y;
 
1795
  word  i;
 
1796
  int   cx[4];
 
1797
  int   cy[4];
 
1798
 
 
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;
 
1803
  cx[3]= +   x1;
 
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;
 
1807
  cy[3]= +   y1;
 
1808
 
 
1809
  // Tra�age de la courbe
 
1810
  old_x=x1;
 
1811
  old_y=y1;
 
1812
  Pixel_figure(old_x,old_y,color);
 
1813
  delta=0.05; // 1.0/20
 
1814
  t=0;
 
1815
  for (i=1; i<=20; i++)
 
1816
  {
 
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);
 
1821
    old_x=x;
 
1822
    old_y=y;
 
1823
  }
 
1824
 
 
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);
 
1830
}
 
1831
 
 
1832
  // -- Tracer une courbe de B�zier d�finitivement --
 
1833
 
 
1834
void Draw_curve_permanent(short x1, short y1,
 
1835
                             short x2, short y2,
 
1836
                             short x3, short y3,
 
1837
                             short x4, short y4,
 
1838
                             byte color)
 
1839
{
 
1840
  Pixel_figure=Pixel_figure_permanent;
 
1841
  Init_permanent_draw();
 
1842
  Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color);
 
1843
}
 
1844
 
 
1845
  // -- Tracer la preview d'une courbe de B�zier --
 
1846
 
 
1847
void Draw_curve_preview(short x1, short y1,
 
1848
                           short x2, short y2,
 
1849
                           short x3, short y3,
 
1850
                           short x4, short y4,
 
1851
                           byte color)
 
1852
{
 
1853
  Pixel_figure=Pixel_figure_preview;
 
1854
  Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color);
 
1855
}
 
1856
 
 
1857
  // -- Effacer la preview d'une courbe de B�zier --
 
1858
 
 
1859
void Hide_curve_preview(short x1, short y1,
 
1860
                            short x2, short y2,
 
1861
                            short x3, short y3,
 
1862
                            short x4, short y4,
 
1863
                            byte color)
 
1864
{
 
1865
  Pixel_figure=Pixel_figure_clear_preview;
 
1866
  Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color);
 
1867
}
 
1868
 
 
1869
 
 
1870
 
 
1871
 
 
1872
  // -- Spray : un petit coup de Pschiitt! --
 
1873
 
 
1874
void Airbrush(short clicked_button)
 
1875
{
 
1876
  short x_pos,y_pos;
 
1877
  short radius=Airbrush_size>>1;
 
1878
  long  radius_squared=(long)radius*radius;
 
1879
  short index,count;
 
1880
  byte  color_index;
 
1881
  byte  direction;
 
1882
 
 
1883
 
 
1884
  Hide_cursor();
 
1885
 
 
1886
  if (Airbrush_mode)
 
1887
  {
 
1888
    for (count=1; count<=Airbrush_mono_flow; count++)
 
1889
    {
 
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 )
 
1893
      {
 
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);
 
1898
        else
 
1899
          Display_paintbrush(x_pos,y_pos,Back_color,0);
 
1900
      }
 
1901
    }
 
1902
  }
 
1903
  else
 
1904
  {
 
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.
 
1908
    direction=rand()&1;
 
1909
    for (index=0,color_index=rand()/*%256*/; index<256; index++)
 
1910
    {
 
1911
      for (count=1; count<=Airbrush_multi_flow[color_index]; count++)
 
1912
      {
 
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 )
 
1916
        {
 
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);
 
1921
          else
 
1922
            Display_paintbrush(x_pos,y_pos,Back_color,0);
 
1923
        }
 
1924
      }
 
1925
      if (direction)
 
1926
        color_index++;
 
1927
      else
 
1928
        color_index--;
 
1929
    }
 
1930
  }
 
1931
 
 
1932
  Display_cursor();
 
1933
}
 
1934
 
 
1935
 
 
1936
 
 
1937
  //////////////////////////////////////////////////////////////////////////
 
1938
  ////////////////////////// GESTION DES DEGRADES //////////////////////////
 
1939
  //////////////////////////////////////////////////////////////////////////
 
1940
 
 
1941
 
 
1942
  // -- Gestion d'un d�grad� de base (le plus moche) --
 
1943
 
 
1944
void Gradient_basic(long index,short x_pos,short y_pos)
 
1945
{
 
1946
  long position;
 
1947
 
 
1948
  // On fait un premier calcul partiel
 
1949
  position=(index*Gradient_bounds_range);
 
1950
 
 
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;
 
1954
 
 
1955
  position/=Gradient_total_range;
 
1956
 
 
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.
 
1959
 
 
1960
  if (position<0)
 
1961
    position=0;
 
1962
  else if (position>=Gradient_bounds_range)
 
1963
    position=Gradient_bounds_range-1;
 
1964
 
 
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);
 
1968
  else
 
1969
    Gradient_pixel(x_pos,y_pos,Gradient_lower_bound+position);
 
1970
}
 
1971
 
 
1972
 
 
1973
  // -- Gestion d'un d�grad� par trames simples --
 
1974
 
 
1975
void Gradient_dithered(long index,short x_pos,short y_pos)
 
1976
{
 
1977
  long position_in_gradient;
 
1978
  long position_in_segment;
 
1979
 
 
1980
  //
 
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:
 
1984
  //
 
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.
 
1987
  //         v
 
1988
  //  |---|---|---|---- - - -
 
1989
  //   ^
 
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.
 
1992
 
 
1993
  // On fait d'abord un premier calcul partiel
 
1994
  position_in_gradient=(index*Gradient_bounds_range);
 
1995
 
 
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;
 
1999
 
 
2000
  if (position_in_gradient<0)
 
2001
    position_in_gradient=0;
 
2002
 
 
2003
  // ... qui nous permet de calculer la position dans le segment
 
2004
  position_in_segment=((position_in_gradient<<2)/Gradient_total_range)&3;
 
2005
 
 
2006
  // On peut ensuite terminer le calcul de l'indice dans le d�grad�
 
2007
  position_in_gradient/=Gradient_total_range;
 
2008
 
 
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.
 
2011
 
 
2012
  switch (position_in_segment)
 
2013
  {
 
2014
    case 0 : // On est sur la gauche du segment
 
2015
      if (((x_pos+y_pos)&1)==0)
 
2016
        position_in_gradient--;
 
2017
      break;
 
2018
 
 
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
 
2021
 
 
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++;
 
2025
  }
 
2026
 
 
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.
 
2029
 
 
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;
 
2034
 
 
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;
 
2038
  else
 
2039
    position_in_gradient=Gradient_lower_bound+position_in_gradient;
 
2040
 
 
2041
  Gradient_pixel(x_pos,y_pos,position_in_gradient);
 
2042
}
 
2043
 
 
2044
 
 
2045
  // -- Gestion d'un d�grad� par trames �tendues --
 
2046
 
 
2047
void Gradient_extra_dithered(long index,short x_pos,short y_pos)
 
2048
{
 
2049
  long position_in_gradient;
 
2050
  long position_in_segment;
 
2051
 
 
2052
//
 
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:
 
2056
  //
 
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.
 
2059
  //         v
 
2060
  //  |---|---|---|---- - - -
 
2061
  //   ^
 
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.
 
2064
 
 
2065
  // On fait d'abord un premier calcul partiel
 
2066
  position_in_gradient=(index*Gradient_bounds_range);
 
2067
 
 
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;
 
2071
 
 
2072
  if (position_in_gradient<0)
 
2073
    position_in_gradient=0;
 
2074
 
 
2075
  // Qui nous permet de calculer la position dans le segment
 
2076
  position_in_segment=((position_in_gradient<<3)/Gradient_total_range)&7;
 
2077
 
 
2078
  // On peut ensuite terminer le calcul de l'indice dans le d�grad�
 
2079
  position_in_gradient/=Gradient_total_range;
 
2080
 
 
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.
 
2083
 
 
2084
  switch (position_in_segment)
 
2085
  {
 
2086
    case 0 : // On est sur l'extr�me gauche du segment
 
2087
      if (((x_pos+y_pos)&1)==0)
 
2088
        position_in_gradient--;
 
2089
      break;
 
2090
 
 
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--;
 
2095
      break;
 
2096
 
 
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
 
2099
 
 
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++;
 
2104
      break;
 
2105
 
 
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++;
 
2109
  }
 
2110
 
 
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.
 
2113
 
 
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;
 
2118
 
 
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;
 
2122
  else
 
2123
    position_in_gradient=Gradient_lower_bound+position_in_gradient;
 
2124
 
 
2125
  Gradient_pixel(x_pos,y_pos,position_in_gradient);
 
2126
}
 
2127
 
 
2128
 
 
2129
 
 
2130
  // -- Tracer un cercle degrad� (une sph�re) --
 
2131
 
 
2132
void Draw_grad_circle(short center_x,short center_y,short radius,short spot_x,short spot_y)
 
2133
{
 
2134
  long start_x;
 
2135
  long start_y;
 
2136
  long x_pos;
 
2137
  long y_pos;
 
2138
  long end_x;
 
2139
  long end_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
 
2142
 
 
2143
  start_x=center_x-radius;
 
2144
  start_y=center_y-radius;
 
2145
  end_x=center_x+radius;
 
2146
  end_y=center_y+radius;
 
2147
 
 
2148
  // Correction des bornes d'apr�s les limites
 
2149
  if (start_y<Limit_top)
 
2150
    start_y=Limit_top;
 
2151
  if (end_y>Limit_bottom)
 
2152
    end_y=Limit_bottom;
 
2153
  if (start_x<Limit_left)
 
2154
    start_x=Limit_left;
 
2155
  if (end_x>Limit_right)
 
2156
    end_x=Limit_right;
 
2157
 
 
2158
  Gradient_total_range=Circle_limit+
 
2159
                           ((center_x-spot_x)*(center_x-spot_x))+
 
2160
                           ((center_y-spot_y)*(center_y-spot_y))+
 
2161
                           (2L*radius*sqrt(
 
2162
                           ((center_x-spot_x)*(center_x-spot_x))+
 
2163
                           ((center_y-spot_y)*(center_y-spot_y))));
 
2164
 
 
2165
  if (Gradient_total_range==0)
 
2166
    Gradient_total_range=1;
 
2167
 
 
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++)
 
2170
  {
 
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())
 
2175
      {
 
2176
        distance_x =(x_pos-spot_x);
 
2177
        distance_x*=distance_x;
 
2178
        Gradient_function(distance_x+distance_y,x_pos,y_pos);
 
2179
      }
 
2180
  }
 
2181
 
 
2182
  Update_part_of_screen(center_x-radius,center_y-radius,2*radius+1,2*radius+1);
 
2183
}
 
2184
 
 
2185
 
 
2186
  // -- Tracer une ellipse degrad�e --
 
2187
 
 
2188
void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y)
 
2189
{
 
2190
  long start_x;
 
2191
  long start_y;
 
2192
  long x_pos;
 
2193
  long y_pos;
 
2194
  long end_x;
 
2195
  long end_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
 
2198
 
 
2199
 
 
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;
 
2204
 
 
2205
  // Calcul des limites de l'ellipse
 
2206
  Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1);
 
2207
 
 
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))+
 
2213
                           (2L
 
2214
                           *sqrt(
 
2215
                           (horizontal_radius*horizontal_radius)+
 
2216
                           (vertical_radius  *vertical_radius  ))
 
2217
                           *sqrt(
 
2218
                           ((center_x-spot_x)*(center_x-spot_x))+
 
2219
                           ((center_y-spot_y)*(center_y-spot_y))));
 
2220
 
 
2221
  if (Gradient_total_range==0)
 
2222
    Gradient_total_range=1;
 
2223
 
 
2224
  // Correction des bornes d'apr�s les limites
 
2225
  if (start_y<Limit_top)
 
2226
    start_y=Limit_top;
 
2227
  if (end_y>Limit_bottom)
 
2228
    end_y=Limit_bottom;
 
2229
  if (start_x<Limit_left)
 
2230
    start_x=Limit_left;
 
2231
  if (end_x>Limit_right)
 
2232
    end_x=Limit_right;
 
2233
 
 
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++)
 
2236
  {
 
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())
 
2241
      {
 
2242
        distance_x =(x_pos-spot_x);
 
2243
        distance_x*=distance_x;
 
2244
        Gradient_function(distance_x+distance_y,x_pos,y_pos);
 
2245
      }
 
2246
  }
 
2247
 
 
2248
  Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1);
 
2249
}
 
2250
 
 
2251
 
 
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)
 
2254
{
 
2255
    short y_pos, x_pos;
 
2256
 
 
2257
    // On commence par s'assurer que le rectangle est � l'endroit
 
2258
    if(rbx < rax)
 
2259
    {
 
2260
      x_pos = rbx;
 
2261
      rbx = rax;
 
2262
      rax = x_pos;
 
2263
    }
 
2264
 
 
2265
    if(rby < ray)
 
2266
    {
 
2267
      y_pos = rby;
 
2268
      rby = ray;
 
2269
      ray = y_pos;
 
2270
    }
 
2271
 
 
2272
    // Correction des bornes d'apr�s les limites
 
2273
    if (ray<Limit_top)
 
2274
      ray=Limit_top;
 
2275
    if (rby>Limit_bottom)
 
2276
      rby=Limit_bottom;
 
2277
    if (rax<Limit_left)
 
2278
      rax=Limit_left;
 
2279
    if (rbx>Limit_right)
 
2280
      rbx=Limit_right;
 
2281
 
 
2282
    if(vbx == vax)
 
2283
    {
 
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);
 
2290
 
 
2291
    }
 
2292
    else
 
2293
    {
 
2294
      float a;
 
2295
      float b;
 
2296
      float distance_x, distance_y;
 
2297
 
 
2298
      Gradient_total_range = sqrt(pow(vby - vay,2)+pow(vbx - vax,2));
 
2299
      a = (float)(vby - vay)/(float)(vbx - vax);
 
2300
      b = vay - a*vax;
 
2301
      
 
2302
      for (y_pos=ray;y_pos<=rby;y_pos++)
 
2303
        for (x_pos = rax;x_pos<=rbx;x_pos++)
 
2304
        {
 
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);
 
2308
      
 
2309
          Gradient_function((int)sqrt(distance_x - distance_y),x_pos,y_pos);
 
2310
        }
 
2311
    }
 
2312
    Update_part_of_screen(rax,ray,rbx,rby);
 
2313
}
 
2314
 
 
2315
 
 
2316
 
 
2317
 
 
2318
// -- Tracer un polyg�ne plein --
 
2319
 
 
2320
typedef struct T_Polygon_edge      /* an active edge */
 
2321
{
 
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;
 
2328
} T_Polygon_edge;
 
2329
 
 
2330
 
 
2331
 
 
2332
/* Fill_edge_structure:
 
2333
 *  Polygon helper function: initialises an edge structure for the 2d
 
2334
 *  rasteriser.
 
2335
 */
 
2336
void Fill_edge_structure(T_Polygon_edge *edge, short *i1, short *i2)
 
2337
{
 
2338
  short *it;
 
2339
 
 
2340
  if (i2[1] < i1[1])
 
2341
  {
 
2342
    it = i1;
 
2343
    i1 = i2;
 
2344
    i2 = it;
 
2345
  }
 
2346
 
 
2347
  edge->top = i1[1];
 
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;
 
2351
  edge->prev = NULL;
 
2352
  edge->next = NULL;
 
2353
 
 
2354
  if (edge->dx+1 < 0.0)
 
2355
    edge->x += edge->dx+1;
 
2356
 
 
2357
  if (edge->dx >= 0.0)
 
2358
    edge->w = edge->dx;
 
2359
  else
 
2360
    edge->w = -(edge->dx);
 
2361
 
 
2362
  if (edge->w-1.0<0.0)
 
2363
    edge->w = 0.0;
 
2364
  else
 
2365
    edge->w = edge->w-1;
 
2366
}
 
2367
 
 
2368
 
 
2369
 
 
2370
/* Add_edge:
 
2371
 *  Adds an edge structure to a linked list, returning the new head pointer.
 
2372
 */
 
2373
T_Polygon_edge * Add_edge(T_Polygon_edge *list, T_Polygon_edge *edge, int sort_by_x)
 
2374
{
 
2375
  T_Polygon_edge *pos = list;
 
2376
  T_Polygon_edge *prev = NULL;
 
2377
 
 
2378
  if (sort_by_x)
 
2379
  {
 
2380
    while ( (pos) && ((pos->x+((pos->w+pos->dx)/2)) < (edge->x+((edge->w+edge->dx)/2))) )
 
2381
    {
 
2382
      prev = pos;
 
2383
      pos = pos->next;
 
2384
    }
 
2385
  }
 
2386
  else
 
2387
  {
 
2388
    while ((pos) && (pos->top < edge->top))
 
2389
    {
 
2390
      prev = pos;
 
2391
      pos = pos->next;
 
2392
    }
 
2393
  }
 
2394
 
 
2395
  edge->next = pos;
 
2396
  edge->prev = prev;
 
2397
 
 
2398
  if (pos)
 
2399
    pos->prev = edge;
 
2400
 
 
2401
  if (prev)
 
2402
  {
 
2403
    prev->next = edge;
 
2404
    return list;
 
2405
  }
 
2406
  else
 
2407
    return edge;
 
2408
}
 
2409
 
 
2410
 
 
2411
 
 
2412
/* Remove_edge:
 
2413
 *  Removes an edge structure from a list, returning the new head pointer.
 
2414
 */
 
2415
T_Polygon_edge * Remove_edge(T_Polygon_edge *list, T_Polygon_edge *edge)
 
2416
{
 
2417
  if (edge->next)
 
2418
    edge->next->prev = edge->prev;
 
2419
 
 
2420
  if (edge->prev)
 
2421
  {
 
2422
    edge->prev->next = edge->next;
 
2423
    return list;
 
2424
  }
 
2425
  else
 
2426
    return edge->next;
 
2427
}
 
2428
 
 
2429
 
 
2430
 
 
2431
/* polygon:
 
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).
 
2435
 */
 
2436
void Polyfill_general(int vertices, short * points, int color)
 
2437
{
 
2438
  short c;
 
2439
  short top = 0x7FFF;
 
2440
  short bottom = 0;
 
2441
  short *i1, *i2;
 
2442
  short x_pos,end_x;
 
2443
  T_Polygon_edge *edge, *next_edge, *initial_edge;
 
2444
  T_Polygon_edge *active_edges = NULL;
 
2445
  T_Polygon_edge *inactive_edges = NULL;
 
2446
 
 
2447
  /* allocate some space and fill the edge table */
 
2448
  initial_edge=edge=(T_Polygon_edge *) malloc(sizeof(T_Polygon_edge) * vertices);
 
2449
 
 
2450
  i1 = points;
 
2451
  i2 = points + ((vertices-1)<<1);
 
2452
 
 
2453
  for (c=0; c<vertices; c++)
 
2454
  {
 
2455
    if (i1[1] != i2[1])
 
2456
    {
 
2457
      Fill_edge_structure(edge, i1, i2);
 
2458
 
 
2459
      if (edge->bottom >= edge->top)
 
2460
      {
 
2461
        if (edge->top < top)
 
2462
          top = edge->top;
 
2463
 
 
2464
        if (edge->bottom > bottom)
 
2465
          bottom = edge->bottom;
 
2466
 
 
2467
        inactive_edges = Add_edge(inactive_edges, edge, 0);
 
2468
        edge++;
 
2469
      }
 
2470
    }
 
2471
    i2 = i1;
 
2472
    i1 += 2;
 
2473
  }
 
2474
 
 
2475
  /* for each scanline in the polygon... */
 
2476
  for (c=top; c<=bottom; c++)
 
2477
  {
 
2478
    /* check for newly active edges */
 
2479
    edge = inactive_edges;
 
2480
    while ((edge) && (edge->top == c))
 
2481
    {
 
2482
      next_edge = edge->next;
 
2483
      inactive_edges = Remove_edge(inactive_edges, edge);
 
2484
      active_edges = Add_edge(active_edges, edge, 1);
 
2485
      edge = next_edge;
 
2486
    }
 
2487
 
 
2488
    /* draw horizontal line segments */
 
2489
    if ((c>=Limit_top) && (c<=Limit_bottom))
 
2490
    {
 
2491
      edge = active_edges;
 
2492
      while ((edge) && (edge->next))
 
2493
      {
 
2494
        x_pos=/*Round*/(edge->x);
 
2495
        end_x=/*Round*/(edge->next->x+edge->next->w);
 
2496
        if (x_pos<Limit_left)
 
2497
          x_pos=Limit_left;
 
2498
        if (end_x>Limit_right)
 
2499
          end_x=Limit_right;
 
2500
        for (; x_pos<=end_x; x_pos++)
 
2501
          Pixel_figure(x_pos,c,color);
 
2502
        edge = edge->next->next;
 
2503
      }
 
2504
    }
 
2505
 
 
2506
    /* update edges, sorting and removing dead ones */
 
2507
    edge = active_edges;
 
2508
    while (edge)
 
2509
    {
 
2510
      next_edge = edge->next;
 
2511
      if (c >= edge->bottom)
 
2512
        active_edges = Remove_edge(active_edges, edge);
 
2513
      else
 
2514
      {
 
2515
        edge->x += edge->dx;
 
2516
        while ((edge->prev) && ( (edge->x+(edge->w/2)) < (edge->prev->x+(edge->prev->w/2))) )
 
2517
        {
 
2518
          if (edge->next)
 
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;
 
2524
          if (edge->prev)
 
2525
            edge->prev->next = edge;
 
2526
          else
 
2527
            active_edges = edge;
 
2528
        }
 
2529
      }
 
2530
      edge = next_edge;
 
2531
    }
 
2532
  }
 
2533
 
 
2534
  free(initial_edge);
 
2535
  initial_edge = NULL;
 
2536
 
 
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);
 
2539
}
 
2540
 
 
2541
 
 
2542
void Polyfill(int vertices, short * points, int color)
 
2543
{
 
2544
  int index;
 
2545
 
 
2546
  Pixel_clipped(points[0],points[1],color);
 
2547
  if (vertices==1)
 
2548
  {
 
2549
    Update_part_of_screen(points[0],points[1],1,1);
 
2550
    return;
 
2551
  }
 
2552
 
 
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);
 
2556
 
 
2557
  Pixel_figure=Pixel_clipped;    
 
2558
  Polyfill_general(vertices,points,color);
 
2559
 
 
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;
 
2563
 
 
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);
 
2568
 
 
2569
  // Restore original feedback value
 
2570
  Update_FX_feedback(Config.FX_Feedback);
 
2571
 
 
2572
}
 
2573
 
 
2574
 
 
2575
 
 
2576
//------------ Remplacement de la couleur point�e par une autre --------------
 
2577
 
 
2578
void Replace(byte New_color)
 
2579
{
 
2580
  byte old_color;
 
2581
 
 
2582
  if ((Paintbrush_X<Main_image_width)
 
2583
   && (Paintbrush_Y<Main_image_height))
 
2584
  {
 
2585
    old_color=Read_pixel_from_current_layer(Paintbrush_X,Paintbrush_Y);
 
2586
    if ( (old_color!=New_color)
 
2587
      && ((!Stencil_mode) || (!Stencil[old_color])) )
 
2588
    {
 
2589
      Replace_a_color(old_color,New_color);
 
2590
      Display_all_screen();
 
2591
    }
 
2592
  }
 
2593
}
 
2594
 
 
2595
 
 
2596
 
 
2597
/******************************************************************************/
 
2598
/********************************** SHADES ************************************/
 
2599
 
 
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)
 
2602
{
 
2603
  int index;
 
2604
  int first;
 
2605
  int last;
 
2606
  int color;
 
2607
  int temp;
 
2608
 
 
2609
 
 
2610
  // On initialise les deux tables de conversion en Identit�
 
2611
  for (index=0;index<256;index++)
 
2612
  {
 
2613
    table_inc[index]=index;
 
2614
    table_dec[index]=index;
 
2615
  }
 
2616
 
 
2617
  // On s'appr�te � examiner l'ensemble de la liste
 
2618
  for (index=0;index<512;index++)
 
2619
  {
 
2620
    // On recherche la premi�re case de la liste non vide (et non inhib�e)
 
2621
    while ((index<512) && (list[index]>255))
 
2622
      index++;
 
2623
 
 
2624
    // On note la position de la premi�re case de la s�quence
 
2625
    first=index;
 
2626
 
 
2627
    // On recherche la position de la derni�re case de la s�quence
 
2628
    for (last=first;list[last+1]<256;last++);
 
2629
 
 
2630
    // Pour toutes les cases non vides (et non inhib�es) qui suivent
 
2631
    switch (mode)
 
2632
    {
 
2633
      case SHADE_MODE_NORMAL :
 
2634
        for (;(index<512) && (list[index]<256);index++)
 
2635
        { // On met � jour les tables de conversion
 
2636
          color=list[index];
 
2637
          table_inc[color]=list[(index+step<=last)?index+step:last];
 
2638
          table_dec[color]=list[(index-step>=first)?index-step:first];
 
2639
        }
 
2640
        break;
 
2641
      case SHADE_MODE_LOOP :
 
2642
        temp=1+last-first;
 
2643
        for (;(index<512) && (list[index]<256);index++)
 
2644
        { // On met � jour les tables de conversion
 
2645
          color=list[index];
 
2646
          table_inc[color]=list[first+((step+index-first)%temp)];
 
2647
          table_dec[color]=list[first+(((temp-step)+index-first)%temp)];
 
2648
        }
 
2649
        break;
 
2650
      default : // SHADE_MODE_NOSAT
 
2651
        for (;(index<512) && (list[index]<256);index++)
 
2652
        { // On met � jour les tables de conversion
 
2653
          color=list[index];
 
2654
          if (index+step<=last)
 
2655
            table_inc[color]=list[index+step];
 
2656
          if (index-step>=first)
 
2657
            table_dec[color]=list[index-step];
 
2658
        }
 
2659
    }
 
2660
  }
 
2661
}
 
2662
 
 
2663
 
 
2664
 
 
2665
// -- Interface avec l'image, affect�e par le facteur de grossissement -------
 
2666
 
 
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().
 
2676
{
 
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)]))) )
 
2680
  {
 
2681
    color=Effect_function(x,y,color);
 
2682
    Pixel_in_current_screen(x,y,color,1);
 
2683
  }
 
2684
}
 
2685
 
 
2686
 
 
2687
 
 
2688
// -- Calcul des diff�rents effets -------------------------------------------
 
2689
 
 
2690
  // -- Aucun effet en cours --
 
2691
 
 
2692
byte No_effect(__attribute__((unused)) word x,__attribute__((unused)) word y,byte color)
 
2693
{
 
2694
  return color;
 
2695
}
 
2696
 
 
2697
  // -- Effet de Shading --
 
2698
 
 
2699
byte Effect_shade(word x,word y,__attribute__((unused)) byte color)
 
2700
{
 
2701
  return Shade_table[Read_pixel_from_feedback_screen(x,y)];
 
2702
}
 
2703
 
 
2704
byte Effect_quick_shade(word x,word y,byte color)
 
2705
{
 
2706
  int c=color=Read_pixel_from_feedback_screen(x,y);
 
2707
  int direction=(Fore_color<=Back_color);
 
2708
  byte start,end;
 
2709
  int width;
 
2710
 
 
2711
  if (direction)
 
2712
  {
 
2713
    start=Fore_color;
 
2714
    end  =Back_color;
 
2715
  }
 
2716
  else
 
2717
  {
 
2718
    start=Back_color;
 
2719
    end  =Fore_color;
 
2720
  }
 
2721
 
 
2722
  if ((c>=start) && (c<=end) && (start!=end))
 
2723
  {
 
2724
    width=1+end-start;
 
2725
 
 
2726
    if ( ((Shade_table==Shade_table_left) && direction) || ((Shade_table==Shade_table_right) && (!direction)) )
 
2727
      c-=Quick_shade_step%width;
 
2728
    else
 
2729
      c+=Quick_shade_step%width;
 
2730
 
 
2731
    if (c<start)
 
2732
      switch (Quick_shade_loop)
 
2733
      {
 
2734
        case SHADE_MODE_NORMAL : return start;
 
2735
        case SHADE_MODE_LOOP : return (width+c);
 
2736
        default : return color;
 
2737
      }
 
2738
 
 
2739
    if (c>end)
 
2740
      switch (Quick_shade_loop)
 
2741
      {
 
2742
        case SHADE_MODE_NORMAL : return end;
 
2743
        case SHADE_MODE_LOOP : return (c-width);
 
2744
        default : return color;
 
2745
      }
 
2746
  }
 
2747
 
 
2748
  return c;
 
2749
}
 
2750
 
 
2751
  // -- Effet de Tiling --
 
2752
 
 
2753
byte Effect_tiling(word x,word y,__attribute__((unused)) byte color)
 
2754
{
 
2755
  return Read_pixel_from_brush((x+Brush_width-Tiling_offset_X)%Brush_width,
 
2756
                               (y+Brush_height-Tiling_offset_Y)%Brush_height);
 
2757
}
 
2758
 
 
2759
  // -- Effet de Smooth --
 
2760
 
 
2761
byte Effect_smooth(word x,word y,__attribute__((unused)) byte color)
 
2762
{
 
2763
  int r,g,b;
 
2764
  byte c;
 
2765
  int weight,total_weight;
 
2766
  byte x2=((x+1)<Main_image_width);
 
2767
  byte y2=((y+1)<Main_image_height);
 
2768
 
 
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;
 
2775
 
 
2776
  if (x)
 
2777
  {
 
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;
 
2783
 
 
2784
    if (y)
 
2785
    {
 
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;
 
2791
 
 
2792
      if (y2)
 
2793
      {
 
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;
 
2799
      }
 
2800
    }
 
2801
  }
 
2802
 
 
2803
  if (x2)
 
2804
  {
 
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;
 
2810
 
 
2811
    if (y)
 
2812
    {
 
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;
 
2818
 
 
2819
      if (y2)
 
2820
      {
 
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;
 
2826
      }
 
2827
    }
 
2828
  }
 
2829
 
 
2830
  if (y)
 
2831
  {
 
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;
 
2837
  }
 
2838
 
 
2839
  if (y2)
 
2840
  {
 
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;
 
2846
  }
 
2847
 
 
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.
 
2855
 
 
2856
void Horizontal_grid_line(word x_pos,word y_pos,word width)
 
2857
{
 
2858
  int x;
 
2859
 
 
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);
 
2862
}
 
2863
 
 
2864
void Vertical_grid_line(word x_pos,word y_pos,word height)
 
2865
{
 
2866
  int y;
 
2867
  
 
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);
 
2870
}
 
2871
 
 
2872
// Tile Grid
 
2873
void Redraw_grid(short x, short y, unsigned short w, unsigned short h)
 
2874
{
 
2875
  int row, col;
 
2876
  if (!Show_grid)
 
2877
    return;
 
2878
    
 
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;
 
2880
  while (row < y+h)
 
2881
  {
 
2882
    Horizontal_grid_line(x, row, w);
 
2883
    row+= Snap_height*Main_magnifier_factor;
 
2884
  }
 
2885
  
 
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;
 
2887
  while (col < x+w)
 
2888
  {
 
2889
    Vertical_grid_line(col, y, h);
 
2890
    col+= Snap_width*Main_magnifier_factor;
 
2891
  }
 
2892
}
 
2893
 
 
2894
byte Read_pixel_from_current_screen  (word x,word y)
 
2895
{
 
2896
  #ifndef NOLAYERS
 
2897
  byte depth;
 
2898
  byte color;
 
2899
  color = *(Main_screen+y*Main_image_width+x);
 
2900
  if (color != Main_backups->Pages->Transparent_color) // transparent color
 
2901
    return color;
 
2902
  
 
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);
 
2905
  #else
 
2906
  return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]);
 
2907
  #endif
 
2908
}
 
2909
 
 
2910
void Pixel_in_current_screen      (word x,word y,byte color,int with_preview)
 
2911
{
 
2912
    #ifndef NOLAYERS
 
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)
 
2916
    {
 
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);
 
2920
      
 
2921
      *(x+y*Main_image_width+Main_screen)=color;
 
2922
      
 
2923
      if (with_preview)
 
2924
        Pixel_preview(x,y,color);
 
2925
    }
 
2926
    #else
 
2927
    *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color;
 
2928
    if (with_preview)
 
2929
        Pixel_preview(x,y,color);
 
2930
    #endif
 
2931
}
 
2932
 
 
2933
void Pixel_in_current_layer(word x,word y, byte color)
 
2934
{
 
2935
  *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color;
 
2936
}
 
2937
 
 
2938
byte Read_pixel_from_current_layer(word x,word y)
 
2939
{
 
2940
  return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]);
 
2941
}