]> 4ch.mooo.com Git - 16.git/blob - 16/dos_gfx.cpp
new file: 16/BANKBLIT.C
[16.git] / 16 / dos_gfx.cpp
1 /*\r
2  * LIB.C v1.2a\r
3  *\r
4  * by Robert Schmidt\r
5  * (C)1993 Ztiff Zox Softwear\r
6  *\r
7  * Simple graphics library to accompany the article\r
8  * \r
9  *                      INTRODUCTION TO MODE X.\r
10  * \r
11  * This library provides the basic functions for initializing and using\r
12  * unchained (planar) 256-color VGA modes.  Currently supported are:\r
13  *\r
14  *      - 320x200\r
15  *      - 320x240\r
16  *\r
17  * Functions are provided for:\r
18  *\r
19  *      - initializing one of the available modes\r
20  *      - setting the start address of the VGA refresh data\r
21  *      - setting active and visible display pages\r
22  *      - writing and reading a single pixel to/from video memory\r
23  *\r
24  * The library is provided as a demonstration only, and is not claimed\r
25  * to be particularly efficient or suited for any purpose.  It has only\r
26  * been tested with Borland C++ 3.1 by the author.  Comments on success\r
27  * or disaster with other compilers are welcome.\r
28  *\r
29  * This file is public domain.  Do with it whatever you'd like, but\r
30  * please don't distribute it without the article.\r
31  *\r
32  * Thanks go out to various helpful netters who spotted the 0xE7 bug\r
33  * in the set320x240x256() function!\r
34  *\r
35  * modified by sparky4 so it can be compiled in open watcom ^^\r
36  */\r
37 \r
38 \r
39 \r
40 \r
41 /*\r
42  * We 'require' a large data model simply to get rid of explicit 'far'\r
43  * pointers and compiler specific '_fmemset()' functions and the likes.\r
44  */\r
45 #if !defined(__COMPACT__)\r
46 # if !defined(__LARGE__)\r
47 #  if !defined(__HUGE__)\r
48 #   error Large data model required!  Try compiling with 'bcc -ml lib.c'.\r
49 #  endif\r
50 # endif\r
51 #endif\r
52 \r
53 #include <dos.h>\r
54 #include <mem.h>\r
55 #include <conio.h>\r
56 \r
57 //code from old library!\r
58 /*src\lib\*/\r
59 #include "dos_gfx.h"\r
60 \r
61 int old_mode;\r
62 //color \82Ä\82·\82Æ\r
63 int gq = LGQ;\r
64 //\82Ä\82·\82Æ\r
65 int q = 0;\r
66 int bakax = 0, bakay = 0;\r
67 int xx = rand()&0%320, yy = rand()&0%240, sx = 0, sy = 0;\r
68 byte coor;\r
69 \r
70 /*\r
71  * Comment out the following #define if you don't want the testing main()\r
72  * to be included.\r
73  */\r
74 #define TESTING\r
75 \r
76 /*\r
77  * Define the port addresses of some VGA registers.\r
78  */\r
79 #define CRTC_ADDR       0x3d4   /* Base port of the CRT Controller (color) */\r
80 \r
81 #define SEQU_ADDR       0x3c4   /* Base port of the Sequencer */\r
82 #define GRAC_ADDR       0x3ce   /* Base port of the Graphics Controller */\r
83 \r
84 \r
85 /*\r
86  * Make a far pointer to the VGA graphics buffer segment.  Your compiler\r
87  * might not have the MK_FP macro, but you'll figure something out.\r
88  */\r
89 byte *vga = (byte *) MK_FP(0xA000, 0);\r
90 \r
91 //fontAddr = getFont();\r
92 \r
93 /*\r
94  * width and height should specify the mode dimensions.  widthBytes\r
95  * specify the width of a line in addressable bytes.\r
96  */\r
97 unsigned width, height, widthBytes;\r
98 \r
99 /*\r
100  * actStart specifies the start of the page being accessed by\r
101  * drawing operations.  visStart specifies the contents of the Screen\r
102  * Start register, i.e. the start of the visible page.\r
103  */\r
104 unsigned actStart, visStart;\r
105 \r
106 /*\r
107  * set320x200x256_X()\r
108  *      sets mode 13h, then turns it into an unchained (planar), 4-page\r
109  *      320x200x256 mode.\r
110  */\r
111 void set320x200x256_X(void)\r
112         {\r
113         union REGS r;\r
114 \r
115         /* Set VGA BIOS mode 13h: */\r
116         r.x.ax = 0x0013;\r
117         int86(0x10, &r, &r);\r
118 \r
119         /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */\r
120         outpw(SEQU_ADDR, 0x0604);\r
121 \r
122         /* Turn off word mode, by setting the Mode Control register\r
123         of the CRT Controller (index 0x17, port 0x3d4): */\r
124         outpw(CRTC_ADDR, 0xE317);\r
125 \r
126         /* Turn off doubleword mode, by setting the Underline Location\r
127            register (index 0x14, port 0x3d4): */\r
128         outpw(CRTC_ADDR, 0x0014);\r
129 \r
130         /* Clear entire video memory, by selecting all four planes, then\r
131            writing 0 to entire segment. */\r
132         outpw(SEQU_ADDR, 0x0F02);\r
133         memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */\r
134         vga[0] = 0;\r
135 \r
136         /* Update the global variables to reflect dimensions of this\r
137            mode.  This is needed by most future drawing operations. */\r
138         width           = 320;\r
139         height  = 200;\r
140 \r
141         /* Each byte addresses four pixels, so the width of a scan line\r
142            in *bytes* is one fourth of the number of pixels on a line. */\r
143         widthBytes = width / 4;\r
144 \r
145         /* By default we want screen refreshing and drawing operations\r
146            to be based at offset 0 in the video segment. */\r
147         actStart = visStart = 0;\r
148         }\r
149 \r
150 /*\r
151  * setActiveStart() tells our graphics operations which address in video\r
152  * memory should be considered the top left corner.\r
153  */\r
154 void setActiveStart(unsigned offset)\r
155         {\r
156         actStart = offset;\r
157         }\r
158 \r
159 /*\r
160  * setVisibleStart() tells the VGA from which byte to fetch the first\r
161  * pixel when starting refresh at the top of the screen.  This version\r
162  * won't look very well in time critical situations (games for\r
163  * instance) as the register outputs are not synchronized with the\r
164  * screen refresh.  This refresh might start when the high byte is\r
165  * set, but before the low byte is set, which produces a bad flicker.\r
166  */\r
167 void setVisibleStart(unsigned offset)\r
168         {\r
169         visStart = offset;\r
170         outpw(CRTC_ADDR, 0x0C);         /* set high byte */\r
171         outpw(CRTC_ADDR+1, visStart >> 8);\r
172         outpw(CRTC_ADDR, 0x0D);         /* set low byte */\r
173         outpw(CRTC_ADDR+1, visStart & 0xff);\r
174         }\r
175 \r
176 /*\r
177  * setXXXPage() sets the specified page by multiplying the page number\r
178  * with the size of one page at the current resolution, then handing the\r
179  * resulting offset value over to the corresponding setXXXStart()\r
180  * function.  The first page is number 0.\r
181  */\r
182 void setActivePage(int page)\r
183         {\r
184         setActiveStart(page * widthBytes * height);\r
185         }\r
186 \r
187 void setVisiblePage(int page)\r
188         {\r
189         setVisibleStart(page * widthBytes * height);\r
190         }\r
191 \r
192 void putPixel_X(int x, int y, byte color)\r
193         {\r
194         /* Each address accesses four neighboring pixels, so set\r
195            Write Plane Enable according to which pixel we want\r
196            to modify.  The plane is determined by the two least\r
197            significant bits of the x-coordinate: */\r
198         outp(0x3c4, 0x02);\r
199         outp(0x3c5, 0x01 << (x & 3));\r
200 \r
201         /* The offset of the pixel into the video segment is\r
202            offset = (width * y + x) / 4, and write the given\r
203            color to the plane we selected above.  Heed the active\r
204            page start selection. */\r
205         vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;\r
206 \r
207         }\r
208 \r
209 byte getPixel_X(int x, int y)\r
210         {\r
211         /* Select the plane from which we must read the pixel color: */\r
212         outpw(GRAC_ADDR, 0x04);\r
213         outpw(GRAC_ADDR+1, x & 3);\r
214 \r
215         return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];\r
216 \r
217         }\r
218 \r
219 void set320x240x256_X(void)\r
220         {\r
221         /* Set the unchained version of mode 13h: */\r
222         set320x200x256_X();\r
223 \r
224         /* Modify the vertical sync polarity bits in the Misc. Output\r
225            Register to achieve square aspect ratio: */\r
226         outp(0x3C2, 0xE3);\r
227 \r
228         /* Modify the vertical timing registers to reflect the increased\r
229            vertical resolution, and to center the image as good as\r
230            possible: */\r
231         outpw(0x3D4, 0x2C11);           /* turn off write protect */\r
232         outpw(0x3D4, 0x0D06);           /* vertical total */\r
233         outpw(0x3D4, 0x3E07);           /* overflow register */\r
234         outpw(0x3D4, 0xEA10);           /* vertical retrace start */\r
235         outpw(0x3D4, 0xAC11);           /* vertical retrace end AND wr.prot */\r
236         outpw(0x3D4, 0xDF12);           /* vertical display enable end */\r
237         outpw(0x3D4, 0xE715);           /* start vertical blanking */\r
238         outpw(0x3D4, 0x0616);           /* end vertical blanking */\r
239 \r
240         /* Update mode info, so future operations are aware of the\r
241            resolution */\r
242         height = 240;\r
243 \r
244         }\r
245
246
247 /*tile*/
248 // This is Bresenham's Line Drawing Algorithm\r
249 void drawline(int x1, int y1, int x2, int y2, char col)\r
250 {\r
251         int d, x, y, ax, ay, sx, sy, dx, dy;\r
252 \r
253         dx = x2-x1;\r
254         ax = ABS(dx) << 1;\r
255         sx = SGN(dx);\r
256         dy = y2-y1;\r
257         ay = ABS(dy) << 1;\r
258         sy = SGN(dy);\r
259 \r
260         x = x1;\r
261         y = y1;\r
262         if( ax > ay )\r
263         {\r
264                 d = ay - (ax >> 1);\r
265                 while( x != x2 )\r
266                 {\r
267                         putPixel_X( x, y, col );\r
268                         if( d >= 0 )\r
269                         {\r
270                                 y += sy;\r
271                                 d -= ax;\r
272                         }\r
273                 x += sx;\r
274                 d += ay;\r
275                 }\r
276         }\r
277         else\r
278         {\r
279                 d = ax - (ay >> 1);\r
280                 while( y != y2 )\r
281                 {\r
282                         putPixel_X( x, y, col );\r
283                         if( d >= 0 )\r
284                         {\r
285                                 x += sx;\r
286                                 d -= ay;\r
287                         }\r
288                         y += sy;\r
289                         d += ax;\r
290                 }\r
291         }\r
292         return;\r
293 }\r
294 \r
295 void drawrect(int x1, int y1, int x2, int y2, char color)\r
296 {
297         drawline(x1,y1,x2,y1,color);\r
298         drawline(x1,y2,x2,y2,color);\r
299         drawline(x1,y1,x1,y2,color);\r
300         drawline(x2,y1,x2,y2+1,color);\r
301 }
302 \r
303 \r
304 /*-----------XXXX-------------*/\r
305 //---------------------------------------------------\r
306 //\r
307 // Use the bios to get the address of the 8x8 font\r
308 //\r
309 // You need a font if you are going to draw text.\r
310 //\r
311 \r
312 int far *\r
313 getFont()\r
314 {\r
315     union REGPACK rg;\r
316     int seg;\r
317     int off;\r
318     memset(&rg, 0, sizeof(rg));\r
319 \r
320     rg.w.ax = 0x1130;\r
321     rg.h.bh = 0x03;\r
322     intr(0x10, &rg);\r
323     seg = rg.w.es;\r
324     off = rg.w.bp;\r
325     \r
326 \r
327     return (int far *)MK_FP(seg, off);\r
328 }\r
329 \r
330 void drawChar(int x, int y, int color, byte c)\r
331 {\r
332         int i, j;\r
333         int mask;\r
334         int far *font = getFont() + (c * 8);\r
335 \r
336         for (i = 0; i < 8; i++)\r
337         {\r
338                 mask = *font;\r
339                 for (j = 0; j < 8; j++)\r
340                 {\r
341                         if (mask & 0x80)\r
342                         {\r
343                                 //pixel(x + j, y + i, color);\r
344                                 putPixel_X(x + j, y + i, color);\r
345                         }\r
346                         mask <<= 1;\r
347                 }\r
348                 font++;\r
349         }\r
350 }\r
351 \r
352 void drawText(int x, int y, int color, byte string)\r
353 {\r
354         while (string)\r
355         {\r
356                 drawChar(x, y, color, string);\r
357                 x += 8;\r
358                 string++;\r
359         }\r
360 }\r
361 \r
362 /////////////////////////////////////////////////////////////////////////////\r
363 //                                                                         //\r
364 // setvideo() - This function Manages the video modes                      //\r
365 //                                                                         //\r
366 /////////////////////////////////////////////////////////////////////////////\r
367 void setvideo(/*byte mode, */int vq){\r
368         union REGS in, out;\r
369 \r
370         if(!vq){ // deinit the video\r
371                 // change to the video mode we were in before we switched to mode 13h\r
372                 in.h.ah = 0x00;\r
373                 in.h.al = old_mode;\r
374                 int86(0x10, &in, &out);\r
375 \r
376         }else if(vq == 1){ // init the video\r
377                 // get old video mode\r
378                 in.h.ah = 0xf;\r
379                 int86(0x10, &in, &out);\r
380                 old_mode = out.h.al;\r
381 \r
382                 // enter mode\r
383                 set320x240x256_X();\r
384         }\r
385 }\r
386 \r
387 /////////////////////////////////////////////////////////////////////////////\r
388 //                                                                         //\r
389 // cls() - This clears the screen to the specified color, on the VGA or on //\r
390 //         the Virtual screen.                                             //\r
391 //                                                                         //\r
392 /////////////////////////////////////////////////////////////////////////////\r
393 void cls(byte color, byte *Where){\r
394         _fmemset(Where, color, width*height);\r
395 }\r
396 \r
397 //color \82Ä\82·\82Æ\r
398 int colortest(){\r
399         if(gq < NUM_COLORS){\r
400                 cls(gq, vga);\r
401                 gq++;\r
402         }else gq = 0;\r
403         return gq;\r
404 }\r
405 \r
406 //color \82Ä\82·\82Æ\r
407 int colorz(){\r
408         if(gq < HGQ){\r
409 //----          cls(gq, vaddr);\r
410                 cls(gq, vga);\r
411                 gq++;\r
412         }else gq = LGQ;\r
413         return gq;\r
414 }\r
415 \r
416 //slow spectrum down\r
417 void ssd(int svq){\r
418         if(sy < height+1){\r
419                 if(sx < width+1){\r
420                         //plotpixel(xx, yy, coor, vga);\r
421                         //ppf(sx, sy, coor, vga);\r
422                         putPixel_X(sx, sy, coor);\r
423                         //printf("%d %d %d %d\n", sx, sy, svq, coor);\r
424                         sx++;\r
425                 }else sx = 0;\r
426                 if(sx == width){\r
427                         sy++;\r
428                         if(svq == 7) coor++;\r
429                         if(sy == height && svq == 8) coor = rand()%NUM_COLORS;\r
430                 }\r
431         }else sy = 0;\r
432 }\r
433 \r
434 /*-----------ding-------------*/\r
435 int ding(int q){\r
436         setActivePage(0);\r
437         setVisiblePage(0);\r
438         int d3y;\r
439 \r
440 //++++  if(q <= 4 && q!=2 && gq == BONK-1) coor = rand()%HGQ;\r
441         if((q == 2\r
442         ||q==4\r
443         ||q==16\r
444         ) && gq == BONK-1){\r
445                         if(coor < HGQ && coor < LGQ) coor = LGQ;\r
446                         if(coor < HGQ-1){\r
447                                 coor++;\r
448                 }else{ coor = LGQ;\r
449                         bakax = rand()%3; bakay = rand()%3;\r
450                 }\r
451         }\r
452 \r
453         if(q == 5){ colortest(); return gq; }\r
454         if(q == 10){ colorz(); return gq; }\r
455         if(q == 11){ colorz(); delay(100); return gq; }\r
456         if(q == 8){ ssd(q); /*printf("%d\n", coor);*/ }\r
457         if(q == 6){\r
458                 coor = rand()%NUM_COLORS;\r
459 //----          cls(coor, vaddr);\r
460                 cls(coor, vga);\r
461                 //updatevbuff();\r
462         }\r
463 \r
464         if(q == 7 || q== 9){\r
465                 if(gq < HGQ){\r
466                         if(q == 7) ssd(q);\r
467                         if(q == 9){ ssd(q); coor++; }\r
468                         gq++;\r
469                 }else gq = LGQ;\r
470         }\r
471         if((q<5 && gq<BONK) || (q==16 && gq<BONK)){ // the number variable make the colors more noticable\r
472                 if(q==1){\r
473                         if(xx==width){bakax=0;}\r
474                         if(xx==0){bakax=1;}\r
475                         if(yy==height){bakay=0;}\r
476                         if(yy==0){bakay=1;}\r
477                 }else if(q==3){\r
478                         if(xx!=width||yy!=height){\r
479                                 if(xx==0){bakax=1;bakay=-1;d3y=1;}\r
480                                 if(yy==0){bakax=1;bakay=0;d3y=1;}\r
481                                 if(xx==width){bakax=-1;bakay=-1;d3y=1;}\r
482                                 if(yy==height){bakax=1;bakay=0;d3y=1;}\r
483                         }else if(xx==width&&yy==height) xx=yy=0;\r
484                 }\r
485                 if(q==3){\r
486                         if(d3y){\r
487                                 if(bakay<0){\r
488                                         yy--;\r
489                                         d3y--;\r
490                                 }else\r
491                                 if(bakay>0){\r
492                                         yy++;\r
493                                         d3y--;\r
494                                 }\r
495                         }\r
496                         if(bakax<0){\r
497                                 xx--;\r
498                         }else\r
499                         if(bakax>0){\r
500                                 xx++;\r
501                         }\r
502                 }else{\r
503                         if(q==16)\r
504                         {\r
505                                 if(!bakax){\r
506                                         xx--;//=TILEWH;\r
507                                 }else if(bakax>0){\r
508                                         xx++;//=TILEWH;\r
509                                 }\r
510                                 if(!bakay){\r
511                                         yy--;//=TILEWH;\r
512                                 }else if(bakay>0){\r
513                                         yy++;//=TILEWH;\r
514                                 }\r
515                         }else{\r
516                                 if(!bakax){\r
517                                         xx-=TILEWH;\r
518                                 }else if(bakax>1){\r
519                                         xx+=TILEWH;\r
520                                 }\r
521                                 if(!bakay){\r
522                                         yy-=TILEWH;\r
523                                 }else if(bakay>1){\r
524                                         yy+=TILEWH;\r
525                                 }\r
526                         }\r
527                 }\r
528                 // fixer\r
529                 if(q!=16){\r
530                         if(xx<0) xx=width;\r
531                         if(yy<0) yy=height;\r
532                         if(xx>width) xx=0;\r
533                         if(yy>height) yy=0;\r
534                 }\r
535 \r
536 //interesting effects\r
537                 if(q==16)\r
538                 {\r
539                 int tx=0,ty=0;\r
540                 tx+=xx+16;\r
541                 ty+=yy+16;\r
542                 putPixel_X(tx, ty, coor);
543                 //drawrect(tx, ty, tx+TILEWH, ty+TILEWH, coor);\r
544                 //printf("%d %d %d %d %d %d\n", xx, yy, tx, ty, TILEWH);\r
545 \r
546                 // plot the pixel\r
547 //----          ppf(xx, yy, coor, vga);\r
548 //++++0000              putPixel_X(xx, yy, coor);\r
549                 }else drawrect(xx, yy, xx+TILEWH-1, yy+TILEWH-1, coor);\r
550 //----          if(q==2) ppf(rand()%, rand()%height, 0, vga);\r
551                 if(q==2||q==16) putPixel_X(rand()%width, rand()%height, 0);\r
552                 if(q==2||q==4||q==16){ bakax = rand()%3; bakay = rand()%3; }\r
553                 gq++;\r
554 //if(xx<0||xx>320||yy<0||yy>240)\r
555 //      printf("%d %d %d %d %d %d\n", xx, yy, coor, bakax, bakay, getPixel_X(xx,yy));\r
556 //      printf("%d\n", getPixel_X(xx,yy));\r
557 //0000\r
558 //      drawText(0, 0, 15, getPixel_X(xx,yy));\r
559         }else gq = LGQ;\r
560         return gq;\r
561 }\r
562 \r
563 \r
564 /*\r
565  * The library testing routines follows below.\r
566  */\r
567 \r
568 \r
569 #ifdef TESTING\r
570 \r
571 #include <stdio.h>\r
572 #include <conio.h>\r
573 \r
574 void doTest(void)\r
575         {\r
576         int p, x, y, pages;\r
577 \r
578         /* This is the way to calculate the number of pages available. */\r
579         pages = 65536L/(widthBytes*height); // apparently this takes the A000 address\r
580 \r
581         printf("%d\n", pages);\r
582 \r
583         for (p = 0; p <= pages; ++p)\r
584                 {\r
585                 setActivePage(p);\r
586 \r
587                 /* On each page draw a single colored border, and dump the palette\r
588                    onto a small square about the middle of the page. */\r
589                    \r
590                    //{\r
591                         for (x = 0; x <= width; ++x)\r
592                                 {\r
593                                 putPixel_X(x, 0, p+1);\r
594                                 if(p!=pages) putPixel_X(x, height-1, p+1);\r
595                                         else putPixel_X(x, 99-1, p+1);\r
596                                 }\r
597 \r
598                         for (y = 0; y <= height; ++y)\r
599                                 {\r
600                                 putPixel_X(0, y, p+1);\r
601                                 if(p!=pages) putPixel_X(width-1, y, p+1);\r
602                                         else putPixel_X(width-1, y, p+1);\r
603                                 }\r
604 \r
605                         for (x = 0; x < 16; ++x)\r
606                                 for (y = 0; y < 16; ++y)\r
607                                         putPixel_X(x+(p+2)*16, y+(p+2)*16, x + y*16);\r
608                         //}\r
609 \r
610                 drawText(0, 0, 15, p);\r
611 \r
612                 }\r
613 \r
614         /* Each pages will now contain a different image.  Let the user cycle\r
615            through all the pages by pressing a key. */\r
616         for (p = 0; p <= pages; ++p)\r
617                 {\r
618                 setVisiblePage(p);\r
619                 //drawText(0, 240, 15, "bakapi");\r
620                 getch();\r
621                 }\r
622 \r
623         }\r
624 \r
625 /*\r
626  * Library test (program) entry point.\r
627  */\r
628 \r
629 int main(void)\r
630         {\r
631         int key,d;\r
632         // main variables\r
633         d=1; // switch variable\r
634         key=4; // default screensaver number\r
635 //      puts("First, have a look at the 320x200 mode.  I will draw some rubbish");\r
636 //      puts("on all of the four pages, then let you cycle through them by");\r
637 //      puts("hitting a key on each page.");\r
638 //      puts("Press a key when ready...");\r
639 //      getch();\r
640 \r
641 //      doTest();\r
642 \r
643 //      puts("Then, check out Mode X, 320x240 with 3 (and a half) pages.");\r
644 //      puts("Press a key when ready...");\r
645 //      getch();\r
646 \r
647         setvideo(1);\r
648 // screen savers\r
649 \r
650 /*while(d!=0){ // on!\r
651                 if(!kbhit()){ // conditions of screen saver\r
652                         ding(key);\r
653                 }else{\r
654                         setvideo(0);\r
655                         // user imput switch\r
656                         printf("Enter 1, 2, 3, 4, or 6 to run a screensaver, or enter 5 to quit.\n", getch());  // prompt the user\r
657                         scanf("%d", &key);\r
658                         //if(key==3){xx=yy=0;} // crazy screen saver wwww\r
659                         if(key==5) d=0;\r
660                         setvideo(1);\r
661                 }\r
662         }*/ // else off\r
663         while(!kbhit()){ // conditions of screen saver\r
664                 ding(4);\r
665         }\r
666         //end of screen savers\r
667         doTest();\r
668         setvideo(0);\r
669         puts("Where to next?  It's your move! wwww");\r
670         printf("bakapi ver. 1.04.09a\nis made by sparky4\81i\81\86\83Ö\81\85\81j feel free to use it ^^\nLicence: GPL v2\n");\r
671         return 0;\r
672         }\r
673 \r
674 #endif\r