1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /* Grafx2 - The Ultimate 256-color bitmap paint program
4
5 Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6
7 Grafx2 is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2
10 of the License.
11
12 Grafx2 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 #include <string.h>
21 #ifndef _MSC_VER
22 #include <strings.h>
23 #endif
24 #include <stdlib.h>
25 #include <math.h>
26 #include "struct.h"
27 #include "global.h"
28 #include "errors.h"
29 #include "buttons.h"
30 #include "engine.h"
31 #include "misc.h"
32 #include "osdep.h"
33 #include "keyboard.h"
34 #include "screen.h"
35 #include "windows.h"
36 #include "palette.h"
37 #include "input.h"
38 #include "graph.h"
39 #include "pages.h"
40
41 ///Count used palette indexes in the whole picture
42 ///Return the total number of different colors
43 ///Fill in "usage" with the count for each color
Count_used_colors(dword * usage)44 word Count_used_colors(dword* usage)
45 {
46 int nb_pixels = 0;
47 byte* current_pixel;
48 byte color;
49 word nb_colors = 0;
50 int i;
51 int layer;
52
53 for (i = 0; i < 256; i++) usage[i]=0;
54
55 // Compute total number of pixels in the picture
56 nb_pixels = Main.image_height * Main.image_width;
57
58 // For each layer
59 for (layer = 0; layer < Main.backups->Pages->Nb_layers; layer++)
60 {
61 current_pixel = Main.backups->Pages->Image[layer].Pixels;
62 // For each pixel in picture
63 for (i = 0; i < nb_pixels; i++)
64 {
65 color=*current_pixel; // get color in picture for this pixel
66
67 usage[color]++; // add it to the counter
68
69 // go to next pixel
70 current_pixel++;
71 }
72 }
73
74 // count the total number of unique used colors
75 for (i = 0; i < 256; i++)
76 {
77 if (usage[i]!=0)
78 nb_colors++;
79 }
80
81 return nb_colors;
82 }
83
84 /// Same as ::Count_used_colors, but use a block screen memory instead of
85 /// picture data. Used to count colors in the loading screen.
Count_used_colors_screen_area(dword * usage,word start_x,word start_y,word width,word height)86 word Count_used_colors_screen_area(dword* usage, word start_x, word start_y,
87 word width, word height)
88 {
89 byte color;
90 word x, y;
91 word nb_colors = 0;
92 int i;
93
94 // Init usage table
95 for (i = 0; i < 256; i++) usage[i]=0;
96
97 // For each pixel in screen area
98 for (y = 0; y < height; y++)
99 {
100 for (x = 0; x < width; x++)
101 {
102 // Get color in screen memory
103 //color=*(Screen_pixels+((start_x + x)+(start_y + y) * Screen_width
104 // * Pixel_height) * Pixel_width);
105 color = Get_Screen_pixel(start_x + x, start_y + y);
106 usage[color]++; //Un point de plus pour cette couleur
107 }
108 }
109 //On va maintenant compter dans la table les couleurs utilisées:
110 for (i = 0; i < 256; i++)
111 {
112 if (usage[i]!=0)
113 nb_colors++;
114 }
115 return nb_colors;
116 }
117
118
119 /// Same as ::Count_used_colors, but for a given rectangle in the picture only.
120 /// Used bu the C64 block constraint checker.
Count_used_colors_area(dword * usage,word start_x,word start_y,word width,word height)121 word Count_used_colors_area(dword* usage, word start_x, word start_y,
122 word width, word height)
123 {
124 byte color;
125 word x, y;
126 word nb_colors = 0;
127 int i;
128
129 // Init usage table
130 for (i = 0; i < 256; i++) usage[i]=0;
131
132 // On parcourt l'écran courant pour compter les utilisations des couleurs
133 for (y = 0; y < height; y++)
134 {
135 for (x = 0; x < width; x++)
136 {
137 // Get color from picture
138 color=*(Main_screen+((start_x + x)+(start_y + y)*Main.image_width));
139 usage[color]++; //Un point de plus pour cette couleur
140 }
141 }
142
143 //On va maintenant compter dans la table les couleurs utilisées:
144 for (i = 0; i < 256; i++)
145 {
146 if (usage[i]!=0)
147 nb_colors++;
148 }
149 return nb_colors;
150 }
151
152
153 // Backup of the currently displayed palette.
154 // It is not always Main_palette ! (for example during a preview)
155 // external code must not modify this array but use Set_palette() / Set_color()
156 // Get_current_palette() offers a READ-ONLY access.
157 static T_Palette Current_palette;
158
Get_current_palette(void)159 const T_Components * Get_current_palette(void)
160 {
161 return Current_palette;
162 }
163
Set_palette(T_Palette palette)164 void Set_palette(T_Palette palette)
165 {
166 int i;
167
168 memcpy(Current_palette, palette, sizeof(T_Palette));
169 for(i=0;i<256;i++)
170 {
171 palette[i].R = Round_palette_component(palette[i].R);
172 palette[i].G = Round_palette_component(palette[i].G);
173 palette[i].B = Round_palette_component(palette[i].B);
174 }
175 GFX2_SetPalette(palette, 0, 256);
176 }
177
Set_color(byte color,byte red,byte green,byte blue)178 void Set_color(byte color, byte red, byte green, byte blue)
179 {
180 Current_palette[color].R = red;
181 Current_palette[color].G = green;
182 Current_palette[color].B = blue;
183 GFX2_SetPalette(Current_palette + color, color, 1);
184 }
185
Wait_end_of_click(void)186 void Wait_end_of_click(void)
187 {
188 // On désactive tous les raccourcis clavier
189
190 while(Mouse_K)
191 Get_input(20);
192 }
193
Clear_current_image_with_stencil(byte color,byte * stencil)194 void Clear_current_image_with_stencil(byte color, byte * stencil)
195 //Effacer l'image courante avec une certaine couleur en mode Stencil
196 {
197 int nb_pixels=0; //ECX
198 //al=color
199 //edi=Screen_pixels
200 byte* pixel=Main.backups->Pages->Image[Main.current_layer].Pixels;
201 int i;
202
203 nb_pixels=Main.image_height*Main.image_width;
204
205 for(i=0;i<nb_pixels;i++)
206 {
207 if (stencil[*pixel]==0)
208 *pixel=color;
209 pixel++;
210 }
211 }
212
Clear_current_image(byte color)213 void Clear_current_image(byte color)
214 // Effacer l'image courante avec une certaine couleur
215 {
216 memset(
217 Main.backups->Pages->Image[Main.current_layer].Pixels,
218 color ,
219 Main.image_width * Main.image_height
220 );
221 }
222
Init_chrono(dword delay)223 void Init_chrono(dword delay)
224 // Démarrer le chrono
225 {
226 Timer_delay = delay;
227 Timer_start = GFX2_GetTicks()/55;
228 return;
229 }
230
Pixel_in_brush(word x,word y,byte color)231 void Pixel_in_brush (word x, word y, byte color)
232 {
233 *(Brush + y * Brush_width + x)=color;
234 }
235
Read_pixel_from_brush(word x,word y)236 byte Read_pixel_from_brush (word x, word y)
237 {
238 return *(Brush + y * Brush_width + x);
239 }
240
Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width)241 void Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width)
242 {
243 // ESI = adresse de la source en (S_Pox_X,source_y)
244 byte* esi = source + source_y * source_width + source_x;
245
246 // EDI = adresse de la destination (dest_x,dest_y)
247 byte* edi = dest + dest_y * destination_width + dest_x;
248
249 int line;
250
251 // Pour chaque ligne
252 for (line=0;line < height; line++)
253 {
254 memcpy(edi,esi,width);
255
256 // Passe à la ligne suivante
257 esi+=source_width;
258 edi+=destination_width;
259 }
260 }
261
Read_pixel_from_spare_screen(word x,word y)262 byte Read_pixel_from_spare_screen(word x,word y)
263 {
264 // return *(Spare_screen+y*Spare.image_width+x);
265
266 // Clipping is required as this can be called with coordinates from main image
267 // (can be a bigger or smaller image)
268 if (x>=Spare.image_width || y>=Spare.image_height)
269 return Spare.backups->Pages->Transparent_color;
270 if (Spare.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
271 {
272 return *(Spare.backups->Pages->Image[Spare.current_layer].Pixels + y*Spare.image_width + x);
273 }
274 else
275 {
276 return *(Spare.visible_image.Image + y*Spare.image_width + x);
277 }
278 }
279
Rotate_90_deg_lowlevel(byte * source,byte * dest,short width,short height)280 void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height)
281 {
282 word x,y;
283
284 for(y=0;y<height;y++)
285 {
286 for(x=0;x<width;x++)
287 {
288 *(dest+height*(width-1-x)+y)=*source;
289 source++;
290 }
291 }
292 }
293
Rotate_270_deg_lowlevel(byte * source,byte * dest,short width,short height)294 void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short height)
295 {
296 word x,y;
297
298 for(y=0;y<height;y++)
299 {
300 for(x=0;x<width;x++)
301 {
302 *(dest+(height-1-y)+x*height)=*source;
303 source++;
304 }
305 }
306 }
307
308 // Replace une couleur par une autre dans un buffer
309
Remap_general_lowlevel(byte * conversion_table,byte * in_buffer,byte * out_buffer,short width,short height,short buffer_width)310 void Remap_general_lowlevel(byte * conversion_table,byte * in_buffer, byte *out_buffer,short width,short height,short buffer_width)
311 {
312 int dx,cx;
313
314 // Pour chaque ligne
315 for(dx=height;dx>0;dx--)
316 {
317 // Pour chaque pixel
318 for(cx=width;cx>0;cx--)
319 {
320 *out_buffer = conversion_table[*in_buffer];
321 in_buffer++;
322 out_buffer++;
323 }
324 in_buffer += buffer_width-width;
325 out_buffer += buffer_width-width;
326 }
327 }
328
Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width)329 void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width)
330 {
331 byte* src=start_y*image_width+start_x+Main.backups->Pages->Image[Main.current_layer].Pixels; //Adr départ image (ESI)
332 byte* dest=Brush_original_pixels; //Adr dest brosse (EDI)
333 int dx;
334
335 for (dx=Brush_height;dx!=0;dx--)
336 //Pour chaque ligne
337 {
338
339 // On fait une copie de la ligne
340 memcpy(dest,src,Brush_width);
341
342 // On passe à la ligne suivante
343 src+=image_width;
344 dest+=Brush_width;
345 }
346
347 }
348
Read_pixel_from_feedback_screen(word x,word y)349 byte Read_pixel_from_feedback_screen (word x,word y)
350 {
351 return *(FX_feedback_screen+y*Main.image_width+x);
352 }
353
Round_div(dword numerator,dword divisor)354 dword Round_div(dword numerator,dword divisor)
355 {
356 return numerator/divisor;
357 }
358
Effect_sieve(word x,word y)359 byte Effect_sieve(word x,word y)
360 {
361 return Sieve[x % Sieve_width][y % Sieve_height];
362 }
363
Replace_colors_within_limits(byte * replace_table)364 void Replace_colors_within_limits(byte * replace_table)
365 {
366 int y;
367 int x;
368 byte* pixel;
369
370 // Pour chaque ligne :
371 for(y = Limit_top;y <= Limit_bottom; y++)
372 {
373 // Pour chaque pixel sur la ligne :
374 for (x = Limit_left;x <= Limit_right;x ++)
375 {
376 pixel = Main.backups->Pages->Image[Main.current_layer].Pixels+y*Main.image_width+x;
377 *pixel = replace_table[*pixel];
378 }
379 }
380 }
381
Read_pixel_from_backup_screen(word x,word y)382 byte Read_pixel_from_backup_screen (word x,word y)
383 {
384 return *(Screen_backup + x + Main.image_width * y);
385 }
386
Effect_interpolated_colorize(word x,word y,byte color)387 byte Effect_interpolated_colorize (word x,word y,byte color)
388 {
389 // factor_a = 256*(100-Colorize_opacity)/100
390 // factor_b = 256*( Colorize_opacity)/100
391 //
392 // (Couleur_dessous*factor_a+color*facteur_B)/256
393 //
394
395 // On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la
396 // palette des teintes) et dans EDI, 3*color.
397 byte color_under = Read_pixel_from_feedback_screen(x,y);
398 byte blue_under=Main.palette[color_under].B;
399 byte blue=Main.palette[color].B;
400 byte green_under=Main.palette[color_under].G;
401 byte green=Main.palette[color].G;
402 byte red_under=Main.palette[color_under].R;
403 byte red=Main.palette[color].R;
404
405 // On récupère les 3 composantes RVB
406
407 // blue
408 blue = (Factors_inv_table[blue]
409 + Factors_table[blue_under]) / 256;
410 green = (Factors_inv_table[green]
411 + Factors_table[green_under]) / 256;
412 red = (Factors_inv_table[red]
413 + Factors_table[red_under]) / 256;
414 return Best_color(red,green,blue);
415
416 }
417
Effect_additive_colorize(word x,word y,byte color)418 byte Effect_additive_colorize (word x,word y,byte color)
419 {
420 byte color_under = Read_pixel_from_feedback_screen(x,y);
421 byte blue_under=Main.palette[color_under].B;
422 byte green_under=Main.palette[color_under].G;
423 byte red_under=Main.palette[color_under].R;
424 byte blue=Main.palette[color].B;
425 byte green=Main.palette[color].G;
426 byte red=Main.palette[color].R;
427
428 return Best_color(
429 red>red_under?red:red_under,
430 green>green_under?green:green_under,
431 blue>blue_under?blue:blue_under);
432 }
433
Effect_substractive_colorize(word x,word y,byte color)434 byte Effect_substractive_colorize(word x,word y,byte color)
435 {
436 byte color_under = Read_pixel_from_feedback_screen(x,y);
437 byte blue_under=Main.palette[color_under].B;
438 byte green_under=Main.palette[color_under].G;
439 byte red_under=Main.palette[color_under].R;
440 byte blue=Main.palette[color].B;
441 byte green=Main.palette[color].G;
442 byte red=Main.palette[color].R;
443
444 return Best_color(
445 red<red_under?red:red_under,
446 green<green_under?green:green_under,
447 blue<blue_under?blue:blue_under);
448 }
449
Effect_alpha_colorize(word x,word y,byte color)450 byte Effect_alpha_colorize (word x,word y,byte color)
451 {
452 byte color_under = Read_pixel_from_feedback_screen(x,y);
453 byte blue_under=Main.palette[color_under].B;
454 byte green_under=Main.palette[color_under].G;
455 byte red_under=Main.palette[color_under].R;
456 int factor=(Main.palette[color].R*76 +
457 Main.palette[color].G*151 +
458 Main.palette[color].B*28)/255;
459
460 return Best_color(
461 (Main.palette[Fore_color].R*factor + red_under*(255-factor))/255,
462 (Main.palette[Fore_color].G*factor + green_under*(255-factor))/255,
463 (Main.palette[Fore_color].B*factor + blue_under*(255-factor))/255);
464 }
465
Check_timer(void)466 void Check_timer(void)
467 {
468 if((GFX2_GetTicks()/55)-Timer_delay>Timer_start) Timer_state=1;
469 }
470
Flip_Y_lowlevel(byte * src,short width,short height)471 void Flip_Y_lowlevel(byte *src, short width, short height)
472 {
473 // ESI pointe sur la partie haute de la brosse
474 // EDI sur la partie basse
475 byte* ESI = src ;
476 byte* EDI = src + (height - 1) *width;
477 byte tmp;
478 word cx;
479
480 while(ESI < EDI)
481 {
482 // Il faut inverser les lignes pointées par ESI et
483 // EDI ("Brush_width" octets en tout)
484
485 for(cx = width;cx>0;cx--)
486 {
487 tmp = *ESI;
488 *ESI = *EDI;
489 *EDI = tmp;
490 ESI++;
491 EDI++;
492 }
493
494 // On change de ligne :
495 // ESI pointe déjà sur le début de la ligne suivante
496 // EDI pointe sur la fin de la ligne en cours, il
497 // doit pointer sur le début de la précédente...
498 EDI -= 2 * width; // On recule de 2 lignes
499 }
500 }
501
Flip_X_lowlevel(byte * src,short width,short height)502 void Flip_X_lowlevel(byte *src, short width, short height)
503 {
504 // ESI pointe sur la partie gauche et EDI sur la partie
505 // droite
506 byte* ESI = src;
507 byte* EDI = src + width - 1;
508
509 byte* line_start;
510 byte* line_end;
511 byte tmp;
512 word cx;
513
514 while(ESI<EDI)
515 {
516 line_start = ESI;
517 line_end = EDI;
518
519 // On échange par colonnes
520 for(cx=height;cx>0;cx--)
521 {
522 tmp=*ESI;
523 *ESI=*EDI;
524 *EDI=tmp;
525 EDI+=width;
526 ESI+=width;
527 }
528
529 // On change de colonne
530 // ESI > colonne suivante
531 // EDI > colonne précédente
532 ESI = line_start + 1;
533 EDI = line_end - 1;
534 }
535 }
536
537 // Rotate a pixel buffer 180º on itself.
Rotate_180_deg_lowlevel(byte * src,short width,short height)538 void Rotate_180_deg_lowlevel(byte *src, short width, short height)
539 {
540 // ESI pointe sur la partie supérieure de la brosse
541 // EDI pointe sur la partie basse
542 byte* ESI = src;
543 byte* EDI = src + height*width - 1;
544 // EDI pointe sur le dernier pixel de la derniere ligne
545 byte tmp;
546 word cx;
547
548 // In case of odd height, the algorithm in this function would
549 // miss the middle line, so we do it this way:
550 if (height & 1)
551 {
552 Flip_X_lowlevel(src, width, height);
553 Flip_Y_lowlevel(src, width, height);
554 return;
555 }
556
557
558 while(ESI < EDI)
559 {
560 // On échange les deux lignes pointées par EDI et
561 // ESI (Brush_width octets)
562 // En même temps, on échange les pixels, donc EDI
563 // pointe sur la FIN de sa ligne
564
565 for(cx=width;cx>0;cx--)
566 {
567 tmp = *ESI;
568 *ESI = *EDI;
569 *EDI = tmp;
570
571 EDI--; // Attention ici on recule !
572 ESI++;
573 }
574 }
575 }
576
Rescale(byte * src_buffer,short src_width,short src_height,byte * dst_buffer,short dst_width,short dst_height,short x_flipped,short y_flipped)577 void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped)
578 {
579 int offset,line,column;
580
581 int x_pos_in_brush; // Position courante dans l'ancienne brosse
582 int y_pos_in_brush;
583 int initial_x_pos; // Position X de début de parcours de ligne
584 int initial_y_pos; // Position Y de début de parcours de ligne
585
586 int delta_x, delta_y;
587
588 offset=0;
589
590 // Calcul de la valeur initiale de y_pos:
591 if (y_flipped) {
592 initial_y_pos=(src_height)-1; // Inversion en Y de la brosse
593 delta_y = -1 * src_height;
594 } else {
595 initial_y_pos=0; // Pas d'inversion en Y de la brosse
596 delta_y = src_height;
597 }
598
599 // Calcul de la valeur initiale de x_pos pour chaque ligne:
600 if (x_flipped) {
601 initial_x_pos = (src_width)-1; // Inversion en X de la brosse
602 delta_x = -1 * src_width;
603 } else {
604 initial_x_pos = 0; // Pas d'inversion en X de la brosse
605 delta_x = src_width;
606 }
607
608 // Pour chaque ligne
609 for (line=0;line<dst_height;line++)
610 {
611 // On passe à la ligne de brosse suivante:
612 y_pos_in_brush = initial_y_pos + line * delta_y / dst_height;
613
614 // Pour chaque colonne:
615 for (column=0;column<dst_width;column++)
616 {
617 // On passe à la colonne de brosse suivante:
618 x_pos_in_brush = initial_x_pos + column * delta_x / dst_width;
619 // On copie le pixel:
620 dst_buffer[offset]=*(src_buffer + x_pos_in_brush + y_pos_in_brush * src_width);
621 // On passe au pixel suivant de la nouvelle brosse:
622 offset++;
623 }
624 }
625 }
626
627
Scroll_picture(byte * main_src,byte * main_dest,short x_offset,short y_offset)628 void Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset)
629 {
630 byte* src = main_src; //source de la copie
631 byte* dest = main_dest + y_offset * Main.image_width + x_offset;
632 const word length = Main.image_width - x_offset; // Nombre de pixels à copier à droite
633 word y;
634 for(y = Main.image_height - y_offset;y>0;y--)
635 {
636 // Pour chaque ligne
637 memcpy(dest,src,length);
638 memcpy(dest - x_offset,src+length,x_offset);
639
640 // On passe à la ligne suivante
641 dest += Main.image_width;
642 src += Main.image_width;
643 }
644
645 // On vient de faire le traitement pour otutes les lignes au-dessous de y_offset
646 // Maintenant on traite celles au dessus
647 dest = x_offset + main_dest;
648 for(y = y_offset;y>0;y--)
649 {
650 memcpy(dest,src,length);
651 memcpy(dest - x_offset,src+length,x_offset);
652
653 dest += Main.image_width;
654 src += Main.image_width;
655 }
656
657 Update_rect(0,0,0,0);
658 }
659
Zoom_a_line(byte * original_line,byte * zoomed_line,word factor,word width)660 void Zoom_a_line(byte* original_line, byte* zoomed_line,
661 word factor, word width
662 )
663 {
664 byte color;
665 word x;
666
667 // Pour chaque pixel
668 for(x=0;x<width;x++){
669 color = *original_line;
670
671 memset(zoomed_line,color,factor);
672 zoomed_line+=factor;
673
674 original_line++;
675 }
676 }
677
678 /*############################################################################*/
679
680 // Arrondir un nombre réel à la valeur entière la plus proche
681 // TODO : this should probably be replaced with round() from C99...
Round(float value)682 short Round(float value)
683 {
684 short temp=value;
685
686 if (value>=0)
687 { if ((value-temp)>= 0.5) temp++; }
688 else
689 { if ((value-temp)<=-0.5) temp--; }
690
691 return temp;
692 }
693
694
695 // Arrondir le résultat d'une division à la valeur entière supérieure
Round_div_max(short numerator,short divisor)696 short Round_div_max(short numerator,short divisor)
697 {
698 if (!(numerator % divisor))
699 return (numerator/divisor);
700 else
701 return (numerator/divisor)+1;
702 }
703
704
705 // Retourne le minimum entre deux nombres
Min(int a,int b)706 int Min(int a,int b)
707 {
708 return (a<b)?a:b;
709 }
710
711
712 // Retourne le maximum entre deux nombres
Max(int a,int b)713 int Max(int a,int b)
714 {
715 return (a>b)?a:b;
716 }
717
718 /* Round number n to d decimal points */
Fround(double n,unsigned d)719 double Fround(double n, unsigned d)
720 {
721 double exp;
722 exp = pow(10.0, d);
723 return floor(n * exp + 0.5) / exp;
724 }
725
726
727 // Fonction retournant le libellé d'une mode (ex: " 320x200")
Mode_label(int mode)728 const char * Mode_label(int mode)
729 {
730 static char str[24];
731 if (! Video_mode[mode].Fullscreen)
732 return "window";
733 sprintf(str, "%dx%d", Video_mode[mode].Width, Video_mode[mode].Height);
734
735 return str;
736 }
737
738
739 // Trouve un mode video à partir d'une chaine: soit "window",
740 // soit de la forme "320x200"
741 // Renvoie -1 si la chaine n'est pas convertible
Convert_videomode_arg(const char * argument)742 int Convert_videomode_arg(const char *argument)
743 {
744 // Je suis paresseux alors je vais juste tester les libellés
745 int mode_index;
746 for (mode_index=0; mode_index<Nb_video_modes; mode_index++)
747 // Attention les vieilles fonctions de lecture .ini mettent tout en MAJUSCULE.
748 if (!strcasecmp(Mode_label(mode_index), argument) && (Video_mode[mode_index].State &128) ==0)
749 return mode_index;
750
751 return -1;
752 }
753