From 63cc18a5bf1d4df4e2ac5979412220516cf828d2 Mon Sep 17 00:00:00 2001 From: toncho11 Date: Mon, 25 May 2026 22:41:04 +0200 Subject: [PATCH 1/7] Add initial support for Nanox graphics backend --- lbaselib.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 227 insertions(+), 7 deletions(-) diff --git a/lbaselib.c b/lbaselib.c index d3e992fd09..1819171bdb 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -23,6 +23,15 @@ #include +#ifdef USE_NANOX_BACKEND +#include +#ifndef MWRGB +#define MWRGB(r,g,b) ((((unsigned long)(r)) << 16) | \ + (((unsigned long)(g)) << 8) | \ + ((unsigned long)(b))) +#endif +#endif + typedef unsigned char byte; byte __far *VGA = (byte __far *)0xA0000000L; @@ -517,11 +526,185 @@ static int luaB_tostring (lua_State *L) { } //START non-standard functions +/* +** Optional graphics backend for the extra Lua drawing functions. +** +** Default build (no USE_NANOX_BACKEND): +** - vga_init(mode) keeps the original BIOS VGA mode-switch behavior. +** - plot_pixel/plot_line keep the original direct VGA framebuffer behavior. +** - sleep_ms(ms) keeps the original usleep-based delay. +** - close_graphics() switches back to text mode 3. +** +** Build with -DUSE_NANOX_BACKEND: +** - vga_init(0x13) opens a 320x200 Nano-X window for compatibility with +** existing Lua scripts. +** - vga_init(3) closes the Nano-X window for old-script compatibility. +** - plot_pixel/plot_line draw into that Nano-X window. +** - sleep_ms(ms) waits while also processing Nano-X events. +** - close_graphics() closes the Nano-X window and connection. +*/ + +#ifdef USE_NANOX_BACKEND + +static GR_WINDOW_ID nx_win = 0; +static GR_GC_ID nx_gc = 0; +static int nx_open = 0; +static int nx_quit_requested = 0; + +static GR_COLOR map_vga_color_to_nanox(unsigned int c) +{ + /* Basic VGA 16-color palette. The cube demo mostly uses 0 and 15. */ + static const GR_COLOR pal[16] = { + MWRGB(0, 0, 0), /* 0 black */ + MWRGB(0, 0, 170), /* 1 blue */ + MWRGB(0, 170, 0), /* 2 green */ + MWRGB(0, 170, 170), /* 3 cyan */ + MWRGB(170, 0, 0), /* 4 red */ + MWRGB(170, 0, 170), /* 5 magenta */ + MWRGB(170, 85, 0), /* 6 brown */ + MWRGB(170, 170, 170), /* 7 light gray */ + MWRGB(85, 85, 85), /* 8 dark gray */ + MWRGB(85, 85, 255), /* 9 light blue */ + MWRGB(85, 255, 85), /* 10 light green */ + MWRGB(85, 255, 255), /* 11 light cyan */ + MWRGB(255, 85, 85), /* 12 light red */ + MWRGB(255, 85, 255), /* 13 light magenta */ + MWRGB(255, 255, 85), /* 14 yellow */ + MWRGB(255, 255, 255) /* 15 white */ + }; + + return pal[c & 15]; +} + +static void close_graphics_backend(void) +{ + if (!nx_open) + return; + + if (nx_gc) + GrDestroyGC(nx_gc); + + if (nx_win) + GrDestroyWindow(nx_win); + + GrClose(); + + nx_win = 0; + nx_gc = 0; + nx_open = 0; + nx_quit_requested = 0; +} + static int luaB_vga_init(lua_State *L) { - lua_Number mode = luaL_checknumber(L, 1); // Get the argument + /* Keep the same Lua signature as the VGA backend. In Nano-X mode, + mode 0x13 opens a 320x200 window and mode 3 closes it, so old + VGA-style scripts can still use vga_init(3) on exit. */ + lua_Number mode = luaL_checknumber(L, 1); unsigned short int mode_int = (unsigned short int) mode; + if (mode_int == 3) { + close_graphics_backend(); + return 0; + } + + if (nx_open) + return 0; + + if (GrOpen() < 0) + return luaL_error(L, "cannot open Nano-X"); + + nx_win = GrNewWindow(GR_ROOT_WINDOW_ID, + 0, 0, + 320, 200, + 0, + map_vga_color_to_nanox(0), + map_vga_color_to_nanox(0)); + + nx_gc = GrNewGC(); + + GrSelectEvents(nx_win, + GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_KEY_DOWN | + GR_EVENT_MASK_CLOSE_REQ); + + GrMapWindow(nx_win); + GrFlush(); + + nx_open = 1; + nx_quit_requested = 0; + + return 0; +} + +static int luaB_close_graphics(lua_State *L) +{ + (void)L; + close_graphics_backend(); + return 0; +} + +static void handle_nanox_event(GR_EVENT *ev) +{ + switch (ev->type) { + case GR_EVENT_TYPE_EXPOSURE: + /* The Lua layer has no redraw callback. For animations like the cube, + clearing the exposed window and letting the next frame draw is enough. */ + if (nx_open) + GrClearWindow(nx_win, 0); + break; + + case GR_EVENT_TYPE_CLOSE_REQ: + nx_quit_requested = 1; + break; + + case GR_EVENT_TYPE_KEY_DOWN: + /* ESC or q stops the Lua animation through pcall(). */ + if (ev->keystroke.ch == 27 || ev->keystroke.ch == 'q') + nx_quit_requested = 1; + break; + + default: + break; + } +} + +static int process_nanox_events(lua_State *L, unsigned int timeout_ms) +{ + GR_EVENT ev; + + if (!nx_open) + return 0; + + if (timeout_ms > 0) { + /* Wait for one event, or until the delay expires. */ + GrGetNextEventTimeout(&ev, timeout_ms); + if (ev.type != GR_EVENT_TYPE_NONE) + handle_nanox_event(&ev); + } + + /* Drain queued events without blocking. */ + while (1) { + GrCheckNextEvent(&ev); + if (ev.type == GR_EVENT_TYPE_NONE) + break; + handle_nanox_event(&ev); + } + + if (nx_quit_requested) { + close_graphics_backend(); + return luaL_error(L, "Interrupted"); + } + + return 0; +} + +#else /* !USE_NANOX_BACKEND */ + +/* Original VGA mode-set logic, factored out so close_graphics() can also + switch to text mode 3 without changing vga_init() semantics. */ +static void set_vga_mode(unsigned short int mode_int) +{ _asm{ push si push di @@ -534,9 +717,27 @@ static int luaB_vga_init(lua_State *L) pop di pop si } - return 1; } +static int luaB_vga_init(lua_State *L) +{ + lua_Number mode = luaL_checknumber(L, 1); // Get the argument + unsigned short int mode_int = (unsigned short int) mode; + + set_vga_mode(mode_int); + + return 0; +} + +static int luaB_close_graphics(lua_State *L) +{ + (void)L; + set_vga_mode(3); + return 0; +} + +#endif /* USE_NANOX_BACKEND */ + static int luaB_plot_pixel(lua_State *L) { lua_Number number = luaL_checknumber(L, 1); @@ -548,10 +749,18 @@ unsigned int y = (unsigned int) number; number = luaL_checknumber(L, 3); unsigned int c = (unsigned int) number; +#ifdef USE_NANOX_BACKEND + if (!nx_open) + return luaL_error(L, "graphics backend not initialized"); + + GrSetGCForeground(nx_gc, map_vga_color_to_nanox(c)); + GrPoint(nx_win, nx_gc, x, y); +#else /* y*320 = y*256 + y*64 = y*2^8 + y*2^6 */ VGA[(y<<8)+(y<<6)+x]=c; +#endif -return 1; +return 0; } static int luaB_plot_line(lua_State *L) @@ -571,6 +780,13 @@ static int luaB_plot_line(lua_State *L) number = luaL_checknumber(L, 5); unsigned int color = (unsigned int) number; +#ifdef USE_NANOX_BACKEND + if (!nx_open) + return luaL_error(L, "graphics backend not initialized"); + + GrSetGCForeground(nx_gc, map_vga_color_to_nanox(color)); + GrLine(nx_win, nx_gc, x0, y0, x1, y1); +#else int dx = abs((int)x1 - x0); int sx = x0 < x1 ? 1 : -1; int dy = abs((int)y1 - y0); @@ -586,8 +802,9 @@ static int luaB_plot_line(lua_State *L) if (e2 > -dx) { err -= dy; x0 += sx; } if (e2 < dy) { err += dx; y0 += sy; } } +#endif - return 1; + return 0; } static int luaB_sleep_ms(lua_State *L) @@ -595,9 +812,12 @@ static int luaB_sleep_ms(lua_State *L) lua_Number number = luaL_checknumber(L, 1); unsigned int ms = (unsigned int) number; +#ifdef USE_NANOX_BACKEND + return process_nanox_events(L, ms); +#else usleep(1000 * ms); - - return 1; + return 0; +#endif } //END non-standard functions @@ -627,6 +847,7 @@ static const luaL_Reg base_funcs[] = { {"type", luaB_type}, {"xpcall", luaB_xpcall}, {"vga_init", luaB_vga_init}, + {"close_graphics", luaB_close_graphics}, {"plot_pixel", luaB_plot_pixel}, {"plot_line", luaB_plot_line}, {"sleep_ms", luaB_sleep_ms}, @@ -649,4 +870,3 @@ LUAMOD_API int luaopen_base (lua_State *L) { lua_setfield(L, -2, "_VERSION"); return 1; } - From 5a0232a0bd1ea68419ed459e4617edb147dfb9f4 Mon Sep 17 00:00:00 2001 From: toncho11 Date: Sat, 30 May 2026 09:29:26 +0200 Subject: [PATCH 2/7] Update Makefile.elks to support Nano X client functions --- Makefile.elks | 92 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 13 deletions(-) diff --git a/Makefile.elks b/Makefile.elks index df42204890..10f333a3b7 100644 --- a/Makefile.elks +++ b/Makefile.elks @@ -1,6 +1,7 @@ # C86 Makefile for ELKS using OpenWatcom C ############# Standard Section for Open Watcom C ############## + ifndef TOPDIR $(error ELKS TOPDIR is not defined) endif @@ -11,46 +12,111 @@ endif CC = owcc LD = owcc + CLBASE = -mcmodel=l CLBASE += -bnone -march=i86 -std=c99 CLBASE += -fno-stack-check -fnostdlib -fsigned-char CLBASE += -Wc,-fpc -Wc,-zev -Wc,-zls -Wc,-x -Wc,-wcd=303 + WARNINGS = -Wall -Wextra + INCLUDES = -I$(TOPDIR)/libc/include -I$(TOPDIR)/elks/include INCLUDES += -I$(TOPDIR)/libc/include/watcom + DEFINES = -D__ELKS__ -DLUA_USE_C89 + +# ------------------------------------------------------------ +# Optional Nano-X client backend +# +# Default: +# make -f Makefile.elks +# +# Build Lua with Nano-X client support: +# make -f Makefile.elks USE_NANOX_BACKEND=1 +# +# NANOX_DIR must point to the Nano-X source directory containing: +# include/ +# nanox/ +# drivers/ +# elksdrivers/ +# +# Example override: +# make -f Makefile.elks USE_NANOX_BACKEND=1 NANOX_DIR=$(TOPDIR)/elkscmd/nano-X +# ------------------------------------------------------------ + +USE_NANOX_BACKEND ?= 0 +NANOX_DIR ?= $(TOPDIR)/elkscmd/nano-X + +# In the ELKS Nano-X Makefile, osdep.c is drivers/osdep.c. +# If your tree has it somewhere else, override this variable. +NANOX_OSDEP ?= $(NANOX_DIR)/drivers/osdep.c + +ifeq ($(USE_NANOX_BACKEND),1) +DEFINES += -DUSE_NANOX_BACKEND +DEFINES += -DELKS=1 -DUNIX=1 -DNONETWORK=0 +DEFINES += -DMWPIXEL_FORMAT=MWPF_PALETTE +DEFINES += -DSCREEN_PIXTYPE=MWPF_PALETTE + +INCLUDES += -I$(NANOX_DIR)/include +INCLUDES += -I$(NANOX_DIR)/nanox +INCLUDES += -I$(NANOX_DIR)/drivers +INCLUDES += -I$(NANOX_DIR)/elksdrivers + +NANOX_CLIENT_OBJS = nx_client.obj nx_nxproto.obj nx_nxutil.obj nx_osdep.obj +endif + +BINDIR = ../elks-bin +LOCALFLAGS = -DNDEBUG +PROG = lua + CFLAGS = -Os $(CLBASE) $(WARNINGS) $(INCLUDES) $(DEFINES) $(LOCALFLAGS) + LDBASE = -bos2 -s LDBASE += -Wl,option -Wl,dosseg LDBASE += -Wl,option -Wl,start=_start LDBASE += -Wl,option -Wl,nodefaultlibs LDBASE += -Wl,option -Wl,stack=0x6000 LDBASE += -Wl,option -Wl,heapsize=512 + LDFLAGS = $(LDBASE) + LDLIBS = -Wl,library -Wl,$(TOPDIR)/libc/libcl.lib -lm -OBJS = $(SRCS:.c=.obj) +SRCS = lua.c mem.c lmathlib.c lapi.c lctype.c lfunc.c loslib.c \ + ltable.c lundump.c lauxlib.c ldblib.c lgc.c lmem.c \ + lparser.c ltablib.c lutf8lib.c lbaselib.c ldebug.c \ + linit.c loadlib.c lstate.c ltm.c lvm.c lcode.c \ + ldo.c liolib.c lobject.c lstring.c lzio.c \ + lcorolib.c ldump.c llex.c lopcodes.c lstrlib.c + +OBJS = $(SRCS:.c=.obj) $(NANOX_CLIENT_OBJS) + %.obj: %.c $(CC) -c $(CFLAGS) -o $*.obj $< ############# End of Standard Section ############## -BINDIR = ../elks-bin -LOCALFLAGS = -DNDEBUG -PROG = lua - -SRCS = lua.c mem.c lmathlib.c lapi.c lctype.c lfunc.c loslib.c \ - ltable.c lundump.c lauxlib.c ldblib.c lgc.c lmem.c \ - lparser.c ltablib.c lutf8lib.c lbaselib.c ldebug.c \ - linit.c loadlib.c lstate.c ltm.c lvm.c lcode.c \ - ldo.c liolib.c lobject.c lstring.c lzio.c \ - lcorolib.c ldump.c llex.c lopcodes.c lstrlib.c \ - - all: $(PROG) $(PROG): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) +# ------------------------------------------------------------ +# Nano-X client-side objects compiled directly into Lua. +# This avoids linking against a prebuilt libnano-X.a/.lib. +# ------------------------------------------------------------ + +nx_client.obj: $(NANOX_DIR)/nanox/client.c + $(CC) -c $(CFLAGS) -o $@ $< + +nx_nxproto.obj: $(NANOX_DIR)/nanox/nxproto.c + $(CC) -c $(CFLAGS) -o $@ $< + +nx_nxutil.obj: $(NANOX_DIR)/nanox/nxutil.c + $(CC) -c $(CFLAGS) -o $@ $< + +nx_osdep.obj: $(NANOX_OSDEP) + $(CC) -c $(CFLAGS) -o $@ $< + clean: rm -f $(PROG) *.obj tmp.h From ce164872f4f4e78e4960f6413b8c5bb37f5173f2 Mon Sep 17 00:00:00 2001 From: toncho11 Date: Sat, 30 May 2026 09:34:52 +0200 Subject: [PATCH 3/7] Update lbaselib.c to better supprt access to nano x main header --- lbaselib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbaselib.c b/lbaselib.c index 1819171bdb..85b27788e1 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -24,7 +24,7 @@ #include #ifdef USE_NANOX_BACKEND -#include +#include "nano-X.h" #ifndef MWRGB #define MWRGB(r,g,b) ((((unsigned long)(r)) << 16) | \ (((unsigned long)(g)) << 8) | \ From 7b27264668e628296cd991f7ce4c1e0a4d187c90 Mon Sep 17 00:00:00 2001 From: toncho11 Date: Sat, 30 May 2026 09:54:27 +0200 Subject: [PATCH 4/7] Update lbaselib.c and fix event handling problem --- lbaselib.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/lbaselib.c b/lbaselib.c index 85b27788e1..3071a4cc33 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -676,20 +676,12 @@ static int process_nanox_events(lua_State *L, unsigned int timeout_ms) if (!nx_open) return 0; - if (timeout_ms > 0) { - /* Wait for one event, or until the delay expires. */ - GrGetNextEventTimeout(&ev, timeout_ms); - if (ev.type != GR_EVENT_TYPE_NONE) - handle_nanox_event(&ev); - } + memset(&ev, 0, sizeof(ev)); - /* Drain queued events without blocking. */ - while (1) { - GrCheckNextEvent(&ev); - if (ev.type == GR_EVENT_TYPE_NONE) - break; + GrGetNextEventTimeout(&ev, timeout_ms); + + if (ev.type != 0) handle_nanox_event(&ev); - } if (nx_quit_requested) { close_graphics_backend(); From c6adbba05bfc46abd12af1b3e897fc1239adcfdc Mon Sep 17 00:00:00 2001 From: toncho11 Date: Sat, 30 May 2026 23:23:50 +0200 Subject: [PATCH 5/7] Refined Makefile.elks --- Makefile.elks | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/Makefile.elks b/Makefile.elks index 10f333a3b7..748ade343c 100644 --- a/Makefile.elks +++ b/Makefile.elks @@ -1,7 +1,7 @@ -# C86 Makefile for ELKS using OpenWatcom C - -############# Standard Section for Open Watcom C ############## +# Lua Makefile for ELKS, compiled using OpenWatcom C +# make -f Makefile.elks +# ELKS' TOPDIR and WATCOM variables are required ifndef TOPDIR $(error ELKS TOPDIR is not defined) endif @@ -26,30 +26,15 @@ INCLUDES += -I$(TOPDIR)/libc/include/watcom DEFINES = -D__ELKS__ -DLUA_USE_C89 # ------------------------------------------------------------ -# Optional Nano-X client backend -# -# Default: -# make -f Makefile.elks -# -# Build Lua with Nano-X client support: -# make -f Makefile.elks USE_NANOX_BACKEND=1 -# -# NANOX_DIR must point to the Nano-X source directory containing: -# include/ -# nanox/ -# drivers/ -# elksdrivers/ -# -# Example override: -# make -f Makefile.elks USE_NANOX_BACKEND=1 NANOX_DIR=$(TOPDIR)/elkscmd/nano-X +# Optional Nano-X client backend. Switches graphics from VGA to Nano-X. +# NANOX_DIR must point to the Nano-X source directory containing: include/ nanox/ drivers/ +# Example console override: +# make -f Makefile.elks USE_NANOX_BACKEND=1 NANOX_DIR=/root/microwindows/src +# Example usage: +# /bin/nano-x & /bin/lua /root/drawcube.lua # ------------------------------------------------------------ - USE_NANOX_BACKEND ?= 0 -NANOX_DIR ?= $(TOPDIR)/elkscmd/nano-X - -# In the ELKS Nano-X Makefile, osdep.c is drivers/osdep.c. -# If your tree has it somewhere else, override this variable. -NANOX_OSDEP ?= $(NANOX_DIR)/drivers/osdep.c +NANOX_DIR ?= /root/toncho11_microwindows/src ifeq ($(USE_NANOX_BACKEND),1) DEFINES += -DUSE_NANOX_BACKEND @@ -60,7 +45,6 @@ DEFINES += -DSCREEN_PIXTYPE=MWPF_PALETTE INCLUDES += -I$(NANOX_DIR)/include INCLUDES += -I$(NANOX_DIR)/nanox INCLUDES += -I$(NANOX_DIR)/drivers -INCLUDES += -I$(NANOX_DIR)/elksdrivers NANOX_CLIENT_OBJS = nx_client.obj nx_nxproto.obj nx_nxutil.obj nx_osdep.obj endif @@ -115,7 +99,7 @@ nx_nxproto.obj: $(NANOX_DIR)/nanox/nxproto.c nx_nxutil.obj: $(NANOX_DIR)/nanox/nxutil.c $(CC) -c $(CFLAGS) -o $@ $< -nx_osdep.obj: $(NANOX_OSDEP) +nx_osdep.obj: $(NANOX_DIR)/drivers/osdep.c $(CC) -c $(CFLAGS) -o $@ $< clean: From 4446e09e9d191a4ea414dfdcd7ca2ebe56750f2a Mon Sep 17 00:00:00 2001 From: toncho11 Date: Sat, 30 May 2026 23:24:51 +0200 Subject: [PATCH 6/7] Update Makefile.elks --- Makefile.elks | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.elks b/Makefile.elks index 748ade343c..b894ffef92 100644 --- a/Makefile.elks +++ b/Makefile.elks @@ -33,7 +33,7 @@ DEFINES = -D__ELKS__ -DLUA_USE_C89 # Example usage: # /bin/nano-x & /bin/lua /root/drawcube.lua # ------------------------------------------------------------ -USE_NANOX_BACKEND ?= 0 +USE_NANOX_BACKEND ?= 1 NANOX_DIR ?= /root/toncho11_microwindows/src ifeq ($(USE_NANOX_BACKEND),1) From 584c3193760fef39beb2e7f3054866321a291cc6 Mon Sep 17 00:00:00 2001 From: toncho11 Date: Sat, 30 May 2026 23:29:20 +0200 Subject: [PATCH 7/7] Update Makefile.elks --- Makefile.elks | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.elks b/Makefile.elks index b894ffef92..1f1695f5c1 100644 --- a/Makefile.elks +++ b/Makefile.elks @@ -26,14 +26,14 @@ INCLUDES += -I$(TOPDIR)/libc/include/watcom DEFINES = -D__ELKS__ -DLUA_USE_C89 # ------------------------------------------------------------ -# Optional Nano-X client backend. Switches graphics from VGA to Nano-X. +# Optional Nano-X client backend. Switches graphics from VGA to Nano-X when USE_NANOX_BACKEND = 1 # NANOX_DIR must point to the Nano-X source directory containing: include/ nanox/ drivers/ # Example console override: # make -f Makefile.elks USE_NANOX_BACKEND=1 NANOX_DIR=/root/microwindows/src # Example usage: # /bin/nano-x & /bin/lua /root/drawcube.lua # ------------------------------------------------------------ -USE_NANOX_BACKEND ?= 1 +USE_NANOX_BACKEND ?= 0 NANOX_DIR ?= /root/toncho11_microwindows/src ifeq ($(USE_NANOX_BACKEND),1)