]> 4ch.mooo.com Git - 16.git/blob - 16/graph.h
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / 16 / graph.h
1 ////////////////////////////////////////\r
2 //  Graph.h\r
3 //       Coded by Denn Man\r
4 //\r
5 //  Licensed under the Academic Free License version 1.2\r
6 //\r
7 //  *Special thanks to Micheal Abrash\r
8 //   and his columns in Dr. Dobbs Journal\r
9 //   (Jul91 and Aug91) documenting\r
10 //   ModeX\r
11 //\r
12 //       For use with Turbo-C\r
13 //  Uses as much assembly as possible\r
14 //   in order to optimize drawing speed\r
15 //       Self-sufficient: Nothing else needed\r
16 ////////////////////////////////////////\r
17 \r
18 #include <alloc.h>\r
19 #include <dos.h>\r
20 #include <math.h>\r
21 #include <stdio.h>\r
22 \r
23 \r
24 // Start of video memory (SEGMENT)\r
25 #define MCGA_MEM                0xA000\r
26 // Video Digital-Analog-Converter Port\r
27 #define VIDEO_DAC               0x03C8\r
28 // Video DAC Read Port\r
29 #define DAC_READ                0x03C7\r
30 // Video Data Port\r
31 #define VIDEO_DATA      0x03C9\r
32 // VGA Sequence Controller\r
33 #define SC_INDEX                0x03C4\r
34 // CRT Control Register\r
35 #define CRTC_INDEX      0x03D4\r
36 // Miscellaneous Output Register\r
37 #define MISC_OUTPUT     0x03C2\r
38 // VGA Map Mask Register\r
39 #define MAP_MASK                0x02\r
40 // Screen Width\r
41 #define SCR_WIDTH               80\r
42 // VGA Graphics Controller Register\r
43 #define GC_INDEX                0x03CE\r
44 // VGA Read Map Register\r
45 #define READ_MAP                0x04\r
46 // PI\r
47 #define PI 3.14159265358\r
48 \r
49 // Datatypes\r
50 typedef unsigned char byte;\r
51 typedef unsigned int word;\r
52 typedef unsigned long dword;\r
53 \r
54 typedef struct tagTILE {\r
55         word height;\r
56         word width;\r
57         byte *data;\r
58 } TILE;\r
59 \r
60 // FOR BITMAP FILES!!!\r
61 typedef struct tagBITMAPFILEHEADER {\r
62         word    bfType;\r
63         dword   bfSize;\r
64         word    bfReserved1;\r
65         word    bfReserved2;\r
66         dword   bfOffBits;\r
67 } BITMAPFILEHEADER;\r
68 \r
69 typedef struct tagBITMAPINFOHEADER {\r
70         dword   biSize;\r
71         dword biWidth;\r
72         dword   biHeight;\r
73         word    biPlanes;\r
74         word    biBitCount;\r
75         dword   biCompression;\r
76         dword   biSizeImage;\r
77         dword   biXPelsPerMeter;\r
78         dword   biYPelsPerMeter;\r
79         dword   biClrUsed;\r
80         dword   biClrImportant;\r
81 } BITMAPINFOHEADER;\r
82 \r
83 typedef struct tagRGBQUAD {\r
84         byte    rgbBlue;\r
85         byte    rgbGreen;\r
86         byte    rgbRed;\r
87         byte    rgbReserved;\r
88 } RGBQUAD;\r
89 \r
90 typedef struct tagBITMAPINFO {\r
91         BITMAPINFOHEADER        bmiHeader;\r
92         RGBQUAD                         bmiColors[256];\r
93 } BITMAPINFO;\r
94 \r
95 typedef struct tagBITMAP {\r
96         BITMAPFILEHEADER        bmFileHeader;\r
97         BITMAPINFO                      bmInfo;\r
98         byte                                    *bmData;\r
99 } BITMAP;\r
100 // DONE WITH BITMAP FILE INFO\r
101 \r
102 // Monitor settings for ModeX\r
103 struct tagCRTParms {\r
104         word V_Total;                   // Vertical Total\r
105         word OverFlow;                  // Overflow\r
106         word CellHeight;                // Cell Height\r
107         word V_Sync_Start;      // Vertical Sync Start\r
108         word V_Sync_End;                // Vertical Sync End\r
109         word V_Disp;                    // Vertical Displayed\r
110         word D_Off;                             // Turn off dword mode\r
111         word V_Blank_Start;     // Vertical Blank Start\r
112         word V_Blank_End;               // Vertical Blank End\r
113         word B_On;                              // Turn byte mode on\r
114 } CRTParms;\r
115 \r
116 byte VIDEO_MODE;        // The current video mode\r
117 word MAX_X;                     // Last available X\r
118 word MAX_Y;                     // Last available Y\r
119 word SCREEN_WIDTH;\r
120 word SCREEN_HEIGHT;\r
121 byte MAX_COLORS;        // Last available color\r
122 byte FG_COLOR;          // For text and mono stuff\r
123 byte BG_COLOR;\r
124 word CUR_X;                     // Current X\r
125 word CUR_Y;                     // Current Y\r
126 word visibleStart;// Start offset in video memory of screen\r
127 word activeStart; // Start offset in video memory to write to\r
128 \r
129 // For rectangle filling (ModeX)\r
130 byte LeftClipPlaneMask[] = { 0x0F, 0x0E, 0x0C, 0x08 };\r
131 byte RightClipPlaneMask[] = { 0x0F, 0x01, 0x03, 0x07 };\r
132 \r
133 // In case things go awry\r
134 char msg_error[81];\r
135 \r
136 void exit_error(void)\r
137 {\r
138         printf("%s\a\n", msg_error);\r
139 }\r
140 \r
141 ////////////////////////////////////////\r
142 // init_modeX\r
143 //\r
144 // -Initialized modeX 320x240x256 graphics\r
145 // -Clears video memory\r
146 // -Sets page 1 active at offset 0\r
147 ////////////////////////////////////////\r
148 void init_modeX(void)\r
149 {\r
150         // Fill the CRT Parameters\r
151         CRTParms.V_Total = 0x0D06;\r
152         CRTParms.OverFlow = 0x3E07;\r
153         CRTParms.CellHeight = 0x4109;\r
154         CRTParms.V_Sync_Start = 0xEA10;\r
155         CRTParms.V_Sync_End = 0xAC11;\r
156         CRTParms.V_Disp = 0xDF12;\r
157         CRTParms.D_Off = 0x0014;\r
158         CRTParms.V_Blank_Start = 0xE715;\r
159         CRTParms.V_Blank_End = 0x0616;\r
160         CRTParms.B_On = 0xE317;\r
161 \r
162         asm {\r
163                 mov ax, 0x0013       // Start in mode 13h\r
164                 int 0x10                                        // Call interrupt\r
165 \r
166                 mov dx, SC_INDEX                // Disable Chain-4 Memory model\r
167                 mov ax, 0x0604\r
168                 out dx, ax\r
169                 mov ax, 0x0100                  // Synchronous reset while switching clocks\r
170                 out dx, ax\r
171 \r
172                 mov dx, MISC_OUTPUT     // Select 28MHz dot clock, 60 Hz scan rate\r
173                 mov al, 0xE3\r
174                 out dx, al\r
175 \r
176                 mov dx, SC_INDEX                // Restart Sequencer\r
177                 mov ax, 0x0300\r
178                 out dx, ax\r
179 \r
180                 mov dx, CRTC_INDEX      // Reprogram the CRT Controller\r
181                 mov al, 0x11                    // Select Write-Protect bit\r
182                 out dx, al\r
183                 inc dx                                  // CRT-Data register into DX now\r
184                 in al, dx                               // Get current VSync End Register setting\r
185                 and al, 0x7F         // Remove write-protect on various registers\r
186                 out dx, al\r
187                 dec dx                                  // CRT-Controller\r
188                 cld                                             // Clear the direction\r
189                 mov si, OFFSET CRTParms // Load settings\r
190                 mov cx, 20                              // 20 Entries\r
191         }\r
192         SetCRTParmsLoop:asm {\r
193                 lodsw                                           // Load the addr:data pair\r
194                 out dx, ax                              // Send them out\r
195                 loop SetCRTParmsLoop    // Do it for each one\r
196 \r
197                 mov dx, SC_INDEX                // Enable write to all bitplanes\r
198                 mov ax, 0x0F02\r
199                 out dx, ax\r
200                 mov ax, MCGA_MEM                // Load video memory\r
201                 mov es, ax\r
202                 mov di, 0            // Start at the top\r
203                 mov ax, 0                               // Store 0's\r
204                 mov cx, 0x8000                  // Do it 8000h times\r
205                 rep stosw                               // Store them\r
206         }\r
207 \r
208         // Fill globals\r
209         VIDEO_MODE = 0xFF;\r
210         MAX_X = 319;\r
211         MAX_Y = 239;\r
212         SCREEN_WIDTH = 320;\r
213         SCREEN_HEIGHT = 240;\r
214         MAX_COLORS = 255;\r
215         FG_COLOR = 15;\r
216         BG_COLOR = 0;\r
217         CUR_X = 0;\r
218         CUR_Y = 0;\r
219 \r
220         activeStart = 0;                        // Write to Page 0\r
221         visibleStart = 0;                       // Read from Page 0\r
222 }\r
223 \r
224 ////////////////////////////////////////\r
225 //      close_graph\r
226 //\r
227 //      -Shuts down graphics, sets text mode,\r
228 //  and fills appropriate variables\r
229 // -Frees memory taken by video buffers\r
230 ////////////////////////////////////////\r
231 void close_graph(void)\r
232 {\r
233         asm {\r
234                 mov ax, 0x0003\r
235                 int 0x10\r
236         }\r
237 \r
238         VIDEO_MODE = 0x03;\r
239         MAX_X = 80;\r
240         MAX_Y = 25;\r
241         SCREEN_WIDTH = 80;\r
242         SCREEN_HEIGHT = 25;\r
243         MAX_COLORS = 15;\r
244         FG_COLOR = 7;\r
245         BG_COLOR = 0;\r
246         CUR_X = 1;\r
247         CUR_Y = 1;\r
248 }\r
249 \r
250 void cleargraph(void)\r
251 {\r
252         asm {\r
253                 pusha\r
254                 push es\r
255                 push di\r
256 \r
257                 mov ax, MCGA_MEM\r
258                 mov es, ax\r
259                 mov di, 0\r
260 \r
261                 mov dx, SC_INDEX                // Enable write to all bitplanes\r
262                 mov ax, 0x0F02\r
263                 out dx, ax\r
264 \r
265                 mov cx, 0x8000\r
266                 mov ax, 0x0000\r
267                 rep stosw\r
268 \r
269                 pop di\r
270                 pop es\r
271                 popa\r
272         }\r
273 }\r
274 \r
275 ////////////////////////////////////////\r
276 // setActiveStart\r
277 //\r
278 // -Sets the starting memory address\r
279 //  at which graphics are written to\r
280 ////////////////////////////////////////\r
281 void setActiveStart(word PageBase)\r
282 {\r
283         activeStart = PageBase;\r
284 }\r
285 \r
286 ////////////////////////////////////////\r
287 // setVisibleStart\r
288 //\r
289 // -Sets the starting memory address\r
290 //  at which graphics are displayed from\r
291 ////////////////////////////////////////\r
292 void setVisibleStart(word PageBase)\r
293 {\r
294         visibleStart = PageBase;\r
295 \r
296         asm {\r
297                 pusha                                           // Dont touch!\r
298 \r
299                 mov bx, PageBase                // Load the offset into BX\r
300                 mov dx, CRTC_INDEX      // Load the CRT Index Port into DX\r
301                 mov al, 0x0C                    // Function 0Ch, High Byte of addres\r
302                 mov ah, bh                              // Load the high byte\r
303                 out dx, ax                              // Send it\r
304                 inc al                                  // Function 0Dh, Low Byte of address\r
305                 mov ah, bl                              // Load the low byte\r
306                 out dx, ax                              // Send it\r
307 \r
308                 popa                                            // We were never here\r
309         }\r
310 }\r
311 \r
312 ////////////////////////////////////////\r
313 // setActivePage\r
314 //\r
315 // -Sets page in which graphics are\r
316 //  written\r
317 ////////////////////////////////////////\r
318 void setActivePage(byte Page)\r
319 {\r
320         // Page = (Page Offset * Width of Screen (Bytes) * Screen Height (Rows))\r
321         setActiveStart(Page * SCR_WIDTH * SCREEN_HEIGHT);\r
322 }\r
323 \r
324 ////////////////////////////////////////\r
325 // setVisiblePage\r
326 //\r
327 // -Sets page from which graphics are\r
328 //  drawn\r
329 ////////////////////////////////////////\r
330 void setVisiblePage(byte Page)\r
331 {\r
332         // Page = (Page Offset * Width of Screen (Bytes) * Screen Height (Rows))\r
333         setVisibleStart(Page * SCR_WIDTH * SCREEN_HEIGHT);\r
334 }\r
335 \r
336 void vScroll(int rows)\r
337 {\r
338         // Scrolling = current start + (rows * bytes in a row)\r
339         setVisibleStart(visibleStart + (rows * SCR_WIDTH));\r
340 }\r
341 \r
342 void read_palette(byte *pal)\r
343 {\r
344         int i;\r
345 \r
346         for (i = 0; i < 256; i++)\r
347         {\r
348                 asm cli\r
349                 outportb(DAC_READ, i);\r
350                 pal[(i * 3) + 0] = inportb(VIDEO_DATA);\r
351                 pal[(i * 3) + 1] = inportb(VIDEO_DATA);\r
352                 pal[(i * 3) + 2] = inportb(VIDEO_DATA);\r
353                 asm sti\r
354         }\r
355 }\r
356 \r
357 void load_palette(byte *pal)\r
358 {\r
359         int i;\r
360 \r
361         for (i = 0; i < 256; i++)\r
362         {\r
363                 asm cli\r
364                 outportb(VIDEO_DAC, i);\r
365                 outportb(VIDEO_DATA, pal[(i * 3) + 0]);\r
366                 outportb(VIDEO_DATA, pal[(i * 3) + 1]);\r
367                 outportb(VIDEO_DATA, pal[(i * 3) + 2]);\r
368                 asm sti\r
369         }\r
370 }\r
371 \r
372 ////////////////////////////////////////\r
373 // setpalette\r
374 //\r
375 // -Self explanatory, sets the color\r
376 //  of a given index in 256 MCGA mode\r
377 ////////////////////////////////////////\r
378 void setpalette(byte index, byte red, byte green, byte blue)\r
379 {\r
380         outportb(VIDEO_DAC, index);\r
381         outportb(VIDEO_DATA, red);\r
382         outportb(VIDEO_DATA, green);\r
383         outportb(VIDEO_DATA, blue);\r
384 }\r
385 \r
386 ////////////////////////////////////////\r
387 // putpixel\r
388 //\r
389 // -Puts a pixel (in modeX) at (X, Y)\r
390 //  in active page\r
391 ////////////////////////////////////////\r
392 void putpixel(word x, word y, byte Color)\r
393 {\r
394         asm {\r
395                 pusha\r
396                 push es\r
397                 push di\r
398 \r
399                 mov ax, SCR_WIDTH          // Load screen width, in bytes\r
400                 mul y                      // Multiply it by Y to get row\r
401                 mov di, x                  // Load X into BX\r
402                 shr di, 2                                               // Divide X by 4 to get plane\r
403                 add di, ax                                              // Add to col offset, row offset\r
404                 add di, activeStart                     // Add the page offset\r
405                 mov ax, MCGA_MEM                                // Load video memory into AX\r
406                 mov es, ax                                              // Then ES\r
407 \r
408                 mov cx, x                                // Get X pos\r
409                 and cl, 0x03                                    // Get X plane\r
410                 mov ax, 0x0100 + MAP_MASK       // Load Map-Mask register\r
411                 shl ah, cl                                              // Write to only the desired plane\r
412                 mov dx, SC_INDEX                                // Tell the Map-Mask to do the same\r
413                 out dx, ax                                              // Do it\r
414 \r
415                 mov al, Color                                   // Load the color\r
416                 stosb                                                           // Store it\r
417 \r
418                 pop di\r
419                 pop es\r
420                 popa\r
421         }\r
422 }\r
423 \r
424 ////////////////////////////////////////\r
425 // getpixel\r
426 //\r
427 // -Returns color of pixel (in ModeX)\r
428 //  at (x, y)\r
429 ////////////////////////////////////////\r
430 byte getpixel(word x, word y)\r
431 {\r
432         byte returnvalue;       // To hold color\r
433 \r
434         asm {\r
435                 pusha                                           // Dont touch anything\r
436                 push es\r
437                 push di\r
438                 mov ax, SCR_WIDTH               // Move screen width (in bytes) into AX\r
439                 mul y                                           // Multiply by y to get row\r
440                 mov bx, x                               // Move x into BX\r
441                 shr bx, 2                               // Divide by 4 to get plane\r
442                 add bx, ax                              // Add the two offsets together\r
443                 add bx, activeStart     // Add the PageBase\r
444                 mov ax, MCGA_MEM                // Video Memory into AX\r
445                 mov es, ax                              // Now into ES\r
446 \r
447                 mov ah, byte ptr x      // X into AH\r
448                 and ah, 0x03                    // Get Plane\r
449                 mov al, READ_MAP                // Tell the Video Card\r
450                 mov dx, GC_INDEX\r
451                 out dx, ax                              // Do it\r
452 \r
453                 mov al, es:[bx]         // Get the color\r
454                 sub ah, ah                              // Clear AH\r
455                 mov returnvalue, al     //      Store the color into returnvalue\r
456                 pop di\r
457                 pop es\r
458                 popa                                            // Put everything back\r
459         }\r
460 \r
461         return returnvalue;             // Return color\r
462 }\r
463 \r
464 ////////////////////////////////////////\r
465 // vline\r
466 //\r
467 // -Draws a vertical line from (x,y1)-(x,y2)\r
468 //  of color in activePage\r
469 ////////////////////////////////////////\r
470 void vline(word y1, word y2, word x, byte color)\r
471 {\r
472         asm {\r
473                 pusha                // Dont touch anything here\r
474                 push es\r
475                 push di\r
476                 push si                                 // For lowY\r
477 \r
478                 mov si, y1                              // Move y1 into SI\r
479                 mov bx, y2                              // y2 into BX\r
480                 cmp si, bx                              // Compare the two\r
481                 jle vline_ordered               // IF y1 <= y2, skip the next lines\r
482 \r
483                 xchg si, bx                             // ELSE switch them\r
484         }\r
485         vline_ordered:asm {\r
486                 mov ax, MCGA_MEM                // Load the video memory into AX\r
487                 mov es, ax                              // then into ES\r
488                 mov ax, SCR_WIDTH               // Load screen width (bytes) into AX\r
489                 mul si                                  // and Multiply by the y1 value\r
490                 mov di, ax                              // Move it into DI\r
491                 mov ax, x                               // x into AX\r
492                 shr ax, 2                               // Divided by 4\r
493                 add di, ax                              // and added to get first point offset\r
494 \r
495                 mov dx, SC_INDEX                // Point to Sequence Controller\r
496                 mov al, MAP_MASK                // Select Map Mask Register (0x02)\r
497                 out dx, al                              // Do it\r
498                 inc dx                                  // Next Register (SC Data)\r
499                 mov cl, byte ptr x      // x into CL\r
500                 and cl, 0x03                    // x & 0011b to get plane\r
501                 mov al, 0x01         // Only one plane, so load 0001b\r
502                 shl ax, cl                              // Shift it left by the plane number\r
503                 out dx, al                              // Send it\r
504 \r
505                 mov cx, bx                              // Load highY into CX\r
506                 sub cx, si                              // Subtract lowY to get ydelta\r
507                 inc cx                                  // Add one\r
508 \r
509                 mov al, color                   // Load the color into AL\r
510         }\r
511         vline_row_top:asm {\r
512                 stosb                                           // Store the color\r
513                 add di, SCR_WIDTH               // Add a row\r
514                 dec di                                  // Subtract one, because STO incs DI\r
515                 loop vline_row_top      // Loop until done\r
516 \r
517                 pop si\r
518                 pop di\r
519                 pop es\r
520                 popa                 // Put everything back\r
521         }\r
522 }\r
523 \r
524 ////////////////////////////////////////\r
525 // hline\r
526 //\r
527 // -Draws a horizontal line from\r
528 //  (x1, y)-(x2, y) of color in activePage\r
529 // -Faster than a speeding bullet! (Draws\r
530 //  four pixels at a time by turning on\r
531 //  all bitplanes for read at once.\r
532 // -This function is ALL MINE!!! Not one\r
533 //  bit of a copy. :)\r
534 ////////////////////////////////////////\r
535 void hline(word x1, word x2, word y, byte color)\r
536 {\r
537         asm {\r
538                 pusha                      // Dont touch anything\r
539                 push es\r
540                 push di\r
541                 push si                                                 // For lowX\r
542 \r
543                 mov ax, MCGA_MEM                                // Load the graphics memory\r
544                 mov es, ax\r
545 \r
546                 mov ax, SCR_WIDTH                               // Screen width (bytes) into AX\r
547                 mul y                                                           // Multiply by y to get row offset\r
548                 mov di, ax                                              // Move row offset into DI\r
549 \r
550                 mov si, x1                                              // This was a pain to order the variables\r
551                 mov cx, x2                                              // Load x1 into SI, x2 into CX\r
552                 cmp si, cx                                              // Compare them\r
553                 jle hline_ordered                               // If x1 is <= x2, skip the next stuff\r
554 \r
555                 xchg si, cx                                             // ELSE switch them\r
556         }\r
557         hline_ordered:asm {\r
558                 mov ax, si                                      // lowX into AX\r
559                 shr ax, 2                                               // Divided by 4\r
560                 add di, ax                                              // Add the lowX offset to DI\r
561 \r
562                 mov ax, si                                              // lowX back into AX\r
563                 and ax, 0x0003                                  // lowX AND 0011b to get left bit planes\r
564         }\r
565         _BH = LeftClipPlaneMask[_AX];   //      Load the left mask into BH\r
566         asm {\r
567                 mov dx, SC_INDEX                                // Sequence Controller into DX\r
568                 mov al, MAP_MASK                                // Map Mask (Function 0Ch) into AL\r
569                 out dx, al                                              // Send it\r
570                 inc dx                                                  // SC Data Register\r
571                 mov al, bh                                              // Load the mask into AL\r
572                 out dx, al                                              // Send it\r
573 \r
574                 mov al, color                                   // Load color into AL\r
575                 stosb                                                           // Store the first byte of line\r
576 \r
577                 mov dx, SC_INDEX           // Loading a mask again\r
578                 mov al, MAP_MASK                                // ...\r
579                 out dx, al                                              // ...\r
580                 inc dx                                                  // ... as before\r
581                 mov al, 0x0F                                    // Turn all bits on, we want MAX SPEED!\r
582                 out dx, al                                              // Send it\r
583 \r
584                 push cx                                                 // Store the highX\r
585                 sub cx, si                                              // Subtract the lowX from highX\r
586                 shr cx, 2                                               // Divide it by 4\r
587                 dec cx                                                  // Minus the last byte\r
588 \r
589                 mov al, color                                   // Load the color into AL\r
590                 rep stosb                                               // Repeat the storing of color\r
591 \r
592                 pop cx                                                  // Get out highX back\r
593                 inc cl                                                  // Increment, BUG FIX : Not sure why\r
594                 and cl, 0x03                                    // AND 0011b to get bit planes\r
595         }\r
596         _BL = RightClipPlaneMask[_CL];// Load the right mask into BL\r
597         asm {\r
598                 mov dx, SC_INDEX                                // Again, we send the mask to the\r
599                 mov al, MAP_MASK                                // VGA card\r
600                 out dx, al                                              // ...\r
601                 inc dx                                                  // ...\r
602                 mov al, bl                                              // ...\r
603                 out dx, al                                              // ... We have seen this already...\r
604 \r
605                 mov al, color                                   // Load the color into AL\r
606                 stosb                                                           // Store the last byte\r
607 \r
608                 pop si\r
609                 pop di\r
610                 pop es\r
611                 popa                                                            // Put everything back, we're done!\r
612         }\r
613 }\r
614 \r
615 ////////////////////////////////////////\r
616 // line\r
617 //\r
618 // -Draws a line from (x1, y1)-(x2, y2)\r
619 //  of color in the active page\r
620 // -Uses Bresenhem's Line routine\r
621 ////////////////////////////////////////\r
622 void line(word x1, word y1, word x2, word y2, byte color)\r
623 {\r
624         int dx, dy;\r
625         int xinc, yinc;\r
626         int P_right;\r
627         int P_right_up;\r
628         int P;\r
629 \r
630         if (x1 == x2)\r
631                 vline(y1, y2, x1, color);\r
632 //      if (y1 == y2)\r
633 //              hline(x1, x1, y1, 0, color);\r
634 \r
635         dx = abs(x2 - x1);\r
636         dy = abs(y2 - y1);\r
637 \r
638         xinc = (x1 > x2) ? -1 : 1;\r
639         yinc = (y1 > y2) ? -1 : 1;\r
640 \r
641         if (dx > dy)\r
642         {\r
643                 P_right = (2 * dy);\r
644                 P_right_up = P_right - (2 * dx);\r
645                 P = P_right - dx;\r
646 \r
647                 for (; dx >= 0; dx--)\r
648                 {\r
649                         putpixel(x1, y1, color);\r
650                         if (P > 0)\r
651                         {\r
652                                 x1 += xinc;\r
653                                 y1 += yinc;\r
654                                 P += P_right_up;\r
655                         }\r
656                         else\r
657                         {\r
658                                 x1 += xinc;\r
659                                 P += P_right;\r
660                         }\r
661                 }\r
662         }\r
663         else\r
664         {\r
665                 P_right = (2 * dx);\r
666                 P_right_up = P_right - (2 * dy);\r
667                 P = P_right - dy;\r
668 \r
669                 for (; dy >= 0; dy--)\r
670                 {\r
671                         putpixel(x1, y1, color);\r
672                         if (P > 0)\r
673                         {\r
674                                 x1 += xinc;\r
675                                 y1 += yinc;\r
676                                 P += P_right_up;\r
677                         }\r
678                         else\r
679                         {\r
680                                 y1 += yinc;\r
681                                 P += P_right;\r
682                         }\r
683                 }\r
684         }\r
685 }\r
686 \r
687 void rect(word x1, word y1, word x2, word y2, byte color)\r
688 {\r
689         // Just draw the four lines, x is longer because hline is a\r
690         // faster routine than vline.\r
691         hline(x1, x2, y1, color);\r
692         hline(x1, x2, y2, color);\r
693         vline(y1 + 1, y2 - 1, x1, color);\r
694         vline(y1 + 1, y2 - 1, x2, color);\r
695 }\r
696 \r
697 ////////////////////////////////////////\r
698 // fillrect\r
699 //\r
700 // -Fills a rectangle (in ModeX) of color\r
701 //  from (x1, y1) to (x2, y2)\r
702 //\r
703 // *Adopted from Dr. Dobbs Journal Sep 91\r
704 ////////////////////////////////////////\r
705 void fillrect(word x1, word y1, word x2, word y2, byte color)\r
706 {\r
707         asm {\r
708                 pusha                         // Dont touch anything\r
709                 push ds\r
710                 push si\r
711                 push es\r
712                 push di\r
713                 push bp\r
714 \r
715                 cld                                                                     // Clear direction flag (left to right)\r
716                 mov ax, SCR_WIDTH                                       // Screen Width (bytes) into AX\r
717                 mul y1                                                          // Times y1 value\r
718                 mov di, x1                                                      // x1 into DI\r
719                 shr di, 2                                                       // Divided by four to get plane\r
720                 add di, ax                                                      // Add the y offset\r
721                 add di, activeStart                             // Add the PageBase\r
722                 mov ax, MCGA_MEM                                        // Now set up the video memory\r
723                 mov es, ax                                                      // into ES\r
724                 mov dx, SC_INDEX                                        // Point to Sequence Controller\r
725                 mov al, MAP_MASK                                        // Select Map Mask Register (0x02)\r
726                 out dx, al                                                      // Do it\r
727                 inc dx                                                          // Next Register (SC Data)\r
728                 mov si, x1                                                      // x1 into SI\r
729                 and si, 0x0003                                          // x1 & 0011b to get plane\r
730         }\r
731         _BH = LeftClipPlaneMask[_SI];           // Select appropriate mask\r
732         asm {\r
733                 mov si, x2                                                      // Do the same for x2\r
734                 and si, 0x0003                                          // x2 & 0011b\r
735         }\r
736         _BL = RightClipPlaneMask[_SI];  // Mask select\r
737         asm {\r
738                 mov cx, x2                    // x2 into CX\r
739                 mov si, x1                                                      // x1 into SI\r
740                 cmp cx, si                                                      // Compare them\r
741                 jle FillDone                                            // IF CX <= SI jump to FillDone\r
742                 dec cx                        // Decrement CX\r
743                 and si, 0xFFFC                // x1 & 1111111111111100\r
744                 sub cx, si                    // Subtract x1 from x2\r
745                 shr cx, 2                     // Divide CX by 4\r
746                 jnz MasksSet                                            // Jump if not zero to MasksSet\r
747                 and bh, bl                                                      // BH = BH and BL\r
748         }\r
749         MasksSet:asm {\r
750                 mov si, y2                                                      // y2 into SI\r
751                 sub si, y1                    // Subtract y1\r
752                 jle FillDone                  // IF SI <= 0 jump to FillDone\r
753                 mov ah, byte ptr color                  // Load color\r
754                 mov bp, SCR_WIDTH                                       // Load screen width (bytes)\r
755                 sub bp, cx                                                      // Subtract xdelta from width\r
756                 dec bp                                                          // Minus 1\r
757         }\r
758         FillRowsLoop:asm {\r
759                 push cx                       // Dont hurt CX\r
760                 mov al, bh                                                      // Left Clip Mask into AL\r
761                 out dx, al                                                      // Send it out\r
762                 mov al, ah                                                      // Color to AL\r
763                 stosb                                                                   // Send it out\r
764                 dec cx                                                          // Minus left edge byte\r
765                 js FillLoopBottom                                       // Jump if SIGNAL flag NOT set\r
766                 jz DoRightEdge                                          // If that's it, do the right.\r
767                 mov al, 0x0F                                            // Turn all bit planes on\r
768                 out dx, al                                                      // Do it\r
769                 mov al, ah                                                      // Load color into AL\r
770                 rep stosb                                                       // Store it over and over\r
771         }\r
772         DoRightEdge:asm {\r
773                 mov al, bl                                                      // Right Clip Mask into AL\r
774                 out dx, al                                                      // Do it\r
775                 mov al, ah                                                      // Load color into AL\r
776                 stosb                                                                   // Store it\r
777         }\r
778         FillLoopBottom:asm {\r
779                 add di, bp                                                      // Next scan line\r
780                 pop cx                                                          // What row?\r
781                 dec si                                                          // One less row\r
782                 jnz FillRowsLoop                                        // If not zero, go again\r
783         }\r
784         FillDone:asm {\r
785                 pop bp\r
786                 pop di\r
787                 pop es\r
788                 pop si\r
789                 pop ds\r
790                 popa                                                            // All done, put everything back\r
791         }\r
792 }\r
793 \r
794 void circle(word x, word y, word radius, byte color)\r
795 {\r
796         float angle;\r
797         float ainc = 1;\r
798         word xc, yc;\r
799 \r
800         if (radius > 119)                       // IF the radius is greater than 119, make the\r
801                 ainc = 0.25;                    // increment smaller\r
802         if (radius > 61)                        // IF it's bigger than 61\r
803                 ainc = 0.5;                             // do the same\r
804 \r
805 \r
806         // Only calculate 1/8th of the circle\r
807         // Four quadrants = (x, y), (-x, y), (-x, -y), (x, -y)\r
808         // Eight octants are made by switching x's and y's.\r
809         // Draw eight pixels per iteration and make the circle\r
810         // eight times faster than conventional routines.\r
811         for (angle = 0; angle <= 45; angle += ainc)\r
812         {\r
813                 xc = (word)floor(cos((angle * PI) / 180) * radius);\r
814                 yc = (word)floor(sin((angle * PI) / 180) * radius);\r
815 \r
816                 putpixel(x + xc, y + yc, color);\r
817                 putpixel(x + xc, y - yc, color);\r
818                 putpixel(x - xc, y + yc, color);\r
819                 putpixel(x - xc, y - yc, color);\r
820 \r
821                 putpixel(x + yc, y + xc, color);\r
822                 putpixel(x + yc, y - xc, color);\r
823                 putpixel(x - yc, y + xc, color);\r
824                 putpixel(x - yc, y - xc, color);\r
825         }\r
826 }\r
827 \r
828 void load_BMP_palette(BITMAP *s)\r
829 {\r
830         int i;\r
831 \r
832         for (i = 0; i < 256; i++)\r
833                 setpalette(i, (byte)floor((s->bmInfo.bmiColors[i].rgbRed / 63) * 255),\r
834                                                   (byte)floor((s->bmInfo.bmiColors[i].rgbGreen / 63) * 255),\r
835                                                   (byte)floor((s->bmInfo.bmiColors[i].rgbBlue / 63) * 255));\r
836 }\r
837 \r
838 ////////////////////////////////////////\r
839 // load_BMP\r
840 //\r
841 // -Opens a bitmap (Non-Compressed) and\r
842 //  stores the data into a given BITMAP\r
843 //  variable\r
844 // -Allocate memory BEFORE calling this\r
845 //  function for the BITMAP structure\r
846 // -Must be 256 Color, Columns divisible\r
847 //  by four\r
848 ////////////////////////////////////////\r
849 void load_BMP(char *filename, TILE *target)\r
850 {\r
851         FILE *inBMP;                                                                                    // Create file handle\r
852         BITMAP *tempBMP;\r
853         int color;\r
854 \r
855         if ((inBMP = fopen(filename, "r+b")) == NULL)// Open it\r
856         {\r
857                 sprintf(msg_error, "Cannot open %s", filename);\r
858                 atexit(exit_error);                                                             // IF error, exit and\r
859                 exit(1);                                                                                                // tell user.\r
860         }\r
861 \r
862         tempBMP = (BITMAP *)malloc(sizeof(BITMAP) - 1);\r
863 \r
864         fseek(inBMP, 0, 0);                          // Goto the beginning\r
865         fread(tempBMP, sizeof(BITMAP) - 1, 1, inBMP);           // And load it all into\r
866                                                                                                                                 // the given variable\r
867 \r
868         fseek(inBMP, 54, 0);                         // Goto color offset\r
869         for (color = 0; color < 256; color++)        // and read 'em in.\r
870         {\r
871                 tempBMP->bmInfo.bmiColors[color].rgbBlue = fgetc(inBMP);\r
872                 tempBMP->bmInfo.bmiColors[color].rgbGreen = fgetc(inBMP);\r
873                 tempBMP->bmInfo.bmiColors[color].rgbRed = fgetc(inBMP);\r
874                 tempBMP->bmInfo.bmiColors[color].rgbReserved = fgetc(inBMP);\r
875         }\r
876 \r
877         load_BMP_palette(tempBMP);\r
878 \r
879         // Allocate space for the data to hold the pixels\r
880         // Goto the pixel offset in the file\r
881         // Read in the pixels\r
882         target->data = (byte *)calloc((tempBMP->bmFileHeader.bfSize - tempBMP->bmFileHeader.bfOffBits), 1);\r
883         target->height = tempBMP->bmInfo.bmiHeader.biHeight;\r
884         target->width = tempBMP->bmInfo.bmiHeader.biWidth;\r
885         fseek(inBMP, tempBMP->bmFileHeader.bfOffBits, 0);\r
886         fread(target->data, target->height * target->width, 1, inBMP);\r
887 \r
888         free(tempBMP);\r
889         fclose(inBMP);                               // Dont forget to close\r
890 }\r
891 \r
892 void show_BMP(TILE *source, word x, word y)\r
893 {\r
894         word row, col, offset = 0;\r
895 \r
896         for (row = source->height; row > 0; row--)\r
897         {\r
898                 for (col = 0; col < source->height; col++)\r
899                 {\r
900                         if (source->data[offset] != 255)\r
901                                 putpixel(x + col, y + row, source->data[offset]);\r
902                         offset++;\r
903                 }\r
904         }\r
905 }\r
906 \r
907 void show_tile(TILE *tile, word x, word y)\r
908 {\r
909         word cx, cy;\r
910 \r
911         for (cy = 1; cy <= tile->height; cy++)\r
912                 for (cx = 0; cx < tile->width; cx++)\r
913                         if (tile->data[cx + (cy * tile->width)] != 255)\r
914                                 putpixel(x + cx, y + cy, tile->data[cx + (cy * tile->width)]);\r
915 }\r
916 \r
917 void make_tile(TILE *target, TILE *source)\r
918 {\r
919         int row, col, offset = 0;\r
920 \r
921         target->data = (byte *)malloc(source->height * source->width + source->width);\r
922 \r
923         target->height = source->height;\r
924         target->width = source->width;\r
925 \r
926         for (row = source->height * source->width; row >= 0; row -= source->width)\r
927         {\r
928                 for (col = 0; col < source->width; col++)\r
929                 {\r
930                         target->data[offset] = source->data[col + row];\r
931                         offset++;\r
932                 }\r
933         }\r
934 }\r
935 \r
936 void get_tile(word x1, word y1, word x2, word y2, TILE *target)\r
937 {\r
938         int cx, cy, offset = 0;\r
939 \r
940         target->height = abs(y2 - y1);\r
941         target->width = abs(x2 - x1);\r
942 \r
943         target->data = (byte *)malloc(target->height * target->width + target->width);\r
944 \r
945         for (cy = 0; cy <= target->height; cy++)\r
946                 for (cx = 0; cx < target->width; cx++)\r
947                 {\r
948                         target->data[offset] = getpixel(x1 + cx, y1 + cy);\r
949                         offset++;\r
950                 }\r
951 }\r