136 lines
2.9 KiB
C++
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, ®s, ®s);
|
|
|
|
//__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, ®s, ®s);
|
|
|
|
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;
|
|
}
|