/* * 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 . * */ #ifdef BACKEND_DJGPP #include "os.h" #include #include #include #include #include #include #include #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, ®s, ®s); 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, ®s, ®s); // 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 \n"); //printf("Based on: VBE 2.0 driver v1.0 (c) 1999, Tobias Koch \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