Initial commit

This commit is contained in:
Scott Duensing 2021-10-13 20:07:25 -05:00
commit 7d2d0c2fc3
44 changed files with 21337 additions and 0 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
*.png filter=lfs diff=lfs merge=lfs -text

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
build-*
*~
*.user
client/bin/
client/obj/
client/retired/

BIN
Icon.png (Stored with Git LFS) Normal file

Binary file not shown.

35
LICENSE Normal file
View file

@ -0,0 +1,35 @@
Kangaroo Punch Multi Player Game Server Mark II
Copyright (C) 2020-2021 Scott Duensing
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Licenses Used By:
Client
======
stb_ds.h
https://github.com/nothings/stb
Public Domain
stb_leakcheck.h
https://github.com/nothings/stb
Public Domain
stb_image.h
https://github.com/nothings/stb
Public Domain

118
client/Makefile.djgpp Normal file
View file

@ -0,0 +1,118 @@
#
# Kangaroo Punch Multi Player Game Server Mark II
# Copyright (C) 2020-2021 Scott Duensing
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# General
CC = gcc
LD = gcc
RM = rm -rf
RMDIR = rmdir
INSTALL = install
DEBUG = -g
## CHANGE THIS ##
TARGET = client
SRCDIR = src
OBJDIR = obj
BINDIR = bin
## CHANGE THIS ##
# CFLAGS, LDFLAGS, CPPFLAGS, PREFIX can be overriden on CLI
CFLAGS := $(DEBUG) -I$(SRCDIR) -I$(SRCDIR)/dos -I$(SRCDIR)/gui -I$(SRCDIR)/thirdparty
CPPFLAGS :=
LDFLAGS :=
PREFIX := /usr/local
TARGET_ARCH :=
# Compiler Flags
ALL_CFLAGS := $(CFLAGS)
ALL_CFLAGS += -Wall -O2
# Preprocessor Flags
ALL_CPPFLAGS := $(CPPFLAGS)
# Linker Flags
ALL_LDFLAGS := $(LDFLAGS)
ALL_LDLIBS := -lc
# Source, Binaries, Dependencies
SRC := $(shell find $(SRCDIR) -type f -name '*.c' | grep -v '/linux/')
OBJ := $(patsubst $(SRCDIR)/%,$(OBJDIR)/%,$(SRC:.c=.o))
DEP := $(OBJ:.o=.d)
BIN := $(BINDIR)/$(TARGET)
-include $(DEP)
# Verbosity Control, ala automake
V = 0
# Verbosity for CC
REAL_CC := $(CC)
CC_0 = @echo "CC $<"; $(REAL_CC)
CC_1 = $(REAL_CC)
CC = $(CC_$(V))
# Verbosity for LD
REAL_LD := $(LD)
LD_0 = @echo "LD $@"; $(REAL_LD)
LD_1 = $(REAL_LD)
LD = $(LD_$(V))
# Verbosity for RM
REAL_RM := $(RM)
RM_0 = @echo "Cleaning..."; $(REAL_RM)
RM_1 = $(REAL_RM)
RM = $(RM_$(V))
# Verbosity for RMDIR
REAL_RMDIR := $(RMDIR)
RMDIR_0 = @$(REAL_RMDIR)
RMDIR_1 = $(REAL_RMDIR)
RMDIR = $(RMDIR_$(V))
# Build Rules
.PHONY: clean
.DEFAULT_GOAL := all
all: setup $(BIN)
setup: dir
remake: clean all
dir:
@mkdir -p $(OBJDIR)
@mkdir -p $(BINDIR)
$(BIN): $(OBJ)
$(LD) $(ALL_LDFLAGS) $^ $(ALL_LDLIBS) -o $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) -c -MMD -MP -o $@ $<
install: $(BIN)
$(INSTALL) -d $(PREFIX)/bin
$(INSTALL) $(BIN) $(PREFIX)/bin
clean:
$(RM) $(OBJ) $(DEP) $(BIN)
$(RMDIR) $(OBJDIR) $(BINDIR) 2> /dev/null; true

25
client/build.sh Executable file
View file

@ -0,0 +1,25 @@
#!/bin/bash
#
# Kangaroo Punch Multi Player Game Server Mark II
# Copyright (C) 2020-2021 Scott Duensing
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
mkdir -p bin obj/dos obj/gui
source /opt/cross/djgpp/setenv
make -f Makefile.djgpp
rm bin/client
cp data/* bin/.

82
client/client.pro Normal file
View file

@ -0,0 +1,82 @@
#
# Kangaroo Punch Multi Player Game Server Mark II
# Copyright (C) 2020-2021 Scott Duensing
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
TEMPLATE = app
CONFIG -= qt
DESTDIR = $$OUT_PWD/bin
DOS_HEADERS =
DOS_SOURCES = \
src/dos/mouse.c \
src/dos/vesa.c
LINUX_INCLUDES = \
$$PWD/src/linux
LINUX_HEADERS =
LINUX_SOURCES = \
src/linux/linux.c
INCLUDEPATH += \
$$LINUX_INCLUDES \
$$PWD/src \
$$PWD/src/gui \
$$PWD/src/thirdparty
HEADERS = \
$$LINUX_HEADERS \
src/thirdparty/stb_ds.h \
src/thirdparty/stb_leakcheck.h \
src/thirdparty/stb_image.h \
src/gui/array.h \
src/gui/font.h \
src/gui/desktop.h \
src/gui/gui.h \
src/gui/widget.h \
src/gui/window.h \
src/gui/log.h \
src/gui/memory.h \
src/gui/mouse.h \
src/gui/vesa.h \
src/gui/image.h \
src/gui/os.h
SOURCES = \
$$LINUX_SOURCES \
src/gui/array.c \
src/gui/font.c \
src/gui/desktop.c \
src/gui/gui.c \
src/gui/widget.c \
src/gui/window.c \
src/gui/image.c \
src/gui/log.c \
src/gui/memory.c \
src/main.c
LIBS = \
-lSDL2
OTHER_FILES = \
Makefile.djgpp \
$$DOS_HEADERS \
$$DOS_SOURCES \
build.sh

BIN
client/data/mouse.png (Stored with Git LFS) Normal file

Binary file not shown.

102
client/src/dos/mouse.c Normal file
View file

@ -0,0 +1,102 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "mouse.h"
#include "vesa.h"
// 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
static MouseT _mouse;
MouseT *mouseRead(void) {
int32_t x;
int32_t y;
int16_t dx;
int16_t dy;
union REGS regs;
regs.x.ax = MOUSE_GETMOTION;
int86(MOUSE_INT, &regs, &regs);
dx = regs.x.cx; // Temporary assignment changes values to signed.
dy = regs.x.dx; // Don't skip this step. :-)
x = _mouse.x + dx;
y = _mouse.y + dy;
if (x < 0) x = 0;
if (x > _mouse.w - 1) x = _mouse.w - 1;
if (y < 0) y = 0;
if (y > _mouse.h - 1) y = _mouse.h - 1;
_mouse.x = (uint16_t)x;
_mouse.y = (uint16_t)y;
_mouse.buttonLeftWasDown = _mouse.buttonLeft;
_mouse.buttonRightWasDown = _mouse.buttonRight;
_mouse.buttonMiddleWasDown = _mouse.buttonMiddle;
regs.x.ax = MOUSE_STATUS;
int86(MOUSE_INT, &regs, &regs);
_mouse.buttonLeft = ((regs.x.bx & MOUSE_LEFT_BUTTON) > 0);
_mouse.buttonRight = ((regs.x.bx & MOUSE_RIGHT_BUTTON) > 0);
_mouse.buttonMiddle = ((regs.x.bx & MOUSE_MIDDLE_BUTTON) > 0);
return &_mouse;
}
void mouseShutdown(void) {
// Nothing to do in DOS
}
int16_t mouseStartup(void) {
union REGS regs;
regs.x.ax = MOUSE_RESET;
int86(MOUSE_INT, &regs, &regs);
_mouse.active = regs.x.ax;
_mouse.buttonCount = regs.x.bx == 0x0002 ? 2 : 3;
_mouse.buttonLeft = 0;
_mouse.buttonRight = 0;
_mouse.buttonMiddle = 0;
_mouse.buttonLeftWasDown = 0;
_mouse.buttonRightWasDown = 0;
_mouse.buttonMiddleWasDown = 0;
_mouse.x = 0;
_mouse.y = 0;
_mouse.w = vbeDisplayWidthGet();
_mouse.h = vbeDisplayHeightGet();
mouseRead();
return _mouse.active;
}

817
client/src/dos/vesa.c Normal file
View file

@ -0,0 +1,817 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "os.h"
#include "vesa.h"
// http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html
// These are all we support
#define VBE_MM_PACKED 4
#define VBE_MM_DCOLOR 6
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;
VBEInfoT *vbeGetInfo(void);
VBEModeInfoT *vbeGetModeInfo(uint16_t vbeModeNumber);
VBEModeInfoT *vbeGetModeInfoPtr(void);
void *vbeGetPmodeInterface(void);
VBESurfaceT *vbeGetVBESurfacePtr(void);
VBESurfaceT *vbeModeInit(uint16_t xRes, uint16_t yRes, uint8_t bpp);
void vbePresent(void);
uint16_t vbeSelectModeNumber(uint16_t xRes, uint16_t yRes, uint8_t bpp);
void vbeSetDisplayStart(uint32_t pixel, uint32_t scanline);
VBESurfaceT *vbeSetMode(uint16_t vbeModeNumber);
uint16_t vbeSetScanlineLength(uint16_t pixelLength);
void (*vbePutPixel)(uint16_t x, uint16_t y, PixelT pixel);
static void (*pmVBESetDisplayStart)(void);
static void vbeCreatePalette(void);
static uint8_t vbeIsDesiredMode(void);
static void vbePutPixel8(uint16_t x, uint16_t y, PixelT pixel);
static void vbePutPixel16(uint16_t x, uint16_t y, PixelT pixel);
static void vbePutPixel32(uint16_t x, uint16_t y, PixelT pixel);
static VBESurfaceT _vbeSurface;
static VBEInfoT _vbeInfo;
static VBEModeInfoT _vbeModeInfo;
static PModeInterfaceT *_pmodeInterfacePtr;
static uint32_t *_yTable;
static SurfaceT *_activeSurface;
static SurfaceT *_offScreenSurface;
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++;
}
}
}
}
uint8_t vbeDisplayDepthGet(void) {
return _vbeSurface.bitsPerPixel;
}
uint16_t vbeDisplayHeightGet(void) {
return _vbeSurface.yResolution;
}
uint16_t vbeDisplayWidthGet(void) {
return _vbeSurface.xResolution;
}
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);
}
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);
}
VBEModeInfoT *vbeGetModeInfoPtr(void) {
return(&_vbeModeInfo);
}
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) {
printf("\nGot IOInfo\n");
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;
}
VBESurfaceT *vbeGetVBESurfacePtr(void) {
return(&_vbeSurface);
}
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) {
// 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;
}
PixelT vbeMakePixel(uint8_t red, uint8_t green, uint8_t blue) {
return
(((red >> _vbeSurface.rShift) << _vbeSurface.rPos) & _vbeSurface.rMask) |
(((green >> _vbeSurface.gShift) << _vbeSurface.gPos) & _vbeSurface.gMask) |
(((blue >> _vbeSurface.bShift) << _vbeSurface.bPos) & _vbeSurface.bMask);
}
VBESurfaceT *vbeModeInit(uint16_t xRes, uint16_t yRes, uint8_t bpp) {
uint16_t vbeModeNumber;
__dpmi_meminfo m;
if (_vbeSurface.vbeBoolean == 0) return NULL;
if (_vbeSurface.vbeInitBoolean == 0) return NULL;
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);
_vbeSurface.vbeInitBoolean = 0;
if ((vbeModeNumber = vbeSelectModeNumber(xRes, yRes, bpp)) == 0) return NULL;
vbeModeNumber |= 0x8000;
if (vbeSetMode(vbeModeNumber) == NULL) return NULL;
return(&_vbeSurface);
}
void vbePresent(void) {
_movedatal(_my_ds(), (int32_t)_offScreenSurface->buffer.bits32, _vbeSurface.lfbSelector, 0x0, _vbeSurface.screenDWords);
//memset(_offScreenSurface->buffer.bits8, 0, _offScreenSurface->bytes);
}
static void vbePutPixel8(uint16_t x, uint16_t y, PixelT pixel) {
//_farpokeb(_vbeSurface.lfbSelector, _yTable[y] + x, (uint8_t)pixel);
_activeSurface->buffer.bits8[y * _activeSurface->width + x] = (uint8_t)pixel;
}
static void vbePutPixel16(uint16_t x, uint16_t y, PixelT pixel) {
//_farpokew(_vbeSurface.lfbSelector, _yTable[y] + (x << 1), (uint16_t)pixel);
_activeSurface->buffer.bits16[y * _activeSurface->width + x] = (uint16_t)pixel;
}
static void vbePutPixel32(uint16_t x, uint16_t y, PixelT pixel) {
//_farpokel(_vbeSurface.lfbSelector, _yTable[y] + (x << 2), pixel);
_activeSurface->buffer.bits32[y * _activeSurface->width + x] = pixel;
}
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]);
}
void vbeSetDisplayStart(uint32_t pixel, uint32_t scanline) {
__dpmi_regs r;
int32_t address;
int32_t selector;
if (pmVBESetDisplayStart) {
address = (_yTable[scanline] + (pixel * _vbeSurface.bytesPerPixel)) >> 2;
selector = (_vbeSurface.ioSegment) ? _vbeSurface.ioSegment : _my_ds();
asm(
" pushw %%es ; "
" movw %w1, %%es ; " // set the IO segment
" call *%0 ; " // call the VESA function
" popw %%es "
: // no outputs
: "S"(pmVBESetDisplayStart), // function pointer in esi
"a"(selector), // IO segment in eax
"b"(0x0080), // mode in ebx
"c"(address & 0xFFFF), // low word of address in ecx
"d"((address >> 16)) // high word of address in edx
: "memory", "%edi", "%cc" // touches edi and flags
);
return;
}
r.x.ax = 0x4F07;
r.x.bx = 0x0080;
r.x.cx = pixel;
r.x.dx = scanline;
__dpmi_int(0x10, &r);
}
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;
// create lookup table for putPixel routines
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
}
_offScreenSurface = vbeSurfaceCreate(_vbeSurface.xResolution, _vbeSurface.yResolution);
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED) {
vbeCreatePalette();
_vbeModeInfo.redFieldPosition = 5;
_vbeModeInfo.greenFieldPosition = 2;
_vbeModeInfo.blueFieldPosition = 0;
_vbeModeInfo.rsvdFieldPosition = 7;
_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;
if (_vbeSurface.bitsPerPixel == 8) vbePutPixel = vbePutPixel8;
if (_vbeSurface.bitsPerPixel == 16) vbePutPixel = vbePutPixel16;
if (_vbeSurface.bitsPerPixel == 15) vbePutPixel = vbePutPixel16;
if (_vbeSurface.bitsPerPixel == 32) vbePutPixel = vbePutPixel32;
return(&_vbeSurface);
}
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);
}
int16_t vbeShowInfo(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) {
printf("No VESA BIOS Extensions found.\n\n");
return(1);
}
printf(
"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) {
printf(
"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 {
printf("VESA BIOS Extension 2.0 or better required!\n\n");
return(1);
}
for (counter=0; ; counter++) {
if (_vbeInfo.videoModePtr[counter] == 0xFFFF) break;
vbeGetModeInfo(_vbeInfo.videoModePtr[counter]);
if (vbeIsDesiredMode()) {
printf("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");
}
}
return(0);
}
int16_t vbeShutdown(void) {
__dpmi_regs r;
__dpmi_meminfo m;
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);
}
vbeSurfaceDestroy(&_offScreenSurface);
// 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);
return(0);
}
uint8_t vbeStartup(uint16_t xRes, uint16_t yRes, uint8_t bpp) {
uint16_t vbeModeNumber;
if (vbeGetInfo() == NULL) {
printf("No VESA BIOS Extensions found.\n");
return 1;
}
if (_vbeInfo.vbeVersion < 0x0200) {
printf("VBE Version 2.0 or better required.\n");
return 2;
}
vbeGetPmodeInterface();
if ((vbeModeNumber = vbeSelectModeNumber(xRes, yRes, bpp)) == 0) {
printf("No appropriate video mode available.\n");
return 3;
}
if (vbeSetMode(vbeModeNumber) == NULL) {
return 4;
}
return 0;
}
void vbeSurfaceBlit(SurfaceT *source, uint16_t x, uint16_t y) {
uint16_t y1;
size_t offsetTarget;
size_t offsetSource;
if (x == 0 && y == 0 && _activeSurface->width == source->width && _activeSurface->height == source->height) {
// Direct blit of entire surface.
memcpy(_activeSurface->buffer.bits8, source->buffer.bits8, source->bytes);
} else {
// Blit into larger surface.
offsetTarget = y * _activeSurface->scanline + x * _vbeSurface.bytesPerPixel;
offsetSource = 0;
for (y1=y; y1<y+source->height; y1++) {
memcpy(&_activeSurface->buffer.bits8[offsetTarget], &source->buffer.bits8[offsetSource], source->scanline);
offsetTarget += _activeSurface->scanline;
offsetSource += source->scanline;
}
}
}
void vbeSurfaceClear(PixelT color) {
uint16_t x;
uint16_t y;
for (y=0; y<_activeSurface->height; y++) {
for (x=0; x<_activeSurface->width; x++) {
vbePutPixel(x, y, color);
}
}
}
SurfaceT *vbeSurfaceCreate(uint16_t width, uint16_t height) {
SurfaceT *surface = (SurfaceT *)malloc(sizeof(SurfaceT));
if (!surface) return NULL;
surface->width = width;
surface->height = height;
surface->scanline = width * _vbeSurface.bytesPerPixel;
surface->bytes = surface->scanline * height;
surface->buffer.bits8 = malloc(surface->bytes);
if (!surface->buffer.bits8) {
free(surface);
return NULL;
}
memset(surface->buffer.bits8, 0, surface->bytes);
return surface;
}
void vbeSurfaceDestroy(SurfaceT **surface) {
SurfaceT *s = *surface;
free(s->buffer.bits8);
free(s);
s = NULL;
}
void vbeSurfaceSet(SurfaceT *surface) {
if (surface) {
_activeSurface = surface;
} else {
_activeSurface = _offScreenSurface;
}
}
void vbeWaitVBlank(void) {
while(inportb(0x3DA) & 8);
while(!(inportb(0x3DA) & 8));
}

22
client/src/gui/array.c Normal file
View file

@ -0,0 +1,22 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#define STB_DS_IMPLEMENTATION
#include "stb_ds.h"

28
client/src/gui/array.h Normal file
View file

@ -0,0 +1,28 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef ARRAY_H
#define ARRAY_H
#include "stb_ds.h"
#endif // ARRAY_H

81
client/src/gui/desktop.c Normal file
View file

@ -0,0 +1,81 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "desktop.h"
void desktopDel(WidgetT **widget) {
DesktopT *d = (DesktopT *)*widget;
vbeSurfaceDestroy(&d->base.surface);
free(d);
d = NULL;
}
WidgetT *desktopInit(WidgetT *desktop) {
DesktopT *d = (DesktopT *)desktop;
d->base.magic = MAGIC_DESKTOP;
d->base.w = vbeDisplayWidthGet();
d->base.h = vbeDisplayHeightGet();
d->base.delMethod = desktopDel;
d->base.paintMethod = desktopPaint;
d->dragOffsetX = 0;
d->dragOffsetY = 0;
d->dragWidget = NULL;
d->base.surface = vbeSurfaceCreate(d->base.w, d->base.h);
if (!d->base.surface) {
free(d);
return NULL;
}
return desktop;
}
DesktopT *desktopNew(void) {
DesktopT *desktop = (DesktopT *)malloc(sizeof(DesktopT));
WidgetT *widget = NULL;
if (!desktop) return NULL;
widget = widgetInit((WidgetT *)desktop);
if (!widget) {
free(desktop);
return NULL;
}
desktop = (DesktopT *)desktopInit((WidgetT *)desktop);
return desktop;
}
void desktopPaint(WidgetT *desktop) {
DesktopT *d = (DesktopT *)desktop;
if (d->base.dirty) {
vbeSurfaceSet(d->base.surface);
vbeSurfaceClear(_guiColor[COLOR_DESKTOP]);
d->base.dirty = 0;
}
}

43
client/src/gui/desktop.h Normal file
View file

@ -0,0 +1,43 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef DESKTOP_H
#define DESKTOP_H
#include "gui.h"
#include "widget.h"
typedef struct DesktopS {
WidgetT base; // Must be first in every widget
uint16_t dragOffsetX;
uint16_t dragOffsetY;
WidgetT *dragWidget;
} DesktopT;
void desktopDel(WidgetT **widget);
WidgetT *desktopInit(WidgetT *desktop);
DesktopT *desktopNew(void);
void desktopPaint(WidgetT *desktop);
#endif // DESKTOP_H

104
client/src/gui/font.c Normal file
View file

@ -0,0 +1,104 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "font.h"
FontT *fontLoad(char *filename) {
FILE *in = NULL;
uint16_t size = 0;
FontT *font = NULL;
in = fopen(filename, "rb");
if (!in) return NULL;
font = (FontT *)malloc(sizeof(FontT));
if (!font) {
fclose(in);
return NULL;
}
font->width = fgetc(in);
font->height = fgetc(in);
font->span = fgetc(in);
font->count = fgetc(in);
font->widthPixels = font->width * font->span;
font->heightPixels = font->height * (font->count / font->span);
size = font->widthPixels * font->heightPixels;
font->bits = (uint8_t *)malloc(size);
if (!font->bits) {
free(font);
fclose(in);
return NULL;
}
fread(font->bits, size, 1, in);
fclose(in);
return font;
}
void fontRender(FontT *font, uint8_t character, PixelT foreground, PixelT background, uint16_t x, uint16_t y) {
uint8_t cx;
uint8_t cy;
uint16_t offset;
uint8_t yl;
uint16_t yp;
uint8_t data;
//***TODO*** This only handles 8x8 fonts.
// Find character position in font grid.
cx = character % font->span;
cy = character / font->span;
// Find offset byte based on font bits.
offset = cy * font->span * font->height + cx;
// Draw out 8 lines.
yp = y;
for (yl=0; yl<8; yl++) {
// We do 8 pixels unrolled hoping it's fast.
data = font->bits[offset];
offset += font->span;
vbePutPixel(x, yp, data & 0x80 ? foreground : background);
vbePutPixel(x + 1, yp, data & 0x40 ? foreground : background);
vbePutPixel(x + 2, yp, data & 0x20 ? foreground : background);
vbePutPixel(x + 3, yp, data & 0x10 ? foreground : background);
vbePutPixel(x + 4, yp, data & 0x08 ? foreground : background);
vbePutPixel(x + 5, yp, data & 0x04 ? foreground : background);
vbePutPixel(x + 6, yp, data & 0x02 ? foreground : background);
vbePutPixel(x + 7, yp, data & 0x01 ? foreground : background);
yp++;
}
}
void fontUnload(FontT **font) {
FontT *f = *font;
free(f->bits);
free(f);
f = NULL;
}

45
client/src/gui/font.h Normal file
View file

@ -0,0 +1,45 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef FONT_H
#define FONT_H
#include "os.h"
#include "vesa.h"
typedef struct FontS {
uint8_t width; // Width of each character in pixels.
uint8_t height; // Height of each character in pixels.
uint8_t span; // Number of characters per line in font data.
uint8_t count; // Number of characters in font, minus 1.
uint16_t widthPixels; // Width of line of font data in pixels/bits.
uint16_t heightPixels; // Number of lines of font data in pixels/bits.
uint8_t *bits; // Actual font bits.
} FontT;
FontT *fontLoad(char *filename);
void fontRender(FontT *font, uint8_t character, PixelT foreground, PixelT background, uint16_t x, uint16_t y);
void fontUnload(FontT **font);
#endif // FONT_H

312
client/src/gui/gui.c Normal file
View file

@ -0,0 +1,312 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "gui.h"
#include "widget.h"
#include "desktop.h"
#include "window.h"
int16_t _guiMetric[METRIC_COUNT];
PixelT _guiColor[COLOR_COUNT];
static DesktopT *_guiDesktop = NULL;
void guiAttach(WidgetT *parent, WidgetT *child) {
// Add us to the child list.
child->parent = parent;
arrput(parent->children, child);
// New windows should be active.
if (child->magic == MAGIC_WINDOW) {
windowSetActive((WindowT *)child);
}
}
void guiComposite() {
WidgetT *widget = (WidgetT *)_guiDesktop;
size_t len = arrlenu(widget->children);
size_t x;
// Repaint anyone who needs it.
guiPaint(widget);
vbeSurfaceSet(NULL);
// Render us?
if (widget->surface) {
vbeSurfaceBlit(widget->surface, widget->x, widget->y);
}
// Now render all surface-containing children to the VBE buffer.
if (len > 0) {
for (x=0; x<len; x++) {
if (widget->children[x]->surface) {
vbeSurfaceBlit(widget->children[x]->surface, widget->children[x]->x, widget->children[x]->y);
}
}
}
}
void guiDelete(WidgetT **widget) {
WidgetT *w = *widget;
size_t len = arrlenu(w->children);
size_t x = 0;
// Delete children.
if (len > 0) {
for (x=0; x<len; x++) {
guiDelete(&w->children[x]);
}
}
arrfree(w->children);
// Delete us.
w->delMethod(&w);
// Make sure we're not drawing into oblivion.
vbeSurfaceSet(NULL);
}
void guiDrawHighlightFrame(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, PixelT upperLeft, PixelT lowerRight) {
guiDrawLine(x1, y1, x2, y1, upperLeft);
guiDrawLine(x1, y1, x1, y2, upperLeft);
guiDrawLine(x1, y2, x2, y2, lowerRight);
guiDrawLine(x2, y1, x2, y2, lowerRight);
}
void guiDrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, PixelT 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) {
vbePutPixel(x, y, color);
if (balance >= 0) {
y += incY;
balance -= dx;
}
balance += dy;
x += incX;
}
vbePutPixel(x, y, color);
} else {
dx <<= 1;
balance = dx - dy;
dy <<= 1;
while (y != y2) {
vbePutPixel(x, y, color);
if (balance >= 0) {
x += incX;
balance -= dy;
}
balance += dx;
y += incY;
}
vbePutPixel(x, y, color);
}
}
void guiDrawFilledRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, PixelT pixel) {
uint16_t x;
uint16_t y;
for (y=y1; y<=y2; y++) {
for (x=x1; x<=x2; x++) {
vbePutPixel(x, y, pixel);
}
}
}
void guiProcessMouse(MouseT *mouse) {
size_t len;
int16_t x;
WidgetT *child;
WindowT *window;
WidgetT *parent = (WidgetT *)_guiDesktop;
static WidgetT *downOnWidget = NULL;
// Is the left button down?
if (mouse->buttonLeft) {
// Was it NOT down before?
if (!mouse->buttonLeftWasDown) {
// Initial click. Are we already dragging something?
if (!_guiDesktop->dragWidget) {
// Can we drag this?
len = arrlenu(parent->children);
for (x=len-1; x>=0; x--) {
child = parent->children[x];
// Are we clicking this widget?
if (mouse->x >= child->x && mouse->y >= child->y && mouse->x < child->x + child->w && mouse->y < child->y + child->h) {
// Remember this widget for when the mouse button is released. Buttons must come up on the same widget they went down on.
downOnWidget = child;
// Is this a Window?
if (child->magic == MAGIC_WINDOW) {
window = (WindowT *)child;
// Is it the active window?
if (GUI_GET_FLAG(window, WINDOW_FLAG_ACTIVE)) {
// Start dragging.
_guiDesktop->dragOffsetX = mouse->x - window->base.x;
_guiDesktop->dragOffsetY = mouse->y - window->base.y;
_guiDesktop->dragWidget = child;
}
}
break;
}
}
}
} else { // Was it NOT down before?
// Still holding left button, but not the initial click. Update dragged widget location.
if (_guiDesktop->dragWidget) {
_guiDesktop->dragWidget->x = mouse->x - _guiDesktop->dragOffsetX;
_guiDesktop->dragWidget->y = mouse->y - _guiDesktop->dragOffsetY;
// Keep it on the screen.
if (_guiDesktop->dragWidget->x < 0) _guiDesktop->dragWidget->x = 0;
if (_guiDesktop->dragWidget->x + _guiDesktop->dragWidget->w > vbeDisplayWidthGet()) _guiDesktop->dragWidget->x = vbeDisplayWidthGet() - _guiDesktop->dragWidget->w;
if (_guiDesktop->dragWidget->y < 0) _guiDesktop->dragWidget->y = 0;
if (_guiDesktop->dragWidget->y + _guiDesktop->dragWidget->h > vbeDisplayHeightGet()) _guiDesktop->dragWidget->y = vbeDisplayHeightGet() - _guiDesktop->dragWidget->h;
}
} // Was it NOT down before?
} else { // Left button down?
// No longer holding left button. Stop dragging.
_guiDesktop->dragWidget = NULL;
// Was the left button down last frame?
if (mouse->buttonLeftWasDown) {
//***TODO*** Right now, this only processes top-level windows attached directly to the desktop.
len = arrlenu(parent->children);
for (x=len-1; x>=0; x--) {
child = parent->children[x];
// Are we clicking this widget?
if (mouse->x >= child->x && mouse->y >= child->y && mouse->x < child->x + child->w && mouse->y < child->y + child->h) {
// Is this the widget we originally clicked? Buttons must come up on the same widget they went down on.
if (child == downOnWidget) {
// Is this a Window?
if (child->magic == MAGIC_WINDOW) {
window = (WindowT *)child;
// Bring window to top.
arrdel(parent->children, x);
arrput(parent->children, child);
windowSetActive(window);
} else {
//***TODO*** Dispatch to proper control if the containing window is active.
}
}
break;
}
}
} // Left button was down last frame.
} // Left button down.
}
void guiPaint(WidgetT *widget) {
size_t len = arrlenu(widget->children);
size_t x;
// Paint us, if needed.
if (widget->dirty && widget->paintMethod) {
widget->paintMethod(widget);
widget->dirty = 0;
}
// Paint all children, if needed.
if (len > 0) {
for (x=0; x<len; x++) {
if (widget->children[x]->dirty && widget->children[x]->paintMethod) {
widget->children[x]->paintMethod(widget->children[x]);
widget->children[x]->dirty = 0;
}
}
}
}
WidgetT *guiRootGet(void) {
return (WidgetT *)_guiDesktop;
}
DesktopT *guiStartup(void) {
_guiMetric[METRIC_WINDOW_BORDER_WIDTH] = 4; // Does not include highlight or shadow lines.
_guiMetric[METRIC_WINDOW_TITLE_HEIGHT] = 17; // Does not include highlight or shadow lines.
_guiColor[COLOR_DESKTOP] = vbeMakePixel( 51, 153, 255);
_guiColor[COLOR_WINDOW_BACKGROUND] = vbeMakePixel(168, 168, 168);
_guiColor[COLOR_WINDOW_HIGHLIGHT] = vbeMakePixel(248, 252, 248);
_guiColor[COLOR_WINDOW_SHADOW] = vbeMakePixel( 80, 84, 80);
_guiColor[COLOR_WINDOW_TITLE_ACTIVE] = vbeMakePixel( 80, 84, 80);
_guiColor[COLOR_WINDOW_TITLE_INACTIVE] = vbeMakePixel(168, 168, 168);
_guiColor[COLOR_WINDOW_TITLE_TEXT_ACTIVE] = vbeMakePixel(248, 252, 248);
_guiColor[COLOR_WINDOW_TITLE_TEXT_INACTIVE] = vbeMakePixel( 0, 0, 0);
// Create desktop and return it. Remember it for later.
_guiDesktop = desktopNew();
return _guiDesktop;
}
void guiShutdown(void) {
// Delete all widgets in GUI tree.
guiDelete((WidgetT **)&_guiDesktop);
}

90
client/src/gui/gui.h Normal file
View file

@ -0,0 +1,90 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef GUI_H
#define GUI_H
// Inspired by https://github.com/JMarlin/wsbe
#include "os.h"
#include "vesa.h"
#include "array.h"
#include "mouse.h"
#define GUI_GET_FLAG(w,f) ((w)->flags & (1 << (f)))
#define GUI_SET_FLAG(w,f) ((w)->flags |= (1 << (f)))
#define GUI_CLEAR_FLAG(w,f) ((w)->flags &= (~(1 << (f))))
// Widget Magics
enum MagicE {
MAGIC_UNKNOWN = 0,
MAGIC_DESKTOP,
MAGIC_WINDOW,
MAGIC_BUTTON,
MAGIC_COUNT
};
// Widget Metrics
enum MetricE {
METRIC_WINDOW_BORDER_WIDTH = 0,
METRIC_WINDOW_TITLE_HEIGHT,
METRIC_COUNT
};
// Widget Colors
enum ColorE {
COLOR_DESKTOP = 0,
COLOR_WINDOW_BACKGROUND,
COLOR_WINDOW_HIGHLIGHT,
COLOR_WINDOW_SHADOW,
COLOR_WINDOW_TITLE_ACTIVE,
COLOR_WINDOW_TITLE_INACTIVE,
COLOR_WINDOW_TITLE_TEXT_ACTIVE,
COLOR_WINDOW_TITLE_TEXT_INACTIVE,
COLOR_COUNT
};
typedef struct WidgetS WidgetT;
typedef struct DesktopS DesktopT;
extern int16_t _guiMetric[METRIC_COUNT];
extern PixelT _guiColor[COLOR_COUNT];
void guiAttach(WidgetT *parent, WidgetT *child);
void guiComposite(void);
void guiDelete(WidgetT **widget);
void guiDrawHighlightFrame(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, PixelT upperLeft, PixelT lowerRight);
void guiDrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, PixelT pixel);
void guiDrawFilledRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, PixelT pixel);
void guiPaint(WidgetT *widget);
void guiProcessMouse(MouseT *mouse);
WidgetT *guiRootGet(void);
DesktopT *guiStartup(void);
void guiShutdown(void);
#endif // GUI_H

158
client/src/gui/image.c Normal file
View file

@ -0,0 +1,158 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_PNG
#include "image.h"
ImageT *imageAllocate(uint16_t w, uint16_t h) {
uint16_t x;
uint16_t y;
ImageT *image;
// Create new native image
image = (ImageT *)malloc(sizeof(ImageT));
if (!image) return NULL;
image->width = w;
image->height = h;
// Create space for converted pixel data - columns
image->pixels = (PixelT **)malloc(sizeof(PixelT *) * image->width);
if (!image->pixels) {
free(image);
return NULL;
}
// Create space for converted pixel data - rows
for (x=0; x<image->width; x++) {
image->pixels[x] = (PixelT *)malloc(sizeof(PixelT) * image->height);
if (!image->pixels[x]) {
for (y=0; y<x; y++) {
free(image->pixels[y]);
}
free(image);
return NULL;
}
}
return image;
}
ImageT *imageCreate(uint16_t w, uint16_t h, PixelT color) {
uint16_t x;
uint16_t y;
ImageT *image = imageAllocate(w, h);
if (!image) return NULL;
for (y=0; y<image->height; y++) {
for (x=0; x<image->width; x++) {
image->pixels[x][y] = color;
}
}
return image;
}
ImageT *imageLoad(char *filename) {
uint16_t x;
uint16_t y;
uint16_t n;
uint32_t b;
unsigned char *raw;
ImageT *image;
// Load image from disk
raw = stbi_load(filename, (int *)&x, (int *)&y, (int *)&n, 3);
if (!raw) return NULL;
// Create native image.
image = imageAllocate(x, y);
if (!image) {
stbi_image_free(raw);
return NULL;
}
// Convert from RGB to our generic 32 bit pixel format
b = 0;
for (y=0; y<image->height; y++) {
for (x=0; x<image->width; x++) {
image->pixels[x][y] = vbeMakePixel(raw[b], raw[b + 1], raw[b + 2]);
b += 3;
}
}
stbi_image_free(raw);
return image;
}
PixelT imagePixelGet(ImageT *image, uint16_t x, uint16_t y) {
return image->pixels[x][y];
}
void imageRender(ImageT *image, uint16_t x, uint16_t y) {
uint16_t x1;
uint16_t y1;
for (y1=0; y1<image->height; y1++) {
for (x1=0; x1<image->width; x1++) {
vbePutPixel(x + x1, y + y1, image->pixels[x1][y1]);
}
}
}
void imageRenderWithAlpha(ImageT *image, uint16_t x, uint16_t y, PixelT alpha) {
uint16_t x1;
uint16_t y1;
uint16_t x2 = image->width;
uint16_t y2 = image->height;
// Clip on right and bottom
if (x + x2 > vbeDisplayWidthGet()) x2 -= x + x2 - vbeDisplayWidthGet();
if (y + y2 > vbeDisplayHeightGet()) y2 -= y + y2 - vbeDisplayHeightGet();
for (y1=0; y1<y2; y1++) {
for (x1=0; x1<x2; x1++) {
if (alpha != image->pixels[x1][y1]) {
vbePutPixel(x + x1, y + y1, image->pixels[x1][y1]);
}
}
}
}
void imageUnload(ImageT **image) {
uint16_t x;
ImageT *i = *image;
for (x=0; x<i->width; x++) {
free(i->pixels[x]);
}
free(i->pixels);
free(i);
i = NULL;
}

47
client/src/gui/image.h Normal file
View file

@ -0,0 +1,47 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef IMAGE_H
#define IMAGE_H
#include "os.h"
#include "vesa.h"
#include "stb_image.h"
typedef struct ImageS {
uint16_t width;
uint16_t height;
PixelT **pixels;
} ImageT;
ImageT *imageAllocate(uint16_t w, uint16_t h);
ImageT *imageCreate(uint16_t w, uint16_t h, PixelT color);
ImageT *imageLoad(char *filename);
PixelT imagePixelGet(ImageT *image, uint16_t x, uint16_t y);
void imageRender(ImageT *image, uint16_t x, uint16_t y);
void imageRenderWithAlpha(ImageT *image, uint16_t x, uint16_t y, PixelT alpha);
void imageUnload(ImageT **image);
#endif // IMAGE_H

50
client/src/gui/log.c Normal file
View file

@ -0,0 +1,50 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "log.h"
FILE *_log = NULL;
uint8_t logOpen(char *filename, uint8_t append) {
_log = fopen(filename, append ? "a" : "w");
if (_log) return 1;
return 0;
}
void logClose(void) {
if (_log) {
fclose(_log);
}
}
void logWrite(char *format, ...) {
va_list args;
if (_log) {
va_start(args, format);
vfprintf(_log, format, args);
va_end(args);
fflush(_log);
}
}

33
client/src/gui/log.h Normal file
View file

@ -0,0 +1,33 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef LOG_H
#define LOG_H
#include "os.h"
uint8_t logOpen(char *filename, uint8_t append);
void logClose(void);
void logWrite(char *format, ...);
#endif // LOG_H

22
client/src/gui/memory.c Normal file
View file

@ -0,0 +1,22 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#define STB_LEAKCHECK_IMPLEMENTATION
#include "stb_leakcheck.h"

31
client/src/gui/memory.h Normal file
View file

@ -0,0 +1,31 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef MEMORY_H
#define MEMORY_H
#include "stb_leakcheck.h"
#define memoryLeaksShow stb_leakcheck_dumpmem
#endif // MEMORY_H

49
client/src/gui/mouse.h Normal file
View file

@ -0,0 +1,49 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef MOUSE_H
#define MOUSE_H
#include "os.h"
typedef struct MouseS {
uint8_t active;
uint8_t buttonCount;
uint8_t buttonLeft;
uint8_t buttonRight;
uint8_t buttonMiddle;
uint8_t buttonLeftWasDown;
uint8_t buttonRightWasDown;
uint8_t buttonMiddleWasDown;
uint16_t w;
uint16_t h;
uint16_t x;
uint16_t y;
} MouseT;
void mouseShutdown(void);
int16_t mouseStartup(void);
MouseT *mouseRead(void);
#endif // MOUSE_H

58
client/src/gui/os.h Normal file
View file

@ -0,0 +1,58 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef OS_H
#define OS_H
#include <math.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#ifdef __linux__
#else
#include <dos.h>
#include <dpmi.h>
#include <go32.h>
#include <conio.h>
#include <sys/nearptr.h>
#include <sys/farptr.h>
#endif
#include "log.h"
// Has to be after system headers in this file.
//#include "memory.h"
#define DIVISIBLE_BY_EIGHT(x) ((((x) >> 3) << 3) == (x))
#endif // OS_H

62
client/src/gui/vesa.h Normal file
View file

@ -0,0 +1,62 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef VESA20_H
#define VESA20_H
#include "os.h"
typedef uint32_t PixelT;
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;
uint8_t vbeStartup(uint16_t xRes, uint16_t yRes, uint8_t bpp);
uint8_t vbeDisplayDepthGet(void);
uint16_t vbeDisplayHeightGet(void);
uint16_t vbeDisplayWidthGet(void);
PixelT vbeMakePixel(uint8_t red, uint8_t green, uint8_t blue);
void vbePresent(void);
int16_t vbeShowInfo(void);
int16_t vbeShutdown(void);
void vbeSurfaceBlit(SurfaceT *source, uint16_t x, uint16_t y);
void vbeSurfaceClear(PixelT color);
SurfaceT *vbeSurfaceCreate(uint16_t width, uint16_t height);
void vbeSurfaceDestroy(SurfaceT **surface);
void vbeSurfaceSet(SurfaceT *surface);
void vbeWaitVBlank(void);
extern void (*vbePutPixel)(uint16_t x, uint16_t y, PixelT pixel);
#endif // VESA20_H

50
client/src/gui/widget.c Normal file
View file

@ -0,0 +1,50 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "widget.h"
WidgetT *widgetInit(WidgetT *widget) {
widget->magic = MAGIC_UNKNOWN;
widget->x = 0;
widget->y = 0;
widget->w = 0;
widget->h = 0;
widget->dirty = 1; // Force a paint right away
widget->surface = NULL;
widget->children = NULL;
widget->parent = NULL;
widget->delMethod = NULL;
widget->paintMethod = NULL;
widget->mouseDownMethod = NULL;
return widget;
}
WidgetT *widgetNew(void) {
WidgetT *widget = (WidgetT *)malloc(sizeof(WidgetT));
if (!widget) return NULL;
widget = widgetInit(widget);
return widget;
}

56
client/src/gui/widget.h Normal file
View file

@ -0,0 +1,56 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef WIDGET_H
#define WIDGET_H
#include "gui.h"
struct WidgetS;
typedef void (*widgetDelMethod)(struct WidgetS **widget);
typedef void (*widgetPaintMethod)(struct WidgetS *widget);
typedef void (*widgetMouseDownMethod)(struct WidgetS *widget, uint16_t x, uint16_t y);
typedef struct WidgetS {
uint8_t magic; // Widget identifier constant
uint8_t dirty; // Does this widget need redrawn
SurfaceT *surface; // Pointer to compositable surface or NULL
int16_t x; // Position of widget on parent
int16_t y; // Position of widget on parent
uint16_t w; // Width of widget
uint16_t h; // Height of widget
struct WidgetS **children; // List of children
struct WidgetS *parent; // Parent of this widget
widgetDelMethod delMethod; // Delete method
widgetPaintMethod paintMethod; // Paint method
widgetMouseDownMethod mouseDownMethod; // Mouse button down handler
} WidgetT;
WidgetT *widgetInit(WidgetT *widget);
WidgetT *widgetNew(void);
#endif // WIDGET_H

137
client/src/gui/window.c Normal file
View file

@ -0,0 +1,137 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "window.h"
static void windowDeactivateAll(WidgetT *widget);
static void windowDeactivateAll(WidgetT *widget) {
size_t len = arrlenu(widget->children);
size_t x;
// Is this a Window?
if (widget->magic == MAGIC_WINDOW) {
// Deactivate it.
GUI_CLEAR_FLAG((WindowT *)widget, WINDOW_FLAG_ACTIVE);
widget->dirty = 1;
}
// Process any children.
if (len > 0) {
for (x=0; x<len; x++) {
windowDeactivateAll(widget->children[x]);
}
}
}
void windowDel(WidgetT **widget) {
WindowT *w = (WindowT *)*widget;
vbeSurfaceDestroy(&w->base.surface);
if (w->title) free(w->title);
free(w);
w = NULL;
}
WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
WindowT *win = (WindowT *)window;
win->base.magic = MAGIC_WINDOW;
win->base.x = x;
win->base.y = y;
win->base.w = w;
win->base.h = h;
win->base.delMethod = windowDel;
win->base.paintMethod = windowPaint;
win->title = NULL;
windowSetTitle(win, title);
win->base.surface = vbeSurfaceCreate(win->base.w, win->base.h);
if (!win->base.surface) {
free(win->title);
free(win);
return NULL;
}
return window;
}
WindowT *windowNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
WindowT *window = (WindowT *)malloc(sizeof(WindowT));
WidgetT *widget = NULL;
if (!window) return NULL;
widget = widgetInit((WidgetT *)window);
if (!widget) {
free(window);
return NULL;
}
window = (WindowT *)windowInit((WidgetT *)window, x, y, w, h, title);
return window;
}
void windowPaint(WidgetT *window) {
WindowT *w = (WindowT *)window;
uint16_t x2 = w->base.w - 1;
uint16_t y2 = w->base.h - 1;
PixelT background = GUI_GET_FLAG(w, WINDOW_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_INACTIVE];
//PixelT text = GUI_GET_FLAG(w, WINDOW_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_TEXT_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_TEXT_INACTIVE];
if (w->base.dirty) {
vbeSurfaceSet(w->base.surface);
// Background.
vbeSurfaceClear(_guiColor[COLOR_WINDOW_BACKGROUND]);
// Outer edge.
guiDrawHighlightFrame(0, 0, x2, y2, _guiColor[COLOR_WINDOW_HIGHLIGHT], _guiColor[COLOR_WINDOW_SHADOW]);
// Inner edge - skip METRIC_WINDOW_BORDER_WIDTH pixels. Be sure shadow and highlight are not included in the width.
guiDrawHighlightFrame(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 2, y2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 2, _guiColor[COLOR_WINDOW_SHADOW], _guiColor[COLOR_WINDOW_HIGHLIGHT]);
// Title bar - METRIC_WINDOW_TITLE_HEIGHT pixels high. Be sure shadow and highlight are not included in the width.
guiDrawHighlightFrame(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 3, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 3, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 3, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 4, _guiColor[COLOR_WINDOW_HIGHLIGHT], _guiColor[COLOR_WINDOW_SHADOW]);
guiDrawFilledRectangle(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 2, background);
w->base.dirty = 0;
}
}
void windowSetActive(WindowT *window) {
windowDeactivateAll(guiRootGet());
GUI_SET_FLAG(window, WINDOW_FLAG_ACTIVE);
}
void windowSetTitle(WindowT *window, char *title) {
if (window->title) free(window->title);
window->title = strdup(title);
}

51
client/src/gui/window.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef WINDOW_H
#define WINDOW_H
#include "gui.h"
#include "widget.h"
enum WindowE {
WINDOW_FLAG_ACTIVE = 0,
WINDOW_FLAG_MODAL,
WINDOW_FLAG_RESIZABLE
};
typedef struct WindowS {
WidgetT base; // Must be first in every widget
uint8_t flags;
char *title;
} WindowT;
void windowDel(WidgetT **widget);
WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title);
WindowT *windowNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title);
void windowPaint(WidgetT *window);
void windowSetActive(WindowT *window);
void windowSetTitle(WindowT *window, char *title);
#endif // WINDOW_H

252
client/src/linux/linux.c Normal file
View file

@ -0,0 +1,252 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <SDL2/SDL.h>
#include "os.h"
#include "mouse.h"
#include "vesa.h"
static SDL_Window *_window = NULL;
static SDL_Renderer *_renderer = NULL;
static SDL_Surface *_surface = NULL;
static SurfaceT *_offScreenBuffer = NULL;
static SurfaceT *_activeSurface = NULL;
static uint16_t _width = 0;
static uint16_t _height = 0;
static MouseT _mouse;
void (*vbePutPixel)(uint16_t x, uint16_t y, PixelT pixel);
static void vbePutPixel32(uint16_t x, uint16_t y, PixelT pixel);
void mouseShutdown(void) {
// Eh, don't care.
}
int16_t mouseStartup(void) {
_mouse.active = 1;
_mouse.buttonCount = 3;
_mouse.buttonLeft = 0;
_mouse.buttonRight = 0;
_mouse.buttonMiddle = 0;
_mouse.buttonLeftWasDown = 0;
_mouse.buttonRightWasDown = 0;
_mouse.buttonMiddleWasDown = 0;
_mouse.x = 0;
_mouse.y = 0;
_mouse.w = vbeDisplayWidthGet();
_mouse.h = vbeDisplayHeightGet();
return _mouse.active;
}
MouseT *mouseRead(void) {
int mouseX = 0;
int mouseY = 0;
int buttons = 0;
SDL_Delay(1);
SDL_PumpEvents();
buttons = SDL_GetMouseState((int *)&mouseX, (int *)&mouseY);
_mouse.buttonLeftWasDown = _mouse.buttonLeft;
_mouse.buttonRightWasDown = _mouse.buttonRight;
_mouse.buttonMiddleWasDown = _mouse.buttonMiddle;
_mouse.buttonLeft = ((buttons & SDL_BUTTON_LMASK) != 0);
_mouse.buttonRight = ((buttons & SDL_BUTTON_RMASK) != 0);
_mouse.buttonMiddle = ((buttons & SDL_BUTTON_MMASK) != 0);
_mouse.x = mouseX;
_mouse.y = mouseY;
return &_mouse;
}
uint8_t vbeDisplayDepthGet(void) {
return 32;
}
uint16_t vbeDisplayHeightGet(void) {
return _height;
}
uint16_t vbeDisplayWidthGet(void) {
return _width;
}
PixelT vbeMakePixel(uint8_t red, uint8_t green, uint8_t blue) {
return
(red << 24) |
(green << 16) |
(blue << 8);
}
void vbePresent(void) {
SDL_SetRenderTarget(_renderer, NULL);
vbeSurfaceBlit(_offScreenBuffer, 0, 0);
SDL_RenderPresent(_renderer);
// Throttle this to some sane frame rate.
SDL_Delay(32);
}
static void vbePutPixel32(uint16_t x, uint16_t y, PixelT pixel) {
uint8_t red = (pixel & 0xff000000) >> 24;
uint8_t green = (pixel & 0x00ff0000) >> 16;
uint8_t blue = (pixel & 0x0000ff00) >> 8;
SDL_SetRenderDrawColor(_renderer, red, green, blue, 0xff);
SDL_RenderDrawPoint(_renderer, x, y);
}
int16_t vbeShowInfo(void) {
// Eh, don't care.
return 0;
}
int16_t vbeShutdown(void) {
vbeSurfaceDestroy(&_offScreenBuffer);
if (_renderer) {
SDL_DestroyRenderer(_renderer);
_renderer = NULL;
}
if (_window) {
SDL_DestroyWindow(_window);
_window = NULL;
}
SDL_Quit();
return 0;
}
uint8_t vbeStartup(uint16_t xRes, uint16_t yRes, uint8_t bpp) {
(void)bpp;
vbePutPixel = vbePutPixel32;
SDL_Init(SDL_INIT_EVERYTHING);
_window = SDL_CreateWindow("GUI Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xRes, yRes, SDL_WINDOW_ALLOW_HIGHDPI);
_surface = SDL_GetWindowSurface(_window);
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderSetLogicalSize(_renderer, xRes, yRes);
_offScreenBuffer = vbeSurfaceCreate(xRes, yRes);
_width = xRes;
_height = yRes;
return 0;
}
void vbeSurfaceBlit(SurfaceT *source, uint16_t x, uint16_t y) {
SDL_Rect r;
r.x = x;
r.y = y;
r.w = source->width;
r.h = source->height;
SDL_RenderCopy(_renderer, (SDL_Texture *)source->buffer.bits8, NULL, &r);
}
void vbeSurfaceClear(PixelT color) {
uint8_t red = (color & 0xff000000) >> 24;
uint8_t green = (color & 0x00ff0000) >> 16;
uint8_t blue = (color & 0x0000ff00) >> 8;
SDL_SetRenderDrawColor(_renderer, red, green, blue, 0xff);
SDL_RenderClear(_renderer);
}
SurfaceT *vbeSurfaceCreate(uint16_t width, uint16_t height) {
SDL_Texture *texture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
SDL_Texture *target = SDL_GetRenderTarget(_renderer);
SurfaceT *surface = (SurfaceT *)malloc(sizeof(SurfaceT));
surface->width = width;
surface->height = height;
surface->scanline = width * 4; // Always 32 bit.
surface->bytes = surface->scanline * height;
surface->buffer.bits8 = (uint8_t *)texture;
SDL_SetRenderTarget(_renderer, texture);
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 0xff);
SDL_RenderClear(_renderer);
SDL_SetRenderTarget(_renderer, target);
return surface;
}
void vbeSurfaceDestroy(SurfaceT **surface) {
SurfaceT *s = *surface;
SDL_DestroyTexture((SDL_Texture *)s->buffer.bits8);
free(s);
s = NULL;
}
void vbeSurfaceSet(SurfaceT *surface) {
SDL_Texture *texture = NULL;
if (surface) {
_activeSurface = surface;
} else {
_activeSurface = _offScreenBuffer;
}
texture = (SDL_Texture *)_activeSurface->buffer.bits8;
SDL_SetRenderTarget(_renderer, texture);
}
void vbeWaitVBlank(void) {
// Eh, don't care.
}

90
client/src/main.c Normal file
View file

@ -0,0 +1,90 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "vesa.h"
#include "mouse.h"
#include "image.h"
#include "font.h"
#include "gui.h"
#include "widget.h"
#include "desktop.h"
#include "window.h"
void test(void) {
MouseT *mouse = NULL;
DesktopT *desktop = NULL;
WindowT *w1 = NULL;
WindowT *w2 = NULL;
WindowT *w3 = NULL;
ImageT *pointer = NULL;
PixelT alpha;
vbeStartup(800, 600, 8);
mouseStartup();
desktop = guiStartup();
pointer = imageLoad("mouse.png");
alpha = imagePixelGet(pointer, 5, 0);
w1 = windowNew(25, 25, 300, 200, "Window 1");
w2 = windowNew(150, 150, 300, 200, "Window 2");
w3 = windowNew(300, 300, 300, 200, "Window 3");
guiAttach((WidgetT *)desktop, (WidgetT *)w1);
guiAttach((WidgetT *)desktop, (WidgetT *)w2);
guiAttach((WidgetT *)desktop, (WidgetT *)w3);
do {
mouse = mouseRead();
guiProcessMouse(mouse);
guiComposite();
imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha);
vbeWaitVBlank();
vbePresent();
} while (!(!mouse->buttonRight && mouse->buttonRightWasDown)); // Exit on release of right-click.
imageUnload(&pointer);
guiShutdown();
mouseShutdown();
vbeShutdown();
}
int main(int argc, char *argv[]) {
(void)argv;
if (argc > 1) {
vbeShowInfo();
return 0;
}
logOpen("test.log", 1);
test();
logClose();
#ifdef memoryLeakShow
memoryLeaksShow();
#endif
return 0;
}

1895
client/src/thirdparty/stb_ds.h vendored Normal file

File diff suppressed because it is too large Load diff

7897
client/src/thirdparty/stb_image.h vendored Normal file

File diff suppressed because it is too large Load diff

194
client/src/thirdparty/stb_leakcheck.h vendored Normal file
View file

@ -0,0 +1,194 @@
// stb_leakcheck.h - v0.6 - quick & dirty malloc leak-checking - public domain
// LICENSE
//
// See end of file.
#ifdef STB_LEAKCHECK_IMPLEMENTATION
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implement more than once
// if we've already included leakcheck before, undefine the macros
#ifdef malloc
#undef malloc
#undef free
#undef realloc
#endif
#ifndef STB_LEAKCHECK_OUTPUT_PIPE
#define STB_LEAKCHECK_OUTPUT_PIPE stdout
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
typedef struct malloc_info stb_leakcheck_malloc_info;
struct malloc_info
{
const char *file;
int line;
size_t size;
stb_leakcheck_malloc_info *next,*prev;
};
static stb_leakcheck_malloc_info *mi_head;
void *stb_leakcheck_malloc(size_t sz, const char *file, int line)
{
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi));
if (mi == NULL) return mi;
mi->file = file;
mi->line = line;
mi->next = mi_head;
if (mi_head)
mi->next->prev = mi;
mi->prev = NULL;
mi->size = (int) sz;
mi_head = mi;
return mi+1;
}
void stb_leakcheck_free(void *ptr)
{
if (ptr != NULL) {
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
mi->size = ~mi->size;
#ifndef STB_LEAKCHECK_SHOWALL
if (mi->prev == NULL) {
assert(mi_head == mi);
mi_head = mi->next;
} else
mi->prev->next = mi->next;
if (mi->next)
mi->next->prev = mi->prev;
free(mi);
#endif
}
}
void *stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line)
{
if (ptr == NULL) {
return stb_leakcheck_malloc(sz, file, line);
} else if (sz == 0) {
stb_leakcheck_free(ptr);
return NULL;
} else {
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
if (sz <= mi->size)
return ptr;
else {
#ifdef STB_LEAKCHECK_REALLOC_PRESERVE_MALLOC_FILELINE
void *q = stb_leakcheck_malloc(sz, mi->file, mi->line);
#else
void *q = stb_leakcheck_malloc(sz, file, line);
#endif
if (q) {
memcpy(q, ptr, mi->size);
stb_leakcheck_free(ptr);
}
return q;
}
}
}
static void stblkck_internal_print(const char *reason, stb_leakcheck_malloc_info *mi)
{
#if defined(_MSC_VER) && _MSC_VER < 1900 // 1900=VS 2015
// Compilers that use the old MS C runtime library don't have %zd
// and the older ones don't even have %lld either... however, the old compilers
// without "long long" don't support 64-bit targets either, so here's the
// compromise:
#if _MSC_VER < 1400 // before VS 2005
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %8d bytes at %p\n", reason, mi->file, mi->line, (int)mi->size, (void*)(mi+1));
#else
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %16lld bytes at %p\n", reason, mi->file, mi->line, (long long)mi->size, (void*)(mi+1));
#endif
#else
// Assume we have %zd on other targets.
#ifdef __MINGW32__
__mingw_fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
#else
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
#endif
#endif
}
void stb_leakcheck_dumpmem(void)
{
stb_leakcheck_malloc_info *mi = mi_head;
while (mi) {
if ((ptrdiff_t) mi->size >= 0)
stblkck_internal_print("LEAKED", mi);
mi = mi->next;
}
#ifdef STB_LEAKCHECK_SHOWALL
mi = mi_head;
while (mi) {
if ((ptrdiff_t) mi->size < 0)
stblkck_internal_print("FREED ", mi);
mi = mi->next;
}
#endif
}
#endif // STB_LEAKCHECK_IMPLEMENTATION
#if !defined(INCLUDE_STB_LEAKCHECK_H) || !defined(malloc)
#define INCLUDE_STB_LEAKCHECK_H
#include <stdlib.h> // we want to define the macros *after* stdlib to avoid a slew of errors
#define malloc(sz) stb_leakcheck_malloc(sz, __FILE__, __LINE__)
#define free(p) stb_leakcheck_free(p)
#define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__)
extern void * stb_leakcheck_malloc(size_t sz, const char *file, int line);
extern void * stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line);
extern void stb_leakcheck_free(void *ptr);
extern void stb_leakcheck_dumpmem(void);
#endif // INCLUDE_STB_LEAKCHECK_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

BIN
font/data/vga8x8.png (Stored with Git LFS) Normal file

Binary file not shown.

31
font/font.pro Normal file
View file

@ -0,0 +1,31 @@
#
# Kangaroo Punch Multi Player Game Server Mark II
# Copyright (C) 2020-2021 Scott Duensing
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
TEMPLATE = app
CONFIG -= qt
DESTDIR = $$OUT_PWD/bin
HEADERS = \
src/stb_image.h \
src/stb_leakcheck.h \
src/stb.h
SOURCES = \
src/stb.c \
src/main.c

83
font/src/main.c Normal file
View file

@ -0,0 +1,83 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include "stb.h"
#define BITMAP_FILE "/home/scott/code/kpmpgsmkii/font/data/vga8x8.png"
#define FONT_FILE "/home/scott/code/kpmpgsmkii/client/bin/vga8x8.dat"
int main(int argc, char *argv[]) {
unsigned char *font = NULL;
unsigned char data = 0;
FILE *out = NULL;
int bits = 0;
int x;
int y;
int n;
int w;
int h;
(void)argc;
(void)argv;
// Load 8x8 font from disk. Font is in a 16x16 grid.
font = stbi_load(BITMAP_FILE, (int *)&w, (int *)&h, (int *)&n, 3);
if (!font) return 1;
// Create data file for font.
out = fopen(FONT_FILE, "wb");
if (!out) {
stbi_image_free(font);
return 2;
}
// Provide some metadata for enhancement later.
fputc(8, out); // Width of characters
fputc(8, out); // Height of characters
fputc(16, out); // Number of characters per row
fputc(255, out); // Number of characters - 1
// Convert bitmap to actual bits.
for (y=0; y<h; y++) {
for (x=0; x<w; x++) {
data <<= 1;
data |= (font[(y * w * 3) + (x * 3)] != 0);
bits++;
if (bits > 7) {
bits = 0;
fputc(data, out);
}
}
}
fclose(out);
// Clean up.
stbi_image_free(font);
// Prove we cleaned up.
stb_leakcheck_dumpmem();
return 0;
}

26
font/src/stb.c Normal file
View file

@ -0,0 +1,26 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_PNG
#include "stb_image.h"
#define STB_LEAKCHECK_IMPLEMENTATION
#include "stb_leakcheck.h"

29
font/src/stb.h Normal file
View file

@ -0,0 +1,29 @@
/*
* Kangaroo Punch Multi Player Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef STB_H
#define STB_H
#include "stb_image.h"
#include "stb_leakcheck.h"
#endif // STB_H

7897
font/src/stb_image.h Normal file

File diff suppressed because it is too large Load diff

194
font/src/stb_leakcheck.h Normal file
View file

@ -0,0 +1,194 @@
// stb_leakcheck.h - v0.6 - quick & dirty malloc leak-checking - public domain
// LICENSE
//
// See end of file.
#ifdef STB_LEAKCHECK_IMPLEMENTATION
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implement more than once
// if we've already included leakcheck before, undefine the macros
#ifdef malloc
#undef malloc
#undef free
#undef realloc
#endif
#ifndef STB_LEAKCHECK_OUTPUT_PIPE
#define STB_LEAKCHECK_OUTPUT_PIPE stdout
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
typedef struct malloc_info stb_leakcheck_malloc_info;
struct malloc_info
{
const char *file;
int line;
size_t size;
stb_leakcheck_malloc_info *next,*prev;
};
static stb_leakcheck_malloc_info *mi_head;
void *stb_leakcheck_malloc(size_t sz, const char *file, int line)
{
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi));
if (mi == NULL) return mi;
mi->file = file;
mi->line = line;
mi->next = mi_head;
if (mi_head)
mi->next->prev = mi;
mi->prev = NULL;
mi->size = (int) sz;
mi_head = mi;
return mi+1;
}
void stb_leakcheck_free(void *ptr)
{
if (ptr != NULL) {
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
mi->size = ~mi->size;
#ifndef STB_LEAKCHECK_SHOWALL
if (mi->prev == NULL) {
assert(mi_head == mi);
mi_head = mi->next;
} else
mi->prev->next = mi->next;
if (mi->next)
mi->next->prev = mi->prev;
free(mi);
#endif
}
}
void *stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line)
{
if (ptr == NULL) {
return stb_leakcheck_malloc(sz, file, line);
} else if (sz == 0) {
stb_leakcheck_free(ptr);
return NULL;
} else {
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
if (sz <= mi->size)
return ptr;
else {
#ifdef STB_LEAKCHECK_REALLOC_PRESERVE_MALLOC_FILELINE
void *q = stb_leakcheck_malloc(sz, mi->file, mi->line);
#else
void *q = stb_leakcheck_malloc(sz, file, line);
#endif
if (q) {
memcpy(q, ptr, mi->size);
stb_leakcheck_free(ptr);
}
return q;
}
}
}
static void stblkck_internal_print(const char *reason, stb_leakcheck_malloc_info *mi)
{
#if defined(_MSC_VER) && _MSC_VER < 1900 // 1900=VS 2015
// Compilers that use the old MS C runtime library don't have %zd
// and the older ones don't even have %lld either... however, the old compilers
// without "long long" don't support 64-bit targets either, so here's the
// compromise:
#if _MSC_VER < 1400 // before VS 2005
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %8d bytes at %p\n", reason, mi->file, mi->line, (int)mi->size, (void*)(mi+1));
#else
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %16lld bytes at %p\n", reason, mi->file, mi->line, (long long)mi->size, (void*)(mi+1));
#endif
#else
// Assume we have %zd on other targets.
#ifdef __MINGW32__
__mingw_fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
#else
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
#endif
#endif
}
void stb_leakcheck_dumpmem(void)
{
stb_leakcheck_malloc_info *mi = mi_head;
while (mi) {
if ((ptrdiff_t) mi->size >= 0)
stblkck_internal_print("LEAKED", mi);
mi = mi->next;
}
#ifdef STB_LEAKCHECK_SHOWALL
mi = mi_head;
while (mi) {
if ((ptrdiff_t) mi->size < 0)
stblkck_internal_print("FREED ", mi);
mi = mi->next;
}
#endif
}
#endif // STB_LEAKCHECK_IMPLEMENTATION
#if !defined(INCLUDE_STB_LEAKCHECK_H) || !defined(malloc)
#define INCLUDE_STB_LEAKCHECK_H
#include <stdlib.h> // we want to define the macros *after* stdlib to avoid a slew of errors
#define malloc(sz) stb_leakcheck_malloc(sz, __FILE__, __LINE__)
#define free(p) stb_leakcheck_free(p)
#define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__)
extern void * stb_leakcheck_malloc(size_t sz, const char *file, int line);
extern void * stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line);
extern void stb_leakcheck_free(void *ptr);
extern void stb_leakcheck_dumpmem(void);
#endif // INCLUDE_STB_LEAKCHECK_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

24
kpmpgsmkii.pro Normal file
View file

@ -0,0 +1,24 @@
#
# Kangaroo Punch Multi Player Game Server Mark II
# Copyright (C) 2020-2021 Scott Duensing
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
TEMPLATE = SUBDIRS
CONFIG *= ORDERED
SUBDIRS = \
font \
client