Logging, surface, platform, and memory debugging added. Issues in DYN loading order.
This commit is contained in:
parent
9caff407f4
commit
3a1aedf14b
15 changed files with 2080 additions and 120 deletions
33
Makefile
33
Makefile
|
|
@ -32,8 +32,8 @@ DXE3GEN := dxe3gen
|
||||||
EXE2COFF := exe2coff
|
EXE2COFF := exe2coff
|
||||||
|
|
||||||
# Compiler Settings
|
# Compiler Settings
|
||||||
CFLAGS := -DPLATFORM_DOS -Wall -MD
|
override CFLAGS += -Wall -MD
|
||||||
LDFLAGS :=
|
override LDFLAGS +=
|
||||||
|
|
||||||
# Output Directories
|
# Output Directories
|
||||||
OBJ := obj
|
OBJ := obj
|
||||||
|
|
@ -47,30 +47,40 @@ FIN := font/in
|
||||||
# Include Paths
|
# Include Paths
|
||||||
INC := include 3rdparty 3rdparty/pthreads/include roo_e
|
INC := include 3rdparty 3rdparty/pthreads/include roo_e
|
||||||
|
|
||||||
|
# Use MEMWATCH?
|
||||||
|
ifneq (,$(findstring MEMWATCH,$(CFLAGS)))
|
||||||
|
MEMWATCH_SRC := 3rdparty/memwatch/memwatch.c
|
||||||
|
MEMWATCH_OBJ := $(OBJ)/$(MEMWATCH_SRC).o
|
||||||
|
INC += 3rdparty/memwatch
|
||||||
|
else
|
||||||
|
MEMWATCH_SRC :=
|
||||||
|
MEMWATCH_OBJ :=
|
||||||
|
endif
|
||||||
|
|
||||||
# Font Compiler Source and Target - NOTE: This is a Linux binary!
|
# Font Compiler Source and Target - NOTE: This is a Linux binary!
|
||||||
FONT_ELF := font
|
FONT_ELF := font
|
||||||
FONT_SRC := $(shell find font/src -name '*.c')
|
FONT_SRC := $(shell find font/src -name '*.c') $(MEMWATCH_SRC)
|
||||||
FONT_OBJ := $(FONT_SRC:%=$(OBJ)/%.o)
|
FONT_OBJ := $(FONT_SRC:%=$(OBJ)/%.o)
|
||||||
FONT_LIB := -lm
|
FONT_LIB := -lm
|
||||||
|
|
||||||
# Roo/E Source and Target
|
# Roo/E Source and Target
|
||||||
ROOE_EXE := roo_e.exe
|
ROOE_EXE := roo_e.exe
|
||||||
ROOE_SRC := $(shell find roo_e -name '*.c')
|
ROOE_SRC := $(shell find roo_e -name '*.c') $(MEMWATCH_SRC)
|
||||||
ROOE_OBJ := $(ROOE_SRC:%=$(OBJ)/%.o)
|
ROOE_OBJ := $(ROOE_SRC:%=$(OBJ)/%.o)
|
||||||
ROOE_LIB := 3rdparty/pthreads/lib/libgthreads.a -lgcc -lm
|
ROOE_LIB := 3rdparty/pthreads/lib/libgthreads.a -lgcc -lm
|
||||||
|
|
||||||
# MultiPlayer Game Client
|
# MultiPlayer Game Client
|
||||||
MPGC_EXE := kpsmpgc.app
|
MPGC_EXE := kpsmpgc.app
|
||||||
MPGC_SRC := $(shell find kpsmpgc -name '*.c')
|
MPGC_SRC := $(shell find kpsmpgc -name '*.c') $(MEMWATCH_SRC)
|
||||||
MPGC_OBJ := $(MPGC_SRC:%=$(OBJ)/%.o)
|
MPGC_OBJ := $(MPGC_SRC:%=$(OBJ)/%.o)
|
||||||
MPGC_LIB :=
|
MPGC_LIB :=
|
||||||
|
|
||||||
DYNS := kpsvideo stbimage
|
DYNS := kpssurf kpsplatf stbimage
|
||||||
FONTS := vga4x8 vga8x8 vga8x14 vga8x16
|
FONTS := vga4x8 vga8x8 vga8x14 vga8x16
|
||||||
|
|
||||||
# Wiring
|
# Wiring
|
||||||
INC_FLAGS := $(addprefix -I,$(INC))
|
override CFLAGS += $(INC_FLAGS)
|
||||||
CFLAGS += $(INC_FLAGS)
|
INC_FLAGS := $(addprefix -I,$(INC)) $(foreach DIR,$(DYNS),-Idyn/$(DIR))
|
||||||
APP_OBJS := $(ROOE_OBJ) $(MPGC_OBJ)
|
APP_OBJS := $(ROOE_OBJ) $(MPGC_OBJ)
|
||||||
FONTS := $(addprefix $(FNT)/,$(addsuffix .fnt,$(FONTS)))
|
FONTS := $(addprefix $(FNT)/,$(addsuffix .fnt,$(FONTS)))
|
||||||
FONT_PNGS := $(subst .fnt,.png,$(subst $(FNT),$(FIN),$(FONTS)))
|
FONT_PNGS := $(subst .fnt,.png,$(subst $(FNT),$(FIN),$(FONTS)))
|
||||||
|
|
@ -96,6 +106,7 @@ clean:
|
||||||
|
|
||||||
# Font Compiler Target
|
# Font Compiler Target
|
||||||
$(BIN)/$(FONT_ELF): $(FONT_OBJ) Makefile
|
$(BIN)/$(FONT_ELF): $(FONT_OBJ) Makefile
|
||||||
|
@echo "\n---------- $@"
|
||||||
mkdir -p $(dir $@) $(BIN)/fonts
|
mkdir -p $(dir $@) $(BIN)/fonts
|
||||||
$(CC) $(FONT_OBJ) -o $@ $(LDFLAGS) $(FONT_LIB)
|
$(CC) $(FONT_OBJ) -o $@ $(LDFLAGS) $(FONT_LIB)
|
||||||
|
|
||||||
|
|
@ -104,6 +115,7 @@ $(FONTS) &: $(FONT_PNGS) $(BIN)/$(FONT_ELF)
|
||||||
|
|
||||||
# Roo/E Target
|
# Roo/E Target
|
||||||
$(BIN)/$(ROOE_EXE): $(ROOE_OBJ) Makefile
|
$(BIN)/$(ROOE_EXE): $(ROOE_OBJ) Makefile
|
||||||
|
@echo "\n---------- $@"
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(CC) $(ROOE_OBJ) -o $@ $(LDFLAGS) $(ROOE_LIB)
|
$(CC) $(ROOE_OBJ) -o $@ $(LDFLAGS) $(ROOE_LIB)
|
||||||
# Embed the DPMI Server
|
# Embed the DPMI Server
|
||||||
|
|
@ -113,16 +125,17 @@ $(BIN)/$(ROOE_EXE): $(ROOE_OBJ) Makefile
|
||||||
|
|
||||||
# MPGC Target
|
# MPGC Target
|
||||||
$(APP)/$(MPGC_EXE): $(MPGC_OBJ) Makefile
|
$(APP)/$(MPGC_EXE): $(MPGC_OBJ) Makefile
|
||||||
|
@echo "\n---------- $@"
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(DXE3GEN) -o $@ $(MPGC_OBJ) -U $(LDFLAGS) $(MPGC_LIB)
|
$(DXE3GEN) -o $@ $(MPGC_OBJ) -U $(LDFLAGS) $(MPGC_LIB)
|
||||||
|
|
||||||
# DYN Targets - This is NOT how make should be used.
|
# DYN Targets - This is NOT how make should be used.
|
||||||
.PHONY: dyns
|
.PHONY: dyns
|
||||||
$(DYN_FILES): $(DYN_SOURCE) Makefile
|
$(DYN_FILES): $(DYN_SOURCE) Makefile
|
||||||
echo $(DYN_SOURCE)
|
@echo "\n---------- $@"
|
||||||
mkdir -p $(DYN) $(OBJ)/dyn/$(basename $(notdir $@)) $(SDK)/lib $(SDK)/include
|
mkdir -p $(DYN) $(OBJ)/dyn/$(basename $(notdir $@)) $(SDK)/lib $(SDK)/include
|
||||||
$(foreach CFILE,$(shell find dyn/$(basename $(notdir $@)) -name '*.c'),$(CC) $(CFLAGS) -o $(OBJ)/dyn/$(basename $(notdir $@))/$(subst dyn/$(basename $(notdir $@))/,,$(CFILE).o) -c $(CFILE) && ) true
|
$(foreach CFILE,$(shell find dyn/$(basename $(notdir $@)) -name '*.c'),$(CC) $(CFLAGS) -o $(OBJ)/dyn/$(basename $(notdir $@))/$(subst dyn/$(basename $(notdir $@))/,,$(CFILE).o) -c $(CFILE) && ) true
|
||||||
$(AR) rcs $(OBJ)/dyn/$(basename $(notdir $@)).a $(OBJ)/dyn/$(basename $(notdir $@))/*.o
|
$(AR) rcs $(OBJ)/dyn/$(basename $(notdir $@)).a $(OBJ)/dyn/$(basename $(notdir $@))/*.o $(MEMWATCH_OBJ)
|
||||||
$(DXE3GEN) -o $@ -Y $@.a --whole-archive -U $(OBJ)/dyn/$(basename $(notdir $@)).a $(LDFLAGS)
|
$(DXE3GEN) -o $@ -Y $@.a --whole-archive -U $(OBJ)/dyn/$(basename $(notdir $@)).a $(LDFLAGS)
|
||||||
mv $@.a $(SDK)/lib/.
|
mv $@.a $(SDK)/lib/.
|
||||||
if [ ! -z "$(shell find dyn/$(basename $(notdir $@)) -name '*.h')" ]; then cp $(shell find dyn/$(basename $(notdir $@)) -name '*.h') $(SDK)/include/.; fi
|
if [ ! -z "$(shell find dyn/$(basename $(notdir $@)) -name '*.h')" ]; then cp $(shell find dyn/$(basename $(notdir $@)) -name '*.h') $(SDK)/include/.; fi
|
||||||
|
|
|
||||||
10
build.sh
10
build.sh
|
|
@ -24,9 +24,15 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Delete things that get built for Linux and also need built for DOS.
|
||||||
|
rm -rf obj/3rdparty/memwatch
|
||||||
|
|
||||||
# Linux side first.
|
# Linux side first.
|
||||||
make linux
|
CFLAGS="-DMEMWATCH" make linux
|
||||||
|
|
||||||
|
# Delete things that get built for Linux and also need built for DOS.
|
||||||
|
rm -rf obj/3rdparty/memwatch
|
||||||
|
|
||||||
# Now do the DOS part.
|
# Now do the DOS part.
|
||||||
eval "$(../toolchains/toolchains.sh use x86 dos)"
|
eval "$(../toolchains/toolchains.sh use x86 dos)"
|
||||||
make dos
|
CFLAGS="-DMEMWATCH" make dos
|
||||||
|
|
|
||||||
785
dyn/kpsplatf/djgpp.c
Normal file
785
dyn/kpsplatf/djgpp.c
Normal file
|
|
@ -0,0 +1,785 @@
|
||||||
|
/*
|
||||||
|
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
||||||
|
* Copyright (C) 2026 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 __DJGPP__
|
||||||
|
|
||||||
|
|
||||||
|
#include "kpsplatf.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(PlatformEventT *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 <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 // __DJGPP__
|
||||||
71
dyn/kpsplatf/kpsplatf.h
Normal file
71
dyn/kpsplatf/kpsplatf.h
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
||||||
|
* Copyright (C) 2026 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef KPSPLATF_H
|
||||||
|
#define KPSPLATF_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "roo_e.h"
|
||||||
|
#include "kpssurf.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define EVENT_FLAG_KEYPRESS 1
|
||||||
|
#define EVENT_FLAG_LEFT_DOWN 2
|
||||||
|
#define EVENT_FLAG_LEFT_UP 4
|
||||||
|
#define EVENT_FLAG_RIGHT_DOWN 8
|
||||||
|
#define EVENT_FLAG_RIGHT_UP 16
|
||||||
|
|
||||||
|
#define BUTTON_LEFT 1
|
||||||
|
#define BUTTON_RIGHT 2
|
||||||
|
|
||||||
|
#define META_ALT 1
|
||||||
|
#define META_CTRL 2
|
||||||
|
#define META_SHIFT 4
|
||||||
|
|
||||||
|
#define KEY_ESC 27
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct PlatformEventS {
|
||||||
|
int32_t flags;
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
int32_t buttons;
|
||||||
|
int32_t key;
|
||||||
|
int32_t kbstat;
|
||||||
|
int32_t dtime;
|
||||||
|
} PlatformEventT;
|
||||||
|
|
||||||
|
|
||||||
|
void platformEventGet(PlatformEventT *event);
|
||||||
|
void platformShutdown(void);
|
||||||
|
uint8_t platformStartup(int16_t width, int16_t height, int16_t depth);
|
||||||
|
|
||||||
|
void videoBlit(int16_t targetX, int16_t targetY, SurfaceT *source);
|
||||||
|
uint16_t videoDisplayHeightGet(void);
|
||||||
|
uint16_t videoDisplayWidthGet(void);
|
||||||
|
void videoModesShow(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // KPSPLATF_H
|
||||||
230
dyn/kpsplatf/sdl2.c
Normal file
230
dyn/kpsplatf/sdl2.c
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
||||||
|
* Copyright (C) 2026 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 __linux__
|
||||||
|
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include "kpsplatf.h"
|
||||||
|
|
||||||
|
|
||||||
|
static SDL_Window *_window = NULL;
|
||||||
|
static SDL_Renderer *_renderer = NULL;
|
||||||
|
static SDL_Texture *_texture = NULL;
|
||||||
|
static uint16_t _width = 0;
|
||||||
|
static uint16_t _height = 0;
|
||||||
|
static uint8_t _windowScale = 1;
|
||||||
|
|
||||||
|
|
||||||
|
void platformEventGet(PlatformEventT *event) {
|
||||||
|
SDL_Event e;
|
||||||
|
static uint8_t ASCII = 0;
|
||||||
|
static uint8_t debounce = 0;
|
||||||
|
static uint8_t buttons = 0;
|
||||||
|
static int16_t x = 0;
|
||||||
|
static int16_t y = 0;
|
||||||
|
|
||||||
|
memset(event, 0, sizeof(EventT));
|
||||||
|
|
||||||
|
while (SDL_PollEvent(&e)) {
|
||||||
|
switch (e.type) {
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
x = e.motion.x;
|
||||||
|
y = e.motion.y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
if (e.button.button == SDL_BUTTON_LEFT) {
|
||||||
|
buttons &= ~BUTTON_LEFT;
|
||||||
|
event->flags |= EVENT_FLAG_LEFT_UP;
|
||||||
|
}
|
||||||
|
if (e.button.button == SDL_BUTTON_RIGHT) {
|
||||||
|
buttons &= ~BUTTON_RIGHT;
|
||||||
|
event->flags |= EVENT_FLAG_RIGHT_UP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
if (e.button.button == SDL_BUTTON_LEFT) {
|
||||||
|
buttons |= BUTTON_LEFT;
|
||||||
|
event->flags |= EVENT_FLAG_LEFT_DOWN;
|
||||||
|
}
|
||||||
|
if (e.button.button == SDL_BUTTON_RIGHT) {
|
||||||
|
buttons |= BUTTON_RIGHT;
|
||||||
|
event->flags |= EVENT_FLAG_RIGHT_DOWN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_KEYUP:
|
||||||
|
ASCII = 0;
|
||||||
|
debounce = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
if (debounce == 0) {
|
||||||
|
if (e.key.keysym.scancode != 0) {
|
||||||
|
// Not a meta key
|
||||||
|
debounce = 1;
|
||||||
|
ASCII = e.key.keysym.sym;
|
||||||
|
//if (e.key.keysym.scancode == SDL_SCANCODE_ESCAPE) ASCII = 27;
|
||||||
|
event->key = ASCII;
|
||||||
|
event->flags |= EVENT_FLAG_KEYPRESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event->x = x;
|
||||||
|
event->y = y;
|
||||||
|
event->buttons = buttons;
|
||||||
|
if ((SDL_GetModState() & KMOD_ALT) != 0) event->kbstat |= META_ALT;
|
||||||
|
if ((SDL_GetModState() & KMOD_CTRL) != 0) event->kbstat |= META_CTRL;
|
||||||
|
if ((SDL_GetModState() & KMOD_SHIFT) != 0) event->kbstat |= META_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void platformShutdown(void) {
|
||||||
|
|
||||||
|
SDL_ShowCursor(SDL_ENABLE);
|
||||||
|
|
||||||
|
surfaceShutdown();
|
||||||
|
|
||||||
|
if (_texture) {
|
||||||
|
SDL_DestroyTexture(_texture);
|
||||||
|
_texture = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_renderer) {
|
||||||
|
SDL_DestroyRenderer(_renderer);
|
||||||
|
_renderer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_window) {
|
||||||
|
SDL_DestroyWindow(_window);
|
||||||
|
_window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t platformStartup(int16_t width, int16_t height, int16_t depth) {
|
||||||
|
SDL_PixelFormatEnum pixelFormat = SDL_PIXELFORMAT_ARGB8888;
|
||||||
|
|
||||||
|
(void)depth;
|
||||||
|
|
||||||
|
/*
|
||||||
|
SDL_Surface *bits8 = SDL_CreateRGBSurfaceWithFormat(0, 320, 200, 8, SDL_PIXELFORMAT_RGB332);
|
||||||
|
SDL_Surface *bits16 = SDL_CreateRGBSurfaceWithFormat(0, 320, 200, 8, SDL_PIXELFORMAT_RGB565);
|
||||||
|
SDL_Surface *bits32 = SDL_CreateRGBSurfaceWithFormat(0, 320, 200, 8, SDL_PIXELFORMAT_ARGB8888);
|
||||||
|
|
||||||
|
logWrite("8 Red Mask %u Shift %u Loss %u\n", bits8->format->Rmask, bits8->format->Rshift, bits8->format->Rloss);
|
||||||
|
logWrite("8 Green Mask %u Shift %u Loss %u\n", bits8->format->Gmask, bits8->format->Gshift, bits8->format->Gloss);
|
||||||
|
logWrite("8 Blue Mask %u Shift %u Loss %u\n", bits8->format->Bmask, bits8->format->Bshift, bits8->format->Bloss);
|
||||||
|
logWrite("8 Alpha Mask %u Shift %u Loss %u\n\n", bits8->format->Amask, bits8->format->Ashift, bits8->format->Aloss);
|
||||||
|
|
||||||
|
logWrite("16 Red Mask %u Shift %u Loss %u\n", bits16->format->Rmask, bits16->format->Rshift, bits16->format->Rloss);
|
||||||
|
logWrite("16 Green Mask %u Shift %u Loss %u\n", bits16->format->Gmask, bits16->format->Gshift, bits16->format->Gloss);
|
||||||
|
logWrite("16 Blue Mask %u Shift %u Loss %u\n", bits16->format->Bmask, bits16->format->Bshift, bits16->format->Bloss);
|
||||||
|
logWrite("16 Alpha Mask %u Shift %u Loss %u\n\n", bits16->format->Amask, bits16->format->Ashift, bits16->format->Aloss);
|
||||||
|
|
||||||
|
logWrite("32 Red Mask %u Shift %u Loss %u\n", bits32->format->Rmask, bits32->format->Rshift, bits32->format->Rloss);
|
||||||
|
logWrite("32 Green Mask %u Shift %u Loss %u\n", bits32->format->Gmask, bits32->format->Gshift, bits32->format->Gloss);
|
||||||
|
logWrite("32 Blue Mask %u Shift %u Loss %u\n", bits32->format->Bmask, bits32->format->Bshift, bits32->format->Bloss);
|
||||||
|
logWrite("32 Alpha Mask %u Shift %u Loss %u\n\n", bits32->format->Amask, bits32->format->Ashift, bits32->format->Aloss);
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (depth) {
|
||||||
|
case 8:
|
||||||
|
pixelFormat = SDL_PIXELFORMAT_RGB332;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
pixelFormat = SDL_PIXELFORMAT_RGB565;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
pixelFormat = SDL_PIXELFORMAT_ARGB8888;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_EVERYTHING);
|
||||||
|
|
||||||
|
_windowScale = 1;
|
||||||
|
|
||||||
|
_window = SDL_CreateWindow("GUI Debug", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
|
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
_texture = SDL_CreateTexture(_renderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||||
|
|
||||||
|
SDL_RenderSetLogicalSize(_renderer, width, height);
|
||||||
|
SDL_SetWindowSize(_window, width * _windowScale, height * _windowScale);
|
||||||
|
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
|
||||||
|
surfaceStartup(depth);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void videoBlit(int16_t targetX, int16_t targetY, SurfaceT *source) {
|
||||||
|
void *pixels;
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
//***TODO*** Does not handle partial blits at this time.
|
||||||
|
(void)targetX;
|
||||||
|
(void)targetY;
|
||||||
|
|
||||||
|
SDL_LockTexture(_texture, NULL, &pixels, &temp);
|
||||||
|
memcpy(pixels, source->buffer.bits8, source->bytes);
|
||||||
|
SDL_UnlockTexture(_texture);
|
||||||
|
SDL_RenderCopy(_renderer, _texture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(_renderer);
|
||||||
|
|
||||||
|
// Throttle this to some sane frame rate.
|
||||||
|
SDL_Delay(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t videoDisplayHeightGet(void) {
|
||||||
|
return _height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t videoDisplayWidthGet(void) {
|
||||||
|
return _width;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void videoModesShow(void) {
|
||||||
|
// Nada
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
570
dyn/kpssurf/kpssurf.c
Normal file
570
dyn/kpssurf/kpssurf.c
Normal file
|
|
@ -0,0 +1,570 @@
|
||||||
|
/*
|
||||||
|
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
||||||
|
* Copyright (C) 2026 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "kpssurf.h"
|
||||||
|
|
||||||
|
|
||||||
|
SurfaceT *__surfaceActive = NULL;
|
||||||
|
uint8_t __surfaceBitsPerPixel = 0;
|
||||||
|
uint8_t __surfaceBytesPerPixel = 0;
|
||||||
|
SurfaceFormatT __surfaceFormat = { 0 };
|
||||||
|
|
||||||
|
|
||||||
|
void (*surfaceLineH)(int16_t x1, int16_t x2, int16_t y, ColorT c);
|
||||||
|
void (*surfaceLineV)(int16_t x, int16_t y1, int16_t y2, ColorT c);
|
||||||
|
ColorT (*surfacePixelGet)(SurfaceT *surface, int16_t x, int16_t y);
|
||||||
|
void (*surfacePixelSet)(uint16_t x, uint16_t y, ColorT color);
|
||||||
|
|
||||||
|
|
||||||
|
static void surfaceLineH8(int16_t x1, int16_t x2, int16_t y, ColorT c);
|
||||||
|
static void surfaceLineH16(int16_t x1, int16_t x2, int16_t y, ColorT c);
|
||||||
|
static void surfaceLineH32(int16_t x1, int16_t x2, int16_t y, ColorT c);
|
||||||
|
|
||||||
|
static void surfaceLineV8(int16_t x, int16_t y1, int16_t y2, ColorT c);
|
||||||
|
static void surfaceLineV16(int16_t x, int16_t y1, int16_t y2, ColorT c);
|
||||||
|
static void surfaceLineV32(int16_t x, int16_t y1, int16_t y2, ColorT c);
|
||||||
|
|
||||||
|
static ColorT surfacePixelGet8(SurfaceT *surface, int16_t x, int16_t y);
|
||||||
|
static ColorT surfacePixelGet16(SurfaceT *surface, int16_t x, int16_t y);
|
||||||
|
static ColorT surfacePixelGet32(SurfaceT *surface, int16_t x, int16_t y);
|
||||||
|
|
||||||
|
static void surfacePixelSet8(uint16_t x, uint16_t y, ColorT color);
|
||||||
|
static void surfacePixelSet16(uint16_t x, uint16_t y, ColorT color);
|
||||||
|
static void surfacePixelSet32(uint16_t x, uint16_t y, ColorT color);
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceBlit(int16_t targetX, int16_t targetY, int16_t offsetX, int16_t offsetY, int16_t width, int16_t height, SurfaceT *source) {
|
||||||
|
int16_t i;
|
||||||
|
int16_t x = 0;
|
||||||
|
int16_t y = 0;
|
||||||
|
size_t bytes;
|
||||||
|
size_t offsetTarget;
|
||||||
|
size_t offsetSource;
|
||||||
|
|
||||||
|
// Did they provide a valid width/height?
|
||||||
|
if (width <= 0 || width > source->width) width = source->width;
|
||||||
|
if (height <= 0 || height > source->height) height = source->height;
|
||||||
|
|
||||||
|
// Clip on top and left. x1 & y1 are pixel locations inside the source bitmap.
|
||||||
|
if (targetX < 0) x = -targetX;
|
||||||
|
if (targetY < 0) y = -targetY;
|
||||||
|
|
||||||
|
// Clip on right and bottom.
|
||||||
|
if (targetX + width - offsetX > __surfaceActive->width) width -= targetX + width - offsetX - __surfaceActive->width;
|
||||||
|
if (targetY + height - offsetY > __surfaceActive->height) height -= targetY + height - offsetY - __surfaceActive->height;
|
||||||
|
|
||||||
|
// Are we still on the screen?
|
||||||
|
if (x < 0 || y < 0 || width < x || height < y) return;
|
||||||
|
|
||||||
|
if (targetX == 0 && targetY == 0 && __surfaceActive->width == source->width && __surfaceActive->height == source->height) {
|
||||||
|
// Direct blit of entire surface.
|
||||||
|
memcpy(__surfaceActive->buffer.bits8, source->buffer.bits8, source->bytes);
|
||||||
|
} else {
|
||||||
|
// Blit into larger surface.
|
||||||
|
offsetTarget = (targetY + y) * __surfaceActive->scanline + (targetX + x) * __surfaceBytesPerPixel;
|
||||||
|
offsetSource = (y + offsetY) * source->scanline + (x + offsetX) * __surfaceBytesPerPixel;
|
||||||
|
bytes = (width - x) * __surfaceBytesPerPixel;
|
||||||
|
for (i=y; i<height; i++) {
|
||||||
|
memcpy(&__surfaceActive->buffer.bits8[offsetTarget], &source->buffer.bits8[offsetSource], bytes);
|
||||||
|
offsetTarget += __surfaceActive->scanline;
|
||||||
|
offsetSource += source->scanline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceBlitWithTransparency(int16_t targetX, int16_t targetY, SurfaceT *source, ColorT transparent) {
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
int16_t x1 = 0;
|
||||||
|
int16_t y1 = 0;
|
||||||
|
int16_t x2 = source->width;
|
||||||
|
int16_t y2 = source->height;
|
||||||
|
ColorT pixel;
|
||||||
|
|
||||||
|
// Clip on top and left. x1 & y1 are pixel locations inside the source bitmap. ox & oy offset those into screen coordinates.
|
||||||
|
if (targetX < 0) x1 = -targetX;
|
||||||
|
if (targetY < 0) y1 = -targetY;
|
||||||
|
|
||||||
|
// Clip on right and bottom.
|
||||||
|
if (targetX + x2 > __surfaceActive->width) x2 -= targetX + x2 - __surfaceActive->width;
|
||||||
|
if (targetY + y2 > __surfaceActive->height) y2 -= targetY + y2 - __surfaceActive->height;
|
||||||
|
|
||||||
|
// Are we still on the screen?
|
||||||
|
if (x1 < 0 || y1 < 0 || x2 < x1 || y2 < y1) return;
|
||||||
|
|
||||||
|
// Blit.
|
||||||
|
for (y=y1; y<y2; y++) {
|
||||||
|
for (x=x1; x<x2; x++) {
|
||||||
|
pixel = surfacePixelGet(source, x, y);
|
||||||
|
if (transparent != pixel) {
|
||||||
|
surfacePixelSet(targetX + x, targetY + y, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceClear(ColorT color) {
|
||||||
|
uint16_t x;
|
||||||
|
size_t offsetTarget;
|
||||||
|
|
||||||
|
// Draw the top line.
|
||||||
|
surfaceLineH(0, __surfaceActive->width - 1, 0, color);
|
||||||
|
|
||||||
|
// Copy it to the other lines.
|
||||||
|
offsetTarget = __surfaceActive->scanline;
|
||||||
|
for (x=1; x<__surfaceActive->height; x++) {
|
||||||
|
memcpy(&__surfaceActive->buffer.bits8[offsetTarget], &__surfaceActive->buffer.bits8[0], __surfaceActive->scanline);
|
||||||
|
offsetTarget += __surfaceActive->scanline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ColorT surfaceColorMake(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
return
|
||||||
|
(r >> __surfaceFormat.rLoss) << __surfaceFormat.rShift |
|
||||||
|
(g >> __surfaceFormat.gLoss) << __surfaceFormat.gShift |
|
||||||
|
(b >> __surfaceFormat.bLoss) << __surfaceFormat.bShift |
|
||||||
|
((255 >> __surfaceFormat.aLoss) << __surfaceFormat.aShift & __surfaceFormat.aMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SurfaceT *surfaceCreate(int16_t width, int16_t height) {
|
||||||
|
SurfaceT *surface = NULL;
|
||||||
|
|
||||||
|
NEW(SurfaceT, surface);
|
||||||
|
if (!surface) return NULL;
|
||||||
|
|
||||||
|
surface->width = width;
|
||||||
|
surface->height = height;
|
||||||
|
surface->scanline = width * __surfaceBytesPerPixel;
|
||||||
|
surface->bytes = surface->scanline * height;
|
||||||
|
|
||||||
|
surface->buffer.bits8 = malloc(surface->bytes);
|
||||||
|
if (!surface->buffer.bits8) {
|
||||||
|
free(surface);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceBox(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c) {
|
||||||
|
surfaceLineH(x1, x2, y1, c);
|
||||||
|
surfaceLineH(x1, x2, y2, c);
|
||||||
|
surfaceLineV(x1, y1, y2, c);
|
||||||
|
surfaceLineV(x2, y1, y2, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceBoxFilled(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c) {
|
||||||
|
int16_t i;
|
||||||
|
size_t offsetTarget;
|
||||||
|
size_t offsetSource;
|
||||||
|
uint16_t width;
|
||||||
|
|
||||||
|
if (x1 > x2) {
|
||||||
|
i = x1;
|
||||||
|
x1 = x2;
|
||||||
|
x2 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y1 > y2) {
|
||||||
|
i = y1;
|
||||||
|
y1 = y2;
|
||||||
|
y2 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
width = (x2 - x1 + 1) * __surfaceBytesPerPixel;
|
||||||
|
|
||||||
|
// Draw the top line.
|
||||||
|
surfaceLineH(x1, x2, y1, c);
|
||||||
|
|
||||||
|
// Copy it to the other lines.
|
||||||
|
offsetTarget = __surfaceActive->scanline * (y1 + 1) + (x1 * __surfaceBytesPerPixel);
|
||||||
|
offsetSource = __surfaceActive->scanline * y1 + (x1 * __surfaceBytesPerPixel);
|
||||||
|
for (i=y1 + 1; i<=y2; i++) {
|
||||||
|
memcpy(&__surfaceActive->buffer.bits8[offsetTarget], &__surfaceActive->buffer.bits8[offsetSource], width);
|
||||||
|
offsetTarget += __surfaceActive->scanline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceBoxHighlight(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT highlight, ColorT shadow) {
|
||||||
|
surfaceLineH(x1, x2, y1, highlight);
|
||||||
|
surfaceLineV(x1, y1, y2, highlight);
|
||||||
|
surfaceLineH(x1, x2, y2, shadow);
|
||||||
|
surfaceLineV(x2, y1, y2, shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceDestroy(SurfaceT **surface) {
|
||||||
|
SurfaceT *s = *surface;
|
||||||
|
DEL(s->buffer.bits8);
|
||||||
|
DEL(s);
|
||||||
|
*surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SurfaceT *surfaceGet(void) {
|
||||||
|
return __surfaceActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int16_t surfaceHeightGet(SurfaceT *surface) {
|
||||||
|
return surface->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) {
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
int16_t dx;
|
||||||
|
int16_t dy;
|
||||||
|
int16_t incX;
|
||||||
|
int16_t incY;
|
||||||
|
int16_t balance;
|
||||||
|
|
||||||
|
if (x2 >= x1) {
|
||||||
|
dx = x2 - x1;
|
||||||
|
incX = 1;
|
||||||
|
} else {
|
||||||
|
dx = x1 - x2;
|
||||||
|
incX = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y2 >= y1) {
|
||||||
|
dy = y2 - y1;
|
||||||
|
incY = 1;
|
||||||
|
} else {
|
||||||
|
dy = y1 - y2;
|
||||||
|
incY = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = x1;
|
||||||
|
y = y1;
|
||||||
|
|
||||||
|
if (dx >= dy) {
|
||||||
|
dy <<= 1;
|
||||||
|
balance = dy - dx;
|
||||||
|
dx <<= 1;
|
||||||
|
while (x != x2) {
|
||||||
|
surfacePixelSet(x, y, color);
|
||||||
|
if (balance >= 0) {
|
||||||
|
y += incY;
|
||||||
|
balance -= dx;
|
||||||
|
}
|
||||||
|
balance += dy;
|
||||||
|
x += incX;
|
||||||
|
}
|
||||||
|
surfacePixelSet(x, y, color);
|
||||||
|
} else {
|
||||||
|
dx <<= 1;
|
||||||
|
balance = dx - dy;
|
||||||
|
dy <<= 1;
|
||||||
|
while (y != y2) {
|
||||||
|
surfacePixelSet(x, y, color);
|
||||||
|
if (balance >= 0) {
|
||||||
|
x += incX;
|
||||||
|
balance -= dy;
|
||||||
|
}
|
||||||
|
balance += dx;
|
||||||
|
y += incY;
|
||||||
|
}
|
||||||
|
surfacePixelSet(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfaceLineH8(int16_t x1, int16_t x2, int16_t y, ColorT c) {
|
||||||
|
int16_t i;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (x1 > x2) {
|
||||||
|
i = x2;
|
||||||
|
x2 = x1;
|
||||||
|
x1 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = y * __surfaceActive->width + x1;
|
||||||
|
for (i=x1; i<=x2; i++) __surfaceActive->buffer.bits8[offset++] = (uint8_t)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfaceLineH16(int16_t x1, int16_t x2, int16_t y, ColorT c) {
|
||||||
|
int16_t i;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (x1 > x2) {
|
||||||
|
i = x2;
|
||||||
|
x2 = x1;
|
||||||
|
x1 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = y * __surfaceActive->width + x1;
|
||||||
|
for (i=x1; i<=x2; i++) __surfaceActive->buffer.bits16[offset++] = (uint16_t)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfaceLineH32(int16_t x1, int16_t x2, int16_t y, ColorT c) {
|
||||||
|
int16_t i;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (x1 > x2) {
|
||||||
|
i = x2;
|
||||||
|
x2 = x1;
|
||||||
|
x1 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = y * __surfaceActive->width + x1;
|
||||||
|
for (i=x1; i<=x2; i++) __surfaceActive->buffer.bits32[offset++] = (uint32_t)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfaceLineV8(int16_t x, int16_t y1, int16_t y2, ColorT c) {
|
||||||
|
int16_t i;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (y1 > y2) {
|
||||||
|
i = y2;
|
||||||
|
y2 = y1;
|
||||||
|
y1 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = y1 * __surfaceActive->width + x;
|
||||||
|
for (i=y1; i<=y2; i++) {
|
||||||
|
__surfaceActive->buffer.bits8[offset] = (uint8_t)c;
|
||||||
|
offset += __surfaceActive->width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfaceLineV16(int16_t x, int16_t y1, int16_t y2, ColorT c) {
|
||||||
|
int16_t i;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (y1 > y2) {
|
||||||
|
i = y2;
|
||||||
|
y2 = y1;
|
||||||
|
y1 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = y1 * __surfaceActive->width + x;
|
||||||
|
for (i=y1; i<=y2; i++) {
|
||||||
|
__surfaceActive->buffer.bits16[offset] = (uint16_t)c;
|
||||||
|
offset += __surfaceActive->width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfaceLineV32(int16_t x, int16_t y1, int16_t y2, ColorT c) {
|
||||||
|
int16_t i;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (y1 > y2) {
|
||||||
|
i = y2;
|
||||||
|
y2 = y1;
|
||||||
|
y1 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = y1 * __surfaceActive->width + x;
|
||||||
|
for (i=y1; i<=y2; i++) {
|
||||||
|
__surfaceActive->buffer.bits32[offset] = (uint32_t)c;
|
||||||
|
offset += __surfaceActive->width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SurfaceT *surfaceLoad(char *filename) {
|
||||||
|
char ext[5] = { 0 };
|
||||||
|
char *name = NULL;
|
||||||
|
FILE *in = NULL;
|
||||||
|
SurfaceT *i = NULL;
|
||||||
|
|
||||||
|
sprintf(ext, "S%d", __surfaceBitsPerPixel);
|
||||||
|
name = utilFileExtensionChange(filename, ext);
|
||||||
|
|
||||||
|
if (!utilFileExists(name)) {
|
||||||
|
in = fopen(name, "rb");
|
||||||
|
if (in) {
|
||||||
|
NEW(SurfaceT, i);
|
||||||
|
if (!i) return NULL;
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||||
|
fread(&i->width, sizeof(uint16_t), 1, in);
|
||||||
|
fread(&i->height, sizeof(uint16_t), 1, in);
|
||||||
|
fread(&i->scanline, sizeof(size_t), 1, in);
|
||||||
|
fread(&i->bytes, sizeof(size_t), 1, in);
|
||||||
|
i->buffer.bits8 = (uint8_t *)malloc(i->bytes);
|
||||||
|
fread(i->buffer.bits8, i->bytes, 1, in);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
fclose(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEL(name);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ColorT surfacePixelGet8(SurfaceT *surface, int16_t x, int16_t y) {
|
||||||
|
return surface->buffer.bits8[y * surface->width + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ColorT surfacePixelGet16(SurfaceT *surface, int16_t x, int16_t y) {
|
||||||
|
return surface->buffer.bits16[y * surface->width + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ColorT surfacePixelGet32(SurfaceT *surface, int16_t x, int16_t y) {
|
||||||
|
return surface->buffer.bits32[y * surface->width + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfacePixelSet8(uint16_t x, uint16_t y, ColorT color) {
|
||||||
|
__surfaceActive->buffer.bits8[y * __surfaceActive->width + x] = (uint8_t)color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfacePixelSet16(uint16_t x, uint16_t y, ColorT color) {
|
||||||
|
__surfaceActive->buffer.bits16[y * __surfaceActive->width + x] = (uint16_t)color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void surfacePixelSet32(uint16_t x, uint16_t y, ColorT color) {
|
||||||
|
__surfaceActive->buffer.bits32[y * __surfaceActive->width + x] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceSave(SurfaceT *surface, char *filename) {
|
||||||
|
char ext[5] = { 0 };
|
||||||
|
char *name = NULL;
|
||||||
|
FILE *out = NULL;
|
||||||
|
|
||||||
|
sprintf(ext, "S%d", __surfaceBitsPerPixel);
|
||||||
|
name = utilFileExtensionChange(filename, ext);
|
||||||
|
|
||||||
|
out = fopen(name, "wb");
|
||||||
|
if (out) {
|
||||||
|
fwrite(&surface->width, sizeof(uint16_t), 1, out);
|
||||||
|
fwrite(&surface->height, sizeof(uint16_t), 1, out);
|
||||||
|
fwrite(&surface->scanline, sizeof(size_t), 1, out);
|
||||||
|
fwrite(&surface->bytes, sizeof(size_t), 1, out);
|
||||||
|
fwrite(surface->buffer.bits8, surface->bytes, 1, out);
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEL(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceSet(SurfaceT *surface) {
|
||||||
|
__surfaceActive = surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceShutdown(void) {
|
||||||
|
// Nada
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceStartup(uint8_t bits) {
|
||||||
|
uint8_t redMaskSize;
|
||||||
|
uint8_t greenMaskSize;
|
||||||
|
uint8_t blueMaskSize;
|
||||||
|
uint8_t alphaMaskSize;
|
||||||
|
|
||||||
|
__surfaceBitsPerPixel = bits;
|
||||||
|
__surfaceBytesPerPixel = bits >> 3;
|
||||||
|
|
||||||
|
switch (bits) {
|
||||||
|
case 8:
|
||||||
|
// xxx 3:3:2
|
||||||
|
alphaMaskSize = 0;
|
||||||
|
redMaskSize = 3;
|
||||||
|
greenMaskSize = 3;
|
||||||
|
blueMaskSize = 2;
|
||||||
|
surfaceLineH = surfaceLineH8;
|
||||||
|
surfaceLineV = surfaceLineV8;
|
||||||
|
surfacePixelSet = surfacePixelSet8;
|
||||||
|
surfacePixelGet = surfacePixelGet8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
// xx 5:6:5
|
||||||
|
alphaMaskSize = 0;
|
||||||
|
redMaskSize = 5;
|
||||||
|
greenMaskSize = 6;
|
||||||
|
blueMaskSize = 5;
|
||||||
|
surfaceLineH = surfaceLineH16;
|
||||||
|
surfaceLineV = surfaceLineV16;
|
||||||
|
surfacePixelSet = surfacePixelSet16;
|
||||||
|
surfacePixelGet = surfacePixelGet16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// x 8:8:8
|
||||||
|
alphaMaskSize = 8;
|
||||||
|
redMaskSize = 8;
|
||||||
|
greenMaskSize = 8;
|
||||||
|
blueMaskSize = 8;
|
||||||
|
surfaceLineH = surfaceLineH32;
|
||||||
|
surfaceLineV = surfaceLineV32;
|
||||||
|
surfacePixelSet = surfacePixelSet32;
|
||||||
|
surfacePixelGet = surfacePixelGet32;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
__surfaceFormat.bShift = 0;
|
||||||
|
__surfaceFormat.gShift = __surfaceFormat.bShift + blueMaskSize;
|
||||||
|
__surfaceFormat.rShift = __surfaceFormat.gShift + greenMaskSize;
|
||||||
|
__surfaceFormat.aShift = __surfaceFormat.rShift + redMaskSize;
|
||||||
|
|
||||||
|
__surfaceFormat.rMask = ((1UL << redMaskSize) - 1) << __surfaceFormat.rShift;
|
||||||
|
__surfaceFormat.gMask = ((1UL << greenMaskSize) - 1) << __surfaceFormat.gShift;
|
||||||
|
__surfaceFormat.bMask = ((1UL << blueMaskSize) - 1) << __surfaceFormat.bShift;
|
||||||
|
__surfaceFormat.aMask = ((1UL << alphaMaskSize) - 1) << __surfaceFormat.aShift;
|
||||||
|
|
||||||
|
__surfaceFormat.rLoss = 8 - redMaskSize;
|
||||||
|
__surfaceFormat.gLoss = 8 - greenMaskSize;
|
||||||
|
__surfaceFormat.bLoss = 8 - blueMaskSize;
|
||||||
|
__surfaceFormat.aLoss = 8 - alphaMaskSize;
|
||||||
|
|
||||||
|
/*
|
||||||
|
logWrite("Surface Red Mask %u Shift %u Loss %u\n", __surfaceFormat.rMask, __surfaceFormat.rShift, __surfaceFormat.rLoss);
|
||||||
|
logWrite("Surface Green Mask %u Shift %u Loss %u\n", __surfaceFormat.gMask, __surfaceFormat.gShift, __surfaceFormat.gLoss);
|
||||||
|
logWrite("Surface Blue Mask %u Shift %u Loss %u\n", __surfaceFormat.bMask, __surfaceFormat.bShift, __surfaceFormat.bLoss);
|
||||||
|
logWrite("Surface Alpha Mask %u Shift %u Loss %u\n\n", __surfaceFormat.aMask, __surfaceFormat.aShift, __surfaceFormat.aLoss);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int16_t surfaceWidthGet(SurfaceT *surface) {
|
||||||
|
return surface->width;
|
||||||
|
}
|
||||||
95
dyn/kpssurf/kpssurf.h
Normal file
95
dyn/kpssurf/kpssurf.h
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
||||||
|
* Copyright (C) 2026 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef KPSSURF_H
|
||||||
|
#define KPSSURF_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "roo_e.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint32_t ColorT;
|
||||||
|
|
||||||
|
typedef struct SurfaceS {
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
size_t scanline;
|
||||||
|
size_t bytes;
|
||||||
|
union {
|
||||||
|
uint8_t *bits8;
|
||||||
|
uint16_t *bits16;
|
||||||
|
uint32_t *bits32;
|
||||||
|
} buffer;
|
||||||
|
} SurfaceT;
|
||||||
|
|
||||||
|
typedef struct SurfaceFormatS {
|
||||||
|
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 rLoss;
|
||||||
|
uint8_t gLoss;
|
||||||
|
uint8_t bLoss;
|
||||||
|
uint8_t aLoss;
|
||||||
|
} SurfaceFormatT;
|
||||||
|
|
||||||
|
|
||||||
|
extern SurfaceT *__surfaceActive;
|
||||||
|
extern uint8_t __surfaceBitsPerPixel;
|
||||||
|
extern uint8_t __surfaceBytesPerPixel;
|
||||||
|
extern SurfaceFormatT __surfaceFormat;
|
||||||
|
|
||||||
|
|
||||||
|
extern void (*surfaceLineH)(int16_t x1, int16_t x2, int16_t y, ColorT c);
|
||||||
|
extern void (*surfaceLineV)(int16_t x, int16_t y1, int16_t y2, ColorT c);
|
||||||
|
extern ColorT (*surfacePixelGet)(SurfaceT *surface, int16_t x, int16_t y);
|
||||||
|
extern void (*surfacePixelSet)(uint16_t x, uint16_t y, ColorT color);
|
||||||
|
|
||||||
|
|
||||||
|
void surfaceBlit(int16_t targetX1, int16_t targetY1, int16_t offsetX, int16_t offsetY, int16_t width, int16_t height, SurfaceT *source);
|
||||||
|
void surfaceBlitWithTransparency(int16_t targetX, int16_t targetY, SurfaceT *source, ColorT transparent);
|
||||||
|
void surfaceClear(ColorT color);
|
||||||
|
ColorT surfaceColorMake(uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
SurfaceT *surfaceCreate(int16_t width, int16_t height);
|
||||||
|
void surfaceBox(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c);
|
||||||
|
void surfaceBoxFilled(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c);
|
||||||
|
void surfaceBoxHighlight(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT highlight, ColorT shadow);
|
||||||
|
void surfaceDestroy(SurfaceT **surface);
|
||||||
|
SurfaceT *surfaceGet(void);
|
||||||
|
int16_t surfaceHeightGet(SurfaceT *surface);
|
||||||
|
void surfaceLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color);
|
||||||
|
SurfaceT *surfaceLoad(char *filename);
|
||||||
|
void surfaceSave(SurfaceT *surface, char *filename);
|
||||||
|
void surfaceSet(SurfaceT *surface);
|
||||||
|
void surfaceShutdown(void);
|
||||||
|
void surfaceStartup(uint8_t bits);
|
||||||
|
int16_t surfaceWidthGet(SurfaceT *surface);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // KPSSURF_H
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
|
||||||
* Copyright (C) 2026 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "roo_e.h"
|
|
||||||
#include "kpsvideo.h"
|
|
||||||
|
|
||||||
|
|
||||||
int dynStart(void) {
|
|
||||||
printf("kpsvideo starting!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int dynStop(void) {
|
|
||||||
printf("kpsvideo stopping!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
/* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
|
||||||
* Copyright (C) 2026 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef KPSVIDEO_H
|
|
||||||
#define KPSVIDEO_H
|
|
||||||
|
|
||||||
#endif // KPSVIDEO_H
|
|
||||||
3
env.sh
3
env.sh
|
|
@ -25,4 +25,5 @@
|
||||||
|
|
||||||
|
|
||||||
eval "$(../toolchains/toolchains.sh use x86 dos)"
|
eval "$(../toolchains/toolchains.sh use x86 dos)"
|
||||||
export C_INCLUDE_PATH=${HOME}/code/toolchains/x-tools/djgpp/i586-pc-msdosdjgpp/sys-include:roo_e
|
export CFLAGS="-DMEMWATCH"
|
||||||
|
export C_INCLUDE_PATH="${HOME}/code/toolchains/x-tools/djgpp/i586-pc-msdosdjgpp/sys-include:roo_e"
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef PLATFORM_LINUX
|
#ifdef MEMWATCH
|
||||||
#define MEMWATCH
|
|
||||||
#include "memwatch/memwatch.h"
|
#include "memwatch/memwatch.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -90,7 +89,6 @@ int main(int argc, char *argv[]) {
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
// Run this in DOS from the BIN folder.
|
|
||||||
makeFont("../font/in/vga4x8.png", "fonts/vga4x8.fnt", 4, 8, 16, 256);
|
makeFont("../font/in/vga4x8.png", "fonts/vga4x8.fnt", 4, 8, 16, 256);
|
||||||
makeFont("../font/in/vga8x8.png", "fonts/vga8x8.fnt", 8, 8, 16, 256);
|
makeFont("../font/in/vga8x8.png", "fonts/vga8x8.fnt", 8, 8, 16, 256);
|
||||||
makeFont("../font/in/vga8x14.png", "fonts/vga8x14.fnt", 8, 14, 16, 256);
|
makeFont("../font/in/vga8x14.png", "fonts/vga8x14.fnt", 8, 14, 16, 256);
|
||||||
|
|
|
||||||
220
roo_e/main.c
220
roo_e/main.c
|
|
@ -27,12 +27,21 @@
|
||||||
|
|
||||||
|
|
||||||
static RooAppThreadT **_appThreadList = NULL; // NOLINT
|
static RooAppThreadT **_appThreadList = NULL; // NOLINT
|
||||||
|
static FILE *_memoryLog = NULL; // NOLINT
|
||||||
|
static FILE *_log = NULL; // NOLINT
|
||||||
|
static uint8_t _ourHandle = 0; // NOLINT
|
||||||
|
static char *_logBuffer = NULL; // NOLINT
|
||||||
|
static uint16_t _logBufferSize = 0; // NOLINT
|
||||||
|
|
||||||
|
|
||||||
static void *rooStartAppThread(void *arg);
|
static void *rooStartAppThread(void *arg);
|
||||||
|
|
||||||
|
|
||||||
#ifdef PLATFORM_DOS
|
#ifdef MEMWATCH
|
||||||
|
void mwLogW(FILE *p);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __DJGPP__
|
||||||
#include <sys/dxe.h>
|
#include <sys/dxe.h>
|
||||||
void *dxeResolver(const char *symbol);
|
void *dxeResolver(const char *symbol);
|
||||||
static int lastResort(void);
|
static int lastResort(void);
|
||||||
|
|
@ -53,15 +62,58 @@ struct __emutls_object // NOLINT
|
||||||
void *__emutls_get_address(struct __emutls_object *); // NOLINT
|
void *__emutls_get_address(struct __emutls_object *); // NOLINT
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
DXE_EXPORT_TABLE(exports)
|
DXE_EXPORT_TABLE(exports)
|
||||||
|
// bios
|
||||||
|
DXE_EXPORT(bioskey)
|
||||||
|
// ctype
|
||||||
|
DXE_EXPORT(toupper)
|
||||||
|
// dos
|
||||||
|
DXE_EXPORT(int86)
|
||||||
|
// dpmi
|
||||||
|
DXE_EXPORT(__dpmi_allocate_ldt_descriptors)
|
||||||
|
DXE_EXPORT(__dpmi_free_ldt_descriptor)
|
||||||
|
DXE_EXPORT(__dpmi_free_physical_address_mapping)
|
||||||
|
DXE_EXPORT(__dpmi_int)
|
||||||
|
DXE_EXPORT(__dpmi_lock_linear_region)
|
||||||
|
DXE_EXPORT(__dpmi_physical_address_mapping)
|
||||||
|
DXE_EXPORT(__dpmi_set_segment_base_address)
|
||||||
|
DXE_EXPORT(__dpmi_set_segment_limit)
|
||||||
|
DXE_EXPORT(__dpmi_unlock_linear_region)
|
||||||
|
DXE_EXPORT(_go32_dpmi_lock_data)
|
||||||
// dxe
|
// dxe
|
||||||
DXE_EXPORT(dlclose)
|
DXE_EXPORT(dlclose)
|
||||||
DXE_EXPORT(dlopen)
|
DXE_EXPORT(dlopen)
|
||||||
DXE_EXPORT(dlregsym)
|
DXE_EXPORT(dlregsym)
|
||||||
DXE_EXPORT(dlstatbind)
|
DXE_EXPORT(dlstatbind)
|
||||||
DXE_EXPORT(dlstatunbind)
|
DXE_EXPORT(dlstatunbind)
|
||||||
|
// farptr
|
||||||
|
DXE_EXPORT(_farpokeb)
|
||||||
|
// go32
|
||||||
|
DXE_EXPORT(_go32_info_block)
|
||||||
// math
|
// math
|
||||||
DXE_EXPORT(ldexp)
|
DXE_EXPORT(ldexp)
|
||||||
DXE_EXPORT(pow)
|
DXE_EXPORT(pow)
|
||||||
|
// movedata
|
||||||
|
DXE_EXPORT(_movedatal)
|
||||||
|
DXE_EXPORT(dosmemget)
|
||||||
|
DXE_EXPORT(dosmemput)
|
||||||
|
// pc
|
||||||
|
DXE_EXPORT(outportb)
|
||||||
|
// Roo/E
|
||||||
|
DXE_EXPORT(logClose)
|
||||||
|
DXE_EXPORT(logOpen)
|
||||||
|
DXE_EXPORT(logOpenByHandle)
|
||||||
|
DXE_EXPORT(logWrite)
|
||||||
|
DXE_EXPORT(logWriteToFileOnly)
|
||||||
|
DXE_EXPORT(utilCreateString)
|
||||||
|
DXE_EXPORT(utilCreateStringVArgs)
|
||||||
|
DXE_EXPORT(utilEndsWith)
|
||||||
|
DXE_EXPORT(utilFileExists)
|
||||||
|
DXE_EXPORT(utilFileExtensionChange)
|
||||||
|
// setjmp
|
||||||
|
DXE_EXPORT(longjmp)
|
||||||
|
DXE_EXPORT(setjmp)
|
||||||
|
// signal
|
||||||
|
DXE_EXPORT(signal)
|
||||||
// stb_ds
|
// stb_ds
|
||||||
DXE_EXPORT(stbds_arrfreef)
|
DXE_EXPORT(stbds_arrfreef)
|
||||||
DXE_EXPORT(stbds_arrgrowf)
|
DXE_EXPORT(stbds_arrgrowf)
|
||||||
|
|
@ -81,26 +133,47 @@ DXE_EXPORT_TABLE(exports)
|
||||||
DXE_EXPORT(fclose)
|
DXE_EXPORT(fclose)
|
||||||
DXE_EXPORT(feof)
|
DXE_EXPORT(feof)
|
||||||
DXE_EXPORT(ferror)
|
DXE_EXPORT(ferror)
|
||||||
|
DXE_EXPORT(fflush)
|
||||||
DXE_EXPORT(fgetc)
|
DXE_EXPORT(fgetc)
|
||||||
|
DXE_EXPORT(fgets)
|
||||||
DXE_EXPORT(fopen)
|
DXE_EXPORT(fopen)
|
||||||
|
DXE_EXPORT(fprintf)
|
||||||
|
DXE_EXPORT(fputc)
|
||||||
DXE_EXPORT(fread)
|
DXE_EXPORT(fread)
|
||||||
DXE_EXPORT(fseek)
|
DXE_EXPORT(fseek)
|
||||||
DXE_EXPORT(ftell)
|
DXE_EXPORT(ftell)
|
||||||
|
DXE_EXPORT(fwrite)
|
||||||
DXE_EXPORT(printf)
|
DXE_EXPORT(printf)
|
||||||
DXE_EXPORT(puts)
|
DXE_EXPORT(puts)
|
||||||
|
DXE_EXPORT(sprintf)
|
||||||
DXE_EXPORT(ungetc)
|
DXE_EXPORT(ungetc)
|
||||||
|
DXE_EXPORT(vsprintf)
|
||||||
// stdlib
|
// stdlib
|
||||||
|
DXE_EXPORT(abort)
|
||||||
|
DXE_EXPORT(atexit)
|
||||||
|
DXE_EXPORT(exit)
|
||||||
DXE_EXPORT(free)
|
DXE_EXPORT(free)
|
||||||
|
DXE_EXPORT(calloc)
|
||||||
DXE_EXPORT(malloc)
|
DXE_EXPORT(malloc)
|
||||||
DXE_EXPORT(realloc)
|
DXE_EXPORT(realloc)
|
||||||
// string
|
// string
|
||||||
DXE_EXPORT(memcpy)
|
DXE_EXPORT(memcpy)
|
||||||
DXE_EXPORT(memset)
|
DXE_EXPORT(memset)
|
||||||
|
DXE_EXPORT(strcat)
|
||||||
DXE_EXPORT(strcmp)
|
DXE_EXPORT(strcmp)
|
||||||
|
DXE_EXPORT(strcpy)
|
||||||
|
DXE_EXPORT(strlen)
|
||||||
DXE_EXPORT(strncmp)
|
DXE_EXPORT(strncmp)
|
||||||
|
DXE_EXPORT(strncpy)
|
||||||
DXE_EXPORT(strtol)
|
DXE_EXPORT(strtol)
|
||||||
|
// time
|
||||||
|
DXE_EXPORT(ctime)
|
||||||
|
DXE_EXPORT(time)
|
||||||
// Compiler stuff.
|
// Compiler stuff.
|
||||||
DXE_EXPORT(__dj_assert)
|
DXE_EXPORT(__dj_assert)
|
||||||
|
DXE_EXPORT(__dj_ctype_toupper)
|
||||||
|
DXE_EXPORT(__dj_stdin)
|
||||||
|
DXE_EXPORT(__djgpp_base_address)
|
||||||
DXE_EXPORT(__emutls_get_address)
|
DXE_EXPORT(__emutls_get_address)
|
||||||
DXE_EXPORT_END
|
DXE_EXPORT_END
|
||||||
|
|
||||||
|
|
@ -120,7 +193,101 @@ static int lastResort(void) {
|
||||||
printf("ROO/E: Last resort function called!\n");
|
printf("ROO/E: Last resort function called!\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // PLATFORM_DOS
|
#endif // __DJGPP__
|
||||||
|
|
||||||
|
|
||||||
|
void logClose(void) {
|
||||||
|
if (_log && _ourHandle) {
|
||||||
|
fclose(_log);
|
||||||
|
_ourHandle = 0;
|
||||||
|
}
|
||||||
|
DEL(_logBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t logOpen(char *filename, uint8_t append) {
|
||||||
|
_log = fopen(filename, append ? "a" : "w");
|
||||||
|
if (_log) {
|
||||||
|
_ourHandle = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void logOpenByHandle(FILE *handle) {
|
||||||
|
_log = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void logWrite(char *format, ...) {
|
||||||
|
va_list args = { 0 };
|
||||||
|
va_list args2 = { 0 };
|
||||||
|
uint16_t length = 0;
|
||||||
|
|
||||||
|
if (_log) {
|
||||||
|
va_start(args, format);
|
||||||
|
va_copy(args2, args);
|
||||||
|
|
||||||
|
// Attempt to write into current log buffer.
|
||||||
|
length = vsnprintf(_logBuffer, _logBufferSize, format, args);
|
||||||
|
|
||||||
|
// Did it fit?
|
||||||
|
if (length >= _logBufferSize) {
|
||||||
|
// Nope. Resize buffer to fit plus a bit more.
|
||||||
|
if (_logBuffer) free(_logBuffer);
|
||||||
|
_logBufferSize = length + 32;
|
||||||
|
_logBuffer = (char *)malloc(_logBufferSize);
|
||||||
|
// Do it again.
|
||||||
|
vsnprintf(_logBuffer, _logBufferSize, format, args2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
// Also output to stdout on Linux.
|
||||||
|
fprintf(stdout, "%s", _logBuffer);
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fprintf(_log, "%s", _logBuffer);
|
||||||
|
fflush(_log);
|
||||||
|
|
||||||
|
va_end(args2);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void logWriteToFileOnly(char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
if (_log) {
|
||||||
|
vfprintf(_log, format, args);
|
||||||
|
fflush(_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FILE *memoryLogHandleGet(void) {
|
||||||
|
return _memoryLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MEMWATCH
|
||||||
|
void memoryOutput(int c) {
|
||||||
|
fputc(c, _memoryLog);
|
||||||
|
fflush(_memoryLog);
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
// Also output to stdout on Linux.
|
||||||
|
fputc(c, stdout);
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
RooAppThreadT *rooStartApp(const char *appName, const int argc, char *argv[]) {
|
RooAppThreadT *rooStartApp(const char *appName, const int argc, char *argv[]) {
|
||||||
|
|
@ -161,9 +328,9 @@ static void *rooStartAppThread(void *arg) {
|
||||||
appThread->running = true;
|
appThread->running = true;
|
||||||
appPtrCast.from = dlsym(appThread->namedPointer->pointer, "_appMain");
|
appPtrCast.from = dlsym(appThread->namedPointer->pointer, "_appMain");
|
||||||
appMain = appPtrCast.to; // NOLINT
|
appMain = appPtrCast.to; // NOLINT
|
||||||
debug("ROO/E: Calling appMain.\n");
|
logWrite("ROO/E: Calling appMain.\n");
|
||||||
appThread->result = appMain(appThread->argc, appThread->argv);
|
appThread->result = appMain(appThread->argc, appThread->argv);
|
||||||
debug("ROO/E: Back from appMain.\n");
|
logWrite("ROO/E: Back from appMain.\n");
|
||||||
appThread->running = false;
|
appThread->running = false;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -199,7 +366,8 @@ int main(const int argc, char *argv[]) {
|
||||||
RooAppThreadT *appThread = NULL;;
|
RooAppThreadT *appThread = NULL;;
|
||||||
RooNamedPointerT **dynList = NULL;
|
RooNamedPointerT **dynList = NULL;
|
||||||
RooNamedPointerT *namedPointer = NULL;
|
RooNamedPointerT *namedPointer = NULL;
|
||||||
int result;
|
char *logName = utilFileExtensionChange("roo_e.exe", "log");
|
||||||
|
int result = -1;
|
||||||
// RooAbortReasonT abort;
|
// RooAbortReasonT abort;
|
||||||
int x;
|
int x;
|
||||||
int (*dynInitStop)(void);
|
int (*dynInitStop)(void);
|
||||||
|
|
@ -212,15 +380,26 @@ int main(const int argc, char *argv[]) {
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
#ifdef PLATFORM_DOS
|
_memoryLog = fopen(logName, "w"); // This used to be encapsulated inside memory.c. Kinda just dangling here now.
|
||||||
|
logOpenByHandle(memoryLogHandleGet());
|
||||||
|
|
||||||
|
#ifdef MEMWATCH
|
||||||
|
mwLogW(_memoryLog);
|
||||||
|
mwSetOutFunc(memoryOutput);
|
||||||
|
mwInit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
free(logName);
|
||||||
|
|
||||||
|
#ifdef __DJGPP__
|
||||||
// Set the error callback function.
|
// Set the error callback function.
|
||||||
_dlsymresolver = dxeResolver;
|
_dlsymresolver = dxeResolver;
|
||||||
// Register the symbols exported into dynamic modules.
|
// Register the symbols exported into dynamic modules.
|
||||||
dlregsym(exports);
|
dlregsym(exports);
|
||||||
#endif // PLATFORM_DOS
|
#endif // __DJGPP__
|
||||||
|
|
||||||
// Load libraries.
|
// Load libraries.
|
||||||
debug("ROO/E: Loading dynamic libraries.\n");
|
logWrite("ROO/E: Loading dynamic libraries.\n");
|
||||||
if ((dir = opendir("dyn/")) == NULL) {
|
if ((dir = opendir("dyn/")) == NULL) {
|
||||||
printf("ROO/E: Unable to open dyn directory!\n");
|
printf("ROO/E: Unable to open dyn directory!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
@ -236,11 +415,11 @@ int main(const int argc, char *argv[]) {
|
||||||
printf("ROO/E: Unable to load %s! %s\n", namedPointer->name, dlerror());
|
printf("ROO/E: Unable to load %s! %s\n", namedPointer->name, dlerror());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
debug("ROO/E: Loaded %s.\n", namedPointer->name);
|
logWrite("ROO/E: Loaded %s.\n", namedPointer->name);
|
||||||
dynPtrCast.from = dlsym(namedPointer->pointer, "_dynStart");
|
dynPtrCast.from = dlsym(namedPointer->pointer, "_dynStart");
|
||||||
if (dynPtrCast.from != NULL) {
|
if (dynPtrCast.from != NULL) {
|
||||||
dynInitStop = dynPtrCast.to; // NOLINT
|
dynInitStop = dynPtrCast.to; // NOLINT
|
||||||
debug("ROO/E: Starting %s.\n", namedPointer->name);
|
logWrite("ROO/E: Starting %s.\n", namedPointer->name);
|
||||||
result = dynInitStop();
|
result = dynInitStop();
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
printf("ROO/E: %s failed to start!\n", namedPointer->name);
|
printf("ROO/E: %s failed to start!\n", namedPointer->name);
|
||||||
|
|
@ -253,7 +432,7 @@ int main(const int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
debug("ROO/E: Loaded %d libraries.\n", arrlen(dynList));
|
logWrite("ROO/E: Loaded %d libraries.\n", arrlen(dynList));
|
||||||
|
|
||||||
// Load the Shell. This needs to be configurable.
|
// Load the Shell. This needs to be configurable.
|
||||||
rooStartApp("kpsmpgc", 0, NULL);
|
rooStartApp("kpsmpgc", 0, NULL);
|
||||||
|
|
@ -263,13 +442,13 @@ int main(const int argc, char *argv[]) {
|
||||||
// Wait for all apps to exit.
|
// Wait for all apps to exit.
|
||||||
for (x=0; x<arrlen(_appThreadList); x++) {
|
for (x=0; x<arrlen(_appThreadList); x++) {
|
||||||
appThread = _appThreadList[x]; // NOLINT
|
appThread = _appThreadList[x]; // NOLINT
|
||||||
debug("ROO/E: App %d of %d running == %d\n", x, arrlen(_appThreadList), (int)appThread->running);
|
logWrite("ROO/E: App %d of %d running == %d\n", x, arrlen(_appThreadList), (int)appThread->running);
|
||||||
if (appThread->running == false) {
|
if (appThread->running == false) {
|
||||||
debug("ROO/E: Joining.\n");
|
logWrite("ROO/E: Joining.\n");
|
||||||
pthread_join(appThread->thread, NULL);
|
pthread_join(appThread->thread, NULL);
|
||||||
debug("ROO/E: Joined.\n");
|
logWrite("ROO/E: Joined.\n");
|
||||||
dlclose(appThread->namedPointer->pointer);
|
dlclose(appThread->namedPointer->pointer);
|
||||||
debug("ROO/E: %s exited.\n", appThread->namedPointer->name);
|
logWrite("ROO/E: %s exited.\n", appThread->namedPointer->name);
|
||||||
DEL(appThread->namedPointer->name);
|
DEL(appThread->namedPointer->name);
|
||||||
DEL(appThread->namedPointer);
|
DEL(appThread->namedPointer);
|
||||||
//***TODO*** Deal with argv cleanup here?
|
//***TODO*** Deal with argv cleanup here?
|
||||||
|
|
@ -297,10 +476,10 @@ int main(const int argc, char *argv[]) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Unload DYNs
|
// Unload DYNs
|
||||||
debug("ROO/E: Unloading %d libraries.\n", arrlen(dynList));
|
logWrite("ROO/E: Unloading %d libraries.\n", arrlen(dynList));
|
||||||
while (arrlen(dynList) > 0) {
|
while (arrlen(dynList) > 0) {
|
||||||
namedPointer = dynList[0]; // NOLINT
|
namedPointer = dynList[0]; // NOLINT
|
||||||
debug("ROO/E: Stopping %s\n", namedPointer->name);
|
logWrite("ROO/E: Stopping %s\n", namedPointer->name);
|
||||||
dynPtrCast.from = dlsym(namedPointer->pointer, "_dynStop");
|
dynPtrCast.from = dlsym(namedPointer->pointer, "_dynStop");
|
||||||
if (dynPtrCast.from != NULL) {
|
if (dynPtrCast.from != NULL) {
|
||||||
dynInitStop = dynPtrCast.to; // NOLINT
|
dynInitStop = dynPtrCast.to; // NOLINT
|
||||||
|
|
@ -316,5 +495,12 @@ int main(const int argc, char *argv[]) {
|
||||||
DEL(namedPointer);
|
DEL(namedPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MEMWATCH
|
||||||
|
unlink("memwatch.log"); // It just insists on creating this!
|
||||||
|
mwTerm();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
logClose();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,35 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "pthread.h"
|
#include "pthread.h"
|
||||||
#include "stbds.h"
|
#include "stbds.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "stddclmr.h"
|
#include "stddclmr.h"
|
||||||
|
|
||||||
|
// This is weird being here, but we have to expose a lot of it via DXE_EXPORT.
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
#include <dos.h>
|
||||||
|
#include <dpmi.h>
|
||||||
|
#include <go32.h>
|
||||||
|
#include <bios.h>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <sys/farptr.h>
|
||||||
|
#include <sys/nearptr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MEMWATCH
|
||||||
|
#include "memwatch/memwatch.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define ROO_CONSTRUCTOR void __attribute__((constructor))
|
#define ROO_CONSTRUCTOR void __attribute__((constructor))
|
||||||
#define ROO_DESTRUCTOR void __attribute__((destructor))
|
#define ROO_DESTRUCTOR void __attribute__((destructor))
|
||||||
|
|
@ -45,6 +65,23 @@
|
||||||
#define NEW(t,v) (v)=(t*)malloc(sizeof(t))
|
#define NEW(t,v) (v)=(t*)malloc(sizeof(t))
|
||||||
#define DEL(v) {if(v) {free(v); v=NULL;}}
|
#define DEL(v) {if(v) {free(v); v=NULL;}}
|
||||||
|
|
||||||
|
// Some helper defines.
|
||||||
|
#define DIVISIBLE_BY_EIGHT(x) ((((x) >> 3) << 3) == (x))
|
||||||
|
#define HIGH_BYTE(b) ((uint8_t)(((b) & 0xFF00) >> 8))
|
||||||
|
#define LOW_BYTE(b) ((uint8_t)((b) & 0x00FF))
|
||||||
|
|
||||||
|
// Return codes.
|
||||||
|
#define SUCCESS 0
|
||||||
|
#define FAIL 1
|
||||||
|
|
||||||
|
#ifndef va_copy
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||||
|
#else
|
||||||
|
#define va_copy(dest, src) (dest = src)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct RooNamedPointerS {
|
typedef struct RooNamedPointerS {
|
||||||
char *name;
|
char *name;
|
||||||
|
|
@ -74,6 +111,12 @@ typedef enum {
|
||||||
} RooAbortReasonT;
|
} RooAbortReasonT;
|
||||||
|
|
||||||
|
|
||||||
|
void logClose(void);
|
||||||
|
uint8_t logOpen(char *filename, uint8_t append);
|
||||||
|
void logOpenByHandle(FILE *handle);
|
||||||
|
void logWrite(char *format, ...);
|
||||||
|
void logWriteToFileOnly(char *format, ...);
|
||||||
|
|
||||||
RooAppThreadT *rooStartApp(const char *appName, int argc, char *argv[]);
|
RooAppThreadT *rooStartApp(const char *appName, int argc, char *argv[]);
|
||||||
RooAbortReasonT rooStopApp(RooAppThreadT **threadPointer, RooStopReasonT reason);
|
RooAbortReasonT rooStopApp(RooAppThreadT **threadPointer, RooStopReasonT reason);
|
||||||
|
|
||||||
|
|
|
||||||
49
roo_e/util.c
49
roo_e/util.c
|
|
@ -21,14 +21,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
|
|
||||||
char *utilCreateString(char *format, ...) {
|
char *utilCreateString(char *format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
@ -78,3 +72,46 @@ bool utilEndsWith(const char *haystack, const char *needle, const bool caseSensi
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t utilFileExists(char *filename) {
|
||||||
|
FILE *f = fopen(filename, "rb");
|
||||||
|
|
||||||
|
if (f) {
|
||||||
|
fclose(f);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *utilFileExtensionChange(char *appName, char *extension) {
|
||||||
|
char *c = NULL;
|
||||||
|
char *newName = NULL;
|
||||||
|
int16_t x = strlen(appName);
|
||||||
|
uint16_t len = 2 + strlen(extension); // 2 = dot in extension and 0 terminator.
|
||||||
|
|
||||||
|
// Find last portion of filename.
|
||||||
|
while (x > 0) {
|
||||||
|
if (appName[x] == '/' || appName[x] == '\\') { x++; break; }
|
||||||
|
x--;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
x--;
|
||||||
|
|
||||||
|
// We use this + length of new extension for new string length.
|
||||||
|
newName = (char *)malloc(len);
|
||||||
|
if (newName) {
|
||||||
|
if (strlen(appName) - x < len) {
|
||||||
|
// Replace extension
|
||||||
|
strncpy(newName, &appName[x + 1], len - 1);
|
||||||
|
c = strstr(newName, ".");
|
||||||
|
if (c) *c = 0;
|
||||||
|
strncat(newName, ".", len - 1);
|
||||||
|
strncat(newName, extension, len - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newName;
|
||||||
|
}
|
||||||
|
|
|
||||||
17
roo_e/util.h
17
roo_e/util.h
|
|
@ -25,25 +25,14 @@
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include "roo_e.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define debug printf
|
|
||||||
|
|
||||||
#ifndef va_copy
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
|
||||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
|
||||||
#else
|
|
||||||
#define va_copy(dest, src) (dest = src)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
char *utilCreateString(char *format, ...);
|
char *utilCreateString(char *format, ...);
|
||||||
char *utilCreateStringVArgs(char *format, va_list args);
|
char *utilCreateStringVArgs(char *format, va_list args);
|
||||||
bool utilEndsWith(const char *haystack, const char *needle, bool caseSensitive);
|
bool utilEndsWith(const char *haystack, const char *needle, bool caseSensitive);
|
||||||
|
char *utilFileExtensionChange(char *appName, char *extension);
|
||||||
|
uint8_t utilFileExists(char *filename);
|
||||||
|
|
||||||
|
|
||||||
#endif // UTIL_H
|
#endif // UTIL_H
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue