Skip to content

Instantly share code, notes, and snippets.

@randrews
Last active April 10, 2021 16:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save randrews/702460c1c3986254d1811ba6774a4dd8 to your computer and use it in GitHub Desktop.
Save randrews/702460c1c3986254d1811ba6774a4dd8 to your computer and use it in GitHub Desktop.
// This will build and run on Borland Turbo C++ with the
// "small" memory model. The declaration of `screen` may
// need to be changed if you use a larger memory model.
// It also may need some changes to build under DJGPP;
// TC++ is... let's say "unique."
#include <conio.h>
#include <dos.h>
#include <mem.h>
// conio is for getch, to pause after it runs
// dos is for MK_FP. Also for the register structs
// mem is for _fmemset
typedef unsigned char byte;
void vgaMode(int mode);
inline int offset(int x, int y);
void px(int x, int y, byte c);
void hline(int x, int y, int len, byte c);
void drawSprite(int x, int y, int *type, byte fg, byte bg);
// It doesn't support binary literals but octal is just as good
int piece1[] = {
0, 0200, 0500, 01040, 02220, 04510, 011044, 022222,
011044, 04510, 02220, 01040, 0500, 0200, 0
};
int piece2[] = {
0, 025252, 012524, 025252, 012524, 025252, 012524,
025252, 012524, 025252, 012524, 025252, 012524,
025252, 0
};
int piece3[] = {
0, 01740, 0200, 0200, 0200, 020202, 020202, 037776,
020202, 020202, 0200, 0200, 0200, 01740, 0
}; // Yes I did these by hand
// DOS is 16-bit but supports megs of memory. How? With a
// non-flat memory map. We want a pointer longer than 16
// bits, which DOS calls a "far pointer." MK_FP makes one.
byte far *screen = (byte far *)MK_FP(0xa000, 0);
void main() {
vgaMode(0x13); // Into mode 13
px(10, 10, 13); // A dot
hline(20, 20, 100, 15); // A line
drawSprite(50, 25, piece1, 15, 3); // Some two-color sprites
drawSprite(25, 50, piece2, 4, 0);
drawSprite(10, 60, piece3, 26, 1);
getch(); // Wait so we can look at it
vgaMode(3); // Back to text mode
}
// Set the VGA mode: put the new mode in AL and call int 10.
// Mode 0x13 is 320x200, 8-bit color.
void vgaMode(int mode){
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode & 0xff;
int86(16, &regs, &regs);
}
// This is faster than multiplying by 320: two shifts and two adds.
inline int offset(int x, int y) {
return x + (y << 8) + (y << 6);
}
// Linear memory for the screen, horizontal lines are just
// memset. But because it's in "far memory" it's _fmemset.
// Also note that we can quickly clear the screen with
// hline(0, 0, 64000, something);
void hline(int x, int y, int len, byte c) {
_fmemset(screen + offset(x, y), c, len);
}
// Setting a pixel.
void px(int x, int y, byte c) {
*(screen + offset(x, y)) = c;
}
// Draws a 15x15 2-color sprite, packed into an array of 15 ints,
// at the given coordinates, in the given colors. Why not 16x16?
// Because it's nice to have odd sizes so there's a center line
// for symmetry.
void drawSprite(int x, int y, int *type, byte fg, byte bg) {
for(int r = 0; r < 15; r++)
for(int c = 0; c < 15; c++)
px(x + c, y + r, (type[r] & (1 << c) ? fg : bg));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment