init
This commit is contained in:
commit
0d6bed04f7
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.zip
|
||||
*.OBJ
|
||||
*.ERR
|
||||
*.EXE
|
||||
.ccls-cache/
|
135
bmp_loader.c
Normal file
135
bmp_loader.c
Normal file
@ -0,0 +1,135 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <dos.h>
|
||||
|
||||
#include "bmp_loader.h"
|
||||
#include "pc_stuff.h"
|
||||
#include "vga.h"
|
||||
|
||||
int readBMPHeader(FILE *fh, struct BMPImage *info) {
|
||||
int sizeOfHeader;
|
||||
unsigned int numberOfUsedColors;
|
||||
|
||||
if ((fgetc(fh) != 'B') || (fgetc(fh) != 'M')) {
|
||||
printf("Not a BMP file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(fh, 12, SEEK_CUR);
|
||||
|
||||
fread(&sizeOfHeader, sizeof(int), 1, fh);
|
||||
fread(&info->width, sizeof(int), 1, fh);
|
||||
fread(&info->height, sizeof(int), 1, fh);
|
||||
fseek(fh, 2, SEEK_CUR);
|
||||
fread(&info->bpp, sizeof(word), 1, fh);
|
||||
|
||||
// for gimp, you need to add colors to the color map until it hits
|
||||
// 16 colors, then the image will be a 256 color, 8 bpp image
|
||||
//
|
||||
// https://www.gimp-forum.net/Thread-indexing-into-8-bit?pid=13233#pid13233
|
||||
if (info->bpp != 8) return 1;
|
||||
|
||||
fseek(fh, 16, SEEK_CUR);
|
||||
fread(&numberOfUsedColors, sizeof(unsigned int), 1, fh);
|
||||
if (numberOfUsedColors > 256) return 1;
|
||||
|
||||
// get down to color data
|
||||
fseek(fh, 14 + sizeOfHeader, SEEK_SET);
|
||||
|
||||
fread(info->colors, sizeof(struct BMPColor), numberOfUsedColors, fh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readBMPIntoMemory(FILE *fh, struct BMPImage *info) {
|
||||
int x, y, plane;
|
||||
int result;
|
||||
byte *currentPointer;
|
||||
|
||||
result = readBMPHeader(fh, info);
|
||||
if (result) return result;
|
||||
|
||||
currentPointer = info->memoryStart;
|
||||
|
||||
for (y = 0; y < info->height; ++y) {
|
||||
for (x = 0; x < info->width; ++x) {
|
||||
currentPointer[(info->height - 1 - y) * info->width + x] = fgetc(fh);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readBMPIntoUnchainedMemory(FILE *fh, struct BMPImage* info) {
|
||||
int x, y, plane;
|
||||
int writeX, writeY, offset;
|
||||
int unchainedLineWidth;
|
||||
int result;
|
||||
byte *rowHolder;
|
||||
|
||||
result = readBMPHeader(fh, info);
|
||||
if (result) return result;
|
||||
|
||||
unchainedLineWidth = info->width / 4;
|
||||
|
||||
// reserve a row's worth of data
|
||||
// read the bitmap data into the row, interleaving for planes
|
||||
// for each plane, memcpy the data to the plane
|
||||
for (y = 0; y < info->height; ++y) {
|
||||
writeY = ((info->height - 1) - y) * unchainedLineWidth;
|
||||
|
||||
for (x = 0; x < info->width; ++x) {
|
||||
plane = x & 0x03;
|
||||
writeX = (x >> 2);
|
||||
|
||||
offset = plane * (unchainedLineWidth * info->height);
|
||||
|
||||
info->memoryStart[offset + writeY + writeX] = fgetc(fh);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readBMPIntoUnchainedVGAMemory(FILE *fh, struct BMPImage* info) {
|
||||
int x, y, plane;
|
||||
int unchainedLineWidth;
|
||||
int result;
|
||||
byte *rowHolder;
|
||||
|
||||
result = readBMPHeader(fh, info);
|
||||
if (result) return result;
|
||||
|
||||
rowHolder = malloc(info->width);
|
||||
unchainedLineWidth = info->width / 4;
|
||||
|
||||
// reserve a row's worth of data
|
||||
// read the bitmap data into the row, interleaving for planes
|
||||
// for each plane, memcpy the data to the plane
|
||||
for (y = 0; y < info->height; ++y) {
|
||||
for (x = 0; x < info->width; ++x) {
|
||||
rowHolder[((x & 3) * 80) + (x >> 2)] = fgetc(fh);
|
||||
}
|
||||
|
||||
for (plane = 0; plane < 4; ++plane) {
|
||||
setActiveVGAMemoryPlanes(1 << plane);
|
||||
|
||||
memcpy(info->memoryStart + ((info->height - 1) - y) * info->width / 4, rowHolder + unchainedLineWidth * plane, unchainedLineWidth);
|
||||
}
|
||||
}
|
||||
|
||||
free(rowHolder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bmp256ColorPaletteToVGAColorPalette(struct BMPImage* bmpImage, struct VGAColor colors[]) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
colors[i].red = bmpImage->colors[i].red >> 2;
|
||||
colors[i].green = bmpImage->colors[i].green >> 2;
|
||||
colors[i].blue = bmpImage->colors[i].blue >> 2;
|
||||
}
|
||||
}
|
23
bmp_loader.h
Normal file
23
bmp_loader.h
Normal file
@ -0,0 +1,23 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct BMPColor {
|
||||
byte blue;
|
||||
byte green;
|
||||
byte red;
|
||||
byte _a;
|
||||
};
|
||||
|
||||
struct BMPImage {
|
||||
int width;
|
||||
int height;
|
||||
word bpp;
|
||||
struct BMPColor colors[256];
|
||||
byte *memoryStart;
|
||||
};
|
||||
|
||||
int readBMPIntoUnchainedMemory(FILE *, struct BMPImage *);
|
||||
int readBMPIntoMemory(FILE *, struct BMPImage *);
|
||||
void bmp256ColorPaletteToVGAColorPalette(struct BMPImage*, struct VGAColor[]);
|
||||
|
6
build.bat
Normal file
6
build.bat
Normal file
@ -0,0 +1,6 @@
|
||||
wcc386.exe -q bmp_loader.c
|
||||
wcc386.exe -q mouse_io.c
|
||||
wcc386.exe -q pc_stuff.c
|
||||
wcc386.exe -q vga.c
|
||||
wcc386.exe -q keyboard.c
|
||||
wcl386.exe -q unch1.c bmp_load.obj mouse_io.obj pc_stuff.obj vga.obj keyboard.obj
|
BIN
chicken.bmp
Normal file
BIN
chicken.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
38
game.c
Normal file
38
game.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include "vga.h"
|
||||
#include "keyboard.h"
|
||||
#include "mouse_io.h"
|
||||
|
||||
struct VGAColor colors[4] = {
|
||||
{ 0, 0, 0 }, { 255, 255, 255 }, { 255, 0, 0 }, { 0, 0, 255 }
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int keepRunning = 1;
|
||||
struct MouseStatus mouseStatus;
|
||||
|
||||
installKeyboardHandler();
|
||||
activateMouse(&mouseStatus);
|
||||
|
||||
while (keepRunning) {
|
||||
|
||||
}
|
||||
// states:
|
||||
// * main menu
|
||||
// * play
|
||||
// * quit
|
||||
// * play
|
||||
// * draw base map
|
||||
// * draw sidebar
|
||||
// * Game loop
|
||||
// * get mouse
|
||||
// * get keyboard
|
||||
// * set character position
|
||||
// * check for enemy spawn and spawn enemy if needed
|
||||
// * check for character firing and able to fire, spawn bullet if allowed
|
||||
// * check for each enemy firing and able to fire, spawn enemy bullet if allowed
|
||||
// * check for bullet collisions
|
||||
// * enemies are destroyed
|
||||
// * character is damaged
|
||||
// * check for bullets hitting the edges of the screen and remove
|
||||
// *
|
||||
}
|
2
in_progress.md
Normal file
2
in_progress.md
Normal file
@ -0,0 +1,2 @@
|
||||
* Preserve video mode
|
||||
* Rename files to 8.3
|
56
keyboard.c
Normal file
56
keyboard.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include <dos.h>
|
||||
#include <conio.h>
|
||||
|
||||
#include "keyboard.h"
|
||||
|
||||
unsigned char keystateBits[16];
|
||||
struct KeyboardKeydownState keyboardKeydownState;
|
||||
|
||||
void far (interrupt *int9Save)();
|
||||
|
||||
void populateKeyboardKeydownState() {
|
||||
keyboardKeydownState.KEY_W = keystateBits[2] & 0x02;
|
||||
keyboardKeydownState.KEY_A = keystateBits[3] & 0x40;
|
||||
keyboardKeydownState.KEY_S = keystateBits[3] & 0x80;
|
||||
keyboardKeydownState.KEY_D = keystateBits[4] & 0x01;
|
||||
}
|
||||
|
||||
void far interrupt keyboardHandler(void) {
|
||||
unsigned char rawcode, scancode, ksbByte, temp;
|
||||
unsigned char mask = 1;
|
||||
|
||||
_disable();
|
||||
|
||||
rawcode = inp(0x60);
|
||||
|
||||
scancode = rawcode & 0x7f;
|
||||
mask = 1 << (scancode & 0x07);
|
||||
ksbByte = scancode >> 3;
|
||||
|
||||
// https://github.com/id-Software/wolf3d/blob/05167784ef009d0d0daefe8d012b027f39dc8541/WOLFSRC/ID_IN.C#L152-L154
|
||||
outp(0x61, (temp = inp(0x61)) | 0x80);
|
||||
outp(0x61, temp);
|
||||
|
||||
/* break */
|
||||
if (rawcode & 0x80) {
|
||||
mask = 0xff - mask;
|
||||
keystateBits[ksbByte] &= mask;
|
||||
/* make */
|
||||
} else {
|
||||
keystateBits[ksbByte] |= mask;
|
||||
}
|
||||
|
||||
// acknowledge we're done with the interrupt
|
||||
outp(0x20, 0x20);
|
||||
|
||||
_enable();
|
||||
}
|
||||
|
||||
void installKeyboardHandler() {
|
||||
int9Save = _dos_getvect(9);
|
||||
_dos_setvect(9, keyboardHandler);
|
||||
}
|
||||
|
||||
void uninstallKeyboardHandler() {
|
||||
_dos_setvect(9, int9Save);
|
||||
}
|
21
keyboard.h
Normal file
21
keyboard.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __KEYBOARD_H__
|
||||
#define __KEYBOARD_H__ 1
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern unsigned char keystateBits[];
|
||||
|
||||
struct KeyboardKeydownState {
|
||||
byte KEY_W;
|
||||
byte KEY_A;
|
||||
byte KEY_S;
|
||||
byte KEY_D;
|
||||
};
|
||||
|
||||
extern struct KeyboardKeydownState keyboardKeydownState;
|
||||
|
||||
void installKeyboardHandler();
|
||||
void uninstallKeyboardHandler();
|
||||
void populateKeyboardKeydownState();
|
||||
|
||||
#endif
|
48
mouse_io.c
Normal file
48
mouse_io.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include <dos.h>
|
||||
#include <conio.h>
|
||||
|
||||
#include "mouse_io.h"
|
||||
|
||||
int activateMouse(struct MouseStatus *status) {
|
||||
union REGS regs;
|
||||
int mouseActivated;
|
||||
|
||||
regs.w.ax = MOUSE_DRIVER_RESET;
|
||||
int386(MOUSE_DRIVER_INTERRUPT, ®s, ®s);
|
||||
|
||||
mouseActivated = regs.w.ax;
|
||||
|
||||
if (mouseActivated) {
|
||||
status->isActive = regs.w.ax;
|
||||
status->buttonCount = regs.w.bx;
|
||||
|
||||
// set horiz and vert range
|
||||
regs.w.ax = 0x07;
|
||||
regs.w.cx = 0;
|
||||
regs.w.dx = VGA_DISPLAY_WIDTH - 1;
|
||||
int386(MOUSE_DRIVER_INTERRUPT, ®s, ®s);
|
||||
|
||||
regs.w.ax = 0x08;
|
||||
regs.w.cx = 0;
|
||||
regs.w.dx = VGA_DISPLAY_HEIGHT - 1;
|
||||
int386(MOUSE_DRIVER_INTERRUPT, ®s, ®s);
|
||||
}
|
||||
|
||||
return mouseActivated;
|
||||
}
|
||||
|
||||
void readMouse(struct MouseStatus *status) {
|
||||
union REGS regs;
|
||||
int buttonStatus;
|
||||
|
||||
regs.w.ax = MOUSE_DRIVER_READ_STATE;
|
||||
int386(MOUSE_DRIVER_INTERRUPT, ®s, ®s);
|
||||
|
||||
buttonStatus = regs.w.bx;
|
||||
status->xPosition = regs.w.cx;
|
||||
status->yPosition = regs.w.dx;
|
||||
|
||||
status->leftButtonDown = buttonStatus & 1;
|
||||
status->rightButtonDown = (buttonStatus >> 1) & 1;
|
||||
}
|
||||
|
18
mouse_io.h
Normal file
18
mouse_io.h
Normal file
@ -0,0 +1,18 @@
|
||||
#include "vga.h"
|
||||
|
||||
typedef struct MouseStatus {
|
||||
int isActive;
|
||||
int buttonCount;
|
||||
int xPosition;
|
||||
int yPosition;
|
||||
int leftButtonDown;
|
||||
int rightButtonDown;
|
||||
};
|
||||
|
||||
#define MOUSE_DRIVER_INTERRUPT (0x33)
|
||||
#define MOUSE_DRIVER_RESET (0x00)
|
||||
#define MOUSE_DRIVER_READ_DELTA_MOTION (0x0B)
|
||||
#define MOUSE_DRIVER_READ_STATE (0x03);
|
||||
|
||||
int activateMouse(struct MouseStatus *);
|
||||
void readMouse(struct MouseStatus *);
|
23
pc_stuff.c
Normal file
23
pc_stuff.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include "pc_stuff.h"
|
||||
|
||||
#define INPUT_STATUS (0x03da)
|
||||
#define VBLANK (0x08)
|
||||
#define BIOS_SET_VIDEO_MODE (0x00)
|
||||
|
||||
byte *VGA = (byte *)0xA0000;
|
||||
|
||||
void setVideoMode(byte videoMode) {
|
||||
union REGS regs;
|
||||
|
||||
regs.h.ah = BIOS_SET_VIDEO_MODE;
|
||||
regs.h.al = videoMode;
|
||||
int386(BIOS_VIDEO_INTERRUPT, ®s, ®s);
|
||||
}
|
||||
|
||||
void waitStartVbl() {
|
||||
while (inp(INPUT_STATUS) & VBLANK);
|
||||
}
|
||||
|
||||
void waitEndVbl() {
|
||||
while (!(inp(INPUT_STATUS) & VBLANK));
|
||||
}
|
25
pc_stuff.h
Normal file
25
pc_stuff.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __PC_STUFF_H__
|
||||
#define __PC_STUFF_H__
|
||||
|
||||
#include <conio.h>
|
||||
#include <dos.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern byte *VGA;
|
||||
|
||||
#define BIOS_GET_VIDEO_MODE (0x0F)
|
||||
#define BIOS_VIDEO_INTERRUPT (0x10)
|
||||
|
||||
#define VIDEO_MODE_VGA_256 (0x13)
|
||||
#define VIDEO_MODE_80x25_TEXT (0x03)
|
||||
|
||||
// remember, little endian, so the "first" value is "last"
|
||||
#define outpw_to_register(indexPort, dataRegister, data) \
|
||||
outpw(indexPort, (((word)(data) << 8)) + (dataRegister))
|
||||
|
||||
#endif
|
||||
|
||||
void setVideoMode(byte);
|
||||
void waitStartVbl();
|
||||
void waitEndVbl();
|
BIN
sprtsht.bmp
Normal file
BIN
sprtsht.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
3
types.h
Normal file
3
types.h
Normal file
@ -0,0 +1,3 @@
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short int word;
|
||||
typedef unsigned long int ulong;
|
155
unch1.c
Normal file
155
unch1.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include <conio.h>
|
||||
#include <dos.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "mouse_io.h"
|
||||
#include "pc_stuff.h"
|
||||
#include "bmp_loader.h"
|
||||
#include "vga.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
byte MOUSE_POINTER[8][8] = {
|
||||
{ 2, 2, 2, 2, 2, 0, 0, 0 },
|
||||
{ 2, 1, 1, 1, 2, 0, 0, 0 },
|
||||
{ 2, 1, 1, 1, 2, 0, 0, 0 },
|
||||
{ 2, 1, 1, 1, 2, 0, 0, 0 },
|
||||
{ 2, 2, 2, 255, 1, 2, 0, 0 },
|
||||
{ 0, 0, 0, 0, 2, 1, 2, 0 },
|
||||
{ 0, 0, 0, 0, 0, 2, 1, 2 },
|
||||
{ 0, 0, 0, 0, 0, 0, 2, 0 },
|
||||
};
|
||||
|
||||
byte WALKER[9][8] = {
|
||||
{ 0, 0, 0, 4, 4, 0, 0, 0 },
|
||||
{ 0, 0, 4, 5, 5, 4, 0, 0 },
|
||||
{ 0, 4, 5, 5, 5, 5, 4, 0 },
|
||||
{ 0, 0, 0, 4, 4, 0, 0, 0 },
|
||||
{ 0, 0, 4, 5, 255, 4, 0, 0 },
|
||||
{ 0, 4, 5, 5, 5, 5, 4, 0 },
|
||||
{ 0, 0, 0, 4, 4, 0, 0, 0 },
|
||||
{ 0, 0, 4, 5, 5, 4, 0, 0 },
|
||||
{ 0, 4, 5, 5, 5, 5, 4, 0 }
|
||||
};
|
||||
|
||||
int main(void) {
|
||||
FILE *fh;
|
||||
struct BMPImage bmpImage, spriteSheetImage;
|
||||
struct MouseStatus mouseStatus = { .xPosition = 0, .yPosition = 0, .leftButtonDown = 0 };
|
||||
struct VGAColor colors[256];
|
||||
byte *spriteSheet, *chicken, *drawBuffer;
|
||||
int i, x, y;
|
||||
|
||||
int currentMouseSprite = 0;
|
||||
int mouseSpriteDelayCount = 0;
|
||||
|
||||
float measuredTime;
|
||||
|
||||
int walkerX = 0, walkerY = 0;
|
||||
int yOffset;
|
||||
|
||||
struct SpriteRender mousePointer = {
|
||||
.data = (byte *)MOUSE_POINTER,
|
||||
.transparentColor = 0,
|
||||
.width = 8,
|
||||
.height = 8,
|
||||
.modulo = 48
|
||||
};
|
||||
|
||||
struct SpriteRender walker = {
|
||||
.data = (byte *)WALKER,
|
||||
.transparentColor = 0,
|
||||
.width = 8,
|
||||
.height = 9,
|
||||
.modulo = 0
|
||||
};
|
||||
|
||||
installKeyboardHandler();
|
||||
|
||||
initializeDrawBuffer();
|
||||
|
||||
spriteSheet = malloc(64 * 64);
|
||||
spriteSheetImage.memoryStart = spriteSheet;
|
||||
|
||||
fh = fopen("sprtsht.bmp", "rb");
|
||||
if (readBMPIntoMemory(fh, &spriteSheetImage)) return 1;
|
||||
fclose(fh);
|
||||
|
||||
setVideoMode(VIDEO_MODE_VGA_256);
|
||||
|
||||
chicken = malloc(320 * 256);
|
||||
bmpImage.memoryStart = chicken;
|
||||
|
||||
fh = fopen("chicken.bmp", "rb");
|
||||
readBMPIntoMemory(fh, &bmpImage);
|
||||
fclose(fh);
|
||||
|
||||
mousePointer.data = spriteSheet;
|
||||
mousePointer.width = 16;
|
||||
mousePointer.height = 16;
|
||||
mousePointer.modulo = 48;
|
||||
|
||||
bmp256ColorPaletteToVGAColorPalette(&bmpImage, colors);
|
||||
setVGAColors(colors);
|
||||
|
||||
activateMouse(&mouseStatus);
|
||||
readMouse(&mouseStatus);
|
||||
|
||||
while (!mouseStatus.leftButtonDown) {
|
||||
readMouse(&mouseStatus);
|
||||
|
||||
populateKeyboardKeydownState();
|
||||
|
||||
if (keyboardKeydownState.KEY_W) walkerY -= 1;
|
||||
if (keyboardKeydownState.KEY_S) walkerY += 1;
|
||||
if (keyboardKeydownState.KEY_A) walkerX -= 1;
|
||||
if (keyboardKeydownState.KEY_D) walkerX += 1;
|
||||
|
||||
|
||||
drawBuffer = getDrawBuffer();
|
||||
|
||||
memcpy(drawBuffer, chicken, 320 * 200);
|
||||
|
||||
mousePointer.x = mouseStatus.xPosition;
|
||||
mousePointer.y = mouseStatus.yPosition;
|
||||
drawSprite(&mousePointer);
|
||||
|
||||
for (i = 0; i < 100; ++i) {
|
||||
walker.x = walkerX + i;
|
||||
walker.y = walkerY + i;
|
||||
drawSprite(&walker);
|
||||
}
|
||||
|
||||
waitStartVbl();
|
||||
memcpy((byte *)0xa0000, drawBuffer, 320 * 200);
|
||||
waitEndVbl();
|
||||
|
||||
//drawBufferToUnchainedMemory();
|
||||
|
||||
|
||||
//copyUnchainedMemoryToActive(chicken);
|
||||
|
||||
//swapPlanes();
|
||||
|
||||
mouseSpriteDelayCount += 1;
|
||||
if (mouseSpriteDelayCount >= 15) {
|
||||
currentMouseSprite = 1 - currentMouseSprite;
|
||||
mousePointer.data = spriteSheet + (currentMouseSprite * 16);
|
||||
mouseSpriteDelayCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uninstallKeyboardHandler();
|
||||
setVideoMode(VIDEO_MODE_80x25_TEXT);
|
||||
free(spriteSheet);
|
||||
free(chicken);
|
||||
|
||||
freeDrawBuffer();
|
||||
|
||||
fprintf(stderr, "%lu %lu %lu\n", startTime, endTime, (clock_t)(endTime - startTime));
|
||||
|
||||
return 0;
|
||||
}
|
456
vga.c
Normal file
456
vga.c
Normal file
@ -0,0 +1,456 @@
|
||||
#include "vga.h"
|
||||
#include "pc_stuff.h"
|
||||
#include <malloc.h>
|
||||
#include <conio.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define VGA_SEQUENCE_CONTROLLER_INDEX (0x03C4)
|
||||
#define VGA_SEQUENCE_CONTROLLER_DATA (0x03C5)
|
||||
|
||||
#define VGA_SEQUENCE_CONTROLLER_MEMORY_MODE (0x04)
|
||||
#define VGA_SEQUENCE_CONTROLLER_ODD_EVEN_SEQUENTIAL_ACCESS (0x04)
|
||||
#define VGA_SEQUENCE_CONTROLLER_EXTENDED_MEMORY (0x02)
|
||||
|
||||
#define VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE (0x02)
|
||||
#define VGA_SEQUENCE_CONTROLLER_ALL_PLANES (0xff)
|
||||
|
||||
#define VGA_GRAPHICS_REGISTERS_INDEX (0x03CE)
|
||||
#define VGA_GRAPHICS_REGISTERS_DATA (0x03CF)
|
||||
|
||||
#define VGA_GRAPHICS_DATA_ROTATE (0x03)
|
||||
|
||||
#define VGA_CRT_CONTROLLER_INDEX (0x03d4)
|
||||
#define VGA_CRT_CONTROLLER_DATA (0x03d5)
|
||||
|
||||
#define VGA_CRT_CONTROLLER_UNDERLINE_MODE (0x14)
|
||||
#define VGA_CRT_CONTROLLER_MODE_CONTROL (0x17)
|
||||
|
||||
#define VGA_CRT_CONTROLLER_DISPLAY_HIGH_ADDRESS (0x0c)
|
||||
#define VGA_CRT_CONTROLLER_DISPLAY_LOW_ADDRESS (0x0d)
|
||||
|
||||
#define VGA_CRT_CONTROLLER_VERTICAL_RETRACE_START (0x10)
|
||||
#define VGA_CRT_CONTROLLER_VERTICAL_RETRACE_END (0x11)
|
||||
#define VGA_CRT_CONTROLLER_VERTICAL_DISPLAY_END (0x12)
|
||||
#define VGA_CRT_CONTROLLER_VERTICAL_BLANK_START (0x15)
|
||||
#define VGA_CRT_CONTROLLER_VERTICAL_BLANK_END (0x16)
|
||||
#define VGA_CRT_CONTROLLER_VERTICAL_TOTAL (0x06)
|
||||
#define VGA_CRT_CONTROLLER_OVERFLOW (0x07)
|
||||
|
||||
int activePage = 0;
|
||||
byte *drawBuffer, *displayMirrorBuffer;
|
||||
|
||||
void initializeDrawBuffer() {
|
||||
int i;
|
||||
|
||||
drawBuffer = (byte *)malloc(VGA_DISPLAY_WIDTH * VGA_DISPLAY_HEIGHT);
|
||||
displayMirrorBuffer = (byte *)malloc(VGA_DISPLAY_WIDTH * VGA_DISPLAY_HEIGHT);
|
||||
|
||||
for (i = 0; i < VGA_DISPLAY_WIDTH * VGA_DISPLAY_HEIGHT; ++i) {
|
||||
drawBuffer[i] = 0;
|
||||
displayMirrorBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void freeDrawBuffer() {
|
||||
free(drawBuffer);
|
||||
free(displayMirrorBuffer);
|
||||
}
|
||||
|
||||
void setActiveVGAMemoryPlanes(int planes) {
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
|
||||
planes
|
||||
);
|
||||
}
|
||||
|
||||
byte *getDrawBuffer() {
|
||||
return drawBuffer;
|
||||
}
|
||||
|
||||
clock_t startTime, endTime;
|
||||
|
||||
void drawBufferToUnchainedMemory() {
|
||||
int x, y, plane, pageOffset, yOffset, yDisplayOffset;
|
||||
byte *vgaStart;
|
||||
unsigned long data;
|
||||
|
||||
int rowsToCopy[VGA_DISPLAY_HEIGHT], minRow = -1, maxRow = 0;
|
||||
|
||||
unsigned long *drawBufferLong = (unsigned long *)drawBuffer,
|
||||
*displayMirrorBufferLong = (unsigned long *)displayMirrorBuffer;
|
||||
|
||||
byte copyRow[VGA_DISPLAY_WIDTH];
|
||||
|
||||
startTime = clock();
|
||||
|
||||
pageOffset = activePage * PAGE_SIZE;
|
||||
vgaStart = (byte *)(VGA + pageOffset);
|
||||
|
||||
for (y = 0; y < VGA_DISPLAY_HEIGHT; ++y) {
|
||||
rowsToCopy[y] = 0;
|
||||
yOffset = y * VGA_UNCHAINED_LINE_WIDTH;
|
||||
|
||||
for (x = 0; x < VGA_UNCHAINED_LINE_WIDTH; x++) {
|
||||
data = *(drawBufferLong++);
|
||||
|
||||
if (displayMirrorBufferLong[yOffset] != data) {
|
||||
rowsToCopy[y] = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
yOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(displayMirrorBuffer, drawBuffer, VGA_DISPLAY_WIDTH * VGA_DISPLAY_HEIGHT);
|
||||
|
||||
for (y = 0; y < VGA_DISPLAY_HEIGHT; ++y) {
|
||||
if (rowsToCopy[y]) {
|
||||
if (minRow == -1) minRow = y;
|
||||
maxRow = y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (minRow == -1) return;
|
||||
|
||||
drawBufferLong = (unsigned long *)drawBuffer;
|
||||
|
||||
for (y = minRow; y <= maxRow; ++y) {
|
||||
if (!rowsToCopy[y]) continue;
|
||||
|
||||
yOffset = y * VGA_UNCHAINED_LINE_WIDTH;
|
||||
|
||||
for (x = 0; x < VGA_UNCHAINED_LINE_WIDTH; ++x) {
|
||||
data = drawBufferLong[yOffset + x];
|
||||
|
||||
for (plane = 0; plane < 4; plane++) {
|
||||
copyRow[x + (plane * VGA_UNCHAINED_LINE_WIDTH)] = data & 0xff;
|
||||
data >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
for (plane = 0; plane < 4; ++plane) {
|
||||
setActiveVGAMemoryPlanes(1 << plane);
|
||||
|
||||
memcpy(vgaStart + yOffset, copyRow + (plane * VGA_UNCHAINED_LINE_WIDTH), VGA_UNCHAINED_LINE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
endTime = clock();
|
||||
|
||||
}
|
||||
|
||||
void enableUnchainedVGAMode() {
|
||||
word clearOffset;
|
||||
|
||||
// convert VGA pointer into a word sized
|
||||
ulong *ptr = (ulong *)VGA;
|
||||
|
||||
// The VGA registers are (mostly) byte sized, and are grouped
|
||||
// logically behind a pair of index/data ports.
|
||||
// To access them, you prep the index port on the VGA card
|
||||
// for the register you want to access, then do that access
|
||||
// via the data port.
|
||||
//
|
||||
// Visual: VGA has pouches which contain organization boxes of
|
||||
// registers.
|
||||
|
||||
// target the Sequence Memory Mode Register for Memory Mode
|
||||
// enable sequential access and extended memory
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MEMORY_MODE,
|
||||
VGA_SEQUENCE_CONTROLLER_EXTENDED_MEMORY | VGA_SEQUENCE_CONTROLLER_ODD_EVEN_SEQUENTIAL_ACCESS
|
||||
);
|
||||
|
||||
// target the Sequence Memory Mode Register for map mask
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
|
||||
VGA_SEQUENCE_CONTROLLER_ALL_PLANES
|
||||
);
|
||||
|
||||
for (clearOffset = 0; clearOffset < PAGE_SIZE; ++clearOffset) {
|
||||
*ptr++ = 0;
|
||||
}
|
||||
|
||||
// there's a way to address memory as words or longs, but we're
|
||||
// going to set it to byte addressing because it makes mroe sense.
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_UNDERLINE_MODE,
|
||||
0x00
|
||||
);
|
||||
|
||||
// * enable hsync and vsync
|
||||
// * activate byte Mode
|
||||
// * ...something with address wrapping that I don't quite understand yet...
|
||||
// * ...even more with address funkiness that I don't understand
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_MODE_CONTROL,
|
||||
0xe3
|
||||
);
|
||||
|
||||
outp(0x3c2, 0xe3);
|
||||
}
|
||||
|
||||
void enable320x256VGAMode() {
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_VERTICAL_RETRACE_END,
|
||||
0x2c
|
||||
);
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_VERTICAL_TOTAL,
|
||||
0x0d
|
||||
);
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_OVERFLOW,
|
||||
0x3e
|
||||
);
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_VERTICAL_RETRACE_START,
|
||||
0xea
|
||||
);
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_VERTICAL_RETRACE_END,
|
||||
0xac
|
||||
);
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_VERTICAL_DISPLAY_END,
|
||||
0xdf
|
||||
);
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_VERTICAL_BLANK_START,
|
||||
0xe7
|
||||
);
|
||||
outpw_to_register(
|
||||
VGA_CRT_CONTROLLER_INDEX,
|
||||
VGA_CRT_CONTROLLER_VERTICAL_BLANK_END,
|
||||
0x06
|
||||
);
|
||||
}
|
||||
|
||||
void clearWithColor(byte color) {
|
||||
int x, y;
|
||||
int pageOffset, drawY;
|
||||
long *start;
|
||||
long newColor = (color << 24) + (color << 16) + (color << 8) + (color);
|
||||
|
||||
// write to all planes
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
|
||||
0xff
|
||||
);
|
||||
|
||||
pageOffset = activePage * PAGE_SIZE;
|
||||
start = (long *)(VGA + pageOffset);
|
||||
|
||||
for (y = 0; y < VGA_DISPLAY_HEIGHT; ++y) {
|
||||
for (x = 0; x < VGA_UNCHAINED_LINE_WIDTH / 4; ++x) {
|
||||
*(start++) = newColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this is very temporary
|
||||
*/
|
||||
void copyUnchainedMemoryToActive(byte *src) {
|
||||
int y, plane, _testSize, _testOffset;
|
||||
|
||||
_testSize = 80 * 240;
|
||||
_testOffset = 80 * 256;
|
||||
|
||||
for (plane = 0; plane < 4; ++plane) {
|
||||
// copying to/from VGA memory requires setting the plane to write to...
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
|
||||
1 << plane
|
||||
);
|
||||
|
||||
memcpy(VGA + activePage * PAGE_SIZE, src + plane * _testOffset, _testSize);
|
||||
}
|
||||
}
|
||||
|
||||
void copyScratchPlanesToActive() {
|
||||
int y, plane;
|
||||
|
||||
for (plane = 0; plane < 4; ++plane) {
|
||||
// copying to/from VGA memory requires setting the plane to write to...
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
|
||||
1 << plane
|
||||
);
|
||||
|
||||
// and to read from
|
||||
outpw_to_register(
|
||||
0x3ce,
|
||||
0x04,
|
||||
plane
|
||||
);
|
||||
|
||||
memcpy(VGA + activePage * PAGE_SIZE, VGA + SCRATCH_PAGE, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void copyScratchPlanesToActiveViaLatches() {
|
||||
int pixel;
|
||||
byte *src, *dest;
|
||||
|
||||
// TODO: VGA latches
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
|
||||
0xff
|
||||
);
|
||||
|
||||
outpw_to_register(
|
||||
VGA_GRAPHICS_REGISTERS_INDEX,
|
||||
VGA_GRAPHICS_DATA_ROTATE,
|
||||
0x10
|
||||
);
|
||||
|
||||
src = VGA + SCRATCH_PAGE;
|
||||
dest = VGA + activePage * PAGE_SIZE;
|
||||
|
||||
for (pixel = 0; pixel < PAGE_SIZE; ++pixel) {
|
||||
volatile char _temp = *(src++);
|
||||
*(dest++) = 0;
|
||||
}
|
||||
|
||||
outpw_to_register(
|
||||
VGA_GRAPHICS_REGISTERS_INDEX,
|
||||
VGA_GRAPHICS_DATA_ROTATE,
|
||||
0x00
|
||||
);
|
||||
}
|
||||
|
||||
void drawSprite(struct SpriteRender* sprite) {
|
||||
int x, y;
|
||||
byte pixel;
|
||||
|
||||
byte* spriteData = sprite->data;
|
||||
byte* drawBufferPos = drawBuffer + sprite->x + (sprite->y * VGA_DISPLAY_WIDTH);
|
||||
|
||||
for (y = 0; y < sprite->height; ++y) {
|
||||
for (x = 0; x < sprite->width; ++x) {
|
||||
pixel = *(spriteData++);
|
||||
if (pixel != sprite->transparentColor) {
|
||||
*(drawBufferPos) = pixel;
|
||||
}
|
||||
|
||||
drawBufferPos++;
|
||||
}
|
||||
|
||||
drawBufferPos += (VGA_DISPLAY_WIDTH - sprite->width);
|
||||
spriteData += sprite->modulo;
|
||||
}
|
||||
}
|
||||
|
||||
void drawUnchainedSprite(struct SpriteRender* sprite) {
|
||||
int dataX, dataY, currentPlane;
|
||||
int drawX, drawY, vgaWriteYStart;
|
||||
int startY, endY;
|
||||
int nextStartX = 1;
|
||||
int planeSampleX = 0, readPositionOffset;
|
||||
int vgaWritePosition, readPosition, spriteAdvance;
|
||||
int activePageOffset, alwaysVGAWriteStart, startVGAWritePosition;
|
||||
byte readResult;
|
||||
|
||||
// precalculate sprite sheet handling and VGA plane
|
||||
currentPlane = sprite->x & 3;
|
||||
spriteAdvance = sprite->width + sprite->modulo;
|
||||
|
||||
outpw_to_register(
|
||||
VGA_SEQUENCE_CONTROLLER_INDEX,
|
||||
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
|
||||
1 << currentPlane
|
||||
);
|
||||
|
||||
// precalculate x pixel drawing
|
||||
activePageOffset = activePage * PAGE_SIZE;
|
||||
|
||||
alwaysVGAWriteStart = sprite->y;
|
||||
if (alwaysVGAWriteStart < 0) alwaysVGAWriteStart = 0;
|
||||
alwaysVGAWriteStart *= VGA_DISPLAY_WIDTH;
|
||||
|
||||
// precalculate y pixel drawing
|
||||
startY = sprite->y;
|
||||
endY = sprite->y + sprite->height;
|
||||
readPositionOffset = 0;
|
||||
|
||||
if (startY < 0) {
|
||||
readPositionOffset = (spriteAdvance * (-startY));
|
||||
startY = 0;
|
||||
}
|
||||
if (endY > VGA_DISPLAY_HEIGHT) { endY = VGA_DISPLAY_HEIGHT; }
|
||||
|
||||
startVGAWritePosition = activePageOffset + (sprite->x + alwaysVGAWriteStart) / PLANE_PIXEL_DISTANCE;
|
||||
|
||||
for (dataX = 0; dataX < sprite->width; ++dataX) {
|
||||
if (planeSampleX >= sprite->width) {
|
||||
planeSampleX = nextStartX;
|
||||
nextStartX++;
|
||||
currentPlane = (currentPlane + 1) & 3;
|
||||
|
||||
startVGAWritePosition = activePageOffset + (planeSampleX + sprite->x + alwaysVGAWriteStart) / PLANE_PIXEL_DISTANCE;
|
||||
|
||||
// save a second out
|
||||
outp(
|
||||
VGA_SEQUENCE_CONTROLLER_DATA,
|
||||
1 << currentPlane
|
||||
);
|
||||
}
|
||||
|
||||
drawX = planeSampleX + sprite->x;
|
||||
if (drawX >= 0 && drawX < VGA_DISPLAY_WIDTH) {
|
||||
vgaWritePosition = startVGAWritePosition;
|
||||
readPosition = planeSampleX + readPositionOffset;
|
||||
|
||||
for (drawY = startY; drawY < endY; ++drawY) {
|
||||
readResult = sprite->data[readPosition];
|
||||
if (readResult != sprite->transparentColor) {
|
||||
VGA[vgaWritePosition] = readResult;
|
||||
}
|
||||
vgaWritePosition += VGA_UNCHAINED_LINE_WIDTH;
|
||||
readPosition += spriteAdvance;
|
||||
}
|
||||
}
|
||||
|
||||
startVGAWritePosition++;
|
||||
planeSampleX += 4;
|
||||
}
|
||||
}
|
||||
void swapPlanes() {
|
||||
outpw(VGA_CRT_CONTROLLER_INDEX, VGA_CRT_CONTROLLER_DISPLAY_HIGH_ADDRESS | ((PAGE_SIZE * activePage) & 0xff00));
|
||||
outpw(VGA_CRT_CONTROLLER_INDEX, VGA_CRT_CONTROLLER_DISPLAY_LOW_ADDRESS | ((PAGE_SIZE * activePage) << 8));
|
||||
|
||||
activePage = 1 - activePage;
|
||||
}
|
||||
|
||||
void setVGAColors(struct VGAColor colors[], int totalColors) {
|
||||
int i;
|
||||
|
||||
outp(0x3c8,0);
|
||||
for (i = 0; i < totalColors; ++i) {
|
||||
outp(0x3c9, colors[i].red);
|
||||
outp(0x3c9, colors[i].green);
|
||||
outp(0x3c9, colors[i].blue);
|
||||
}
|
||||
}
|
51
vga.h
Normal file
51
vga.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef __VGA_H__
|
||||
#define __VGA_H__
|
||||
|
||||
#include "types.h"
|
||||
#include <time.h>
|
||||
|
||||
#define PLANE_PIXEL_DISTANCE (4)
|
||||
#define VGA_DISPLAY_WIDTH (320)
|
||||
#define VGA_DISPLAY_HEIGHT (200)
|
||||
#define VGA_UNCHAINED_LINE_WIDTH (VGA_DISPLAY_WIDTH / PLANE_PIXEL_DISTANCE)
|
||||
|
||||
// there are four of these in a row
|
||||
#define PAGE_SIZE (VGA_DISPLAY_WIDTH*VGA_DISPLAY_HEIGHT/4)
|
||||
#define SCRATCH_PAGE (PAGE_SIZE * 2)
|
||||
|
||||
struct VGAColor {
|
||||
byte red;
|
||||
byte green;
|
||||
byte blue;
|
||||
};
|
||||
|
||||
struct SpriteRender {
|
||||
byte* data;
|
||||
int x;
|
||||
int y;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
int transparentColor;
|
||||
unsigned int modulo;
|
||||
};
|
||||
|
||||
extern clock_t startTime, endTime;
|
||||
|
||||
void enableUnchainedVGAMode();
|
||||
void enable320x256VGAMode();
|
||||
void setVGAColors(struct VGAColor[], int);
|
||||
void copyUnchainedMemoryToActive();
|
||||
void copyScratchPlanesToActive();
|
||||
void copyScratchPlanesToActiveViaLatches();
|
||||
void drawSprite(struct SpriteRender *sprite);
|
||||
void swapPlanes();
|
||||
void setActiveVGAMemoryPlanes(int);
|
||||
void clearWithColor(byte);
|
||||
|
||||
void initializeDrawBuffer();
|
||||
void freeDrawBuffer();
|
||||
void drawBufferToUnchainedMemory();
|
||||
|
||||
byte *getDrawBuffer();
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user