DVX_GUI/dvx/platform/dvxPlatform.h

234 lines
11 KiB
C

// dvxPlatform.h -- Platform abstraction layer for DVX GUI
//
// All OS-specific and CPU-specific code is isolated behind this
// interface. To port DVX to a new platform, implement a new
// dvxPlatformXxx.c against this header.
//
// Currently two implementations exist:
// dvxPlatformDos.c -- DJGPP/DPMI: real VESA VBE, INT 33h mouse,
// INT 16h keyboard, rep movsd/stosl asm spans
// dvxPlatformLinux.c -- SDL2: software rendering to an SDL window,
// used for development and testing on Linux
//
// The abstraction covers five areas: video mode setup, framebuffer
// flushing, optimized memory spans, mouse input, and keyboard input.
// File system operations are minimal (just filename validation) because
// the C standard library handles most file I/O portably.
//
// Design rule: functions in this header must be stateless or manage their
// own internal state. They must not reference AppContextT or any layer
// above dvxTypes.h. This ensures the platform layer can be compiled and
// tested independently.
#ifndef DVX_PLATFORM_H
#define DVX_PLATFORM_H
#include "../dvxTypes.h"
// ============================================================
// Keyboard event
// ============================================================
//
// Separating ASCII value from scancode handles the DOS keyboard model
// where extended keys (arrows, F-keys) produce a zero ASCII byte followed
// by a scancode. The platform layer normalizes this into a single struct.
typedef struct {
int32_t ascii; // ASCII value, 0 for extended/function keys
int32_t scancode; // PC scan code (0x48=Up, 0x50=Down, etc.)
} PlatformKeyEventT;
// ============================================================
// System lifecycle
// ============================================================
// One-time platform initialisation. On DOS this installs signal handlers
// for clean shutdown on Ctrl+C/Ctrl+Break. On Linux this initializes SDL.
void platformInit(void);
// Cooperative yield -- give up the CPU timeslice when the event loop has
// nothing to do. On DOS this calls __dpmi_yield() to be friendly to
// multitaskers (Windows 3.x, OS/2, DESQview). On Linux this calls
// SDL_Delay(1) to avoid busy-spinning at 100% CPU.
void platformYield(void);
// ============================================================
// Video
// ============================================================
// Probe for a suitable video mode, enable it, map the framebuffer, and
// allocate the system RAM backbuffer. On DOS this involves VBE BIOS calls
// and DPMI physical memory mapping. On Linux this creates an SDL window
// and software surface. Fills in all DisplayT fields on success.
int32_t platformVideoInit(DisplayT *d, int32_t requestedW, int32_t requestedH, int32_t preferredBpp);
// Restore the previous video mode and free all video resources. On DOS
// this restores VGA text mode (mode 3) and frees the DPMI memory mapping.
void platformVideoShutdown(DisplayT *d);
// Enumerate LFB-capable graphics modes. The callback is invoked for each
// available mode. Used by videoInit() to find the best match for the
// requested resolution and depth. On Linux, this reports a fixed set of
// common resolutions since SDL doesn't enumerate modes the same way.
void platformVideoEnumModes(void (*cb)(int32_t w, int32_t h, int32_t bpp, void *userData), void *userData);
// Program the VGA/VESA DAC palette registers (8-bit mode only). pal
// points to RGB triplets (3 bytes per entry). On Linux this is a no-op
// since the SDL surface is always truecolor.
void platformVideoSetPalette(const uint8_t *pal, int32_t firstEntry, int32_t count);
// ============================================================
// Framebuffer flush
// ============================================================
// Copy a rectangle from the system RAM backbuffer (d->backBuf) to the
// display surface (d->lfb). On DOS this copies to real video memory via
// the LFB mapping -- the critical path where PCI bus write speed matters.
// On Linux this copies to the SDL surface, then SDL_UpdateRect is called.
// Each scanline is copied as a contiguous block; rep movsd on DOS gives
// near-optimal bus utilization for aligned 32-bit writes.
void platformFlushRect(const DisplayT *d, const RectT *r);
// ============================================================
// Optimised memory operations (span fill / copy)
// ============================================================
//
// These are the innermost loops of the renderer -- called once per
// scanline of every rectangle fill, blit, and text draw. On DOS they
// use inline assembly: rep stosl for fills (one instruction fills an
// entire scanline) and rep movsd for copies. On Linux they use memset/
// memcpy which the compiler can auto-vectorize.
//
// Three variants per operation (8/16/32 bpp) because the fill semantics
// differ by depth: 8-bit fills a byte per pixel, 16-bit fills a word
// (must handle odd counts), and 32-bit fills a dword. The copy variants
// differ only in the byte count computation (count * bytesPerPixel).
// drawInit() selects the right function pointers into BlitOpsT at startup.
void platformSpanFill8(uint8_t *dst, uint32_t color, int32_t count);
void platformSpanFill16(uint8_t *dst, uint32_t color, int32_t count);
void platformSpanFill32(uint8_t *dst, uint32_t color, int32_t count);
void platformSpanCopy8(uint8_t *dst, const uint8_t *src, int32_t count);
void platformSpanCopy16(uint8_t *dst, const uint8_t *src, int32_t count);
void platformSpanCopy32(uint8_t *dst, const uint8_t *src, int32_t count);
// ============================================================
// Input -- Mouse
// ============================================================
// Initialize the mouse driver and constrain movement to the screen bounds.
// On DOS this calls INT 33h functions to detect the mouse, set the X/Y
// range, and center the cursor. On Linux this initializes SDL mouse state.
void platformMouseInit(int32_t screenW, int32_t screenH);
// Poll the current mouse state. Buttons is a bitmask: bit 0 = left,
// bit 1 = right, bit 2 = middle. Polling (rather than event-driven
// callbacks) is the natural model for a cooperative event loop -- the
// main loop polls once per frame and compares with the previous state
// to detect press/release edges.
void platformMousePoll(int32_t *mx, int32_t *my, int32_t *buttons);
// Detect and activate mouse wheel support. Returns true if the mouse
// driver supports the CuteMouse Wheel API (INT 33h AX=0011h). This
// call also activates wheel reporting -- after it returns true, function
// 03h will return wheel delta in BH. Must be called after platformMouseInit.
bool platformMouseWheelInit(void);
// Read the accumulated wheel delta since the last call. Positive = scroll
// down, negative = scroll up. Returns 0 if no wheel movement or if wheel
// is not supported. The delta is cleared on each read (accumulated by the
// driver between polls).
int32_t platformMouseWheelPoll(void);
// Set the double-speed threshold in mickeys/second. When the mouse
// moves faster than this, cursor movement is doubled by the driver.
// A very high value (e.g. 10000) effectively disables acceleration.
void platformMouseSetAccel(int32_t threshold);
// Move the mouse cursor to an absolute screen position. Uses INT 33h
// function 04h on DOS, SDL_WarpMouseInWindow on Linux. Used to clamp
// the cursor to window edges during resize operations.
void platformMouseWarp(int32_t x, int32_t y);
// ============================================================
// Input -- Keyboard
// ============================================================
// Return the current modifier key state in BIOS shift-state format:
// bits 0-1 = either shift, bit 2 = ctrl, bit 3 = alt. On DOS this
// reads the BIOS data area at 0040:0017. On Linux this queries SDL
// modifier state and translates to the same bit format.
int32_t platformKeyboardGetModifiers(void);
// Non-blocking read of the next key from the keyboard buffer. Returns
// true if a key was available. On DOS this uses INT 16h AH=11h (check)
// + AH=10h (read). Extended keys (0xE0 prefix from enhanced keyboard)
// are normalized by zeroing the ASCII byte so the scancode identifies
// them unambiguously.
bool platformKeyboardRead(PlatformKeyEventT *evt);
// Translate an Alt+key scancode to its corresponding ASCII character.
// When Alt is held, DOS doesn't provide the ASCII value -- only the
// scancode. This function contains a lookup table mapping scancodes
// to their unshifted letter/digit. Returns 0 for scancodes that don't
// map to a printable character (e.g. Alt+F1).
char platformAltScanToChar(int32_t scancode);
// ============================================================
// System information
// ============================================================
// Maximum size of the formatted system information text
#define PLATFORM_SYSINFO_MAX 4096
// Gather hardware information (CPU, clock, memory, DOS/DPMI version,
// video, mouse, disk drives) and return as a pre-formatted text string.
// The display pointer provides the current video mode info. Returns a
// pointer to a static buffer valid for the lifetime of the process.
// On DOS this uses CPUID, RDTSC, DPMI, INT 21h, INT 33h, and VBE.
// On other platforms it returns whatever the OS can report.
const char *platformGetSystemInfo(const DisplayT *display);
// ============================================================
// File system
// ============================================================
// Validate a filename against platform-specific rules. On DOS this
// enforces 8.3 naming (no long filenames), checks for reserved device
// names (CON, PRN, etc.), and rejects characters illegal in FAT filenames.
// On Linux the rules are much more permissive (just no slashes or NUL).
// Returns NULL if the filename is valid, or a human-readable error string
// describing why it's invalid. Used by the file dialog's save-as validation.
const char *platformValidateFilename(const char *name);
// Query current system memory. Sets totalKb and freeKb to the total
// and free physical memory in kilobytes. Returns false if unavailable.
bool platformGetMemoryInfo(uint32_t *totalKb, uint32_t *freeKb);
// Create a directory and all parent directories (like mkdir -p).
// Returns 0 on success, -1 on failure. Existing directories are not
// an error.
int32_t platformMkdirRecursive(const char *path);
// Change the working directory, including drive letter on DOS. Standard
// chdir() does not switch drives under DJGPP; this wrapper calls setdisk()
// first when the path contains a drive prefix (e.g. "A:\DVX").
void platformChdir(const char *path);
// Free the backbuffer and palette without restoring text mode. Used
// when switching between graphics modes live.
void platformVideoFreeBuffers(DisplayT *d);
// Return a pointer to the last directory separator in path, or NULL if
// none is found. On DOS this checks both '/' and '\\' since DJGPP
// accepts either. On other platforms only '/' is recognised.
char *platformPathDirEnd(const char *path);
// Return the platform's native line ending string.
// "\r\n" on DOS/Windows, "\n" on Unix/Linux.
const char *platformLineEnding(void);
// Strip platform-specific line ending characters from a buffer in place.
// On DOS this removes '\r' from CR+LF pairs. Returns the new length.
int32_t platformStripLineEndings(char *buf, int32_t len);
#endif // DVX_PLATFORM_H