diff --git a/.gitignore b/.gitignore index d9ab992..cb6c1ea 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.ERR *.EXE .ccls-cache/ +*.LNK diff --git a/bmp_loader.c b/bmpload.c similarity index 52% rename from bmp_loader.c rename to bmpload.c index 74429e0..b2f8194 100644 --- a/bmp_loader.c +++ b/bmpload.c @@ -3,12 +3,13 @@ #include #include -#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; diff --git a/bmp_loader.h b/bmpload.h similarity index 72% rename from bmp_loader.h rename to bmpload.h index b216371..123fb1b 100644 --- a/bmp_loader.h +++ b/bmpload.h @@ -1,3 +1,6 @@ +#ifndef __BMP_LOADER_H__ +#define __BMP_LOADER_H__ + #include #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 diff --git a/build.bat b/build.bat index 112a3aa..181ae06 100644 --- a/build.bat +++ b/build.bat @@ -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 + diff --git a/const.h b/const.h new file mode 100644 index 0000000..e69de29 diff --git a/game.c b/game.c index d303251..65dad36 100644 --- a/game.c +++ b/game.c @@ -1,20 +1,54 @@ +#include + #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; } diff --git a/makefile b/makefile new file mode 100644 index 0000000..a32a827 --- /dev/null +++ b/makefile @@ -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 diff --git a/mouse_io.h b/mouse_io.h index 4759877..7c43583 100644 --- a/mouse_io.h +++ b/mouse_io.h @@ -1,6 +1,6 @@ #include "vga.h" -typedef struct MouseStatus { +struct MouseStatus { int isActive; int buttonCount; int xPosition; diff --git a/spritesheet.xcf b/spritesheet.xcf new file mode 100644 index 0000000..6618ef8 Binary files /dev/null and b/spritesheet.xcf differ diff --git a/sprtsht.bmp b/sprtsht.bmp index 534d3a4..eec24cd 100644 Binary files a/sprtsht.bmp and b/sprtsht.bmp differ diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..5b09ec6 --- /dev/null +++ b/timer.c @@ -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() +} + + diff --git a/unchained.c b/unchained.c new file mode 100644 index 0000000..24e4e8e --- /dev/null +++ b/unchained.c @@ -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; +} + diff --git a/vga.c b/vga.c index d13360a..bb593fd 100644 --- a/vga.c +++ b/vga.c @@ -6,64 +6,27 @@ #include #include -#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; diff --git a/vga.h b/vga.h index cf9837a..c3a6028 100644 --- a/vga.h +++ b/vga.h @@ -1,17 +1,13 @@ #ifndef __VGA_H__ #define __VGA_H__ -#include "types.h" #include -#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