1 ////////////////////////////////////////
\r
5 // Licensed under the Academic Free License version 1.2
\r
7 // *Special thanks to Micheal Abrash
\r
8 // and his columns in Dr. Dobbs Journal
\r
9 // (Jul91 and Aug91) documenting
\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
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
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
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
47 #define PI 3.14159265358
\r
50 typedef unsigned char byte;
\r
51 typedef unsigned int word;
\r
52 typedef unsigned long dword;
\r
54 typedef struct tagTILE {
\r
60 // FOR BITMAP FILES!!!
\r
61 typedef struct tagBITMAPFILEHEADER {
\r
69 typedef struct tagBITMAPINFOHEADER {
\r
75 dword biCompression;
\r
77 dword biXPelsPerMeter;
\r
78 dword biYPelsPerMeter;
\r
80 dword biClrImportant;
\r
83 typedef struct tagRGBQUAD {
\r
90 typedef struct tagBITMAPINFO {
\r
91 BITMAPINFOHEADER bmiHeader;
\r
92 RGBQUAD bmiColors[256];
\r
95 typedef struct tagBITMAP {
\r
96 BITMAPFILEHEADER bmFileHeader;
\r
100 // DONE WITH BITMAP FILE INFO
\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
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
120 word SCREEN_HEIGHT;
\r
121 byte MAX_COLORS; // Last available color
\r
122 byte FG_COLOR; // For text and mono stuff
\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
129 // For rectangle filling (ModeX)
\r
130 byte LeftClipPlaneMask[] = { 0x0F, 0x0E, 0x0C, 0x08 };
\r
131 byte RightClipPlaneMask[] = { 0x0F, 0x01, 0x03, 0x07 };
\r
133 // In case things go awry
\r
134 char msg_error[81];
\r
136 void exit_error(void)
\r
138 printf("%s\a\n", msg_error);
\r
141 ////////////////////////////////////////
\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
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
163 mov ax, 0x0013 // Start in mode 13h
\r
164 int 0x10 // Call interrupt
\r
166 mov dx, SC_INDEX // Disable Chain-4 Memory model
\r
169 mov ax, 0x0100 // Synchronous reset while switching clocks
\r
172 mov dx, MISC_OUTPUT // Select 28MHz dot clock, 60 Hz scan rate
\r
176 mov dx, SC_INDEX // Restart Sequencer
\r
180 mov dx, CRTC_INDEX // Reprogram the CRT Controller
\r
181 mov al, 0x11 // Select Write-Protect bit
\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
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
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
197 mov dx, SC_INDEX // Enable write to all bitplanes
\r
200 mov ax, MCGA_MEM // Load video memory
\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
212 SCREEN_WIDTH = 320;
\r
213 SCREEN_HEIGHT = 240;
\r
220 activeStart = 0; // Write to Page 0
\r
221 visibleStart = 0; // Read from Page 0
\r
224 ////////////////////////////////////////
\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
242 SCREEN_HEIGHT = 25;
\r
250 void cleargraph(void)
\r
261 mov dx, SC_INDEX // Enable write to all bitplanes
\r
275 ////////////////////////////////////////
\r
278 // -Sets the starting memory address
\r
279 // at which graphics are written to
\r
280 ////////////////////////////////////////
\r
281 void setActiveStart(word PageBase)
\r
283 activeStart = PageBase;
\r
286 ////////////////////////////////////////
\r
289 // -Sets the starting memory address
\r
290 // at which graphics are displayed from
\r
291 ////////////////////////////////////////
\r
292 void setVisibleStart(word PageBase)
\r
294 visibleStart = PageBase;
\r
297 pusha // Dont touch!
\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
308 popa // We were never here
\r
312 ////////////////////////////////////////
\r
315 // -Sets page in which graphics are
\r
317 ////////////////////////////////////////
\r
318 void setActivePage(byte Page)
\r
320 // Page = (Page Offset * Width of Screen (Bytes) * Screen Height (Rows))
\r
321 setActiveStart(Page * SCR_WIDTH * SCREEN_HEIGHT);
\r
324 ////////////////////////////////////////
\r
327 // -Sets page from which graphics are
\r
329 ////////////////////////////////////////
\r
330 void setVisiblePage(byte Page)
\r
332 // Page = (Page Offset * Width of Screen (Bytes) * Screen Height (Rows))
\r
333 setVisibleStart(Page * SCR_WIDTH * SCREEN_HEIGHT);
\r
336 void vScroll(int rows)
\r
338 // Scrolling = current start + (rows * bytes in a row)
\r
339 setVisibleStart(visibleStart + (rows * SCR_WIDTH));
\r
342 void read_palette(byte *pal)
\r
346 for (i = 0; i < 256; i++)
\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
357 void load_palette(byte *pal)
\r
361 for (i = 0; i < 256; i++)
\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
372 ////////////////////////////////////////
\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
380 outportb(VIDEO_DAC, index);
\r
381 outportb(VIDEO_DATA, red);
\r
382 outportb(VIDEO_DATA, green);
\r
383 outportb(VIDEO_DATA, blue);
\r
386 ////////////////////////////////////////
\r
389 // -Puts a pixel (in modeX) at (X, Y)
\r
391 ////////////////////////////////////////
\r
392 void putpixel(word x, word y, byte Color)
\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
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
415 mov al, Color // Load the color
\r
424 ////////////////////////////////////////
\r
427 // -Returns color of pixel (in ModeX)
\r
429 ////////////////////////////////////////
\r
430 byte getpixel(word x, word y)
\r
432 byte returnvalue; // To hold color
\r
435 pusha // Dont touch anything
\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
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
451 out dx, ax // Do it
\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
458 popa // Put everything back
\r
461 return returnvalue; // Return color
\r
464 ////////////////////////////////////////
\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
473 pusha // Dont touch anything here
\r
476 push si // For lowY
\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
483 xchg si, bx // ELSE switch them
\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
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
505 mov cx, bx // Load highY into CX
\r
506 sub cx, si // Subtract lowY to get ydelta
\r
509 mov al, color // Load the color into AL
\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
520 popa // Put everything back
\r
524 ////////////////////////////////////////
\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
538 pusha // Dont touch anything
\r
541 push si // For lowX
\r
543 mov ax, MCGA_MEM // Load the graphics memory
\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
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
555 xchg si, cx // ELSE switch them
\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
562 mov ax, si // lowX back into AX
\r
563 and ax, 0x0003 // lowX AND 0011b to get left bit planes
\r
565 _BH = LeftClipPlaneMask[_AX]; // Load the left mask into BH
\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
574 mov al, color // Load color into AL
\r
575 stosb // Store the first byte of line
\r
577 mov dx, SC_INDEX // Loading a mask again
\r
578 mov al, MAP_MASK // ...
\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
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
589 mov al, color // Load the color into AL
\r
590 rep stosb // Repeat the storing of color
\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
596 _BL = RightClipPlaneMask[_CL];// Load the right mask into BL
\r
598 mov dx, SC_INDEX // Again, we send the mask to the
\r
599 mov al, MAP_MASK // VGA card
\r
603 out dx, al // ... We have seen this already...
\r
605 mov al, color // Load the color into AL
\r
606 stosb // Store the last byte
\r
611 popa // Put everything back, we're done!
\r
615 ////////////////////////////////////////
\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
631 vline(y1, y2, x1, color);
\r
633 // hline(x1, x1, y1, 0, color);
\r
638 xinc = (x1 > x2) ? -1 : 1;
\r
639 yinc = (y1 > y2) ? -1 : 1;
\r
643 P_right = (2 * dy);
\r
644 P_right_up = P_right - (2 * dx);
\r
647 for (; dx >= 0; dx--)
\r
649 putpixel(x1, y1, color);
\r
665 P_right = (2 * dx);
\r
666 P_right_up = P_right - (2 * dy);
\r
669 for (; dy >= 0; dy--)
\r
671 putpixel(x1, y1, color);
\r
687 void rect(word x1, word y1, word x2, word y2, byte color)
\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
697 ////////////////////////////////////////
\r
700 // -Fills a rectangle (in ModeX) of color
\r
701 // from (x1, y1) to (x2, y2)
\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
708 pusha // Dont touch anything
\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
731 _BH = LeftClipPlaneMask[_SI]; // Select appropriate mask
\r
733 mov si, x2 // Do the same for x2
\r
734 and si, 0x0003 // x2 & 0011b
\r
736 _BL = RightClipPlaneMask[_SI]; // Mask select
\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
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
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
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
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
790 popa // All done, put everything back
\r
794 void circle(word x, word y, word radius, byte color)
\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
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
813 xc = (word)floor(cos((angle * PI) / 180) * radius);
\r
814 yc = (word)floor(sin((angle * PI) / 180) * radius);
\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
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
828 void load_BMP_palette(BITMAP *s)
\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
838 ////////////////////////////////////////
\r
841 // -Opens a bitmap (Non-Compressed) and
\r
842 // stores the data into a given BITMAP
\r
844 // -Allocate memory BEFORE calling this
\r
845 // function for the BITMAP structure
\r
846 // -Must be 256 Color, Columns divisible
\r
848 ////////////////////////////////////////
\r
849 void load_BMP(char *filename, TILE *target)
\r
851 FILE *inBMP; // Create file handle
\r
855 if ((inBMP = fopen(filename, "r+b")) == NULL)// Open it
\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
862 tempBMP = (BITMAP *)malloc(sizeof(BITMAP) - 1);
\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
868 fseek(inBMP, 54, 0); // Goto color offset
\r
869 for (color = 0; color < 256; color++) // and read 'em in.
\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
877 load_BMP_palette(tempBMP);
\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
889 fclose(inBMP); // Dont forget to close
\r
892 void show_BMP(TILE *source, word x, word y)
\r
894 word row, col, offset = 0;
\r
896 for (row = source->height; row > 0; row--)
\r
898 for (col = 0; col < source->height; col++)
\r
900 if (source->data[offset] != 255)
\r
901 putpixel(x + col, y + row, source->data[offset]);
\r
907 void show_tile(TILE *tile, word x, word y)
\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
917 void make_tile(TILE *target, TILE *source)
\r
919 int row, col, offset = 0;
\r
921 target->data = (byte *)malloc(source->height * source->width + source->width);
\r
923 target->height = source->height;
\r
924 target->width = source->width;
\r
926 for (row = source->height * source->width; row >= 0; row -= source->width)
\r
928 for (col = 0; col < source->width; col++)
\r
930 target->data[offset] = source->data[col + row];
\r
936 void get_tile(word x1, word y1, word x2, word y2, TILE *target)
\r
938 int cx, cy, offset = 0;
\r
940 target->height = abs(y2 - y1);
\r
941 target->width = abs(x2 - x1);
\r
943 target->data = (byte *)malloc(target->height * target->width + target->width);
\r
945 for (cy = 0; cy <= target->height; cy++)
\r
946 for (cx = 0; cx < target->width; cx++)
\r
948 target->data[offset] = getpixel(x1 + cx, y1 + cy);
\r