more prep stuff

This commit is contained in:
John Bintz 2024-02-15 08:34:50 -05:00
parent 0d6bed04f7
commit d52426a877
14 changed files with 598 additions and 488 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
*.ERR
*.EXE
.ccls-cache/
*.LNK

View File

@ -3,12 +3,13 @@
#include <malloc.h>
#include <dos.h>
#include "bmp_loader.h"
#include "bmpload.h"
#include "pc_stuff.h"
#include "vga.h"
int readBMPHeader(FILE *fh, struct BMPImage *info) {
int sizeOfHeader;
char value;
unsigned int numberOfUsedColors;
if ((fgetc(fh) != 'B') || (fgetc(fh) != 'M')) {
@ -42,14 +43,26 @@ int readBMPHeader(FILE *fh, struct BMPImage *info) {
return 0;
}
int readBMPIntoNewMemory(FILE *fh, struct BMPImage *info) {
int result;
result = readBMPHeader(fh, info);
if (result) return result;
info->memoryStart = malloc(info->width * info->height);
return readBMPIntoMemory(fh, info);
}
void freeBMP(struct BMPImage *info) {
free(info->memoryStart);
}
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) {
@ -61,69 +74,6 @@ int readBMPIntoMemory(FILE *fh, struct BMPImage *info) {
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;

View File

@ -1,3 +1,6 @@
#ifndef __BMP_LOADER_H__
#define __BMP_LOADER_H__
#include <stdio.h>
#include "types.h"
@ -15,9 +18,12 @@ struct BMPImage {
word bpp;
struct BMPColor colors[256];
byte *memoryStart;
int transparentColor;
};
int readBMPIntoUnchainedMemory(FILE *, struct BMPImage *);
int readBMPIntoMemory(FILE *, struct BMPImage *);
int readBMPIntoNewMemory(FILE *, struct BMPImage *);
void bmp256ColorPaletteToVGAColorPalette(struct BMPImage*, struct VGAColor[]);
#endif

View File

@ -3,4 +3,5 @@ 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
wcl386.exe -q game.c bmp_load.obj mouse_io.obj pc_stuff.obj vga.obj keyboard.obj

0
const.h Normal file
View File

43
game.c
View File

@ -1,20 +1,54 @@
#include <stdio.h>
#include "vga.h"
#include "keyboard.h"
#include "mouse_io.h"
#include "pc_stuff.h"
#include "bmpload.h"
struct VGAColor colors[4] = {
{ 0, 0, 0 }, { 255, 255, 255 }, { 255, 0, 0 }, { 0, 0, 255 }
}
struct BMPImage spritesheetImage;
struct VGAColor vgaColors[256];
struct SpriteRender arenaWallTop, arenaWallSide, arenaFloor;
int main(void) {
FILE *fh;
int keepRunning = 1;
struct MouseStatus mouseStatus;
installKeyboardHandler();
activateMouse(&mouseStatus);
initializeDrawBuffer();
fh = fopen("sprtsht.bmp", "rb");
if (readBMPIntoNewMemory(fh, &spritesheetImage)) return 1;
fclose(fh);
return 0;
spritesheetImage.transparentColor = 0;
buildSpriteFromSpritesheet(
&spritesheetImage,
&arenaWallTop,
0, 0, 20, 20
);
setVideoMode(VIDEO_MODE_VGA_256);
bmp256ColorPaletteToVGAColorPalette(&spritesheetImage, vgaColors);
setVGAColors(vgaColors, 256);
while (keepRunning) {
arenaWallTop.x = 0;
arenaWallTop.y = 0;
drawSprite(&arenaWallTop);
waitStartVbl();
copyDrawBufferToDisplay();
waitEndVbl();
}
// states:
// * main menu
@ -35,4 +69,7 @@ int main(void) {
// * character is damaged
// * check for bullets hitting the edges of the screen and remove
// *
//
return 0;
}

13
makefile Normal file
View File

@ -0,0 +1,13 @@
.c.obj
wcc386 -q $<
game.exe: bmpload.obj mouse_io.obj pc_stuff.obj vga.obj keyboard.obj game.obj
%write game.lnk NAME $@
%write game.lnk SYSTEM DOS4G
%write game.lnk FILE bmpload.obj
%write game.lnk FILE mouse_io.obj
%write game.lnk FILE pc_stuff.obj
%write game.lnk FILE vga.obj
%write game.lnk FILE keyboard.obj
%write game.lnk FILE game.obj
wlink @game.lnk

View File

@ -1,6 +1,6 @@
#include "vga.h"
typedef struct MouseStatus {
struct MouseStatus {
int isActive;
int buttonCount;
int xPosition;

BIN
spritesheet.xcf Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 39 KiB

21
timer.c Normal file
View File

@ -0,0 +1,21 @@
char canRenderFrame = 0;
char elapsedTicks = 0;
void far (interrupt *oldTimer());
void far interrupt timerInterrupt() {
_disable();
elapsedTicks++;
if (elapsedTicks > SOME_THRESHOLD_FOR_30FPS) {
canRenderFrame = 1;
elapsedTicks = 0;
}
oldTimer();
int(0x20, 0x20);
_enable()
}

466
unchained.c Normal file
View File

@ -0,0 +1,466 @@
#define PLANE_PIXEL_DISTANCE (4)
#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)
#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 readBMPIntoUnchainedMemory(FILE *, struct BMPImage *);
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 setActiveVGAMemoryPlanes(int planes) {
outpw_to_register(
VGA_SEQUENCE_CONTROLLER_INDEX,
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE,
planes
);
}
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
);
}
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;
}

414
vga.c
View File

@ -6,64 +6,27 @@
#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;
byte *drawBuffer;
void initializeDrawBuffer() {
byte *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;
}
return drawBuffer;
}
void copyDrawBufferToDisplay() {
memcpy(VGA, drawBuffer, 320 * 200);
}
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() {
@ -72,273 +35,19 @@ byte *getDrawBuffer() {
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 buildSpriteFromSpritesheet(
struct BMPImage *spritesheetImage,
struct SpriteRender *spriteRender,
int positionX,
int positionY,
int width,
int height
) {
spriteRender->data = spritesheetImage->memoryStart + positionY * spritesheetImage->width + positionX;
spriteRender->modulo = spritesheetImage->width - width;
spriteRender->width = width;
spriteRender->height = height;
spriteRender->transparentColor = spritesheetImage->transparentColor;
}
void drawSprite(struct SpriteRender* sprite) {
@ -363,87 +72,6 @@ void drawSprite(struct SpriteRender* sprite) {
}
}
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;

31
vga.h
View File

@ -1,17 +1,13 @@
#ifndef __VGA_H__
#define __VGA_H__
#include "types.h"
#include <time.h>
#define PLANE_PIXEL_DISTANCE (4)
#include "types.h"
#include "bmpload.h"
#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;
@ -29,23 +25,14 @@ struct SpriteRender {
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();
void buildSpriteFromSpritesheet(struct BMPImage*, struct SpriteRender*, int, int, int, int);
byte *initializeDrawBuffer();
byte *getDrawBuffer();
void freeDrawBuffer();
void copyDrawBufferToDisplay();
void setVGAColors(struct VGAColor[], int);
#endif