dosgame1/system/Video.cpp

136 lines
2.9 KiB
C++

#include <dos.h>
#include <sys/nearptr.h>
#include "Video.h"
#include "../util/Asm.h"
#include "../util/Log.h"
#define VGA_DAC_ADDR_RD 0x3c7
#define VGA_DAC_ADDR_WR 0x3c8
#define VGA_DAC_DATA 0x3c9
#define VGA_EXT_INPUT_STATUS 0x3da
#define VGA_EXT_INPUT_STATUS_VRETRACE 8
Video video;
Video::Video() {
__djgpp_nearptr_enable();
// Store current video mode
_oldMode = GetMode();
// Store current palette
for (auto i = 0; i < 256; i++) {
GetPaletteEntry(i, &_oldPalette[i]);
}
}
Video::~Video() {
Exit();
}
void Video::Enter() {
SetMode(0x13);
}
void Video::Exit() {
// Restore old palette
for (auto i = 0; i < 256; i++) {
SetPaletteEntry(i, &_oldPalette[i]);
}
// Restore old video mode
SetMode(_oldMode);
}
void Video::SetMode(uint8_t mode) {
union REGS regs;
regs.h.ah = 0x00;
regs.h.al = mode;
int86(0x10, &regs, &regs);
//__djgpp_nearptr_enable();
switch (mode) {
default:
case 0x13:
_fb = (uint8_t *)(0xA0000 + __djgpp_conventional_base);
}
}
uint8_t Video::GetMode() {
union REGS regs;
regs.h.ah = 0x0f;
regs.h.al = 0;
int86(0x10, &regs, &regs);
return regs.h.al;
}
void Video::SetPaletteEntry(uint8_t index, PaletteEntry entry) {
SetPaletteEntry(index, &entry);
}
Video::PaletteEntry Video::GetPaletteEntry(uint8_t index) {
PaletteEntry entry;
GetPaletteEntry(index, &entry);
return entry;
}
void Video::SetPaletteEntry(uint8_t index, PaletteEntry *entry) {
outb(VGA_DAC_ADDR_WR, index);
outb(VGA_DAC_DATA, entry->r >> 2);
outb(VGA_DAC_DATA, entry->g >> 2);
outb(VGA_DAC_DATA, entry->b >> 2);
}
void Video::GetPaletteEntry(uint8_t index, PaletteEntry *entry) {
outb(VGA_DAC_ADDR_RD, index);
entry->r = inb(VGA_DAC_DATA);
entry->g = inb(VGA_DAC_DATA);
entry->b = inb(VGA_DAC_DATA);
}
void *Video::GetFB() {
return _renderBuffer;
}
void Video::WaitForVerticalSync() {
auto state = inb(VGA_EXT_INPUT_STATUS) & VGA_EXT_INPUT_STATUS_VRETRACE;
if (!state) {
// We started before a retrace, so wait until it begins
while (!(inb(VGA_EXT_INPUT_STATUS) & VGA_EXT_INPUT_STATUS_VRETRACE)) {}
}
// Wait until it ends
while (inb(VGA_EXT_INPUT_STATUS) & VGA_EXT_INPUT_STATUS_VRETRACE);
}
void Video::UpdateRect(const Rect &rect) {
// Merge rect if it overlaps with an existing rect
for (auto i = 0; i < _updateRectIndex; i++) {
auto &r = _updatedRects[i];
if (r.overlaps(rect)) {
r += rect;
return;
}
}
// Add a new rect to the list
_updatedRects[_updateRectIndex++] = rect;
}
void Video::Flip() {
for (auto i = 0; i <= MAX_UPDATE_RECT_INDEX; i++) {
auto &rect = _updatedRects[i];
for (auto y = rect.y1; y <= rect.y2; y++) {
auto yOffset = y * SCREEN_WIDTH;
for (auto x = rect.x1; x <= rect.x2; x++) {
_fb[yOffset + x] = _renderBuffer[yOffset + x];
}
}
}
_updateRectIndex = 0;
}