roo_e/roo-e/src/platform/djgpp.c
2022-06-28 16:00:42 -05:00

795 lines
24 KiB
C

/*
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
* Copyright (C) 2022 Scott Duensing
*
* http://kangaroopunch.com
*
*
* This file is part of Roo/E.
*
* Roo/E is free software: you can redistribute it and/or modify it under the
* terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Roo/E is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Roo/E. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef BACKEND_DJGPP
#include "os.h"
#include <dos.h>
#include <dpmi.h>
#include <go32.h>
#include <bios.h>
#include <conio.h>
#include <sys/farptr.h>
#include <sys/nearptr.h>
#include "platform.h"
// These are all we support
#define VBE_MM_PACKED 4
#define VBE_MM_DCOLOR 6
// Based on http://www.brackeen.com/vga/source/djgpp20/mouse.c.html
#define MOUSE_INT 0x33
#define MOUSE_RESET 0x00
#define MOUSE_STATUS 0x03
#define MOUSE_GETMOTION 0x0B
#define MOUSE_LEFT_BUTTON 0x01
#define MOUSE_RIGHT_BUTTON 0x02
#define MOUSE_MIDDLE_BUTTON 0x04
#define KEYBOARD_READ_EXTENDED 0x10
#define KEYBOARD_CHECK_EXTENDED 0x11
#define KEYBOARD_META_EXTENDED 0x12
enum MetaBitsE {
KEY_META_SHIFT_RIGHT = 0,
KEY_META_SHIFT_LEFT,
KEY_META_CONTROL,
KEY_META_ALT,
KEY_META_SCROLL_LOCKED,
KEY_META_NUM_LOCKED,
KEY_META_CAPS_LOCKED,
KEY_META_INSERT_LOCKED,
KEY_META_CONTROL_LEFT,
KEY_META_ALT_LEFT,
KEY_META_CONTROL_RIGHT,
KEY_META_ALT_RIGHT,
KEY_META_SCROLL_LOCK,
KEY_META_NUM_LOCK,
KEY_META_CAPS_LOCK,
KEY_META_SYSREQ
};
typedef struct VBEInfoS {
char vbeSignature[4]; // 'VESA' 4 byte signature
int16_t vbeVersion; // VBE version number
char *oemStringPtr; // Pointer to OEM string
uint32_t capabilities; // Capabilities of video card
uint16_t *videoModePtr; // Pointer to supported modes
uint16_t totalMemory; // Number of 64kb memory blocks
// added for VBE 2.0
uint16_t oemSoftwareRev; // OEM Software revision number
char *oemVendorNamePtr; // Pointer to Vendor Name string
char *oemProductNamePtr; // Pointer to Product Name string
char *oemProductRevPtr; // Pointer to Product Revision str
char reserved[222]; // Pad to 256 byte block size
char oemData[256]; // Scratch pad for OEM data
} __attribute__ ((packed)) VBEInfoT;
typedef struct VBEModeInfoS {
// Mandatory information for all VBE revisions:
uint16_t modeAttributes; // mode attributes
uint8_t winAAttributes; // window A attributes
uint8_t winBAttributes; // window B attributes
uint16_t winGranularity; // window granularity
uint16_t winSize; // window size
uint16_t winASegment; // window A start segment
uint16_t winBSegment; // window B start segment
uint32_t winFuncPtr; // pointer to window function
uint16_t bytesPerScanLine; // bytes per scan line
// Mandatory information for VBE 1.2 and above:
uint16_t xResolution; // horizontal resolution in pixels or chars
uint16_t yResolution; // vertical resolution in pixels or chars
uint8_t xCharSize; // character cell width in pixels
uint8_t yCharSize; // character cell height in pixels
uint8_t numberOfPlanes; // number of memory planes
uint8_t bitsPerPixel; // bits per pixel
uint8_t numberOfBanks; // number of banks
uint8_t memoryModel; // memory model type
uint8_t bankSize; // bank size in KB
uint8_t numberOfImagePages; // number of images
uint8_t reserved; // reserved for page function
// Direct Color fields (required for direct/6 and YUV/7 memory models)
uint8_t redMaskSize; // size of direct color red mask in bits
uint8_t redFieldPosition; // bit position of lsb of red mask
uint8_t greenMaskSize; // size of direct color green mask in bits
uint8_t greenFieldPosition; // bit position of lsb of green mask
uint8_t blueMaskSize; // size of direct color blue mask in bits
uint8_t blueFieldPosition; // bit position of lsb of blue mask
uint8_t rsvdMaskSize; // size of direct color reserved mask in bits
uint8_t rsvdFieldPosition; // bit position of lsb of reserved mask
uint8_t directColorModeInfo; // direct color mode attributes
// Mandatory information for VBE 2.0 and above:
uint32_t physBasePtr; // physical address for flat frame buffer
uint32_t offScreenMemOffset; // pointer to start of off screen memory
uint16_t offScreenMemSize; // amount of off screen memory in 1k units
char reservedBuf[206];
} __attribute__ ((packed)) VBEModeInfoT;
typedef struct PModeInterfaceS {
int16_t setWindow;
int16_t setDisplayStart;
int16_t setPalette;
int16_t ioInfo;
} __attribute__ ((packed)) PModeInterfaceT;
typedef struct VBESurfaceS {
uint32_t lfbLinearAddress;
uint16_t lfbSelector;
void *lfbNearPtr;
uint32_t lfbMemSize;
uint16_t xResolution;
uint16_t yResolution;
uint32_t bitsPerPixel;
uint16_t virtualXResolution;
uint32_t bytesPerPixel;
uint32_t screenBytes;
uint32_t screenDWords;
uint32_t centerX;
uint32_t centerY;
uint16_t numberOfOffscreens;
uint8_t vbeBoolean;
uint8_t vbeInitBoolean;
int32_t ioSegment;
uint32_t ioLinear;
uint32_t rMask;
uint32_t gMask;
uint32_t bMask;
uint32_t aMask;
uint8_t rShift;
uint8_t gShift;
uint8_t bShift;
uint8_t aShift;
uint8_t rPos;
uint8_t gPos;
uint8_t bPos;
uint8_t aPos;
} VBESurfaceT;
static VBESurfaceT _vbeSurface;
static VBEInfoT _vbeInfo;
static VBEModeInfoT _vbeModeInfo;
static PModeInterfaceT *_pmodeInterfacePtr;
static uint32_t *_yTable;
static void vbeCreatePalette(void);
static VBEInfoT *vbeGetInfo(void);
static VBEModeInfoT *vbeGetModeInfo(uint16_t vbeModeNumber);
static void *vbeGetPmodeInterface(void);
static uint8_t vbeIsDesiredMode(void);
static uint16_t vbeSelectModeNumber(uint16_t xRes, uint16_t yRes, uint8_t bpp);
static VBESurfaceT *vbeSetMode(uint16_t vbeModeNumber);
static uint16_t vbeSetScanlineLength(uint16_t pixelLength);
static void (*pmVBESetDisplayStart)(void);
void platformEventGet(EventT *event) {
int32_t x;
int32_t y;
int16_t dx;
int16_t dy;
int16_t h = videoDisplayHeightGet();
int16_t w = videoDisplayWidthGet();
int16_t ext = bioskey(KEYBOARD_CHECK_EXTENDED);
int16_t meta = bioskey(KEYBOARD_META_EXTENDED);
int16_t key = 0;
union REGS regs;
static int32_t lastX = 0;
static int32_t lastY = 0;
static int32_t lastButtons = 0;
event->buttons = lastButtons;
// Read mouse motion.
regs.x.ax = MOUSE_GETMOTION;
int86(MOUSE_INT, &regs, &regs);
dx = regs.x.cx; // Temporary assignment changes values to signed.
dy = regs.x.dx; // Don't skip this step. :-)
x = lastX + dx;
y = lastY + dy;
if (x < 0) x = 0;
if (x > w - 1) x = w - 1;
if (y < 0) y = 0;
if (y > h - 1) y = h - 1;
lastX = x;
lastY = y;
event->x = x;
event->y = y;
// Read mouse buttons.
regs.x.ax = MOUSE_STATUS;
int86(MOUSE_INT, &regs, &regs);
// Was the left button down?
if (event->buttons & BUTTON_LEFT) {
// Yes. Is it still down?
if ((regs.x.bx & MOUSE_LEFT_BUTTON) > 0) {
// Yes. Do nothing.
} else {
// No! Clear it and set UP event.
event->buttons &= ~BUTTON_LEFT;
event->flags |= EVENT_FLAG_LEFT_UP;
}
} else {
// No. Is it down now?
if ((regs.x.bx & MOUSE_LEFT_BUTTON) > 0) {
// Yes! Set bit and DOWN event.
event->buttons |= BUTTON_LEFT;
event->flags |= EVENT_FLAG_LEFT_DOWN;
} else {
// No. Do nothing.
}
}
// Was the right button down?
if (event->buttons & BUTTON_RIGHT) {
// Yes. Is it still down?
if ((regs.x.bx & MOUSE_RIGHT_BUTTON) > 0) {
// Yes. Do nothing.
} else {
// No! Clear it and set UP event.
event->buttons &= ~BUTTON_RIGHT;
event->flags |= EVENT_FLAG_RIGHT_UP;
}
} else {
// No. Is it down now?
if ((regs.x.bx & MOUSE_RIGHT_BUTTON) > 0) {
// Yes! Set bit and DOWN event.
event->buttons |= BUTTON_RIGHT;
event->flags |= EVENT_FLAG_RIGHT_DOWN;
} else {
// No. Do nothing.
}
}
// Read keyboard.
event->key = 0;
event->kbstat = 0;
if (ext > 0) {
key = bioskey(KEYBOARD_READ_EXTENDED);
// The value returned is a combination of the key's scan code in the high 8 bits
// and its ASCII code in the low 8 bits. For non-alphanumeric keys, such as the
// arrow keys, the low 8 bits are zeroed.
// Extended keys have the E0h prefix in the low 8 bits.
event->flags |= EVENT_FLAG_KEYPRESS;
if (LOW_BYTE(key) == 0xE0) {
//_extended = 1;
event->key = HIGH_BYTE(key);
} else {
//_extended = 0;
event->key = LOW_BYTE(key);
}
if ((meta & (1 << KEY_META_ALT)) + (meta & (1 << KEY_META_ALT_LEFT)) + (meta & (1 << KEY_META_ALT_RIGHT))) event->kbstat |= META_ALT;
if ((meta & (1 << KEY_META_CONTROL)) + (meta & (1 << KEY_META_CONTROL_LEFT)) + (meta & (1 << KEY_META_CONTROL_RIGHT))) event->kbstat |= META_CTRL;
if ((meta & (1 << KEY_META_SHIFT_LEFT)) + (meta & (1 << KEY_META_SHIFT_RIGHT))) event->kbstat |= META_SHIFT;
}
lastButtons = event->buttons;
}
void platformShutdown(void) {
__dpmi_regs r;
__dpmi_meminfo m;
surfaceShutdown();
if (_vbeSurface.vbeInitBoolean == 0) {
r.x.ax = 0x03; // make sure we're in 3h
__dpmi_int(0x10, &r); // for buggy vesa implementations
//return(1);
}
if (_yTable) free(_yTable);
// free mapping etc.
m.size = (_vbeInfo.totalMemory * 64 * 1024);
m.address = _vbeSurface.lfbLinearAddress;
__dpmi_unlock_linear_region(&m);
__dpmi_free_physical_address_mapping(&m);
__dpmi_free_ldt_descriptor(_vbeSurface.lfbSelector);
// get rid of PMI interface
if (_pmodeInterfacePtr) free(_pmodeInterfacePtr);
if (_vbeSurface.ioSegment) {
m.address = _vbeSurface.ioLinear;
__dpmi_free_physical_address_mapping(&m);
__dpmi_free_ldt_descriptor(_vbeSurface.ioSegment);
}
// return do DOS
r.x.ax = 0x03;
__dpmi_int(0x10, &r);
// deinit VBE surface
_vbeSurface.vbeInitBoolean = 0;
_vbeSurface.vbeBoolean = 0;
// dealloc mode list
free(_vbeInfo.videoModePtr);
}
uint8_t platformStartup(int16_t width, int16_t height, int16_t depth) {
uint16_t vbeModeNumber;
if (vbeGetInfo() == NULL) {
logWrite("No VESA BIOS Extensions found.\n");
platformShutdown();
return FAIL;
}
if (_vbeInfo.vbeVersion < 0x0200) {
logWrite("VBE Version 2.0 or better required.\n");
platformShutdown();
return FAIL;
}
vbeGetPmodeInterface();
if ((vbeModeNumber = vbeSelectModeNumber(width, height, depth)) == 0) {
logWrite("No appropriate video mode available.\n");
platformShutdown();
return FAIL;
}
if (vbeSetMode(vbeModeNumber) == NULL) {
platformShutdown();
return FAIL;
}
surfaceStartup(_vbeSurface.bitsPerPixel);
return SUCCESS;
}
static void vbeCreatePalette(void) {
uint8_t color = 0;
uint8_t red;
uint8_t green;
uint8_t blue;
// Create palette for 3:3:2 true color emulation
for (red = 4; red < 68; red += 8) {
for (green = 4; green < 68; green += 8) {
for (blue = 4; blue < 68; blue += 16) {
outportb(0x3C8, color);
outportb(0x3C9, red);
outportb(0x3C9, green);
outportb(0x3C9, blue);
color++;
}
}
}
}
static VBEInfoT *vbeGetInfo(void) {
uint16_t counter = 0;
uint16_t offset = 0;
uint16_t vbeMode = 0xFFFF;
uint16_t *vbeModeList = 0;
__dpmi_regs r;
// we want VBE 2.0+ info
memcpy(_vbeInfo.vbeSignature, "VBE2", 4);
// request info
r.x.ax = 0x4F00;
r.x.di = __tb & 0x0F;
r.x.es = (__tb >> 4) & 0xFFFF;
dosmemput(&_vbeInfo, sizeof(VBEInfoT), __tb);
__dpmi_int(0x10, &r);
if (r.x.ax != 0x004F) return NULL;
dosmemget(__tb, sizeof(VBEInfoT), &_vbeInfo);
if (strncmp(_vbeInfo.vbeSignature, "VESA", 4) != 0) return NULL; // VESA ?
// get the videomode list
do {
dosmemget(((((long)_vbeInfo.videoModePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.videoModePtr & 0xFFFF) + (counter * sizeof(short)), sizeof(short), &vbeMode);
counter++;
} while (vbeMode != 0xFFFF);
vbeModeList = malloc((counter + 1) * sizeof(short));
counter = 0;
do {
dosmemget(((((long)_vbeInfo.videoModePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.videoModePtr & 0xFFFF) + (counter * sizeof(short)), sizeof(short), &vbeModeList[counter]);
counter++;
} while (vbeModeList[counter - 1] != 0xFFFF);
_vbeInfo.videoModePtr = vbeModeList;
// get the OEM string
counter = 0;
do {
dosmemget(((((long)_vbeInfo.oemStringPtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemStringPtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter]);
counter++;
} while (_vbeInfo.oemData[counter - 1] != 0);
_vbeInfo.oemStringPtr = &_vbeInfo.oemData[0];
offset = counter;
if (_vbeInfo.vbeVersion >= 0x0200) {
// get the vendor name
counter = 0;
do {
dosmemget(((((long)_vbeInfo.oemVendorNamePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemVendorNamePtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter + offset]);
counter++;
} while (_vbeInfo.oemData[counter + offset - 1] != 0);
_vbeInfo.oemVendorNamePtr = &_vbeInfo.oemData[offset];
offset = offset + counter;
// get the product name
counter = 0;
do {
dosmemget(((((long)_vbeInfo.oemProductNamePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemProductNamePtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter + offset]);
counter++;
} while (_vbeInfo.oemData[counter + offset - 1] != 0);
_vbeInfo.oemProductNamePtr = &_vbeInfo.oemData[offset];
offset = offset + counter;
//get the product revision
counter = 0;
do {
dosmemget(((((long)_vbeInfo.oemProductRevPtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemProductRevPtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter + offset]);
counter++;
} while (_vbeInfo.oemData[counter + offset - 1] != 0);
_vbeInfo.oemProductRevPtr = &_vbeInfo.oemData[offset];
}
_vbeSurface.vbeBoolean = 1;
return(&_vbeInfo);
}
static VBEModeInfoT *vbeGetModeInfo(uint16_t vbeModeNumber) {
__dpmi_regs r;
if (_vbeSurface.vbeBoolean == 0) return NULL;
r.x.ax = 0x4F01;
r.x.cx = vbeModeNumber;
r.x.di = __tb & 0x0F;
r.x.es = (__tb >> 4) & 0xFFFF;
__dpmi_int(0x10, &r);
if (r.x.ax != 0x004F) return NULL;
dosmemget(__tb, sizeof(VBEModeInfoT), &_vbeModeInfo);
// Fake 3:3:2 true color for packed modes.
if (_vbeModeInfo.bitsPerPixel == 8) {
_vbeModeInfo.blueMaskSize = 2;
_vbeModeInfo.greenMaskSize = 3;
_vbeModeInfo.redMaskSize = 3;
}
if (_vbeModeInfo.bitsPerPixel == 16) {
// for buggy VBE implementations
_vbeModeInfo.bitsPerPixel = _vbeModeInfo.redMaskSize + _vbeModeInfo.greenMaskSize + _vbeModeInfo.blueMaskSize;
}
return(&_vbeModeInfo);
}
static void *vbeGetPmodeInterface(void) {
__dpmi_regs r;
__dpmi_meminfo m;
uint16_t *ptr;
// only available in VBE 2.0+
if (_vbeInfo.vbeVersion < 0x200) return NULL;
r.x.ax = 0x4F0A;
r.x.bx = 0;
__dpmi_int(0x10, &r);
if (r.x.ax != 0x004F) return NULL;
// copy interface
_pmodeInterfacePtr = (PModeInterfaceT *)malloc(r.x.cx);
dosmemget((r.x.es * 16) + r.x.di, r.x.cx, _pmodeInterfacePtr);
_go32_dpmi_lock_data(_pmodeInterfacePtr, r.x.cx);
// need memory-mapped IO?
if (_pmodeInterfacePtr->ioInfo) {
ptr = (uint16_t *)((char *)_pmodeInterfacePtr + _pmodeInterfacePtr->ioInfo);
// skip the port table...
while (*ptr != 0xFFFF)
ptr++;
ptr++;
// ...and get descriptor
if (*ptr != 0xFFFF) {
m.address = *((uint32_t *)ptr);
m.size = *(ptr + 2);
if (__dpmi_physical_address_mapping(&m) != 0) return NULL;
_vbeSurface.ioLinear = m.address;
__dpmi_lock_linear_region(&m);
_vbeSurface.ioSegment = __dpmi_allocate_ldt_descriptors(1);
if (_vbeSurface.ioSegment < 0) {
__dpmi_unlock_linear_region(&m);
__dpmi_free_physical_address_mapping(&m);
return NULL;
}
__dpmi_set_segment_base_address(_vbeSurface.ioSegment, _vbeSurface.ioLinear);
__dpmi_set_segment_limit(_vbeSurface.ioSegment, m.size - 1);
}
}
pmVBESetDisplayStart = (void *)((char *)_pmodeInterfacePtr + _pmodeInterfacePtr->setDisplayStart);
return pmVBESetDisplayStart;
}
static uint8_t vbeIsDesiredMode(void) {
// This is a custom filter to remove modes not supported by the calling application.
// Must be linear.
if (((_vbeModeInfo.modeAttributes) & (1<<7)) >> 7) {
// Packed or Direct Color mode.
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED || _vbeModeInfo.memoryModel == VBE_MM_DCOLOR) {
// We only handle these bit depths.
if ((_vbeModeInfo.bitsPerPixel == 8) || (_vbeModeInfo.bitsPerPixel == 16) || (_vbeModeInfo.bitsPerPixel == 32)) {
// Resolution minimum of 640x480.
if (_vbeModeInfo.xResolution >= 640 && _vbeModeInfo.yResolution >= 480) {
// Multiple of 8
if (DIVISIBLE_BY_EIGHT(_vbeModeInfo.xResolution) && DIVISIBLE_BY_EIGHT(_vbeModeInfo.yResolution)) {
// Valid mode!
return 1;
}
}
}
}
}
// Rejected!
return 0;
}
static uint16_t vbeSelectModeNumber(uint16_t xRes, uint16_t yRes, uint8_t bpp) {
uint16_t counter;
if (_vbeSurface.vbeBoolean == 0) return(0);
for (counter = 0; ; counter++) {
if (_vbeInfo.videoModePtr[counter] == 0xFFFF) return(0);
vbeGetModeInfo(_vbeInfo.videoModePtr[counter]);
if (vbeIsDesiredMode()) {
if (_vbeModeInfo.xResolution == xRes && _vbeModeInfo.yResolution == yRes && _vbeModeInfo.bitsPerPixel == bpp)
break;
}
}
return(_vbeInfo.videoModePtr[counter]);
}
static VBESurfaceT *vbeSetMode(uint16_t vbeModeNumber) {
__dpmi_regs r;
__dpmi_meminfo m;
uint32_t counter;
if (_vbeSurface.vbeBoolean == 0) return NULL;
if (_vbeSurface.vbeInitBoolean == 1) return NULL;
if (vbeGetModeInfo(vbeModeNumber) == 0) return NULL;
if (_yTable) free(_yTable);
if ((_yTable = malloc(4 * (_vbeModeInfo.yResolution + 1))) == 0) return NULL;
for (counter = 0; counter <= _vbeModeInfo.yResolution; counter++) {
_yTable[counter] = _vbeModeInfo.xResolution * counter;// * ((_vbeModeInfo.bitsPerPixel + 1) / 8);
}
// request frame buffer
r.x.ax = 0x4F02;
r.x.bx = (vbeModeNumber | 0x4000);
__dpmi_int(0x10, &r);
if (r.x.ax != 0x004F) return(0);
m.size = (_vbeInfo.totalMemory * 64 * 1024);
m.address = _vbeModeInfo.physBasePtr;
__dpmi_physical_address_mapping(&m);
__dpmi_lock_linear_region(&m);
_vbeSurface.lfbLinearAddress = m.address;
_vbeSurface.lfbSelector = __dpmi_allocate_ldt_descriptors(1);
__dpmi_set_segment_base_address(_vbeSurface.lfbSelector, _vbeSurface.lfbLinearAddress);
__dpmi_set_segment_limit(_vbeSurface.lfbSelector, (_vbeInfo.totalMemory * 64 * 1024) - 1);
_vbeSurface.lfbNearPtr = (void *)(_vbeSurface.lfbLinearAddress + __djgpp_conventional_base);
_vbeSurface.xResolution = _vbeModeInfo.xResolution;
_vbeSurface.yResolution = _vbeModeInfo.yResolution;
_vbeSurface.bitsPerPixel = _vbeModeInfo.bitsPerPixel;
_vbeSurface.virtualXResolution = _vbeModeInfo.xResolution;
_vbeSurface.bytesPerPixel = (_vbeModeInfo.bitsPerPixel + 1) / 8;
_vbeSurface.centerX = _vbeSurface.virtualXResolution / 2;
_vbeSurface.centerY = _vbeSurface.yResolution / 2;
_vbeSurface.numberOfOffscreens = vbeSetScanlineLength(_vbeModeInfo.xResolution) / _vbeModeInfo.yResolution;
_vbeSurface.vbeInitBoolean = 1;
_vbeSurface.screenBytes = (_vbeSurface.xResolution * _vbeSurface.yResolution * _vbeSurface.bytesPerPixel);
_vbeSurface.screenDWords = _vbeSurface.screenBytes / 4;
_vbeSurface.lfbMemSize = (_vbeSurface.xResolution * _vbeSurface.yResolution * _vbeSurface.bytesPerPixel) / 1024 + _vbeModeInfo.offScreenMemSize;
for (counter = 0; counter < (_vbeSurface.lfbMemSize * 1024); counter++) {
_farpokeb(_vbeSurface.lfbSelector, counter, 0x0); // clear Lfb
}
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED) {
vbeCreatePalette();
_vbeModeInfo.redFieldPosition = 5;
_vbeModeInfo.greenFieldPosition = 2;
_vbeModeInfo.blueFieldPosition = 0;
_vbeModeInfo.rsvdFieldPosition = 8;
_vbeModeInfo.redMaskSize = 3;
_vbeModeInfo.greenMaskSize = 3;
_vbeModeInfo.blueMaskSize = 2;
_vbeModeInfo.rsvdMaskSize = 0;
}
_vbeSurface.rMask = ((1UL << _vbeModeInfo.redMaskSize) - 1) << _vbeModeInfo.redFieldPosition;
_vbeSurface.gMask = ((1UL << _vbeModeInfo.greenMaskSize) - 1) << _vbeModeInfo.greenFieldPosition;
_vbeSurface.bMask = ((1UL << _vbeModeInfo.blueMaskSize) - 1) << _vbeModeInfo.blueFieldPosition;
_vbeSurface.aMask = ((1UL << _vbeModeInfo.rsvdMaskSize) - 1) << _vbeModeInfo.rsvdFieldPosition;
_vbeSurface.rShift = 8 - _vbeModeInfo.redMaskSize;
_vbeSurface.gShift = 8 - _vbeModeInfo.greenMaskSize;
_vbeSurface.bShift = 8 - _vbeModeInfo.blueMaskSize;
_vbeSurface.aShift = 8 - _vbeModeInfo.rsvdMaskSize;
_vbeSurface.rPos = _vbeModeInfo.redFieldPosition;
_vbeSurface.gPos = _vbeModeInfo.greenFieldPosition;
_vbeSurface.bPos = _vbeModeInfo.blueFieldPosition;
_vbeSurface.aPos = _vbeModeInfo.rsvdFieldPosition;
/*
logWrite("VESA Red Mask %u Shift %u Loss %u\n", _vbeSurface.rMask, _vbeSurface.rPos, _vbeSurface.rShift);
logWrite("VESA Green Mask %u Shift %u Loss %u\n", _vbeSurface.gMask, _vbeSurface.gPos, _vbeSurface.gShift);
logWrite("VESA Blue Mask %u Shift %u Loss %u\n", _vbeSurface.bMask, _vbeSurface.bPos, _vbeSurface.bShift);
logWrite("VESA Alpha Mask %u Shift %u Loss %u\n\n", _vbeSurface.aMask, _vbeSurface.aPos, _vbeSurface.aShift);
*/
return(&_vbeSurface);
}
static uint16_t vbeSetScanlineLength(uint16_t pixelLength) {
__dpmi_regs r;
if (_vbeSurface.vbeBoolean == 0) return(0);
r.x.ax = 0x4F06;
r.x.bx = 0x0000;
r.x.cx = pixelLength;
__dpmi_int(0x10, &r);
if (r.h.ah != 0) return(0);
if (r.x.cx != pixelLength) return(0);
_vbeSurface.virtualXResolution = pixelLength;
return(r.x.dx);
}
void videoBlit(int16_t targetX, int16_t targetY, SurfaceT *source) {
//***TODO*** Does not handle partial blits at this time.
(void)targetX;
(void)targetY;
_movedatal(_my_ds(), (int32_t)source->buffer.bits32, _vbeSurface.lfbSelector, 0x0, _vbeSurface.screenDWords);
}
uint16_t videoDisplayHeightGet(void) {
return _vbeSurface.yResolution;
}
uint16_t videoDisplayWidthGet(void) {
return _vbeSurface.xResolution;
}
void videoModesShow(void) {
int8_t counter;
// 0 1 2 3 4 5 6 7 8
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
//printf("VBE 2.0 driver v1.0 (c) 2021, Scott Duensing <scott@kangaroopunch.com>\n");
//printf("Based on: VBE 2.0 driver v1.0 (c) 1999, Tobias Koch <tobias.koch@gmail.com>\n\n");
if (vbeGetInfo() == NULL) {
logWrite("No VESA BIOS Extensions found.\n");
platformShutdown();
return;
}
logWrite(
"Video Memory - %d KB\n"
"VBE Version - %d.%d detected\n"
"OEM Specification - %s\n",
_vbeInfo.totalMemory * 64,
_vbeInfo.vbeVersion >> 8, _vbeInfo.vbeVersion & 0x00FF,
_vbeInfo.oemStringPtr);
if (_vbeInfo.vbeVersion >= 0x0200) {
logWrite(
"OEM Software Revision - %d.%d\n"
"OEM Vendor Name - %s\n"
"OEM Product Name - %s\n"
"OEM Product Revision - %s\n"
"Protected Mode Interface - %s\n\n",
_vbeInfo.oemSoftwareRev >> 8, _vbeInfo.oemSoftwareRev & 0x00FF,
_vbeInfo.oemVendorNamePtr,
_vbeInfo.oemProductNamePtr,
_vbeInfo.oemProductRevPtr,
vbeGetPmodeInterface() ? "Found" : "Missing");
} else {
logWrite("VESA BIOS Extension 2.0 or better required!\n");
platformShutdown();
return;
}
for (counter=0; ; counter++) {
if (_vbeInfo.videoModePtr[counter] == 0xFFFF) break;
vbeGetModeInfo(_vbeInfo.videoModePtr[counter]);
if (vbeIsDesiredMode()) {
logWrite("Mode %Xh - %4d x %4d x %2d - RGB %d:%d:%d - %s\n",
_vbeInfo.videoModePtr[counter],
_vbeModeInfo.xResolution,
_vbeModeInfo.yResolution,
_vbeModeInfo.bitsPerPixel,
_vbeModeInfo.redMaskSize,
_vbeModeInfo.greenMaskSize,
_vbeModeInfo.blueMaskSize,
((_vbeModeInfo.memoryModel / 2) - 2) ? "DCOLOR" : "PACKED");
}
}
platformShutdown();
}
#endif // BACKEND_DJGPP