From b4644bbd6fdb08e9696795dbe2f94cb80094407c Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Mon, 6 Jan 2025 04:39:01 +0100 Subject: [PATCH 01/15] first steps to add SDL2 support Since SDL2 requires the main() function to be called with C linkage, and I don't wan't to mess around with linking C with C++ anymore, I just converted the frontpanel library to C... With SDL2 the JPEG code in the frontpanel library isn't used anymore, instead SDL2_image is used to load texture files. This also adds support for other file types (bmp, png, ppm, ...). SDL2 (and macOS, and possible other OS's) require drawing, event handling, window creation etc. to be done from the main thread. So the simulator code now runs in a separate thread. Invoking just "make" compiles for X11, "WANT_SDL=YES make" compiles for SDL2. Not perfect, more work to do. --- Makefile | 2 + README.md | 27 +- altairsim/conf/system.conf | 14 +- altairsim/srcsim/Makefile | 104 +- altairsim/srcsim/simcfg.c | 52 +- altairsim/srcsim/simctl.c | 28 +- cpmsim/srcsim/Makefile | 26 +- cromemcosim/srcsim/Makefile | 105 +- cromemcosim/srcsim/simctl.c | 28 +- doc/CREDITS | 1 + doc/README-debian.txt | 6 +- doc/README-osx.txt | 25 +- doc/README-wsl.txt | 7 +- frontpanel/COPYING | 1 + frontpanel/Makefile | 50 +- frontpanel/README | 19 +- frontpanel/frontpanel.h | 106 +- frontpanel/{jpeg.cpp => jpeg.c} | 109 +- frontpanel/jpeg.h | 14 +- frontpanel/lp_font.c | 136 ++ frontpanel/lp_font.cpp | 143 -- frontpanel/lp_font.h | 10 +- frontpanel/lp_gfx.c | 923 +++++++++++++ frontpanel/lp_gfx.cpp | 875 ------------ frontpanel/lp_gfx.h | 235 ++-- frontpanel/lp_main.c | 422 ++++++ frontpanel/lp_main.cpp | 354 ----- frontpanel/lp_main.h | 25 +- frontpanel/lp_materials.c | 340 +++++ frontpanel/lp_materials.cpp | 340 ----- frontpanel/lp_materials.h | 42 +- frontpanel/lp_switch.c | 933 +++++++++++++ frontpanel/lp_switch.cpp | 978 -------------- frontpanel/lp_switch.h | 177 +-- frontpanel/lp_utils.c | 845 ++++++++++++ frontpanel/lp_utils.cpp | 1072 --------------- frontpanel/lp_utils.h | 166 ++- frontpanel/lp_window.c | 1247 ++++++++++++++++++ frontpanel/lp_window.cpp | 1049 --------------- frontpanel/lpanel.c | 2067 +++++++++++++++++++++++++++++ frontpanel/lpanel.cpp | 2188 ------------------------------- frontpanel/lpanel.h | 566 ++++---- frontpanel/lpanel_data.h | 55 +- imsaisim/conf_2d/system.conf | 12 +- imsaisim/conf_3d/system.conf | 12 +- imsaisim/srcsim/Makefile | 105 +- imsaisim/srcsim/simcfg.c | 52 +- imsaisim/srcsim/simctl.c | 28 +- intelmdssim/srcsim/Makefile | 104 +- intelmdssim/srcsim/simctl.c | 28 +- iodevices/cromemco-dazzler.c | 590 +++++---- iodevices/cromemco-dazzler.h | 2 + iodevices/imsai-vio.c | 359 ++++- iodevices/imsai-vio.h | 8 +- iodevices/proctec-vdm.c | 249 +++- iodevices/proctec-vdm.h | 8 +- mosteksim/srcsim/Makefile | 26 +- z80core/fpmain.cpp | 15 - z80core/simmain.c | 5 +- z80core/simmain.h | 14 +- z80core/simsdl.c | 154 +++ z80core/simsdl.h | 27 + z80sim/srcsim/Makefile | 26 +- 63 files changed, 9245 insertions(+), 8491 deletions(-) rename frontpanel/{jpeg.cpp => jpeg.c} (77%) create mode 100644 frontpanel/lp_font.c delete mode 100644 frontpanel/lp_font.cpp create mode 100644 frontpanel/lp_gfx.c delete mode 100644 frontpanel/lp_gfx.cpp create mode 100644 frontpanel/lp_main.c delete mode 100644 frontpanel/lp_main.cpp create mode 100644 frontpanel/lp_materials.c delete mode 100644 frontpanel/lp_materials.cpp create mode 100644 frontpanel/lp_switch.c delete mode 100644 frontpanel/lp_switch.cpp create mode 100644 frontpanel/lp_utils.c delete mode 100644 frontpanel/lp_utils.cpp create mode 100644 frontpanel/lp_window.c delete mode 100644 frontpanel/lp_window.cpp create mode 100644 frontpanel/lpanel.c delete mode 100644 frontpanel/lpanel.cpp delete mode 100644 z80core/fpmain.cpp create mode 100644 z80core/simsdl.c create mode 100644 z80core/simsdl.h diff --git a/Makefile b/Makefile index 11ee2bbe..71c95849 100644 --- a/Makefile +++ b/Makefile @@ -142,5 +142,7 @@ distclean: $(MAKE) -C $$subdir/srcsim distclean; \ done +.NOTPARALLEL: all + .PHONY: all tools libs bioses misc machines reassemble FORCE \ install uninstall clean distclean diff --git a/README.md b/README.md index 0ebe58ce..65af8554 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,22 @@ Full documentation is at https://www.icl1900.co.uk/unix4fun/z80pack ## Ubuntu ### Building -First install the needed dependencies: +First install the needed dependencies for X11: sudo apt install build-essential libglu1-mesa-dev libjpeg9-dev -Then run +or for SDL2: + + sudo apt install build-essential libsdl2-dev libsdl2-image-dev + +Then for X11 run make +or for SDL2 run + + WANT_SDL=YES make + to build all the MACHINES mentioned in the Makefile. ## Release vs Development @@ -42,7 +50,8 @@ finished release. ### Running CP/M 2.2 -CP/M 2.2 is the ancestor of MS-DOS. Use this command to invoke CP/M 2.2 with two disks containing some sample programs and sources. +CP/M 2.2 is the ancestor of MS-DOS. Use this command to invoke CP/M 2.2 with +two disks containing some sample programs and sources. (cd cpmsim; ./cpm22) @@ -92,7 +101,8 @@ Clock frequency 630.22 MHz ### Running CP/M 3 -CP/M 3 was the next generation of CP/M with features from MP/M to notably be able to use more RAM along with a lot of other nice features. +CP/M 3 was the next generation of CP/M with features from MP/M to notably +be able to use more RAM along with a lot of other nice features. Run with: @@ -173,10 +183,11 @@ A>dir a: A: CPM3 SYS : VT100DYN COM : TRACE UTL : HIST UTL : PROFILE SUB SYSTEM FILE(S) EXIST A>dir b: -B: BNKBDOS3 SPR : CPM3 SYS : LDRBIOS3 MAC : SCB MAC : RESBDOS3 SPR : BIOS3 MAC : PATCH COM -B: GENCPM COM : BDOS3 SPR : GENCPM DAT : BOOT Z80 : M80 COM : LINK COM : L80 COM -B: WM COM : MAC COM : WM HLP : BNKBIOS3 SPR : LDR SUB : INITDIR COM : CPMLDR COM -B: COPYSYS COM : CPMLDR REL : RMAC COM : SYSGEN SUB +B: BNKBDOS3 SPR : CPM3 SYS : LDRBIOS3 MAC : SCB MAC : RESBDOS3 SPR +B: BIOS3 MAC : PATCH COM : GENCPM COM : BDOS3 SPR : GENCPM DAT +B: BOOT Z80 : M80 COM : LINK COM : L80 COM : WM COM +B: MAC COM : WM HLP : BNKBIOS3 SPR : LDR SUB : INITDIR COM +B: CPMLDR COM : COPYSYS COM : CPMLDR REL : RMAC COM : SYSGEN SUB A>bye System halted diff --git a/altairsim/conf/system.conf b/altairsim/conf/system.conf index 5e3febd8..2c0dec7d 100644 --- a/altairsim/conf/system.conf +++ b/altairsim/conf/system.conf @@ -33,16 +33,16 @@ fp_size 800 # front panel port value for machine without fp in hex (00 - FF) fp_port 0 -# VDM background and foreground colors in hex RGB format +# VDM background and foreground colors in RGB format # white Monitor -vdm_bg 303030 -vdm_fg FFFFFF +vdm_bg 48,48,48 +vdm_fg 255,255,255 # green Monitor -#vdm_bg 002000 -#vdm_fg 00BF00 +#vdm_bg 0,32,0 +#vdm_fg 0,191,0 # amber Monitor -#vdm_bg 202000 -#vdm_fg FFBF00 +#vdm_bg 32,32,0 +#vdm_fg 255,191,0 # Add scanlines to VDM monitor, 0 = no scanlines vdm_scanlines 1 diff --git a/altairsim/srcsim/Makefile b/altairsim/srcsim/Makefile index efb03a93..bad492a7 100644 --- a/altairsim/srcsim/Makefile +++ b/altairsim/srcsim/Makefile @@ -5,7 +5,9 @@ # and the executable saved as '../machinesim' MACHINE = altair # emulate a machine's frontpanel -FRONTPANEL = YES +FRONTPANEL ?= YES +# use SDL2 instead of X11 +WANT_SDL ?= NO # machine specific system source files MACHINE_SRCS = simcfg.c simio.c simmem.c simctl.c # machine specific I/O source files @@ -34,28 +36,6 @@ ROMS_DIR = $(DATADIR)/roms ### END MACHINE DEPENDENT VARIABLES ### -### -### FRONTPANEL VARIABLES -### -ifeq ($(FRONTPANEL),YES) -FP_SRCS = fpmain.cpp -FP_DEFS = -DFRONTPANEL -FP_LIB = $(FP_DIR)/libfrontpanel.a -FP_LDLIBS = -lfrontpanel -ljpeg -lGL -lGLU -LINK = $(CXX) -LINKFLAGS = $(CXXFLAGS) -else -FP_SRCS = -FP_DEFS = -FP_LIB = -FP_LDLIBS = -LINK = $(CC) -LINKFLAGS = $(CFLAGS) -endif -### -### END FRONTPANEL VARIABLES -### - SIM = ../$(MACHINE)sim CORE_DIR = ../../z80core @@ -64,58 +44,86 @@ FP_DIR = ../../frontpanel VPATH = $(CORE_DIR) $(IO_DIR) $(FP_DIR) -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os +### +### SDL2/X11 PLATFORM VARIABLES +### +ifeq ($(WANT_SDL),YES) +PLAT_DEFS = -DWANT_SDL +ifeq ($(TARGET_OS),BSD) +PLAT_INCS = -I/usr/local/include/SDL2 +PLAT_LDFLAGS = -L/usr/local/lib +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),LINUX) +PLAT_INCS = -I/usr/include/SDL2 +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDLIBS = -framework SDL2 +endif +else ifeq ($(TARGET_OS),BSD) PLAT_INCS = -I/usr/local/include PLAT_LDFLAGS = -L/usr/local/lib -PLAT_LDLIBS = -lthr +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),LINUX) +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include +PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib +PLAT_LDLIBS = -LX11 endif -ifeq ($(TARGET_OS),LINUX) -PLAT_LDLIBS = -lm -lpthread endif +### +### END SDL2/X11 PLATFORM VARIABLES +### + +### +### FRONTPANEL VARIABLES +### +ifeq ($(FRONTPANEL),YES) +FP_DEFS = -DFRONTPANEL +FP_LIB = $(FP_DIR)/libfrontpanel.a +ifeq ($(WANT_SDL),YES) ifeq ($(TARGET_OS),OSX) -PLAT_INCS = -I/opt/X11/include -PLAT_LDFLAGS = -L/usr/local/lib -L/opt/X11/lib +FP_LDLIBS = -lfrontpanel -framework SDL2_image -framework OpenGL +else +FP_LDLIBS = -lfrontpanel -lSDL2_image -lGL +endif +else +FP_LDLIBS = -lfrontpanel -ljpeg -lGL +endif endif ### -### END O/S DEPENDENT VARIABLES +### END FRONTPANEL VARIABLES ### DEFS = -DCONFDIR=\"$(CONF_DIR)\" -DDISKSDIR=\"$(DISKS_DIR)\" \ - -DBOOTROM=\"$(ROMS_DIR)\" $(FP_DEFS) + -DBOOTROM=\"$(ROMS_DIR)\" $(FP_DEFS) $(PLAT_DEFS) INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) -I$(FP_DIR) $(PLAT_INCS) CPPFLAGS = $(DEFS) $(INCS) CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L CWARNS = -Wall -Wextra -Wwrite-strings -CXXSTDS = -std=c++03 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L -CXXWARNS = -Wall -Wextra # Production - the default COPTS = -O3 -U_FORTIFY_SOURCE -CXXOPTS = -O3 -U_FORTIFY_SOURCE # Development - use `MODE=DEV make build` ifeq ($(MODE),DEV) COPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 -CXXOPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 endif # Debug - use `DEBUG=1 make build` ifneq ($(DEBUG),) COPTS = -O -g -CXXOPTS = -O -g endif -CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) $(PLAT_CFLAGS) -CXXFLAGS = $(CXXSTDS) $(CXXOPTS) $(CXXWARNS) $(PLAT_CXXFLAGS) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) LDFLAGS = -L$(FP_DIR) $(PLAT_LDFLAGS) -LDLIBS = $(FP_LDLIBS) -lX11 $(PLAT_LDLIBS) +LDLIBS = $(FP_LDLIBS) $(PLAT_LDLIBS) -lm -lpthread INSTALL = install INSTALL_PROGRAM = $(INSTALL) @@ -123,26 +131,22 @@ INSTALL_DATA = $(INSTALL) -m 644 # core system source files for the CPU simulation CORE_SRCS = sim8080.c simcore.c simdis.c simfun.c simglb.c simice.c simint.c \ - simmain.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c simz80-ed.c \ - simz80-fd.c simz80-fdcb.c + simmain.c simsdl.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c \ + simz80-ed.c simz80-fd.c simz80-fdcb.c SRCS = $(CORE_SRCS) $(MACHINE_SRCS) $(IO_SRCS) -XXSRCS = $(FP_SRCS) -OBJS = $(SRCS:.c=.o) $(XXSRCS:.cpp=.o) -DEPS = $(SRCS:.c=.d) $(XXSRCS:.cpp=.d) +OBJS = $(SRCS:.c=.o) +DEPS = $(SRCS:.c=.d) all: $(SIM) $(SIM): $(OBJS) $(FP_LIB) - $(LINK) $(LINKFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ $(DEPS): sim.h %.d: %.c @$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< > $@ -%.d: %.cpp - @$(CXX) -MM $(CXXFLAGS) $(CPPFLAGS) $< > $@ - -include $(DEPS) $(FP_LIB): FORCE diff --git a/altairsim/srcsim/simcfg.c b/altairsim/srcsim/simcfg.c index bd9f7117..68758f23 100644 --- a/altairsim/srcsim/simcfg.c +++ b/altairsim/srcsim/simcfg.c @@ -3,6 +3,7 @@ * * Copyright (C) 2008-2021 Udo Munk * Copyright (C) 2021 David McNaughton + * Copyright (C) 2025 by Thomas Eberhardt * * This module reads the system configuration file and sets * global variables, so that the system can be configured. @@ -29,6 +30,7 @@ * 22-JAN-2021 added option for config file * 31-JUL-2021 allow building machine without frontpanel * 29-AUG-2021 new memory configuration sections + * 03-JAN-2025 changed colors configuration to RGB-triple */ #include @@ -59,7 +61,7 @@ void config(void) FILE *fp; char buf[BUFSIZE]; char *s, *t1, *t2, *t3, *t4; - int v1, v2; + int v1, v2, v3; char fn[MAX_LFN - 1]; int num_segs = 0; @@ -224,9 +226,53 @@ void config(void) fp_size = atoi(t2); #endif } else if (!strcmp(t1, "vdm_bg")) { - strncpy(&bg_color[1], t2, 6); + if ((t3 = strtok(NULL, " \t,")) == NULL || + (t4 = strtok(NULL, " \t,")) == NULL) { + LOGW(TAG, "missing parameter for %s", t1); + continue; + } + v1 = strtol(t2, NULL, 0); + if (v1 < 0 || v1 > 255) { + LOGW(TAG, "invalid red component %d", v1); + continue; + } + v2 = strtol(t3, NULL, 0); + if (v2 < 0 || v2 > 255) { + LOGW(TAG, "invalid green component %d", v2); + continue; + } + v3 = strtol(t4, NULL, 0); + if (v3 < 0 || v3 > 255) { + LOGW(TAG, "invalid blue component %d", v3); + continue; + } + bg_color[0] = v1; + bg_color[1] = v2; + bg_color[2] = v3; } else if (!strcmp(t1, "vdm_fg")) { - strncpy(&fg_color[1], t2, 6); + if ((t3 = strtok(NULL, " \t,")) == NULL || + (t4 = strtok(NULL, " \t,")) == NULL) { + LOGW(TAG, "missing parameter for %s", t1); + continue; + } + v1 = strtol(t2, NULL, 0); + if (v1 < 0 || v1 > 255) { + LOGW(TAG, "invalid red component %d", v1); + continue; + } + v2 = strtol(t3, NULL, 0); + if (v2 < 0 || v2 > 255) { + LOGW(TAG, "invalid green component %d", v2); + continue; + } + v3 = strtol(t4, NULL, 0); + if (v3 < 0 || v3 > 255) { + LOGW(TAG, "invalid blue component %d", v3); + continue; + } + fg_color[0] = v1; + fg_color[1] = v2; + fg_color[2] = v3; } else if (!strcmp(t1, "vdm_scanlines")) { if (*t2 != '0') slf = 2; diff --git a/altairsim/srcsim/simctl.c b/altairsim/srcsim/simctl.c index 7100f84e..5b437d73 100644 --- a/altairsim/srcsim/simctl.c +++ b/altairsim/srcsim/simctl.c @@ -4,6 +4,7 @@ * This module allows operation of the system from an Altair 8800 front panel * * Copyright (C) 2008-2024 by Udo Munk + * Copyright (C) 2025 by Thomas Eberhardt * * History: * 20-OCT-2008 first version finished @@ -31,6 +32,7 @@ * 04-NOV-2019 eliminate usage of mem_base() * 31-JUL-2021 allow building machine without frontpanel * 29-APR-2024 print CPU execution statistics + * 04-JAN-2025 add SDL2 support */ #include @@ -53,7 +55,11 @@ #include "unix_terminal.h" #ifdef FRONTPANEL +#ifdef WANT_SDL +#include "simsdl.h" +#else #include +#endif #include "frontpanel.h" #include "log.h" static const char *TAG = "system"; @@ -72,6 +78,16 @@ static void protect_clicked(int state, int val); static void int_clicked(int state, int val); static void power_clicked(int state, int val); static void quit_callback(void); + +#ifdef WANT_SDL +static int fp_win_id; /* frontpanel window id */ +static win_funcs_t fp_win_funcs = { + fp_openWindow, + fp_quit, + fp_procEvent, + fp_draw +}; +#endif #endif /* FRONTPANEL */ int boot_switch; /* boot address for switch */ @@ -88,13 +104,17 @@ void mon(void) { #ifdef FRONTPANEL if (F_flag) { - /* initialize frontpanel */ +#ifndef WANT_SDL XInitThreads(); - +#endif + /* initialize frontpanel */ if (!fp_init2(confdir, "panel.conf", fp_size)) { LOGE(TAG, "frontpanel error"); exit(EXIT_FAILURE); } +#ifdef WANT_SDL + fp_win_id = simsdl_create(&fp_win_funcs); +#endif fp_addQuitCallback(quit_callback); fp_framerate(fp_fps); @@ -225,7 +245,11 @@ void mon(void) sleep_for_ms(999); /* shutdown frontpanel */ +#ifdef WANT_SDL + simsdl_destroy(fp_win_id); +#else fp_quit(); +#endif } #endif diff --git a/cpmsim/srcsim/Makefile b/cpmsim/srcsim/Makefile index d958bc8a..19fbd36a 100644 --- a/cpmsim/srcsim/Makefile +++ b/cpmsim/srcsim/Makefile @@ -35,23 +35,10 @@ IO_DIR = ../../iodevices VPATH = $(CORE_DIR) $(IO_DIR) -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os -ifeq ($(TARGET_OS),BSD) -endif -ifeq ($(TARGET_OS),LINUX) -endif -ifeq ($(TARGET_OS),OSX) -endif -### -### END O/S DEPENDENT VARIABLES -### - DEFS = -DCONFDIR=\"$(CONF_DIR)\" -DDISKSDIR=\"$(DISKS_DIR)\" -INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) $(PLAT_INCS) +INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) CPPFLAGS = $(DEFS) $(INCS) CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L @@ -70,11 +57,10 @@ ifneq ($(DEBUG),) COPTS = -O -g endif -CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) $(PLAT_CFLAGS) -CXXFLAGS = $(CXXSTDS) $(CXXOPTS) $(CXXWARNS) $(PLAT_CXXFLAGS) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) -LDFLAGS = $(PLAT_LDFLAGS) -LDLIBS = $(PLAT_LDLIBS) +LDFLAGS = +LDLIBS = INSTALL = install INSTALL_PROGRAM = $(INSTALL) @@ -82,8 +68,8 @@ INSTALL_DATA = $(INSTALL) -m 644 # core system source files for the CPU simulation CORE_SRCS = sim8080.c simcore.c simdis.c simfun.c simglb.c simice.c simint.c \ - simmain.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c simz80-ed.c \ - simz80-fd.c simz80-fdcb.c + simmain.c simsdl.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c \ + simz80-ed.c simz80-fd.c simz80-fdcb.c SRCS = $(CORE_SRCS) $(MACHINE_SRCS) $(IO_SRCS) OBJS = $(SRCS:.c=.o) DEPS = $(SRCS:.c=.d) diff --git a/cromemcosim/srcsim/Makefile b/cromemcosim/srcsim/Makefile index 6fd50d00..182777a6 100644 --- a/cromemcosim/srcsim/Makefile +++ b/cromemcosim/srcsim/Makefile @@ -5,7 +5,9 @@ # and the executable saved as '../machinesim' MACHINE = cromemco # emulate a machine's frontpanel -FRONTPANEL = YES +FRONTPANEL ?= YES +# use SDL2 instead of X11 +WANT_SDL ?= NO # machine specific system source files MACHINE_SRCS = simcfg.c simio.c simmem.c simctl.c # machine specific I/O source files @@ -39,28 +41,6 @@ DOCROOT_DIR = $(DATADIR)/www ### END MACHINE DEPENDENT VARIABLES ### -### -### FRONTPANEL VARIABLES -### -ifeq ($(FRONTPANEL),YES) -FP_SRCS = fpmain.cpp -FP_DEFS = -DFRONTPANEL -FP_LIB = $(FP_DIR)/libfrontpanel.a -FP_LDLIBS = -lfrontpanel -ljpeg -lGL -lGLU -LINK = $(CXX) -LINKFLAGS = $(CXXFLAGS) -else -FP_SRCS = -FP_DEFS = -FP_LIB = -FP_LDLIBS = -LINK = $(CC) -LINKFLAGS = $(CFLAGS) -endif -### -### END FRONTPANEL VARIABLES -### - SIM = ../$(MACHINE)sim CORE_DIR = ../../z80core @@ -71,59 +51,88 @@ CIV_DIR = $(NET_DIR)/civetweb VPATH = $(CORE_DIR) $(IO_DIR) $(FP_DIR) $(NET_DIR) $(CIV_DIR) -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os +### +### SDL2/X11 PLATFORM VARIABLES +### +ifeq ($(WANT_SDL),YES) +PLAT_DEFS = -DWANT_SDL +ifeq ($(TARGET_OS),BSD) +PLAT_INCS = -I/usr/local/include/SDL2 +PLAT_LDFLAGS = -L/usr/local/lib +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),LINUX) +PLAT_INCS = -I/usr/include/SDL2 +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDLIBS = -framework SDL2 +endif +else ifeq ($(TARGET_OS),BSD) PLAT_INCS = -I/usr/local/include PLAT_LDFLAGS = -L/usr/local/lib -PLAT_LDLIBS = -lthr +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),LINUX) +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include +PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib +PLAT_LDLIBS = -LX11 endif -ifeq ($(TARGET_OS),LINUX) -PLAT_LDLIBS = -lm -lpthread endif +### +### END SDL2/X11 PLATFORM VARIABLES +### + +### +### FRONTPANEL VARIABLES +### +ifeq ($(FRONTPANEL),YES) +FP_DEFS = -DFRONTPANEL +FP_LIB = $(FP_DIR)/libfrontpanel.a +ifeq ($(WANT_SDL),YES) ifeq ($(TARGET_OS),OSX) -PLAT_INCS = -I/opt/X11/include -PLAT_LDFLAGS = -L/usr/local/lib -L/opt/X11/lib +FP_LDLIBS = -lfrontpanel -framework SDL2_image -framework OpenGL +else +FP_LDLIBS = -lfrontpanel -lSDL2_image -lGL +endif +else +FP_LDLIBS = -lfrontpanel -ljpeg -lGL +endif endif ### -### END O/S DEPENDENT VARIABLES +### END FRONTPANEL VARIABLES ### DEFS = -DCONFDIR=\"$(CONF_DIR)\" -DDISKSDIR=\"$(DISKS_DIR)\" \ - -DBOOTROM=\"$(ROMS_DIR)\" -DSYSDOCROOT=\"$(DOCROOT_DIR)\" $(FP_DEFS) + -DBOOTROM=\"$(ROMS_DIR)\" -DSYSDOCROOT=\"$(DOCROOT_DIR)\" $(FP_DEFS) \ + $(PLAT_DEFS) INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) -I$(FP_DIR) -I$(NET_DIR) \ -I$(CIV_DIR)/include $(PLAT_INCS) CPPFLAGS = $(DEFS) $(INCS) CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L CWARNS = -Wall -Wextra -Wwrite-strings -CXXSTDS = -std=c++03 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L -CXXWARNS = -Wall -Wextra # Production - the default COPTS = -O3 -U_FORTIFY_SOURCE -CXXOPTS = -O3 -U_FORTIFY_SOURCE # Development - use `MODE=DEV make build` ifeq ($(MODE),DEV) COPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 -CXXOPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 endif # Debug - use `DEBUG=1 make build` ifneq ($(DEBUG),) COPTS = -O -g -CXXOPTS = -O -g endif -CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) $(PLAT_CFLAGS) -CXXFLAGS = $(CXXSTDS) $(CXXOPTS) $(CXXWARNS) $(PLAT_CXXFLAGS) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) LDFLAGS = -L$(FP_DIR) -L$(CIV_DIR) $(PLAT_LDFLAGS) -LDLIBS = $(CIV_LDLIBS) $(FP_LDLIBS) -lX11 $(PLAT_LDLIBS) +LDLIBS = $(CIV_LDLIBS) $(FP_LDLIBS) $(PLAT_LDLIBS) -lm -lpthread INSTALL = install INSTALL_PROGRAM = $(INSTALL) @@ -131,26 +140,22 @@ INSTALL_DATA = $(INSTALL) -m 644 # core system source files for the CPU simulation CORE_SRCS = sim8080.c simcore.c simdis.c simfun.c simglb.c simice.c simint.c \ - simmain.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c simz80-ed.c \ - simz80-fd.c simz80-fdcb.c + simmain.c simsdl.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c \ + simz80-ed.c simz80-fd.c simz80-fdcb.c SRCS = $(CORE_SRCS) $(MACHINE_SRCS) $(IO_SRCS) -XXSRCS = $(FP_SRCS) -OBJS = $(SRCS:.c=.o) $(XXSRCS:.cpp=.o) -DEPS = $(SRCS:.c=.d) $(XXSRCS:.cpp=.d) +OBJS = $(SRCS:.c=.o) +DEPS = $(SRCS:.c=.d) all: $(SIM) $(SIM): $(OBJS) $(CIV_LIB) $(FP_LIB) - $(LINK) $(LINKFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ $(DEPS): sim.h %.d: %.c @$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< > $@ -%.d: %.cpp - @$(CXX) -MM $(CXXFLAGS) $(CPPFLAGS) $< > $@ - -include $(DEPS) $(CIV_LIB): FORCE diff --git a/cromemcosim/srcsim/simctl.c b/cromemcosim/srcsim/simctl.c index 6dd28342..73530cbf 100644 --- a/cromemcosim/srcsim/simctl.c +++ b/cromemcosim/srcsim/simctl.c @@ -4,6 +4,7 @@ * This module allows operation of the system from a Cromemco Z-1 front panel * * Copyright (C) 2014-2024 by Udo Munk + * Copyright (C) 2025 by Thomas Eberhardt * * History: * 15-DEC-2014 first version @@ -26,6 +27,7 @@ * 04-NOV-2019 eliminate usage of mem_base() * 17-JUN-2021 allow building machine without frontpanel * 29-APR-2024 added CPU execution statistics + * 04-JAN-2025 add SDL2 support */ #include @@ -51,7 +53,11 @@ #endif #ifdef FRONTPANEL +#ifdef WANT_SDL +#include "simsdl.h" +#else #include +#endif #include "frontpanel.h" #include "log.h" static const char *TAG = "system"; @@ -68,6 +74,16 @@ static void examine_clicked(int state, int val); static void deposit_clicked(int state, int val); static void power_clicked(int state, int val); static void quit_callback(void); + +#ifdef WANT_SDL +static int fp_win_id; /* frontpanel window id */ +static win_funcs_t fp_win_funcs = { + fp_openWindow, + fp_quit, + fp_procEvent, + fp_draw +}; +#endif #endif /* FRONTPANEL */ /* @@ -87,13 +103,17 @@ void mon(void) #ifdef FRONTPANEL if (F_flag) { - /* initialize front panel */ +#ifndef WANT_SDL XInitThreads(); - +#endif + /* initialize front panel */ if (!fp_init2(&confdir[0], "panel.conf", fp_size)) { LOGE(TAG, "frontpanel error"); exit(EXIT_FAILURE); } +#ifdef WANT_SDL + fp_win_id = simsdl_create(&fp_win_funcs); +#endif fp_addQuitCallback(quit_callback); fp_framerate(fp_fps); @@ -231,7 +251,11 @@ void mon(void) sleep_for_ms(999); /* shutdown frontpanel */ +#ifdef WANT_SDL + simsdl_destroy(fp_win_id); +#else fp_quit(); +#endif } #endif diff --git a/doc/CREDITS b/doc/CREDITS index 079d3df8..cad23937 100644 --- a/doc/CREDITS +++ b/doc/CREDITS @@ -60,3 +60,4 @@ regression tests. For the implementation of the Intel Intellec MDS-800 system. For the rewrite of the disassembler. For the implementation of a hardware breakpoint in the ICE. +For adding support for SDL2. diff --git a/doc/README-debian.txt b/doc/README-debian.txt index 870996d4..41ae708b 100644 --- a/doc/README-debian.txt +++ b/doc/README-debian.txt @@ -1,3 +1,7 @@ -For building the frontpanel machines on some Debian Linux you need: +For building the frontpanel machines on some Debian Linux for X11 you need: sudo apt install libjpeg9-dev libgl1-mesa-dev libglu1-mesa-dev + +and for SDL2: + +sudo apt install libsdl2-dev libsdl2-image-dev diff --git a/doc/README-osx.txt b/doc/README-osx.txt index 1e7d60e8..185076d6 100644 --- a/doc/README-osx.txt +++ b/doc/README-osx.txt @@ -2,12 +2,12 @@ For installation on OSX you need compiler command line tools, xcode is not mandatory. If you execute gcc --version on a new system, it will tell you the command to install compilers. -For the frontpanel machines you need X11, install the latest XQuartz -release from here: https://www.xquartz.org/ +If you want to use X11 with the frontpanel machines +--------------------------------------------------- -Apple still doesn't include JPEG support, probably because of -licence and patent issues. There are open source implementations -that private users are free to use without legal hassles. For this +Install the latest XQuartz release from here: https://www.xquartz.org/ + +You also need a JPEG library for the frontpanel machines. For this you need to install brew first, which you will need anyway: https://brew.sh/ @@ -16,3 +16,18 @@ Then install JPEG support with 'brew install jpeg'. Now you are all set and should be able to build the z80pack machines from source, following the other instructions here. + +If you want to use SDL2 with the frontpanel machines +---------------------------------------------------- + +Install the SDL2 and SDL2_image frameworks from +https://github.com/libsdl-org/SDL/releases/ +and +https://github.com/libsdl-org/SDL_image/releases/ + +Grab the latest SDL2-2.x.x.dmg and SDL2_image-2.x.x.dmg, and copy +the framework bundles into /Library/Frameworks (create this directory +if it doesn't exist). + +Now you are all set and should be able to build the z80pack machines +from source, following the other instructions here. diff --git a/doc/README-wsl.txt b/doc/README-wsl.txt index 10f540b8..bd60ce6c 100644 --- a/doc/README-wsl.txt +++ b/doc/README-wsl.txt @@ -13,8 +13,11 @@ In the Ubuntu shell enter "mkdir bin", then "exit". Open a new Windows Terminal and start a "Ubuntu" session. -Enter: -sudo apt install gcc g++ make libjpeg-turbo8-dev libgl1-mesa-dev libglu1-mesa-dev +For using X11, enter: +sudo apt install gcc make libjpeg-turbo8-dev libgl1-mesa-dev libglu1-mesa-dev + +Or for SDL2, enter: +sudo apt install gcc make libsdl2-dev libsdl2-image-dev Now unpack the z80pack source distribution and follow, for example, "README-frontpanel.txt". diff --git a/frontpanel/COPYING b/frontpanel/COPYING index 0738a37f..a7ce5287 100644 --- a/frontpanel/COPYING +++ b/frontpanel/COPYING @@ -1,6 +1,7 @@ /* Copyright (c) 2007-2008, John Kichury + C and SDL2 conversion is Copyright (c) 2024-2025, Thomas Eberhardt This software is freely distributable free of charge and without license fees with the following conditions: diff --git a/frontpanel/Makefile b/frontpanel/Makefile index bae30b02..405cd3be 100644 --- a/frontpanel/Makefile +++ b/frontpanel/Makefile @@ -1,45 +1,55 @@ +# use SDL2 instead of X11 +WANT_SDL ?= NO + LIB = libfrontpanel.a -SRCS = jpeg.cpp lpanel.cpp lp_gfx.cpp lp_main.cpp lp_utils.cpp lp_window.cpp \ - lp_switch.cpp lp_font.cpp lp_materials.cpp +SRCS = jpeg.c lpanel.c lp_gfx.c lp_main.c lp_utils.c lp_window.c \ + lp_switch.c lp_font.c lp_materials.c CORE_DIR = ../z80core -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os +### +### SDL2/X11 PLATFORM VARIABLES +### +ifeq ($(WANT_SDL),YES) +PLAT_DEFS = -DWANT_SDL ifeq ($(TARGET_OS),BSD) -PLAT_INCS = -I/usr/local/include -endif -ifeq ($(TARGET_OS),LINUX) +PLAT_INCS = -I/usr/local/include/SDL2 +else ifeq ($(TARGET_OS),LINUX) +PLAT_INCS = -I/usr/include/SDL2 +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers \ + -I/Library/Frameworks/SDL2_image.framework/Headers endif -ifeq ($(TARGET_OS),OSX) -PLAT_INCS = -I/opt/X11/include endif ### -### END O/S DEPENDENT VARIABLES +### END SDL2 VARIABLES ### -CXXSTDS = -std=c++03 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L -CXXWARNS = -Wall -Wextra +CPPFLAGS = $(PLAT_DEFS) $(PLAT_INCS) + +CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L +CWARNS = -Wall -Wextra -Wwrite-strings # Production - the default -CXXFLAGS = -O3 $(CXXSTDS) $(CXXWARNS) $(PLAT_CXXFLAGS) -U_FORTIFY_SOURCE $(PLAT_INCS) +COPTS = -O3 -U_FORTIFY_SOURCE # Development - use `MODE=DEV make build` ifeq ($(MODE),DEV) -CXXFLAGS = -O3 $(CXXSTDS) $(CXXWARNS) $(PLAT_CXXFLAGS) -fstack-protector-all -D_FORTIFY_SOURCE=2 $(PLAT_INCS) +COPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 endif # Debug - use `DEBUG=1 make build` ifneq ($(DEBUG),) -CXXFLAGS = -O -g $(CXXSTDS) $(CXXWARNS) $(PLAT_CXXFLAGS) $(PLAT_INCS) +COPTS = -O -g endif -OBJS = $(SRCS:.cpp=.o) -DEPS = $(SRCS:.cpp=.d) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) + +OBJS = $(SRCS:.c=.o) +DEPS = $(SRCS:.c=.d) all: $(LIB) @@ -47,8 +57,8 @@ $(LIB): $(OBJS) @rm -f $@ ar cq $@ $(OBJS) -%.d: %.cpp - @$(CXX) -MM $(CXXFLAGS) $< > $@ +%.d: %.c + @$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< > $@ -include $(DEPS) diff --git a/frontpanel/README b/frontpanel/README index 37dcf548..c7ca1911 100644 --- a/frontpanel/README +++ b/frontpanel/README @@ -6,6 +6,7 @@ Copyright (c) 2007-2008, John Kichury Windows port is Copyright (c) 2014, Stefano Bodrato + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt This software is freely distributable free of charge and without license fees with the following conditions: @@ -21,26 +22,36 @@ -Dependencies: +X11 Dependencies: libjpeg X11 OpenGL - c++ compiler (g++) + c compiler (gcc) libpthread Windows port dependencies : libjpeg - OpenGL32 (-lopengl32 -lgdi32 -lglu32) - c++ compiler (g++) + OpenGL32 (-lopengl32 -lgdi32) + c compiler (gcc) libpthread +SDL2 Dependencies: + + SDL2 + SDL2_image + OpenGL + c compiler (gcc) + -DWANT_SDL compiler flag + + For more information consult the user manual in the doc directory. - John Kichury - Stefano Bodrato + - Thomas Eberhardt diff --git a/frontpanel/frontpanel.h b/frontpanel/frontpanel.h index 937c0327..7cc4b72e 100644 --- a/frontpanel/frontpanel.h +++ b/frontpanel/frontpanel.h @@ -1,9 +1,9 @@ -/* frontpanel.h front panel api include file */ - +// frontpanel.h frontpanel api include file /* Copyright (c) 2007-2008, John Kichury + C and SDL2 conversion is Copyright (c) 2024-2025, Thomas Eberhardt - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -17,68 +17,78 @@ */ -#ifndef _FP_API_DEFS -#define _FP_API_DEFS +#ifndef _FRONTPANEL_DEFS +#define _FRONTPANEL_DEFS -#ifdef __cplusplus - extern "C" { +#include +#include +#ifdef WANT_SDL +#include #endif +#ifdef __cplusplus +extern "C" { +#endif #define FP_SW_DOWN 0 #define FP_SW_UP 1 #define FP_SW_CENTER 2 -int fp_test(int n); -int fp_init2(const char *cfg_root_path, const char *cfg_fname, int size); -int fp_init(const char *cfg_fname); -int fp_openWindow(const char *title); -void fp_framerate(float f); -void fp_sampleData(void); -void fp_sampleDataWarp(int clockwarp); -void fp_sampleLightGroup(int groupnum, int clockwarp); -void fp_sampleSwitches(void); -void fp_quit(void); +extern int fp_test(int n); +extern int fp_init2(const char *cfg_root_path, const char *cfg_fname, int size); +extern int fp_init(const char *cfg_fname); +extern void fp_openWindow(void); +#ifdef WANT_SDL +extern void fp_procEvent(SDL_Event *event); +extern void fp_draw(bool tick); +#else +extern void fp_procEvents(void); +extern void fp_draw(void); +#endif +extern void fp_framerate(float f); +extern void fp_sampleData(void); +extern void fp_sampleDataWarp(int clockwarp); +extern void fp_sampleLightGroup(int groupnum, int clockwarp); +extern void fp_sampleSwitches(void); +extern void fp_quit(void); /* data binding functions */ -//void fp_bindSimclock(const uint64_t *addr); -////void fp_bindRunFlag(const uint8_t *addr); - -void fp_bindSimclock(uint64_t *addr); -void fp_bindRunFlag(uint8_t *addr); - -int fp_bindLight64(const char *name, uint64_t *bits, int bitnum); -int fp_bindLight32(const char *name, uint32_t *bits, int bitnum); -int fp_bindLight16(const char *name, uint16_t *bits, int bitnum); -int fp_bindLightfv(const char *name, float *bits); -int fp_bindLight8(const char *name, uint8_t *bits, int bitnum); -int fp_bindLight8invert(const char *name, uint8_t *bits, int bitnum, uint8_t mask); -int fp_bindLight16invert(const char *name, uint16_t *bits, int bitnum, uint16_t mask); -int fp_bindLight32invert(const char *name, uint32_t *bits, int bitnum, uint32_t mask); -int fp_bindLight64invert(const char *name, uint64_t *bits, int bitnum, uint64_t mask); - -int fp_bindSwitch64(const char *name, uint64_t *loc_down, uint64_t *loc_up, int bitnum); -int fp_bindSwitch32(const char *name, uint32_t *loc_down, uint32_t *loc_up, int bitnum); -int fp_bindSwitch16(const char *name, uint16_t *loc_down, uint16_t *loc_up, int bitnum); -int fp_bindSwitch8(const char *name, uint8_t *loc_down, uint8_t *loc_up, int bitnum); - - -int fp_smoothLight(const char *name, int nframes); +extern void fp_bindSimclock(uint64_t *addr); +extern void fp_bindRunFlag(uint8_t *addr); + +extern int fp_bindLight64(const char *name, uint64_t *bits, int bitnum); +extern int fp_bindLight32(const char *name, uint32_t *bits, int bitnum); +extern int fp_bindLight16(const char *name, uint16_t *bits, int bitnum); +extern int fp_bindLightfv(const char *name, float *bits); +extern int fp_bindLight8(const char *name, uint8_t *bits, int bitnum); +extern int fp_bindLight8invert(const char *name, uint8_t *bits, int bitnum,uint8_t mask); +extern int fp_bindLight16invert(const char *name, uint16_t *bits, int bitnum, uint16_t mask); +extern int fp_bindLight32invert(const char *name, uint32_t *bits, int bitnum, uint32_t mask); +extern int fp_bindLight64invert(const char *name, uint64_t *bits, int bitnum, uint64_t mask); + +extern int fp_bindSwitch64(const char *name, uint64_t *loc_down, uint64_t *loc_up, + int bitnum); +extern int fp_bindSwitch32(const char *name, uint32_t *loc_down, uint32_t *loc_up, + int bitnum); +extern int fp_bindSwitch16(const char *name, uint16_t *loc_down, uint16_t *loc_up, + int bitnum); +extern int fp_bindSwitch8(const char *name, uint8_t *loc_down, uint8_t *loc_up, int bitnum); + +extern int fp_smoothLight(const char *name, int nframes); /* callbacks */ -int fp_addSwitchCallback(const char *name, void (*cbfunc)(int state, int val), int userval); -void fp_addQuitCallback(void (*cbfunc)(void)); +extern int fp_addSwitchCallback(const char *name, void (*cbfunc)(int state, int val), + int userval); +extern void fp_addQuitCallback(void (*cbfunc)(void)); /* error reporting */ -void fp_ignoreBindErrors(int n); /* n=1 - ignore n=0 report errors */ -#ifdef __cplusplus - } -#endif - - +extern void fp_ignoreBindErrors(int n); /* n=1 ignore, n=0 report errors */ +#ifdef __cplusplus +} #endif +#endif /* !_FRONTPANEL_DEFS */ diff --git a/frontpanel/jpeg.cpp b/frontpanel/jpeg.c similarity index 77% rename from frontpanel/jpeg.cpp rename to frontpanel/jpeg.c index 0cfe6fc7..a8849f3c 100644 --- a/frontpanel/jpeg.cpp +++ b/frontpanel/jpeg.c @@ -1,5 +1,6 @@ -// jpeg +// jpeg +#ifndef WANT_SDL #include #include @@ -9,8 +10,8 @@ #define UNUSED(x) (void) (x) -unsigned char *pixels; -int xsize, ysize, ncomps; +static unsigned char *pixels; +static int xsize, ysize, ncomps; /* * Since BMP stores scanlines bottom-to-top, we have to invert the image @@ -53,12 +54,11 @@ put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, UNUSED(rows_supplied); /* Access next row in virtual array */ - image_ptr = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, dest->whole_image, - dest->cur_output_row, (JDIMENSION) 1, TRUE); + image_ptr = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE); dest->cur_output_row++; - /* Transfer data. + /* Transfer data. */ inptr = dest->pub.buffer[0]; outptr = image_ptr[0]; @@ -75,7 +75,6 @@ put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, JDIMENSION rows_supplied) /* This version is for grayscale OR quantized color output */ { -//printf("put gray rows\n"); bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; JSAMPARRAY image_ptr; JSAMPROW inptr, outptr; @@ -84,10 +83,11 @@ put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, UNUSED(rows_supplied); + // printf("put gray rows\n"); + /* Access next row in virtual array */ - image_ptr = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, dest->whole_image, - dest->cur_output_row, (JDIMENSION) 1, TRUE); + image_ptr = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE); dest->cur_output_row++; /* Transfer data. */ @@ -111,27 +111,27 @@ start_output_pixels (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) UNUSED(cinfo); UNUSED(dinfo); -//printf("start output\n"); + // printf("start output\n"); + /* no work here */ } - METHODDEF(void) finish_output_pixels (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) { unsigned char *p; - bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; - JSAMPARRAY image_ptr; JSAMPROW data_ptr; JDIMENSION row; JDIMENSION col; cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; - p = pixels; // final output -//printf("finish output_pixels row_width=%d\n",dest->row_width); + p = pixels; // final output + + // printf("finish output_pixels row_width=%d\n",dest->row_width); + /* Write the file body from our virtual array */ for (row = cinfo->output_height; row > 0; row--) { if (progress != NULL) { @@ -139,19 +139,18 @@ finish_output_pixels (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) progress->pub.pass_limit = (long) cinfo->output_height; (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); } - image_ptr = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE); + image_ptr = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + dest->whole_image, row-1, (JDIMENSION) 1, FALSE); data_ptr = image_ptr[0]; - for (col = dest->row_width; col > 0; col--) + for (col = dest->row_width; col > 0; col--) { -// putc(GETJSAMPLE(*data_ptr), outfile); + // putc(GETJSAMPLE(*data_ptr), outfile); *p++ = *data_ptr; data_ptr++; } } if (progress != NULL) progress->completed_extra_passes++; - } @@ -166,9 +165,8 @@ jinit_write_pixels (j_decompress_ptr cinfo) JDIMENSION row_width; /* Create module interface object, fill in method pointers */ - dest = (bmp_dest_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(bmp_dest_struct)); + dest = (bmp_dest_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_dest_struct)); dest->pub.start_output = start_output_pixels; dest->pub.finish_output = finish_output_pixels; @@ -180,7 +178,7 @@ jinit_write_pixels (j_decompress_ptr cinfo) else dest->pub.put_pixel_rows = put_pixel_rows; } else { - ERREXIT(cinfo, JERR_BMP_COLORSPACE); + ERREXIT(cinfo, JERR_BMP_COLORSPACE); } /* Calculate output image dimensions so we can allocate space */ @@ -195,8 +193,8 @@ jinit_write_pixels (j_decompress_ptr cinfo) ysize = cinfo->output_height; ncomps = cinfo->output_components; - //allocate space for final pixels - pixels = new unsigned char[xsize*ysize*ncomps]; + // allocate space for final pixels + pixels = (unsigned char *) malloc(xsize * ysize * ncomps); /* Allocate space for inversion array, prepare for write pass */ dest->whole_image = (*cinfo->mem->request_virt_sarray) @@ -216,29 +214,29 @@ jinit_write_pixels (j_decompress_ptr cinfo) return (djpeg_dest_ptr) dest; } + #define DBG 0 -unsigned char -*read_jpeg(char *fname, int *width, int *height, int *num_components) +GLOBAL(unsigned char *) +read_jpeg (char *fname, int *width, int *height, int *num_components) { - FILE *fd; + FILE *fd; - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - djpeg_dest_ptr dest_mgr = NULL; + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + djpeg_dest_ptr dest_mgr = NULL; - pixels = NULL; + pixels = NULL; - int num_scanlines; + int num_scanlines; - if( (fd = fopen(fname,"rb")) == NULL) - { - fprintf(stderr,"read_jpeg: could not open file %s\n",fname); - return NULL; - } + if( (fd = fopen(fname,"rb")) == NULL) { + fprintf(stderr,"read_jpeg: could not open file %s\n",fname); + return NULL; + } #if DBG -fprintf(stderr,"read_jpeg: reading file %s\n",fname); + fprintf(stderr,"read_jpeg: reading file %s\n",fname); #endif cinfo.err = jpeg_std_error(&jerr); @@ -246,44 +244,39 @@ fprintf(stderr,"read_jpeg: reading file %s\n",fname); /* Specify data source for decompression */ jpeg_stdio_src(&cinfo, fd); - + /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); dest_mgr = jinit_write_pixels(&cinfo); - // print header information + // print header information - - /* Start decompressor */ + /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); #if DBG -fprintf(stderr,"read_jpeg: started decompressor for file %s\n",fname); + fprintf(stderr,"read_jpeg: started decompressor for file %s\n",fname); #endif /* Write output file header */ (*dest_mgr->start_output) (&cinfo, dest_mgr); - -#if 1 -// (*dest_mgr->start_output) (&cinfo, dest_mgr); - /* Process data */ while (cinfo.output_scanline < cinfo.output_height) { - num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); + num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, + dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } -#endif (*dest_mgr->finish_output) (&cinfo, dest_mgr); (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); + *width = xsize; + *height = ysize; + *num_components = ncomps; - *width = xsize; - *height = ysize; - *num_components=ncomps; - return pixels; + return pixels; } - +#endif /* !WANT_SDL */ diff --git a/frontpanel/jpeg.h b/frontpanel/jpeg.h index 5517674c..8301eaf4 100644 --- a/frontpanel/jpeg.h +++ b/frontpanel/jpeg.h @@ -1,9 +1,15 @@ // jpeg.h -#ifndef __JPEG_DEFS__ -#define __JPEG_DEFS__ +#ifndef _JPEG_DEFS +#define _JPEG_DEFS -unsigned char -*read_jpeg(char *fname, int *width, int *height, int *num_components); +#ifndef WANT_SDL + +#include "jpeglib.h" + +EXTERN(unsigned char *) read_jpeg JPP((char *fname, int *width, int *height, + int *num_components)); #endif + +#endif /* !_JPEG_DEFS */ diff --git a/frontpanel/lp_font.c b/frontpanel/lp_font.c new file mode 100644 index 00000000..4b190599 --- /dev/null +++ b/frontpanel/lp_font.c @@ -0,0 +1,136 @@ +#include +#ifdef WANT_SDL +#include +#else +#include +#endif + +#include "lp_font.h" + +static GLubyte rasters[][13] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, + {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, + {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, + {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, + {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, + {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, + {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, + {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, + {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, + {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, + {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, + {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, + {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, + {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, + {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, + {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, + {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, + {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, + {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, + {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, + {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, + {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} +}; + +static GLuint fontOffset; + +void makeRasterFont(void) +{ + GLuint i; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + fontOffset = glGenLists(128); + for (i = 32; i < 127; i++) { + glNewList(i + fontOffset, GL_COMPILE); + glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, rasters[i - 32]); + glEndList(); + } +} + +void printString(char *s) +{ + glPushAttrib(GL_LIST_BIT); + glListBase(fontOffset); + glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); + glPopAttrib(); +} + +void printStringAt(char *s, float xpos, float ypos) +{ + glRasterPos2f(xpos, ypos); + printString(s); +} diff --git a/frontpanel/lp_font.cpp b/frontpanel/lp_font.cpp deleted file mode 100644 index 52104d3a..00000000 --- a/frontpanel/lp_font.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -#include -#else -#include -#include -#include -#include -#include -#endif -#include -#include -#include -#include "lp_font.h" - - -static GLubyte rasters[][13] = { -{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, -{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, -{0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, -{0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, -{0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, -{0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, -{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, -{0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, -{0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, -{0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, -{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, -{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, -{0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, -{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, -{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, -{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, -{0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, -{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, -{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, -{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, -{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, -{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, -{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, -{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, -{0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, -{0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, -{0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, -{0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, -{0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, -{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, -{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, -{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, -{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, -{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, -{0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, -{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, -{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, -{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, -{0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, -{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, -{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, -{0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, -{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, -{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, -{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, -{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, -{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, -{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, -{0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, -{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, -{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, -{0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, -{0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, -{0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, -{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, -{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, -{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, -{0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, -{0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, -{0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, -{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, -{0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, -{0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, -{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, -{0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, -{0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, -{0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, -{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, -{0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, -{0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, -{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, -{0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, -{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} -}; - -static GLuint fontOffset; - -void makeRasterFont(void) -{ - GLuint i; - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - fontOffset = glGenLists (128); - for (i = 32; i < 127; i++) { - glNewList(i+fontOffset, GL_COMPILE); - glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, rasters[i-32]); - glEndList(); - } -} - - -void printString(char *s) -{ - glPushAttrib (GL_LIST_BIT); - glListBase(fontOffset); - glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); - glPopAttrib (); -} - -void printStringAt(char *s,float xpos,float ypos) -{ - glRasterPos2f(xpos,ypos); - printString(s); -} - diff --git a/frontpanel/lp_font.h b/frontpanel/lp_font.h index 368037cd..9c9220d1 100644 --- a/frontpanel/lp_font.h +++ b/frontpanel/lp_font.h @@ -1,6 +1,8 @@ +#ifndef _LP_FONT_DEFS +#define _LP_FONT_DEFS -void makeRasterFont(void); -void printString(char *s); -void printStringAt(char *s,float xpos,float ypos); - +extern void makeRasterFont(void); +extern void printString(char *s); +extern void printStringAt(char *s, float xpos, float ypos); +#endif /* !_LP_FONT_DEFS */ diff --git a/frontpanel/lp_gfx.c b/frontpanel/lp_gfx.c new file mode 100644 index 00000000..cd3cc59f --- /dev/null +++ b/frontpanel/lp_gfx.c @@ -0,0 +1,923 @@ +// lp_gfx.c lightpanel graphics + +/* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt + + This software is freely distributable free of charge and without license fees with the + following conditions: + + 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 + JOHN KICHURY 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. + + The above copyright notice must be included in any copies of this software. + +*/ + +#include +#include +#include +#ifdef WANT_SDL +#include +#include +#include +#else +#include +#include "jpeg.h" +#endif + +#include "lpanel.h" +#include "lp_utils.h" +#include "lp_gfx.h" +#include "lp_materials.h" + +#define UNUSED(x) (void) (x) + +// static GLfloat mtl2_amb[] = { 0.2, 0.2, 0.2, 1.0 }; +// static GLfloat mtl2_dif[] = { 1.0, 1.0, 1.0, 1.0 }; +// static GLfloat mtl2_spec[] = { 0.0, 0.0, 0.0, 1.0 }; +// static GLfloat mtl2_shine[] = { 0.0 }; +// static GLfloat mtl2_emission[] = { 0.0, 0.0, 0.0, 1.0 }; + +lpObject_t *Lpanel_addObject(Lpanel_t *p) +{ + lpObject_t *obj; + + if (p->num_objects + 1 > p->max_objects) + Lpanel_growObjects(p); + obj = lpObject_new(); + + if (obj) { + obj->color[0] = .1; + obj->color[1] = .1; + obj->color[2] = .1; + obj->referenced = false; + p->objects[p->num_objects] = obj; + p->num_objects++; + } + return obj; +} + +void Lpanel_addAlphaObject(Lpanel_t *p, lpObject_t *obj) +{ + if (p->num_alpha_objects + 1 > p->max_alpha_objects) + Lpanel_growAlphaObjects(p); + + if (obj) { + p->alpha_objects[p->num_alpha_objects] = obj; + p->num_alpha_objects++; + } +} + +lpObject_t *Lpanel_findObjectByName(Lpanel_t *p, char *name) +{ + int i; + + for (i = 0; i < p->num_objects; i++) + if (p->objects[i]->name) + if (!strcmp(name, p->objects[i]->name)) + return p->objects[i]; + + return NULL; +} + +void Lpanel_genGraphicsData(Lpanel_t *p) +{ + int i, j, first; + + // generate data such as geometric extents, texture coords etc. + // for all graphics objects + + for (i = 0; i < p->num_objects; i++) + lpObject_genGraphicsData(p->objects[i]); + + // get bounding box for all geometry and put any alpha objects that are + // not referenced on the alpha list + + first = 1; + + for (i = 0; i < p->num_objects; i++) { + if (p->objects[i]->referenced) + continue; + + if (p->objects[i]->is_alpha) + Lpanel_addAlphaObject(p, p->objects[i]); + + if (first) { + for (j = 0; j < 3; j++) { + p->bbox.xyz_min[j] = p->objects[i]->bbox.xyz_min[j]; + p->bbox.xyz_max[j] = p->objects[i]->bbox.xyz_max[j]; + } + first = 0; + } else { + for (j = 0; j < 3; j++) { + p->bbox.xyz_min[j] = min(p->bbox.xyz_min[j], + p->objects[i]->bbox.xyz_min[j]); + p->bbox.xyz_max[j] = max(p->bbox.xyz_max[j], + p->objects[i]->bbox.xyz_max[j]); + } + } + } + + for (j = 0; j < 3; j++) + p->bbox.center[j] = (p->bbox.xyz_min[j] + p->bbox.xyz_max[j]) / 2.0f; +} + +void Lpanel_growObjects(Lpanel_t *p) +{ + lpObject_t **new_objects; + + new_objects = (lpObject_t **) realloc(p->objects, + sizeof(lpObject_t *) * (p->num_objects + 1)); + p->max_objects += 1; + p->objects = new_objects; +} + +void Lpanel_growAlphaObjects(Lpanel_t *p) +{ + lpObject_t **new_alpha_objects; + + new_alpha_objects = (lpObject_t **) realloc(p->alpha_objects, + sizeof(lpObject_t *) * + (p->num_alpha_objects + 1)); + p->max_alpha_objects += 1; + p->alpha_objects = new_alpha_objects; +} + + +// --------------------- +// object class + +lpObject_t *lpObject_new(void) +{ + lpObject_t *p = (lpObject_t *) calloc(1, sizeof(lpObject_t)); + + if (p) + lpObject_init(p); + + return p; +} + +void lpObject_delete(lpObject_t *p) +{ + if (p) { + lpObject_fini(p); + free(p); + } +} + +void lpObject_init(lpObject_t *p) // initializer +{ + int i; + + p->num_elements = p->max_elements = 0; + p->elements = NULL; + p->name = NULL; + p->instance_name = NULL; + p->instance_object = NULL; + p->have_normals = false; + p->material = 0; + p->is_alpha = false; + p->texture_num = 0; + p->textures = NULL; + p->envmapped = false; + p->texture_scale[0] = p->texture_scale[1] = 1.0; + p->texture_translate[0] = p->texture_translate[1] = 0.0; + + for (i = 0; i < 3; i++) { + p->rotate[i] = 0.; + p->translate[i] = 0.; + p->origin[i] = 0.; + } + + lpBBox_init(&p->bbox); +} + +void lpObject_fini(lpObject_t *p) +{ + int i; + + if (p->elements) { + for (i = 0; i < p->num_elements; i++) + if (p->elements[i]) + lpElement_delete(p->elements[i]); + + free(p->elements); + } + if (p->name) + free(p->name); + + lpBBox_fini(&p->bbox); +} + +lpElement_t *lpObject_addElement(lpObject_t *p, lpObject_t *obj) +{ + lpElement_t *element; + + if (p->num_elements + 1 > p->max_elements) + lpObject_growElements(obj); + + element = lpElement_new(); + if (element) { + p->elements[p->num_elements] = element; + p->num_elements++; + element->parent = obj; + } + + return element; +} + +void lpObject_draw(lpObject_t *p) +{ + int i; + lpObject_t *obj; + + if (p->referenced) + return; + + // glDisable(GL_DEPTH_TEST); + + if (p->have_normals) { + glEnable(GL_LIGHTING); + if (p->material) + lp_bind_material(p->material); + } else { + glDisable(GL_LIGHTING); + glColor3fv(p->color); + } + + if (p->texture_num) { + glEnable(GL_TEXTURE_2D); + if (p->envmapped) { + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + } + } else { + glDisable(GL_TEXTURE_2D); + } + + glPushMatrix(); + + glRotatef(p->rotate[2], 1., 0., 0.); + glRotatef(p->rotate[0], 1., 0., 0.); + glRotatef(p->rotate[1], 1., 0., 0.); + + for (i = 0; i < p->num_elements; i++) + lpElement_draw(p->elements[i]); + + obj = p->instance_object; + + while (obj) { + if (!obj->referenced) { + if (obj->have_normals) { + glEnable(GL_LIGHTING); + if (obj->material) + lp_bind_material(obj->material); + } else { + glEnable(GL_LIGHTING); + glColor3fv(obj->color); + } + + for (i = 0; i < obj->num_elements; i++) + lpElement_draw(obj->elements[i]); + } + obj = obj->instance_object; + } + + glPopMatrix(); + + if (p->envmapped) { + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + } +} + +void lpObject_draw_refoverride(lpObject_t *p, int refoverride) +{ + int i; + lpObject_t *obj; + + if (p->texture_num) { + glEnable(GL_TEXTURE_2D); + lpTextures_bindTexture(p->textures, p->texture_num); + + if (p->envmapped) { + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + } + } else { + glDisable(GL_TEXTURE_2D); + } + + if (p->have_normals) { + glEnable(GL_LIGHTING); + if (p->material) + lp_bind_material(p->material); + } else { + glDisable(GL_LIGHTING); + if (refoverride != 2) + glColor3fv(p->color); + } + + glPushMatrix(); + +#if 1 + glRotatef(p->rotate[2], 1., 0., 0.); + glRotatef(p->rotate[0], 1., 0., 0.); + glRotatef(p->rotate[1], 1., 0., 0.); +#endif + + for (i = 0; i < p->num_elements; i++) + lpElement_draw(p->elements[i]); + + obj = p->instance_object; + + while (obj) { + if (obj->have_normals) { + glEnable(GL_LIGHTING); + if (p->material) + lp_bind_material(p->material); + } else { + glEnable(GL_LIGHTING); + glColor3fv(obj->color); + } + + for (i = 0; i < obj->num_elements; i++) + lpElement_draw(obj->elements[i]); + + obj = obj->instance_object; + + } + glPopMatrix(); +} + +void lpObject_genGraphicsData(lpObject_t *p) +{ + int i, j, first = 1; + lpElement_t *ep; + + // generate data such as geometric extents, texture coords etc. + // for this object + + for (i = 0; i < p->num_elements; i++) { + ep = p->elements[i]; + + lpElement_genGraphicsData(ep); + + if (first) { + for (j = 0; j < 3; j++) { + p->bbox.xyz_min[j] = ep->bbox.xyz_min[j]; + p->bbox.xyz_max[j] = ep->bbox.xyz_max[j]; + } + first = 0; + } else { + for (j = 0; j < 3; j++) { + p->bbox.xyz_min[j] = min(p->bbox.xyz_min[j], ep->bbox.xyz_min[j]); + p->bbox.xyz_max[j] = max(p->bbox.xyz_max[j], ep->bbox.xyz_max[j]); + } + } + } + + for (j = 0; j < 3; j++) + p->bbox.center[j] = (p->bbox.xyz_min[j] + p->bbox.xyz_max[j]) / 2.0f; + + // if this object has a texture defined, + // generate texture coords for elements that need them + + if (p->texture_num != 0) + for (i = 0; i < p->num_elements; i++) { + lpElement_genTextureCoords(p->elements[i], p, &p->bbox); + } +} + +void lpObject_growElements(lpObject_t *p) +{ + lpElement_t **new_elements; + + new_elements = (lpElement_t **) realloc(p->elements, + sizeof(lpElement_t *) * (p->num_elements + 1)); + p->max_elements += 1; + p->elements = new_elements; +} + +void lpObject_setName(lpObject_t *p, char *s) +{ + if (p->name) + free(p->name); + p->name = (char *) malloc(strlen(s) + 1); + strcpy(p->name, s); +} + +void lpObject_setInstanceName(lpObject_t *p, char *s) +{ + if (p->instance_name) + free(p->instance_name); + p->instance_name = (char *) malloc(strlen(s) + 1); + strcpy(p->instance_name, s); +} + +void lpObject_setTextureManager(lpObject_t *p, lpTextures_t *textures) +{ + p->textures = textures; +}; + + +lpElement_t *lpElement_new(void) +{ + lpElement_t *p = (lpElement_t *) calloc(1, sizeof(lpElement_t)); + + if (p) + lpElement_init(p); + + return p; +} + +void lpElement_delete(lpElement_t *p) +{ + if (p) { + lpElement_fini(p); + free(p); + } +} + +void lpElement_init(lpElement_t *p) +{ + p->parent = NULL; + p->num_verts = p->max_verts = 0; + p->have_tcoords = false; + p->have_normals = false; + p->verts = NULL; + + lpBBox_init(&p->bbox); +} + +void lpElement_fini(lpElement_t *p) +{ + int i; + + if (p->verts) { + for (i = 0; i < p->num_verts; i++) + if (p->verts[i]) + free(p->verts[i]); + + free(p->verts); + } + + lpBBox_fini(&p->bbox); +} + +vertex_t *lpElement_addVertex(lpElement_t *p) +{ + int i; + vertex_t *vert; + + if (p->num_verts + 1 > p->max_verts) + lpElement_growVerts(p); + + vert = (vertex_t *) malloc(sizeof(vertex_t)); + if (vert) { + for (i = 0; i < 3; i++) { + vert->xyz[i] = 0.; + vert->norm[i] = 0.; + } + + for (i = 0; i < 2; i++) + vert->st[i] = 0.; + + p->verts[p->num_verts] = vert; + p->num_verts++; + } + + return vert; +} + +void lpElement_draw(lpElement_t *p) +{ + int i; + +#if 0 + if (p->have_tcoords) + glEnable(GL_TEXTURE_2D); + else + glDisable(GL_TEXTURE_2D); +#endif + + switch (p->type) { + case LP_LINE: + glBegin(GL_LINE_LOOP); + break; + case LP_POLYGON: + glBegin(GL_POLYGON); + break; + case LP_TRISTRIP: + glBegin(GL_TRIANGLE_STRIP); + break; + default: + break; + } + + if (p->parent->have_normals) { + if (p->have_tcoords) { + for (i = 0; i < p->num_verts; i++) { + lpTextures_TexCoord2fv(p->textures, p->verts[i]->st); + glNormal3fv(p->verts[i]->norm); + glVertex3fv(p->verts[i]->xyz); + } + } else { + for (i = 0; i < p->num_verts; i++) { + glNormal3fv(p->verts[i]->norm); + glVertex3fv(p->verts[i]->xyz); + } + } + } else { + if (p->have_tcoords) { + for (i = 0; i < p->num_verts; i++) { + lpTextures_TexCoord2fv(p->textures, p->verts[i]->st); + glVertex3fv(p->verts[i]->xyz); + } + } else { + for (i = 0; i < p->num_verts; i++) { + glVertex3fv(p->verts[i]->xyz); + } + } + } + glEnd(); +} + +void lpElement_genGraphicsData(lpElement_t *p) +{ + int first = 1, i, j; + vertex_t *vp; + + // calc bbox for this element + + for (i = 0; i < p->num_verts; i++) { + vp = p->verts[i]; + + if (first) { + for (j = 0; j < 3; j++) + p->bbox.xyz_min[j] = p->bbox.xyz_max[j] = vp->xyz[j]; + + first = 0; + } else { + for (j = 0; j < 3; j++) { + p->bbox.xyz_min[j] = min(p->bbox.xyz_min[j], vp->xyz[j]); + p->bbox.xyz_max[j] = max(p->bbox.xyz_max[j], vp->xyz[j]); + } + } + } +} + +void lpElement_genTextureCoords(lpElement_t *p, lpObject_t *obj, lpBBox_t *bbox) +{ + int i, j; + vertex_t *vp; + + if (p->have_tcoords) + return; // already have them from config file + + // generate texture coordinates + + for (i = 0; i < p->num_verts; i++) { + vp = p->verts[i]; + + for (j = 0; j < 2; j++) { + vp->st[j] = (1.0 / (bbox->xyz_max[j] - bbox->xyz_min[j])) * + (vp->xyz[j] - bbox->xyz_min[j]); + vp->st[j] *= 1.0 / obj->texture_scale[j]; + vp->st[j] -= obj->texture_translate[j]; + } + } + // vp->st[j] = (1.0 / (bbox->xyz_max[j] - bbox->xyz_min[j])) * + // (vp->xyz[j] - bbox->xyz_min[j]); + + p->have_tcoords = true; +} + +void lpElement_growVerts(lpElement_t *p) +{ + vertex_t **new_verts; + + new_verts = (vertex_t **) realloc(p->verts, + sizeof(vertex_t *) * (p->num_verts + 4)); + p->max_verts += 4; + p->verts = new_verts; +} + +void lpElement_setTextureManager(lpElement_t *p, lpTextures_t *textures) +{ + p->textures = textures; +}; + + +// texture class + +lpTextures_t *lpTextures_new(void) +{ + lpTextures_t *p = (lpTextures_t *) calloc(1, sizeof(lpTextures_t)); + + if (p) + lpTextures_init(p); + + return p; +} + +void lpTextures_delete(lpTextures_t *p) +{ + if (p) { + lpTextures_fini(p); + free(p); + } +} + +void lpTextures_init(lpTextures_t *p) +{ + p->tex = (texture_t **) malloc(sizeof(texture_t *)); + p->tex[0] = (texture_t *) calloc(1, sizeof(texture_t)); + p->num_textures = 1; // start at 1, zero reserved for unbinding + p->max_textures = 1; + p->last_accessed = 0; +} + +void lpTextures_fini(lpTextures_t *p) +{ + int i; + + if (p->tex) { + for (i = 0; i < p->num_textures; i++) + if (p->tex[i]) { + if (p->tex[i]->texels) + free(p->tex[i]->texels); + free(p->tex[i]); + } + + free(p->tex); + } +} + +int lpTextures_addTexture(lpTextures_t *p, char *fname) +{ + int texnum; + texture_t *tp; +#ifdef WANT_SDL + SDL_Surface *surface, *temp_surface; + SDL_PixelFormat *format; +#else + unsigned char *pixels; +#endif + + if (p->num_textures + 1 > p->max_textures) + lpTextures_growTextures(p); + texnum = p->num_textures; + + p->tex[texnum] = tp = (texture_t *) calloc(1, sizeof(texture_t)); + +#ifdef WANT_SDL + temp_surface = IMG_Load(fname); + if (!temp_surface) + return 0; + /* convert loaded image to RGB pixels */ + format = SDL_AllocFormat(SDL_PIXELFORMAT_RGB24); + surface = SDL_ConvertSurface(temp_surface, format, 0); + SDL_FreeSurface(temp_surface); + SDL_FreeFormat(format); + if (!surface) + return 0; + tp->imgXsize = surface->w; + tp->imgYsize = surface->h; + tp->imgZsize = surface->format->BytesPerPixel; + tp->surface = surface; +#else /* !WANT_SDL */ + pixels = read_jpeg(fname, &tp->imgXsize, &tp->imgYsize, &tp->imgZsize); + if (!pixels) + return 0; + tp->pixels = pixels; +#endif /* !WANT_SDL */ + + p->num_textures++; + + // printf("\n\nAddTextureFile: added %s %dx%dx%d as texnum %d \n", fname, + // tp->imgXsize, tp->imgYsize, tp->imgZsize, texnum); + + p->last_accessed = texnum; + + return texnum; +} + +/* get power of 2 */ + +static int GetPowerOf2i(int n) +{ + int result = 0x2; + + while (result < n) + result = result << 1; + return result; +} + +int lpTextures_downloadTextures(lpTextures_t *p) +{ + int texnum, n; + texture_t *tp; + + for (texnum = 1; texnum < p->num_textures; texnum++) { + tp = p->tex[texnum]; + +#ifdef WANT_SDL + if (tp->surface) { +#else + if (tp->pixels) { +#endif + // calc power of two S and T dimensions + + tp->texSsize = GetPowerOf2i(tp->imgXsize); + tp->texTsize = GetPowerOf2i(tp->imgYsize); + + // set gl parms + + switch (tp->imgZsize) { + case 1: + tp->format = GL_LUMINANCE; + break; + case 2: + tp->format = GL_LUMINANCE_ALPHA; + break; + case 3: + tp->format = GL_RGB; + break; + case 4: + tp->format = GL_RGBA; + break; + default: + fprintf(stderr, "addTexture: Invalid # texture components.\n"); + return 0; + } + + // set type + + tp->type = GL_UNSIGNED_BYTE; + + // calc S and T limits + + tp->texSmin = 0; + tp->texTmin = 0; + tp->texSmax = (float) tp->imgXsize / (float) tp->texSsize; + + tp->texTmax = (float) tp->imgYsize / (float) tp->texTsize; + +#ifdef WANT_SDL + // copy SDL surface pixel data to texel data bottom to top + + unsigned char *src, *rsrc, *dst; + int x, y, z; + + // lock SDL surface for direct access + if (SDL_MUSTLOCK(tp->surface) && SDL_LockSurface(tp->surface) < 0) { + fprintf(stderr, "addTexture: Can't lock SDL surface.\n"); + return 0; + } + + // position after last row of pixels + rsrc = (unsigned char *) tp->surface->pixels + + tp->surface->pitch * tp->imgYsize; + + tp->texels = (unsigned char *) malloc(tp->texSsize * tp->texTsize * + tp->imgZsize); + + dst = tp->texels; + + for (y = 0; y < tp->texTsize; y++) { + // move up one row of pixels + rsrc -= tp->surface->pitch; + src = rsrc; + for (x = 0; x < tp->texSsize; x++) + for (z = 0; z < tp->imgZsize; z++) + if (y < tp->imgYsize && x < tp->imgXsize) { + *dst++ = *src++; + } else + *dst++ = 0; + } + + // unlock SDL surface and free it + if (SDL_MUSTLOCK(tp->surface)) + SDL_UnlockSurface(tp->surface); + SDL_FreeSurface(tp->surface); + tp->surface = NULL; +#else /* !WANT_SDL */ + // copy image pixel data to texel data + + unsigned char *src, *dst; + int x,y,z; + + src = tp->pixels; + + tp->texels = (unsigned char *) malloc(tp->texSsize * tp->texTsize * + tp->imgZsize); + + dst = tp->texels; + + for (y = 0; y < tp->texTsize; y++) + for (x = 0; x < tp->texSsize; x++) + for (z = 0; z < tp->imgZsize; z++) + if (y < tp->imgYsize && x < tp->imgXsize) + *dst++ = *src++; + else + *dst++ = 0; + + // free pixels + free(tp->pixels); + tp->pixels = NULL; +#endif /* !WANT_SDL */ + + // get a bind id from OpenGL + + n = glGetError(); /* clear any gl errors */ + + glGenTextures(1, (GLuint *) &tp->bind_id); + glBindTexture(GL_TEXTURE_2D, tp->bind_id); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, tp->imgZsize, tp->texSsize, tp->texTsize, + 0, tp->format, GL_UNSIGNED_BYTE, tp->texels); + + glBindTexture(GL_TEXTURE_2D, 0); + + n = glGetError(); + if (n) + fprintf(stderr, "addTexture: glError %d\n", n); + } + } // end for(texnum... + + return 1; +} + +void lpTextures_bindTexture(lpTextures_t *p, int n) +{ + if (n == 0) + glBindTexture(GL_TEXTURE_2D, 0); + else { + if (n > p->num_textures) { + fprintf(stderr, "bindTexture: Invalid texture number (%d)\n", n); + return; + } else { + // printf("bind %d %d\n", n, tex[n]->bind_id); + glBindTexture(GL_TEXTURE_2D, p->tex[n]->bind_id); + } + } + p->last_accessed = n; +} + +void lpTextures_growTextures(lpTextures_t *p) +{ + int n = 20; + texture_t **new_tex; + + new_tex = (texture_t **) realloc(p->tex, + sizeof(texture_t *) * (p->num_textures + n)); + p->max_textures += n; + p->tex = new_tex; +} + +void lpTextures_TexCoord2fv(lpTextures_t *p, float *st) +{ + glTexCoord2f(st[0] * p->tex[p->last_accessed]->texSmax, + st[1] * p->tex[p->last_accessed]->texTmax); +} + + +// Bbox class + +lpBBox_t *lpBBox_new(void) +{ + lpBBox_t *p = (lpBBox_t *) calloc(1, sizeof(lpBBox_t)); + + if (p) + lpBBox_init(p); + + return p; +} + +void lpBBox_delete(lpBBox_t *p) +{ + lpBBox_fini(p); + free(p); +} + +void lpBBox_init(lpBBox_t *p) +{ + int i; + + for (i = 0; i < 3; i++) + p->xyz_min[i] = p->xyz_max[i] = p->center[i] = 0.0f; +} + +void lpBBox_fini(lpBBox_t *p) +{ + UNUSED(p); +} diff --git a/frontpanel/lp_gfx.cpp b/frontpanel/lp_gfx.cpp deleted file mode 100644 index 23654c5d..00000000 --- a/frontpanel/lp_gfx.cpp +++ /dev/null @@ -1,875 +0,0 @@ -// lp_gfx.cpp light panel graphics - - -/* Copyright (c) 2007-2008, John Kichury - - This software is freely distributable free of charge and without license fees with the - following conditions: - - 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 - JOHN KICHURY 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. - - The above copyright notice must be included in any copies of this software. - -*/ - - -#include -#include -#include -#include -#include "lpanel.h" -#include "lp_utils.h" -#include "lp_materials.h" -#include "jpeg.h" - -// static GLfloat mtl2_amb[] = { 0.2, 0.2, 0.2, 1.0 }; -// static GLfloat mtl2_dif[] = { 1.0, 1.0, 1.0, 1.0 }; -// static GLfloat mtl2_spec[] = { 0.0, 0.0, 0.0, 1.0 }; -// static GLfloat mtl2_shine[] = { 0.0 }; -// static GLfloat mtl2_emission[] = { 0.0, 0.0, 0.0, 1.0 }; - - - -lpObject * -Lpanel::addObject(void) -{ - lpObject *obj; - - if(num_objects + 1 > max_objects) - growObjects(); - obj = new lpObject; - - if(obj) - { - obj->color[0] = .1; - obj->color[1] = .1; - obj->color[2] = .1; - obj->referenced = 0; - objects[num_objects] = obj; - num_objects++; - } - return obj; -} - -void -Lpanel::addAlphaObject(lpObject *obj) -{ - if(num_alpha_objects + 1 > max_alpha_objects) - growAlphaObjects(); - - if(obj) - { - alpha_objects[num_alpha_objects] = obj; - num_alpha_objects++; - } -} - -lpObject * -Lpanel::findObjectByName(char *name) -{ - int i; - - for(i=0;iname) - if(!strcmp(name, objects[i]->name)) return objects[i]; - - return NULL; -} - -void -Lpanel::genGraphicsData(void) -{ - int i,j, first; - - // generate data such as geometric extents, texture coords etc. - // for all graphics objects - - for(i=0;igenGraphicsData(); - - // get bounding box for all geometry and put any alpha objects that are not referenced on - // the alpha list - - first = 1; - - for(i=0;ireferenced) continue; - - if(objects[i]->is_alpha) addAlphaObject(objects[i]); - - if(first) - { - for(j=0;j<3;j++) - { bbox.xyz_min[j] = objects[i]->bbox.xyz_min[j]; - bbox.xyz_max[j] = objects[i]->bbox.xyz_max[j]; - } - first=0; - } - else - { - for(j=0;j<3;j++) - { bbox.xyz_min[j] = min(bbox.xyz_min[j], objects[i]->bbox.xyz_min[j]); - bbox.xyz_max[j] = max(bbox.xyz_max[j], objects[i]->bbox.xyz_max[j]); - } - } - } - - for(j=0;j<3;j++) - bbox.center[j] = (bbox.xyz_min[j] + bbox.xyz_max[j]) / 2.0f; - -} - -void -Lpanel::growObjects(void) -{ - int i; - lpObject **new_objects; - - new_objects = new lpObject * [num_objects + 1]; - for(i=0;i max_elements) - growElements(); - - element = new lpElement; - if(element) - { - elements[num_elements] = element; - num_elements++; - } - element->parent = p; - return element; -} - -void -lpObject::draw(void) -{ - int i; - lpObject *obj; - - if(referenced) return; - -// glDisable(GL_DEPTH_TEST); - - if(have_normals) - { - glEnable(GL_LIGHTING); - if(material) lp_bind_material(material); - } - else - { - glDisable(GL_LIGHTING); - glColor3fv(color); - } - - if(texture_num) - { glEnable(GL_TEXTURE_2D); - if(envmapped) - { - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - } - } - else - { - glDisable(GL_TEXTURE_2D); - } - - glPushMatrix(); - - glRotatef(rotate[2],1.,0.,0.); - glRotatef(rotate[0],1.,0.,0.); - glRotatef(rotate[1],1.,0.,0.); - - for(i=0;idraw(); - - obj = instance_object; - - while(obj) - { - if(!obj->referenced) - { - if(obj->have_normals) - { - glEnable(GL_LIGHTING); - if(obj->material) lp_bind_material(obj->material); - } - else - { - glEnable(GL_LIGHTING); - glColor3fv(obj->color); - } - - for(i=0;inum_elements;i++) - obj->elements[i]->draw(); - } - obj = obj->instance_object; - - } - - glPopMatrix(); - - if(envmapped) - { - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } -} - -void -lpObject::draw(int referenced) -{ - int i; - lpObject *obj; - - if(texture_num) - { - glEnable(GL_TEXTURE_2D); - textures->bindTexture(texture_num); - - if(envmapped) - { - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - } - } - else - { - glDisable(GL_TEXTURE_2D); - } - - if(have_normals) - { - glEnable(GL_LIGHTING); - if(material) lp_bind_material(material); - } - else - { - glDisable(GL_LIGHTING); - if(referenced != 2) - glColor3fv(color); - } - - glPushMatrix(); - -#if 1 - glRotatef(rotate[2],1.,0.,0.); - glRotatef(rotate[0],1.,0.,0.); - glRotatef(rotate[1],1.,0.,0.); -#endif - - for(i=0;idraw(); - - obj = instance_object; - - while(obj) - { - if(obj->have_normals) - { - glEnable(GL_LIGHTING); - if(material) lp_bind_material(material); - } - else - { - glEnable(GL_LIGHTING); - glColor3fv(obj->color); - } - - for(i=0;inum_elements;i++) - obj->elements[i]->draw(); - - obj = obj->instance_object; - - } - glPopMatrix(); -} - -void -lpObject::genGraphicsData(void) -{ - int i, j, first=1; - - // generate data such as geometric extents, texture coords etc. - // for this object - - for(i=0;igenGraphicsData(); - - if(first) - { - for(j=0;j<3;j++) - { bbox.xyz_min[j] = elements[i]->bbox.xyz_min[j]; - bbox.xyz_max[j] = elements[i]->bbox.xyz_max[j]; - } - first=0; - } - else - { - for(j=0;j<3;j++) - { bbox.xyz_min[j] = min(bbox.xyz_min[j], elements[i]->bbox.xyz_min[j]); - bbox.xyz_max[j] = max(bbox.xyz_max[j], elements[i]->bbox.xyz_max[j]); - } - } - - } - - for(j=0;j<3;j++) - bbox.center[j] = (bbox.xyz_min[j] + bbox.xyz_max[j]) / 2.0f; - - - // if this object has a texture defined, generate texture coords for elements that need them - - if(texture_num != 0) - for(i=0;igenTextureCoords(this, &bbox); - - } -} - -void -lpObject::growElements(void) -{ - int i; - lpElement **new_elements; - - new_elements = new lpElement* [num_elements+ 1]; - for(i=0;i max_verts ) - growVerts(); - - vert = new vertex_t; - if(vert) - { for(i=0;i<3;i++) - { vert->xyz[i] = 0.; - vert->norm[i] = 0.; - } - - for(i=0;i<2;i++) - vert->st[i] = 0.; - - verts[num_verts] = vert; - num_verts++; - } - - return vert; -} - -void -lpElement::draw(void) -{ - int i; - -#if 0 - if(have_tcoords) - glEnable(GL_TEXTURE_2D); - else - glDisable(GL_TEXTURE_2D); -#endif - - switch(type) - { case LP_LINE: - glBegin(GL_LINE_LOOP); - break; - case LP_POLYGON: - glBegin(GL_POLYGON); - break; - case LP_TRISTRIP: - glBegin(GL_TRIANGLE_STRIP); - break; - default: - break; - } - - if(parent->have_normals) - { - if(have_tcoords) - { - for(i=0;iTexCoord2fv( verts[i]->st ); - glNormal3fv( verts[i]->norm ); - glVertex3fv( verts[i]->xyz ); - } - } - else - { - for(i=0;inorm ); - glVertex3fv( verts[i]->xyz ); - } - } - } - else - { - if(have_tcoords) - { - for(i=0;iTexCoord2fv( verts[i]->st ); - glVertex3fv( verts[i]->xyz ); - } - } - else - { - for(i=0;ixyz ); - } - } - } - glEnd(); -} - -void -lpElement::genGraphicsData(void) -{ - int first=1, - i,j; - - // calc bbox for this element - - - for(i=0;ixyz[j]; - - first = 0; - } - else - { - for(j=0;j<3;j++) - { - bbox.xyz_min[j] = min(bbox.xyz_min[j],verts[i]->xyz[j]); - bbox.xyz_max[j] = max(bbox.xyz_max[j],verts[i]->xyz[j]); - } - } - } - -} - -void -lpElement::genTextureCoords(lpObject *obj, lpBBox *bbox) -{ - int i,j; - - if(have_tcoords) return; // already have them from config file - - // generate texture coordinates - - for(i=0;ist[j] = (1.0 / (bbox->xyz_max[j] - bbox->xyz_min[j])) * (verts[i]->xyz[j] - bbox->xyz_min[j]); - verts[i]->st[j] *= 1.0 / obj->texture_scale[j]; - verts[i]->st[j] -= obj->texture_translate[j]; - } - //verts[i]->st[j] = (1.0 / (bbox->xyz_max[j] - bbox->xyz_min[j])) * (verts[i]->xyz[j] - bbox->xyz_min[j]); - - have_tcoords = 1; - -} - -void -lpElement::growVerts(void) -{ - int i; - vertex_t **new_verts; - - new_verts = new vertex_t * [num_verts + 4]; - if(new_verts) - { - for(i=0;itexels) delete tex[i]->texels; - delete tex[i]; - } - - delete[] tex; - } - -} - - -int -lpTextures::addTexture(char *fname) -{ - int texnum; - unsigned char *p; - - - - if(num_textures + 1 > max_textures) growTextures(); - texnum = num_textures; - - tex[texnum] = new texture_t; - -#if 0 - if((tex[texnum]->pixels = read_jpeg(fname, &tex[texnum]->imgXsize, - &tex[texnum]->imgYsize, - &tex[texnum]->imgZsize)) == 0) return 0; -#endif - - p = read_jpeg(fname, &tex[texnum]->imgXsize, - &tex[texnum]->imgYsize, - &tex[texnum]->imgZsize); - if(!p) return 0; - tex[texnum]->pixels = p; - num_textures++; - -// printf("\n\nAddTextureFile: added %s %dx%dx%d as texnum %d \n",fname,tex[texnum]->imgXsize, -// tex[texnum]->imgYsize, tex[texnum]->imgZsize,texnum); - - last_accessed = texnum; - return texnum; -} - - -int -lpTextures::downloadTextures(void) -{ - int texnum; - // int n; - -for(texnum = 1; texnum < num_textures; texnum++) - if(tex[texnum]->pixels) - { - // calc power of two S and T dimensions - - tex[texnum]->texSsize = GetPowerOf2i(tex[texnum]->imgXsize); - tex[texnum]->texTsize = GetPowerOf2i(tex[texnum]->imgYsize); - - // set gl parms - - switch(tex[texnum]->imgZsize) - { case 1: - tex[texnum]->format = GL_LUMINANCE; - break; - case 2: - tex[texnum]->format = GL_LUMINANCE_ALPHA; - break; - case 3: - tex[texnum]->format = GL_RGB; - break; - case 4: - tex[texnum]->format = GL_RGBA; - break; - default: - fprintf(stderr,"addTexture: Invalid # texture components.\n"); - return 0; - break; - - return 1; - } - - // set type - - tex[texnum]->type = GL_UNSIGNED_BYTE; - - // calc S and T limits - - tex[texnum]->texSmin = 0; - tex[texnum]->texTmin = 0; - tex[texnum]->texSmax = (float) tex[texnum]->imgXsize / - (float) tex[texnum]->texSsize; - - tex[texnum]->texTmax = (float) tex[texnum]->imgYsize / - (float) tex[texnum]->texTsize; - - // copy image pixel data to texel data - - unsigned char *src, *dst; - int x,y,z; - - src = tex[texnum]->pixels; - -#if 0 - tex[texnum]->texels = (unsigned char *) malloc(tex[texnum]->texSsize * - tex[texnum]->texTsize * - tex[texnum]->imgZsize); -#endif - - tex[texnum]->texels = new unsigned char [tex[texnum]->texSsize * - tex[texnum]->texTsize * - tex[texnum]->imgZsize]; - - dst = tex[texnum]->texels; - -#if 0 - for(y=0;ytexTsize;y++) - for(x=0;xtexSsize;x++) - for(z=0;zimgZsize;z++) - if(y < tex[texnum]->texTsize && x < tex[texnum]->texSsize) - { *dst++ = *src++; - } - else *dst++ = 0; -#endif - - for(y=0;ytexTsize;y++) - for(x=0;xtexSsize;x++) - for(z=0;zimgZsize;z++) - if(y < tex[texnum]->imgYsize && x < tex[texnum]->imgXsize) - { - *dst++ = *src++; - } - else *dst++ = 0; - - // get a bind id from OpenGL - - /* n = */ (void)glGetError(); /* clear any gl errors */ - - glGenTextures(1,(GLuint *)&tex[texnum]->bind_id); - glBindTexture( GL_TEXTURE_2D, tex[texnum]->bind_id ); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTexImage2D(GL_TEXTURE_2D, 0, tex[texnum]->imgZsize, tex[texnum]->texSsize, - tex[texnum]->texTsize, 0, tex[texnum]->format, GL_UNSIGNED_BYTE, - tex[texnum]->texels); - - glBindTexture( GL_TEXTURE_2D, 0 ); - check_glerror(); - - } // end for(texnum... - - return 1; -} - -void -lpTextures::bindTexture(int n) -{ - if(n == 0) - glBindTexture(GL_TEXTURE_2D, 0); - else - { - if( n > num_textures ) - { - fprintf(stderr,"bindTexture: Invalid texture number (%d)\n",n); - return; - } - else - { - // printf("bind %d %d\n", n, tex[n]->bind_id); - glBindTexture(GL_TEXTURE_2D,tex[n]->bind_id); - } - } - last_accessed = n; -} - -void -lpTextures::growTextures(void) -{ - int i, n=20; - texture_t **new_tex; - - new_tex = new texture_t * [num_textures + n]; - - if(new_tex) - { - for(i=0;itexSmax, - st[1] * tex[last_accessed]->texTmax); - -} - - - -// Bbox class - -lpBBox::lpBBox(void) -{ - int i; - for(i=0;i<3;i++) - xyz_min[i] = xyz_max[i] = center[i] = 0.0f; - -} -lpBBox::~lpBBox(void) -{ -} - - - diff --git a/frontpanel/lp_gfx.h b/frontpanel/lp_gfx.h index ff12f640..c1cf456e 100644 --- a/frontpanel/lp_gfx.h +++ b/frontpanel/lp_gfx.h @@ -1,8 +1,9 @@ -// lp_gfx.h light panel graphics classes and data structures +// lp_gfx.h lightpanel graphics classes and data structures /* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -16,180 +17,184 @@ */ - #ifndef _LP_GFX_DEFS #define _LP_GFX_DEFS +#include +#ifdef WANT_SDL +#include +#include +#else +#include +#endif + enum lp_el_types { LP_POLYGON, LP_TRISTRIP, LP_LINE }; -typedef struct -{ - float xyz[3], - norm[3], - st[2]; +typedef struct { + float xyz[3], + norm[3], + st[2]; } vertex_t; - // forward references -class lpElement; -class lpTextures; - -class lpBBox -{ - private: - - public: - lpBBox(); - ~lpBBox(); +struct lpElement; +struct lpTextures; - float xyz_min[3], - xyz_max[3], - center[3]; -}; +typedef struct lpBBox { + float xyz_min[3], + xyz_max[3], + center[3]; +} lpBBox_t; -class lpObject -{ +extern lpBBox_t *lpBBox_new(void); +extern void lpBBox_delete(lpBBox_t *p); +extern void lpBBox_init(lpBBox_t *p); +extern void lpBBox_fini(lpBBox_t *p); - private: - - - void growElements(void); - - public: - - lpObject(); - ~lpObject(); +typedef struct lpObject { int num_elements, max_elements; - lpElement **elements; - - char *name; - void setName(char *s); + struct lpElement **elements; - char *instance_name; - void setInstanceName(char *s); - lpObject *instance_object; + char *name; - lpElement *addElement(lpObject *p); - void draw(void); - void draw(int referenced); // draw with reference override + char *instance_name; + struct lpObject *instance_object; float color[3]; float texture_scale[2], texture_translate[2]; int texture_num, - envmapped; - int referenced, // object is only drawn by another object referencing it + material; + bool envmapped, + referenced, // object is only drawn by another object referencing it have_normals, - material, is_alpha; // object has transparent material or texture float rotate[3], // rotate hpr translate[3], // translate origin[3]; // object origin - lpTextures *textures; - void setTextureManager(lpTextures *p) { textures = p; }; + struct lpTextures *textures; + lpBBox_t bbox; +} lpObject_t; - void genGraphicsData(void); - lpBBox bbox; -}; +extern lpObject_t *lpObject_new(void); +extern void lpObject_delete(lpObject_t *p); +extern void lpObject_init(lpObject_t *p); +extern void lpObject_fini(lpObject_t *p); +// private functions -class lpElement -{ - private: +extern void lpObject_growElements(lpObject_t *p); - void growVerts(void); +// public functions - public: +extern void lpObject_setName(lpObject_t *p, char *s); +extern void lpObject_setInstanceName(lpObject_t *p, char *s); +extern struct lpElement *lpObject_addElement(lpObject_t *p, lpObject_t *obj); +extern void lpObject_draw(lpObject_t *p); +extern void lpObject_draw_refoverride(lpObject_t *p, int refoverride); +extern void lpObject_setTextureManager(lpObject_t *p, struct lpTextures *textures); +extern void lpObject_genGraphicsData(lpObject_t *p); - lpElement(); - ~lpElement(); - int type, // LP_POLYGON, LP_LINE - num_verts, - max_verts, - have_tcoords, - have_normals; +typedef struct lpElement { + int type, // LP_POLYGON, LP_LINE + num_verts, + max_verts; + bool have_tcoords, + have_normals; - lpObject *parent; - vertex_t **verts; + lpObject_t *parent; + vertex_t **verts; - vertex_t *addVertex(void); - void draw(void); - void genGraphicsData(void); - void genTextureCoords(lpObject *obj, lpBBox *bbox); + struct lpTextures *textures; - lpTextures *textures; - void setTextureManager(lpTextures *p) { textures = p; }; + lpBBox_t bbox; // element bounding box +} lpElement_t; - lpBBox bbox; // element bounding box -}; +extern lpElement_t *lpElement_new(void); +extern void lpElement_delete(lpElement_t *p); +extern void lpElement_init(lpElement_t *p); +extern void lpElement_fini(lpElement_t *p); +// private functions -#endif +extern void lpElement_growVerts(lpElement_t *p); +// public functions -// texture class for managing graphics textures - -typedef struct -{ +extern vertex_t *lpElement_addVertex(lpElement_t *p); +extern void lpElement_draw(lpElement_t *p); +extern void lpElement_genGraphicsData(lpElement_t *p); +extern void lpElement_genTextureCoords(lpElement_t *p, lpObject_t *obj, + lpBBox_t *bbox); +extern void lpElement_setTextureManager(lpElement_t *p, struct lpTextures *textures); - // image specific attributes - int imgXsize, - imgYsize, - imgZsize; +// texture class for managing graphics textures +typedef struct texture { + // image specific attributes - unsigned char *pixels; + int imgXsize, + imgYsize, + imgZsize; - // texture specific attributes +#ifdef WANT_SDL + SDL_Surface *surface; +#else + unsigned char *pixels; +#endif - GLuint bind_id; - GLuint format, // GL_RGB etc. - type; // GL_UNSIGNED_BYTE etc. + // texture specific attributes - unsigned char *texels; + GLuint bind_id; + GLuint format, // GL_RGB etc. + type; // GL_UNSIGNED_BYTE etc. - int texSsize, // power of 2 texture size - texTsize; + unsigned char *texels; - float texSmin, - texSmax, - texTmin, - texTmax, + int texSsize, // power of 2 texture size + texTsize; - texCropSmin, // for cropping grab data - texCropSmax, - texCropTmin, - texCropTmax; + float texSmin, + texSmax, + texTmin, + texTmax, + texCropSmin, // for cropping grab data + texCropSmax, + texCropTmin, + texCropTmax; } texture_t; -class lpTextures -{ - private: - - void growTextures(void); - - public: - lpTextures(); - ~lpTextures(); - +typedef struct lpTextures { int num_textures, - max_textures, + max_textures, last_accessed; texture_t **tex; +} lpTextures_t; + +extern lpTextures_t *lpTextures_new(void); +extern void lpTextures_delete(lpTextures_t *p); +extern void lpTextures_init(lpTextures_t *p); +extern void lpTextures_fini(lpTextures_t *p); + +// private functions + +extern void lpTextures_growTextures(lpTextures_t *p); + +// public functions - int addTexture(char *fname); - int downloadTextures(void); - void bindTexture(int n); - void TexCoord2fv(float *st); -}; +extern int lpTextures_addTexture(lpTextures_t *p, char *fname); +extern int lpTextures_downloadTextures(lpTextures_t *p); +extern void lpTextures_bindTexture(lpTextures_t *p, int n); +extern void lpTextures_TexCoord2fv(lpTextures_t *p, float *st); +#endif /* !_LP_GFX_DEFS */ diff --git a/frontpanel/lp_main.c b/frontpanel/lp_main.c new file mode 100644 index 00000000..f662a544 --- /dev/null +++ b/frontpanel/lp_main.c @@ -0,0 +1,422 @@ +// lp_main.c lightpanel main interface + +/* Copyright (c) 2007-2015, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt + + This software is freely distributable free of charge and without license fees with the + following conditions: + + 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 + JOHN KICHURY 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. + + The above copyright notice must be included in any copies of this software. + +*/ + +/* Fixed portability problems, March 2014, Udo Munk */ + +#include +#include +#ifdef WANT_SDL +#include +#include +#else +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) +#include +#endif +#include +#include +#include +#endif + +#include "frontpanel.h" +#include "lpanel.h" +#include "lp_main.h" +#include "lp_utils.h" + +#define UNUSED(x) (void) (x) + +#ifdef WANT_SDL +static SDL_mutex *data_sample_lock; +#else +static pthread_mutex_t data_lock; +static pthread_mutex_t data_sample_lock; +static thread_info_t thread_info; +#endif + +static int framecount = 0; +static int samplecount = 0; + +Lpanel_t *panel; +Parser_t parser; + +#ifndef WANT_SDL + +static void *lp_mainloop_thread(void *n) +{ + int quit = 0; + double t1, t2; + + UNUSED(n); + + // printf("mainloop thread starting\n"); + thread_info.running = 1; + Lpanel_openWindow(panel, "FrontPanel"); + + t1 = frate_gettime(); + framerate_start_frame(); + + while(!quit) { + // lock + pthread_mutex_lock(&data_lock); + + // proc events + // Lpanel_sampleData(panel); + Lpanel_procEvents(panel); + + // draw + pthread_mutex_lock(&data_sample_lock); + Lpanel_draw(panel); + pthread_mutex_unlock(&data_sample_lock); + + // unlock + pthread_mutex_unlock(&data_lock); + + // sleep remainder of fps time + glFinish(); + framerate_wait(); + t2 = frate_gettime(); + framecount++; + framerate_start_frame(); + + if (t2 - t1 > 1.0) { + panel->frames_per_second = framecount; + panel->samples_per_second = samplecount; + t1 = frate_gettime(); + framecount = 0; + samplecount = 0; + } + + if (!thread_info.run) + quit = 1; + + } // end while(!quit) + + pthread_mutex_lock(&data_lock); + Lpanel_destroyWindow(panel); + pthread_mutex_unlock(&data_lock); + thread_info.running = 0; + return NULL; +} + +static int start_threads(void) +{ + int n; + + pthread_mutex_init(&data_lock, NULL); + pthread_mutex_init(&data_sample_lock, NULL); + thread_info.run = 1; + n = pthread_create(&thread_info.thread_id, NULL, lp_mainloop_thread, + &thread_info.thread_no); + if (n) { + fprintf(stderr, "error %d starting mainloop thread\n",n); + return 0; + } + + // fprintf(stderr, "FrontPanel mainloop thread start (PID=%d)\n", thread_info.thread_id); + + return 1; +} + +#endif /* !WANT_SDL */ + +// bind functions + +int fp_bindLight64(const char *name, uint64_t *bits, int bitnum) +{ + // printf("fp_bindLight64: name=%s *bits=%lx bitnum=%d\n", name, *bits, bitnum); + Lpanel_bindLight64(panel, name, bits, bitnum); + return 1; +} + +int fp_bindLight32(const char *name, uint32_t *bits, int bitnum) +{ + Lpanel_bindLight32(panel, name, bits, bitnum); + return 1; +} + +int fp_bindLight16(const char *name, uint16_t *bits, int bitnum) +{ + Lpanel_bindLight16(panel, name, bits, bitnum); + return 1; +} + +int fp_bindLightfv(const char *name, float *bits) +{ + Lpanel_bindLightfv(panel, name, bits); + return 1; +} + +int fp_bindLight8(const char *name, uint8_t *bits, int bitnum) +{ + Lpanel_bindLight8(panel, name, bits, bitnum); + return 1; +} + +int fp_bindLight8invert(const char *name, uint8_t *bits, int bitnum, uint8_t mask) +{ + Lpanel_bindLight8invert(panel, name, bits, bitnum, mask); + return 1; +} + +int fp_bindLight16invert(const char *name, uint16_t *bits, int bitnum, uint16_t mask) +{ + Lpanel_bindLight16invert(panel, name, bits, bitnum, mask); + return 1; +} + +int fp_bindLight32invert(const char *name, uint32_t *bits, int bitnum, uint32_t mask) +{ + Lpanel_bindLight32invert(panel, name, bits, bitnum, mask); + return 1; +} + +int fp_bindLight64invert(const char *name, uint64_t *bits, int bitnum, uint64_t mask) +{ + Lpanel_bindLight64invert(panel, name, bits, bitnum, mask); + return 1; +} + +int fp_smoothLight(const char *name, int nframes) +{ + Lpanel_smoothLight(panel, name, nframes); + return 1; +} + +void fp_bindRunFlag(uint8_t *addr) +{ + Lpanel_bindRunFlag(panel, addr); +} + +void fp_bindSimclock(uint64_t *addr) +{ + Lpanel_bindSimclock(panel, addr); +} + +int fp_bindSwitch8(const char *name, uint8_t *loc_down, uint8_t *loc_up, int bitnum) +{ + Lpanel_bindSwitch8(panel, name, loc_down, loc_up, bitnum); + return 1; +} + +int fp_bindSwitch16(const char *name, uint16_t *loc_down, uint16_t *loc_up, int bitnum) +{ + Lpanel_bindSwitch16(panel, name, loc_down, loc_up, bitnum); + return 1; +} + +int fp_bindSwitch32(const char *name, uint32_t *loc_down, uint32_t *loc_up, int bitnum) +{ + Lpanel_bindSwitch32(panel, name, loc_down, loc_up, bitnum); + return 1; +} + +int fp_bindSwitch64(const char *name, uint64_t *loc_down, uint64_t *loc_up, int bitnum) +{ + Lpanel_bindSwitch64(panel, name, loc_down, loc_up, bitnum); + return 1; +} + +void fp_ignoreBindErrors(int n) +{ + Lpanel_ignoreBindErrors(panel, n != 0); +} + +void fp_framerate(float v) +{ + Lpanel_framerate_set(panel, v); + framerate_set(v); +} + +int fp_init(const char *cfg_fname) +{ + return fp_init2(NULL, cfg_fname, 800); +} + +int fp_init2(const char *cfg_root_path, const char *cfg_fname, int size) +{ + printf("FrontPanel Simulator v2.1 Copyright (C) 2007-2015 by John Kichury\n"); +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + printf("Windows version Copyright (C) 2014 by Stefano Bodrato\n"); +#endif +#ifdef WANT_SDL + printf("SDL2 version Copyright (C) 2024-2025 by Thomas Eberhardt\n"); +#endif + + // allocate & initialize panel and parser instance + panel = Lpanel_new(); + Parser_init(&parser); + + if (cfg_root_path) + Lpanel_setConfigRootPath(panel, cfg_root_path); + + // set a default framerate + fp_framerate(30.); + + // set initial window size + panel->window_xsize = size; + + if (!Lpanel_readConfig(panel, cfg_fname)) { + fprintf(stderr, "fp_init: error initializing the panel\n"); + return 0; + } + +#ifndef WANT_SDL + start_threads(); +#endif + + return 1; +} + +#ifdef WANT_SDL + +void fp_openWindow(void) +{ + data_sample_lock = SDL_CreateMutex(); + + Lpanel_openWindow(panel, "FrontPanel"); + Lpanel_initGraphics(panel); +} + +void fp_procEvent(SDL_Event *event) +{ + Lpanel_procEvent(panel, event); +} + +void fp_draw(bool tick) +{ + SDL_LockMutex(data_sample_lock); + Lpanel_draw(panel); + SDL_UnlockMutex(data_sample_lock); + glFinish(); + framecount++; + if (tick) { + panel->frames_per_second = framecount; + panel->samples_per_second = samplecount; + framecount = 0; + samplecount = 0; + } +} + +#else /* !WANT_SDL */ + +void fp_openWindow(void) +{ + start_threads(); +} + +void fp_procEvents(void) +{ + Lpanel_procEvents(panel); +} + +void fp_draw(void) +{ + Lpanel_draw(panel); +} + +#endif /* !WANT_SDL */ + +void fp_sampleData(void) +{ + // mutex lock +#ifdef WANT_SDL + SDL_LockMutex(data_sample_lock); +#else + pthread_mutex_lock(&data_sample_lock); +#endif + + Lpanel_sampleData(panel); + + // mutex unlock +#ifdef WANT_SDL + SDL_UnlockMutex(data_sample_lock); +#else + pthread_mutex_unlock(&data_sample_lock); +#endif + + samplecount++; +} + +void fp_sampleLightGroup(int groupnum, int clockwarp) +{ + Lpanel_sampleLightGroup(panel, groupnum, clockwarp); + samplecount++; +} + +void fp_sampleSwitches(void) +{ + Lpanel_sampleSwitches(panel); +} + +// callback functions + +int fp_addSwitchCallback(const char *name, void (*cbfunc)(int state, int val), + int userval) +{ + Lpanel_addSwitchCallback(panel, name, cbfunc, userval); + return 1; +} + +void fp_addQuitCallback(void (*cbfunc)(void)) +{ + Lpanel_addQuitCallback(panel, cbfunc); +} + +void fp_quit(void) +{ +#ifdef WANT_SDL + Lpanel_destroyWindow(panel); + + SDL_DestroyMutex(data_sample_lock); +#else /* !WANT_SDL */ + int i; + bool okay = false; + + pthread_mutex_lock(&data_lock); + thread_info.run = 0; + pthread_mutex_unlock(&data_lock); + + for (i = 0; i < 10; i++) { + pthread_mutex_lock(&data_lock); + if(thread_info.running == 0) { + okay = true; + break; + } + pthread_mutex_unlock(&data_lock); +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + Sleep(1000); +#else + sleep(1); +#endif + } + + if (!okay) { + Lpanel_destroyWindow(panel); + fprintf(stderr, "Error. lightpanel draw thread did not terminate\n"); + } +#endif /* !WANT_SDL */ + + // finalize & deallocate panel and parser instance + Parser_fini(&parser); + Lpanel_delete(panel); +} + +int fp_test(int n) +{ + return Lpanel_test(panel, n); +} diff --git a/frontpanel/lp_main.cpp b/frontpanel/lp_main.cpp deleted file mode 100644 index 477b2e66..00000000 --- a/frontpanel/lp_main.cpp +++ /dev/null @@ -1,354 +0,0 @@ -// lp_main.cpp light panel main interface - -/* Copyright (c) 2007-2015, John Kichury - - This software is freely distributable free of charge and without license fees with the - following conditions: - - 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 - JOHN KICHURY 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. - - The above copyright notice must be included in any copies of this software. - -*/ - -/* Fixed portability problems, March 2014, Udo Munk */ - - -#include -#include -#include -#include - -#include -#include -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -#include -#else -#include -#endif -#ifdef __linux__ -#include -#endif -#include - -#include "lpanel.h" -#include "lp_main.h" -#include "lp_utils.h" - -#define UNUSED(x) (void) (x) - - -//static pthread_mutex_t data_lock; -pthread_mutex_t data_lock; -pthread_mutex_t data_sample_lock; -extern pthread_mutex_t data_sample_lock; - -static thread_info_t thread_info; -static Lpanel *panel = new Lpanel; -static int samplecount = 0; - -void * -lp_mainloop_thread(void *n) -{ - int quit = 0; - double t1, t2; - int framecount = 0; - - UNUSED(n); - - //printf("mainloop thread starting\n"); - thread_info.running = 1; - panel->openWindow("FrontPanel"); - - t1 = frate_gettime(); - framerate_start_frame(); - - while(!quit) - { - // lock - pthread_mutex_lock(&data_lock); - - // proc events - -// panel->sampleData(); - panel->procEvents(); - - // draw - - pthread_mutex_lock(&data_sample_lock); - panel->draw(); - pthread_mutex_unlock(&data_sample_lock); - - // unlock - pthread_mutex_unlock(&data_lock); - - // sleep remainder of fps time - glFinish(); - framerate_wait(); - t2 = frate_gettime(); - framecount++; - framerate_start_frame(); - - if(t2 - t1 > 1.0) - { - panel->frames_per_second = framecount; - panel->samples_per_second = samplecount; - t1 = frate_gettime(); - framecount = 0; - samplecount = 0; - } - - if( !thread_info.run ) quit = 1; - - } // end while(!quit) - pthread_mutex_lock(&data_lock); - panel->Quit(); - panel->destroyWindow(); - pthread_mutex_unlock(&data_lock); - thread_info.running = 0; - return NULL; -} - -int start_threads(void) -{ - // don't use unitialised attr, use NULL pointer instead. **UM** - //static pthread_attr_t attr; - int n; - - pthread_mutex_init(&data_lock,NULL); - pthread_mutex_init(&data_sample_lock,NULL); - thread_info.run = 1; - //n = pthread_create(&thread_info.thread_id, &attr, lp_mainloop_thread, &thread_info.thread_no); - n = pthread_create(&thread_info.thread_id, NULL, lp_mainloop_thread, &thread_info.thread_no); - if(n) - { fprintf(stderr,"error %d starting mainloop thread\n",n); - return 0; - } - - //fprintf(stderr,"FrontPanel mainloop thread start (PID=%d)\n",thread_info.thread_id); - - return 1; -} - -// bind functions - -int fp_bindLight64(const char *name, uint64_t *bits, int bitnum) -{ -//printf("fp_bindLight64: name=%s *bits=%lx bitnum=%d\n",name,*bits,bitnum); - panel->bindLight64(name,bits,bitnum); - return 1; -} - -int fp_bindLight32(const char *name, uint32_t *bits, int bitnum) -{ - panel->bindLight32(name,bits,bitnum); - return 1; -} - -int fp_bindLight16(const char *name, uint16_t *bits, int bitnum) -{ - panel->bindLight16(name,bits,bitnum); - return 1; -} - -int fp_bindLightfv(const char *name, float *bits) -{ - panel->bindLightfv(name,bits); - return 1; -} - -int fp_bindLight8(const char *name, uint8_t *bits, int bitnum) -{ - panel->bindLight8(name,bits,bitnum); - return 1; -} - -int fp_bindLight8invert(const char *name, uint8_t *bits, int bitnum, uint8_t mask) -{ - panel->bindLight8invert(name,bits,bitnum, mask); - return 1; -} - -int fp_bindLight16invert(const char *name, uint16_t *bits, int bitnum, uint16_t mask) -{ - panel->bindLight16invert(name,bits,bitnum, mask); - return 1; -} - -int fp_bindLight32invert(const char *name, uint32_t *bits, int bitnum, uint32_t mask) -{ - panel->bindLight32invert(name,bits,bitnum, mask); - return 1; -} - -int fp_bindLight64invert(const char *name, uint64_t *bits, int bitnum, uint64_t mask) -{ - panel->bindLight64invert(name,bits,bitnum, mask); - return 1; -} - -int fp_smoothLight(const char *name, int nframes) -{ - panel->smoothLight(name,nframes); - return 1; -} - -void fp_bindRunFlag(uint8_t *addr) -{ - panel->bindRunFlag(addr); -} - -void fp_bindSimclock( uint64_t *addr) -{ - panel->bindSimclock(addr); -} - -int fp_bindSwitch8(const char *name, uint8_t *loc_down, uint8_t *loc_up, int bitnum) -{ - panel->bindSwitch8(name, loc_down, loc_up, bitnum); - return 1; -} - -int fp_bindSwitch16(const char *name, uint16_t *loc_down, uint16_t *loc_up, int bitnum) -{ - panel->bindSwitch16(name, loc_down, loc_up, bitnum); - return 1; -} - -int fp_bindSwitch32(const char *name, uint32_t *loc_down, uint32_t *loc_up, int bitnum) -{ - panel->bindSwitch32(name, loc_down, loc_up, bitnum); - return 1; -} -int fp_bindSwitch64(const char *name, uint64_t *loc_down, uint64_t *loc_up, int bitnum) -{ - panel->bindSwitch64(name, loc_down, loc_up, bitnum); - return 1; -} - -void fp_ignoreBindErrors(int n) -{ panel->ignoreBindErrors(n); -} - -void fp_framerate(float v) -{ - if(panel) panel->framerate_set(v); - framerate_set(v); -} - -int fp_init(const char *cfg_fname) -{ - return fp_init2(NULL, cfg_fname, 800); -} - - -int fp_init2(const char *cfg_root_path, const char *cfg_fname, int size) -{ - printf("FrontPanel Simulator v2.1 Copyright (C) 2007-2015 by John Kichury\n"); -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - printf("Windows version Copyright (C) 2014 by Stefano Bodrato\n"); -#endif - - if(panel == NULL) panel = new Lpanel; - - // set a default framerate - - if(cfg_root_path) panel->setConfigRootPath(cfg_root_path); - - fp_framerate(30.); - - // set initial window size - panel->window_xsize = size; - - if(!panel->readConfig(cfg_fname)) - { fprintf(stderr, "fp_init: error initializing the panel\n"); - return 0; - } - - start_threads(); - return 1; -} - -int fp_openWindow(const char *title) -{ - UNUSED(title); - - start_threads(); - return 1; -} - -void fp_procEvents(void) -{ - panel->procEvents(); -} -void fp_draw(void) -{ - panel->draw(); -} - -void fp_sampleData(void) -{ panel->sampleData(); - samplecount++; -} - -void fp_sampleLightGroup(int groupnum, int clockwarp) -{ panel->sampleLightGroup(groupnum, clockwarp); - samplecount++; -} - -void fp_sampleSwitches(void) -{ panel->sampleSwitches(); -} - -// callback functions - -int fp_addSwitchCallback(const char *name, void (*cbfunc)(int state, int val), int userval) -{ - panel->addSwitchCallback(name, cbfunc, userval); - return 1; -} - -void fp_addQuitCallback(void (*cbfunc)(void)) -{ - panel->addQuitCallback(cbfunc); -} - -void fp_quit(void) -{ - int i, okay=0; - - pthread_mutex_lock(&data_lock); - thread_info.run = 0; - pthread_mutex_unlock(&data_lock); - - for(i=0;i<10;i++) - { - pthread_mutex_lock(&data_lock); - if(thread_info.running == 0) - { okay = 1; - break; - } - pthread_mutex_unlock(&data_lock); -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - Sleep(1000); -#else - sleep(1); -#endif - } - - if(!okay) fprintf(stderr, "Error. lightpanel draw thread did not terminate\n"); - -} - - -int -fp_test(int n) -{ - return panel->test(n); -} - diff --git a/frontpanel/lp_main.h b/frontpanel/lp_main.h index d6391591..b3683471 100644 --- a/frontpanel/lp_main.h +++ b/frontpanel/lp_main.h @@ -2,7 +2,7 @@ /* Copyright (c) 2007-2008, John Kichury - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -16,22 +16,21 @@ */ -#include "frontpanel.h" - #ifndef _LP_MAIN_DEFS #define _LP_MAIN_DEFS -typedef struct -{ - int thread_no; - int quit; - int run; - int running; - pthread_t thread_id; -} thread_info_t; +#ifndef WANT_SDL -void fp_procEvents(void); -void fp_draw(void); +#include +typedef struct thread_info { + int thread_no; + int quit; + int run; + int running; + pthread_t thread_id; +} thread_info_t; #endif + +#endif /* !_LP_MAIN_DEFS */ diff --git a/frontpanel/lp_materials.c b/frontpanel/lp_materials.c new file mode 100644 index 00000000..2782c670 --- /dev/null +++ b/frontpanel/lp_materials.c @@ -0,0 +1,340 @@ +/* lp_materials.c materials functions + + Copyright (c) 2007-2008, John Kichury + + This software is freely distributable free of charge and without license fees with the + following conditions: + + 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 + JOHN KICHURY 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. + + The above copyright notice must be included in any copies of this software. + +*/ + +#include +#ifdef WANT_SDL +#include +#else +#include +#endif + +#include "lp_materials.h" + +#define MAX_MATERIALS 200 + +#define AMBIENT 0 +#define DIFFUSE 4 +#define SPECULAR 8 +#define SHININESS 12 +#define EMISSION 13 + +static float materials[MAX_MATERIALS][17]; +static int material_flag[MAX_MATERIALS]; /* true = material set by user */ +static int material_used_flag[MAX_MATERIALS]; /* true = material is used */ +static int material_alpha_flag[MAX_MATERIALS]; /* true = material has an alpha component < 1.0 */ +static int list_offset = 0; + +void lp_init_materials_flags(void) +{ + int i; + + for (i = 0; i < MAX_MATERIALS; i++) { + material_flag[i] = GL_FALSE; + material_used_flag[i] = GL_FALSE; + material_alpha_flag[i] = GL_FALSE; + } +} + +void lp_init_materials_dlist(void) +{ + if (list_offset) + glDeleteLists(list_offset, MAX_MATERIALS); + list_offset = glGenLists(MAX_MATERIALS); +} + +bool lp_is_material_alpha(int n) +{ + return material_alpha_flag[n] == GL_TRUE; + +} +void lp_init_materials(void) +{ + lp_init_materials_flags(); + + lp_set_material_params(1, 0.01, 0.01, 0.01, 1.0, /* black */ + 0.0, 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(2, 0.1, 0.0, 0.0, 1.0, /* red */ + 1.0, 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(3, 0.2, 0.12, 0.0, 1.0, /* orange */ + 1.0, 0.6, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(4, 0.2, 0.2, 0.0, 1.0, /* yellow */ + 1.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(5, 0.0, 0.2, 0.0, 1.0, /* green */ + 0.0, 0.5, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(6, 0.0, 0.2, 0.2, 1.0, /* cyan */ + 0.0, 1.0, 1.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(7, 0.0, 0.0, 0.2, 1.0, /* blue */ + 0.0, 0.0, 1.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(8, 0.2, 0.0, 0.2, 1.0, /* violet */ + 1.0, 0.0, 1.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(9, 0.12, 0.02, 0.0, 1.0, /* brown */ + 0.63, 0.10, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(10, 0.2, 0.2, 0.2, 1.0, /* white */ + 1.0, 1.0, 1.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(11, 0.2, 0.02, 0.02, 1.0, /* pink */ + 1.0, 0.5, 0.5, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(12, 0.06, 0.0, 0.18, 1.0, /* mauve */ + 0.3, 0.0, 0.9, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(13, 0.0, 0.2, 0.2, 1.0, /* turquoise */ + 0.0, 1.0, 1.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(14, 0.078, 0.0, 0.2, 1.0, /* indigo */ + 0.39, 0.0, 1.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(15, 0.15, 0.15, 0.15, 1.0, /* grey */ + 0.78, 0.78, 0.78, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(16, 0.2, 0.0, 0.2, 1.0, /* magenta */ + 1.0, 0.0, 1.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + /* specular materials */ + + lp_set_material_params(17, 0.02, 0.02, 0.02, 1.0, /* shiny black */ + 0.0, 0.0, 0.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(18, 0.2, 0.0, 0.0, 1.0, /* shiny red */ + 1.0, 0.0, 0.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(19, 0.2, 0.1, 0.0, 1.0, /* shiny orange */ + 1.0, 0.6, 0.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(20, 0.2, 0.2, 0.0, 1.0, /* shiny yellow */ + 1.0, 1.0, 0.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(21, 0.0, 0.2, 0.0, 1.0, /* shiny green */ + 0.0, 1.0, 0.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(22, 0.0, 0.2, 0.2, 1.0, /* shiny cyan */ + 0.0, 1.0, 1.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(23, 0.0, 0.0, 0.2, 1.0, /* shiny blue */ + 0.0, 0.0, 1.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(24, 0.2, 0.0, 0.2, 1.0, /* shiny violet */ + 1.0, 0.0, 1.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(25, 0.12, 0.02, 0.0, 1.0, /* shiny brown */ + 0.63, 0.10, 0.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(26, 0.2, 0.2, 0.2, 1.0, /* shiny white */ + 1.0, 1.0, 1.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(27, 0.2, 0.02, 0.02, 1.0, /* shiny pink */ + 1.0, 0.5, 0.5, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(28, 0.06, 0.0, 0.18, 1.0, /* shiny mauve */ + 0.3, 0.0, 0.9, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(29, 0.0, 0.2, 0.2, 1.0, /* shiny turquoise */ + 0.0, 1.0, 1.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(30, 0.078, 0.0, 0.2, 1.0, /* shiny indigo */ + 0.39, 0.0, 1.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(31, 0.15, 0.15, 0.15, 1.0, /* shiny grey */ + 0.78, 0.78, 0.78, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(32, 0.2, 0.0, 0.2, 1.0, /* shiny magenta */ + 1.0, 0.0, 1.0, 1.0, + 0.4, 0.4, 0.4, 1.0, 10.0, 0.0, 0.0, 0.0, 1.0); + + /* special materials */ + + lp_set_material_params(33, 0.35, 0.25, 0.1, 1.0, /* brass */ + 0.65, 0.5, 0.35, 1.0, + 0.0, 0.0, 0.0, 1.0, + 2.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(34, 0.25, 0.15, 0.0, 1.0, /* shiny brass */ + 0.65, 0.5, 0.35, 1.0, + 0.9, 0.6, 0.0, 1.0, + 20.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(35, 0.0, 0.0, 0.0, 1.0, /* pewter */ + 0.6, 0.55, 0.65, 1.0, + 0.9, 0.9, 0.95, 1.0, + 10.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(36, 0.4, 0.4, 0.4, 1.0, /* silver */ + 0.3, 0.3, 0.3, 1.0, + 0.9, 0.9, 0.95, 1.0, + 30.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(37, 0.4, 0.2, 0.0, 1.0, /* gold */ + 0.9, 0.5, 0.0, 1.0, + 0.5, 0.5, 0.0, 1.0, + 2.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(38, 0.4, 0.2, 0.0, 1.0, /* shiny gold */ + 0.9, 0.5, 0.0, 1.0, + 0.9, 0.9, 0.0, 1.0, + 20.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(39, 0.3, 0.1, 0.1, 1.0, /* red plastic */ + 0.5, 0.1, 0.1, 1.0, + 0.45, 0.45, 0.45, 1.0, + 30.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(40, 0.1, 0.3, 0.1, 1.0, /* green plastic */ + 0.1, 0.5, 0.1, 1.0, + 0.45, 0.45, 0.45, 1.0, + 30.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(41, 0.1, 0.1, 0.3, 1.0, /* blue plastic */ + 0.1, 0.1, 0.5, 1.0, + 0.45, 0.45, 0.45, 1.0, + 30.0, 0.0, 0.0, 0.0, 1.0); + + lp_set_material_params(42, 0.2, 0.2, 0.2, 1.0, /* plaster */ + 0.95, 0.95, 0.95, .80, + 0.0, 0.0, 0.0, 1., + 1.0, 0.0, 0.0, 0.0, 1.0); + +} + +void lp_set_material_params(int n, /* material number */ + float Ar, float Ag, float Ab, float Aa, /* Ambient rgba */ + float Dr, float Dg, float Db, float Da, /* Diffuse rgba */ + float Sr, float Sg, float Sb, float Sa, /* Specular rgba */ + float shine, /* shinyness */ + float Er, float Eg, float Eb, float Ea) /* emission rgba */ +{ + if (n >= MAX_MATERIALS) { + printf("Attempt to exceed Max amount of defined materials.\n"); + printf("Max allowed is %d.\n", MAX_MATERIALS); + return; + } + + /* if the material flag is TRUE, ignore this material, user has this defined + as a custom material. */ + + if (material_flag[n]) + return; + + materials[n][AMBIENT] = Ar; + materials[n][AMBIENT + 1] = Ag; + materials[n][AMBIENT + 2] = Ab; + materials[n][AMBIENT + 3] = Aa; + + materials[n][DIFFUSE] = Dr; + materials[n][DIFFUSE + 1] = Dg; + materials[n][DIFFUSE + 2] = Db; + materials[n][DIFFUSE + 3] = Da; + + materials[n][SPECULAR] = Sr; + materials[n][SPECULAR + 1] = Sg; + materials[n][SPECULAR + 2] = Sb; + materials[n][SPECULAR + 3] = Sa; + + materials[n][SHININESS] = shine; + + materials[n][EMISSION] = Er; + materials[n][EMISSION + 1] = Eg; + materials[n][EMISSION + 2] = Eb; + materials[n][EMISSION + 3] = Ea; + + if (Aa < 1.0 || Da < 1.0 || Sa < 1.0 || Ea < 1.0) + material_alpha_flag[n] = GL_TRUE; +} /* end set_material_params() */ + +void lp_set_user_material_params(int n, /* material num */ + float Ar, float Ag, float Ab, float Aa, /* Ambient rgba */ + float Dr, float Dg, float Db, float Da, /* Diffuse rgba */ + float Sr, float Sg, float Sb, float Sa, /* Specular rgba */ + float shine, /* shinyness */ + float Er, float Eg, float Eb, float Ea) /* emission rgba */ +{ + if (n >= MAX_MATERIALS) { + printf("Attempt to exceed Max amount of defined materials.\n"); + printf("Max allowed is %d.\n", MAX_MATERIALS); + return; + } + lp_set_material_params(n, Ar, Ag, Ab, Aa, Dr, Dg, Db, Da, Sr, Sg, Sb, Sa, shine, + Er, Eg, Eb, Ea); + material_flag[n] = GL_TRUE; /* mark it as a custom material */ + + if (Aa < 1.0 || Da < 1.0 || Sa < 1.0 || Ea < 1.0) + material_alpha_flag[n] = GL_TRUE; +} + +void lp_bind_material(int n) +{ + static int currmat = -1; + + if (n >= MAX_MATERIALS) + return; + + if (n != currmat) { + if (material_used_flag[n]) { + glCallList(n + list_offset); + } else { + glNewList(n + list_offset, GL_COMPILE_AND_EXECUTE); + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &materials[n][AMBIENT]); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &materials[n][DIFFUSE]); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &materials[n][SPECULAR]); + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &materials[n][SHININESS]); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &materials[n][EMISSION]); + glEndList(); + material_used_flag[n] = GL_TRUE; + } + currmat = n; + } +} diff --git a/frontpanel/lp_materials.cpp b/frontpanel/lp_materials.cpp deleted file mode 100644 index 2f40f5b3..00000000 --- a/frontpanel/lp_materials.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/* lp_materials.C materials functions - - Copyright (c) 2007-2008, John Kichury - - This software is freely distributable free of charge and without license fees with the - following conditions: - - 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 - JOHN KICHURY 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. - - The above copyright notice must be included in any copies of this software. - -*/ - -#include -#include -#include -#include "lp_materials.h" - -#define MAX_MATERIALS 200 - -#define AMBIENT 0 -#define DIFFUSE 4 -#define SPECULAR 8 -#define SHININESS 12 -#define EMISSION 13 - -static float materials[MAX_MATERIALS][17]; -static int material_flag[MAX_MATERIALS]; /* true = material set by user */ -static int material_used_flag[MAX_MATERIALS]; /* true = material is used */ -static int material_alpha_flag[MAX_MATERIALS]; /* true = material has an alpha component < 1.0*/ -static int list_offset = 0; - -void lp_init_materials_flags(void) -{ int i; - - for(i=0;i= MAX_MATERIALS) - { printf("Attempt to exceed Max amount of defined materials.\n"); - printf("Max allowed is %d.\n",MAX_MATERIALS); - return; - } - - /* if the material flag is TRUE, ignore this material, user has this defined - as a custom material. */ - - if(material_flag[n] ) return; - - materials[n][AMBIENT] = Ar; - materials[n][AMBIENT+1] = Ag; - materials[n][AMBIENT+2] = Ab; - materials[n][AMBIENT+3] = Aa; - - materials[n][DIFFUSE] = Dr; - materials[n][DIFFUSE+1] = Dg; - materials[n][DIFFUSE+2] = Db; - materials[n][DIFFUSE+3] = Da; - - materials[n][SPECULAR] = Sr; - materials[n][SPECULAR+1] = Sg; - materials[n][SPECULAR+2] = Sb; - materials[n][SPECULAR+3] = Sa; - - materials[n][SHININESS] = shine; - - materials[n][EMISSION] = Er; - materials[n][EMISSION+1] = Eg; - materials[n][EMISSION+2] = Eb; - materials[n][EMISSION+3] = Ea; - - if(Aa < 1.0 || Da < 1.0 || Sa < 1.0 || Ea < 1.0) - material_alpha_flag[n] = GL_TRUE; -} /* end set_material_params() */ - - - - -void lp_set_user_material_params(int n, /* material num */ - float Ar,float Ag,float Ab,float Aa, /* Ambient rgba */ - float Dr, float Dg,float Db,float Da, /* Diffuse rgba */ - float Sr,float Sg,float Sb,float Sa, /* Specular rgba */ - float shine, /* shinyness */ - float Er,float Eg,float Eb,float Ea) /* emission rgba */ -{ - if(n >= MAX_MATERIALS) - { printf("Attempt to exceed Max amount of defined materials.\n"); - printf("Max allowed is %d.\n",MAX_MATERIALS); - return; - } - lp_set_material_params(n,Ar,Ag,Ab,Aa,Dr,Dg,Db,Da,Sr,Sg,Sb,Sa,shine,Er,Eg,Eb,Ea); - material_flag[n] = GL_TRUE; /* mark it as a custom material */ - - if(Aa < 1.0 || Da < 1.0 || Sa < 1.0 || Ea < 1.0) - material_alpha_flag[n] = GL_TRUE; -} - - -void lp_bind_material(int n) -{ - static int currmat = -1; - - - if(n >= MAX_MATERIALS) return; - - if(n != currmat) - { - if(material_used_flag[n]) - { - glCallList(n + list_offset); - } - else - { glNewList(n + list_offset,GL_COMPILE_AND_EXECUTE); - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &materials[n][AMBIENT]); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &materials[n][DIFFUSE]); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &materials[n][SPECULAR]); - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &materials[n][SHININESS]); - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &materials[n][EMISSION]); - glEndList(); - material_used_flag[n] = GL_TRUE; - } - currmat = n; - } -} - diff --git a/frontpanel/lp_materials.h b/frontpanel/lp_materials.h index 3582bdb5..01f5c64f 100644 --- a/frontpanel/lp_materials.h +++ b/frontpanel/lp_materials.h @@ -1,9 +1,8 @@ // lp_materials.h - /* Copyright (c) 2007-2008, John Kichury - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -17,27 +16,28 @@ */ -#ifndef _MTL_DEFS_ -#define _MTL_DEFS_ +#ifndef _LP_MATERIALS_DEFS_ +#define _LP_MATERIALS_DEFS_ -void lp_set_material_params(int n, /* material num */ - float Ar,float Ag,float Ab,float Aa, /* Ambient rgba */ - float Dr, float Dg,float Db,float Da, /* Diffuse rgba */ - float Sr,float Sg,float Sb,float Sa, /* Specular rgba */ - float shine, /* shinyness */ - float Er,float Eg,float Eb,float Ea); /* emission rgba */ +#include -void lp_set_user_material_params(int n, /* material num */ - float Ar,float Ag,float Ab,float Aa, /* Ambient rgba */ - float Dr, float Dg,float Db,float Da, /* Diffuse rgba */ - float Sr,float Sg,float Sb,float Sa, /* Specular rgba */ - float shine, /* shinyness */ - float Er,float Eg,float Eb,float Ea); /* emission rgba */ +extern void lp_set_material_params(int n, /* material num */ + float Ar, float Ag, float Ab, float Aa, /* Ambient rgba */ + float Dr, float Dg, float Db, float Da, /* Diffuse rgba */ + float Sr, float Sg, float Sb, float Sa, /* Specular rgba */ + float shine, /* shinyness */ + float Er, float Eg, float Eb, float Ea); /* emission rgba */ -void lp_bind_material(int n); -void lp_init_materials(void); -void lp_init_materials_dlist(void); -int lp_is_material_alpha(int n); -#endif +extern void lp_set_user_material_params(int n, /* material num */ + float Ar, float Ag, float Ab, float Aa, /* Ambient rgba */ + float Dr, float Dg, float Db, float Da, /* Diffuse rgba */ + float Sr, float Sg, float Sb, float Sa, /* Specular rgba */ + float shine, /* shinyness */ + float Er, float Eg, float Eb, float Ea); /* emission rgba */ +extern void lp_bind_material(int n); +extern void lp_init_materials(void); +extern void lp_init_materials_dlist(void); +extern bool lp_is_material_alpha(int n); +#endif /* !_LP_MATERIALS_DEFS */ diff --git a/frontpanel/lp_switch.c b/frontpanel/lp_switch.c new file mode 100644 index 00000000..5dd651e0 --- /dev/null +++ b/frontpanel/lp_switch.c @@ -0,0 +1,933 @@ +// lp_switch.c lightpanel switch class + +/* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt + + This software is freely distributable free of charge and without license fees with the + following conditions: + + 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 + JOHN KICHURY 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. + + The above copyright notice must be included in any copies of this software. + +*/ + +#include +#include +#include +#include +#ifdef WANT_SDL +#include +#else +#include +#endif + +#include "lpanel.h" +#include "lp_switch.h" +#include "lp_utils.h" + +#define UNUSED(x) (void) (x) + +// parse rules for switches defined in the user configuration file + +static parser_rules_t switch_parse_rules[] = { + { "type", 1, 1, PARSER_STRING }, + { "operate", 1, 1, PARSER_STRING }, + { "pos", 2, 3, PARSER_FLOAT }, + { "size", 2, 3, PARSER_FLOAT }, + { "objects", 1, 3, PARSER_STRING }, + { NULL, 0, 0, 0 } +}; + +extern Parser_t parser; // parser class for parsing config arguments + +// supporting render functions + +static void lp_drawSwitchObjectDummy(lpSwitch_t *p) +{ + UNUSED(p); + + // a stub function for switches that do not have a render object defined +} + +static void lp_drawSwitchObject(lpSwitch_t *p) +{ + int state = p->state; + + glPushMatrix(); + + glTranslatef(p->parms->pos[0], p->parms->pos[1], p->parms->pos[2]); + + glScalef(p->parms->scale[0], p->parms->scale[1], p->parms->scale[2]); + +#if 1 + lpObject_draw_refoverride(p->object_refs[state], 1); +#else + int i; + int flag = 0; + + if (!strcmp(p->name, "SW_11")) + flag = 1; + + glColor3f(1., 0., 0.); + glBegin(GL_POLYGON); + if (flag) + printf("sw_11 targ=\n"); + for (i = 0; i < 4; i++) { + if (flag) + printf("= %f %f\n", + p->up_target[i][0], + p->up_target[i][1]); + glVertex3fv(&p->up_target[i][0]); + } + glEnd(); + + glColor3f(0., 1., 0.); + glBegin(GL_POLYGON); + for (i = 0; i < 4; i++) + glVertex3fv(&p->down_target[i][0]); + glEnd(); +#endif + + glPopMatrix(); +} + +#if 0 +static void lp_drawSwitchObject_rotated(lpSwitch_t *p) +{ + int state = p->state; + + glPushMatrix(); + + glTranslatef(p->parms->pos[0], p->parms->pos[1], p->parms->pos[2]); + + glScalef(p->parms->scale[0], p->parms->scale[1], p->parms->scale[2]); + + glRotatef(p->rotate[state][0], + p->rotate[state][1], + p->rotate[state][2], + p->rotate[state][3]); + + lpObject_draw_refoverride(p->object_refs[state], 1); + + glPopMatrix(); +} + +static void lp_drawSwitchPaddle(lpSwitch_t *p) +{ + int state = p->state; + + glPushMatrix(); + + glTranslatef(p->parms->pos[0], p->parms->pos[1], p->parms->pos[2]); + + glScalef(p->parms->scale[0], p->parms->scale[1], p->parms->scale[2]); + + glRotatef(p->rotate[state][0], + p->rotate[state][1], + p->rotate[state][2], + p->rotate[state][3]); + + // draw_paddle(); + + glPopMatrix(); +} + +static void lp_drawSwitchToggle(lpSwitch_t *p) +{ + int state = p->state; + + glPushMatrix(); + + glTranslatef(p->parms->pos[0], p->parms->pos[1], p->parms->pos[2]); + + glScalef(p->parms->scale[0], p->parms->scale[1], p->parms->scale[2]); + + glRotatef(p->rotate[state][0], + p->rotate[state][1], + p->rotate[state][2], + p->rotate[state][3]); + + // draw_toggle(); + + glPopMatrix(); +} +#endif + + +// lpSwitch class +// -------------- + +lpSwitch_t *lpSwitch_new(void) +{ + lpSwitch_t *p = (lpSwitch_t *) calloc(1, sizeof(lpSwitch_t)); + + if (p) + lpSwitch_init(p); + + return p; +} + +void lpSwitch_delete(lpSwitch_t *p) +{ + if (p) { + lpSwitch_fini(p); + free(p); + } +} + +void lpSwitch_init(lpSwitch_t *p) +{ + p->name = NULL; + p->parms = NULL; + p->gfx_mode = LP_SWITCH_GFX_TOGGLE; + p->state = LP_SWITCH_DOWN; + p->operation = LP_SWITCH_OP_ON_OFF; + p->num_object_refs = 0; + p->drawFunc = NULL; + p->dataptr[0] = p->dataptr[1] = NULL; + p->object_ref_names = NULL; + p->select_up_name = p->select_dn_name = 0; + p->callback = NULL; + p->userdata = 0; +} + +void lpSwitch_fini(lpSwitch_t *p) +{ + int i; + + if (p->name) + free(p->name); + if (p->parms) + free(p->parms); + + if (p->object_ref_names) { + for (i = 0; i < p->num_object_refs; i++) + free(p->object_ref_names[i]); + free(p->object_ref_names); + } +} + +// +// switch action +// ------------- +// val 0=down 1=up 2=release (momentary ) + +void lpSwitch_action(lpSwitch_t *p, int val) +{ + switch (val) { + case 0: // down + + if (p->operation == LP_SWITCH_OP_OFF_MOM) + break; + + p->state = LP_SWITCH_DOWN; + + switch (p->operation) { + case LP_SWITCH_OP_MOM_OFF_MOM: + + p->panel->mom_switch_pressed = p; + + if (p->dataptr[p->state]) + switch (p->datatype) { + case LP_SWITCH_DATATYPE_UINT8: { + uint8_t *ptr, val; + + ptr = (uint8_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr | val; + } + break; + + case LP_SWITCH_DATATYPE_UINT16: { + uint16_t *ptr, val; + + ptr = (uint16_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr | val; + } + break; + case LP_SWITCH_DATATYPE_UINT32: { + uint32_t *ptr, val; + + ptr = (uint32_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr | val; + } + break; + } + break; + + case LP_SWITCH_OP_ON_OFF: + if (p->dataptr[p->state]) + switch (p->datatype) { + case LP_SWITCH_DATATYPE_UINT8: { + uint8_t *ptr, val; + + ptr = (uint8_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr & (~val); + } + break; + case LP_SWITCH_DATATYPE_UINT16: { + uint16_t *ptr, val; + + ptr = (uint16_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr & (~val); + } + break; + case LP_SWITCH_DATATYPE_UINT32: { + uint32_t *ptr, val; + + ptr = (uint32_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr & (~val); + } + break; + } + break; + + } + break; + + case 1: // up + + p->state = LP_SWITCH_UP; + + switch (p->operation) { + case LP_SWITCH_OP_MOM_OFF_MOM: + case LP_SWITCH_OP_OFF_MOM: + p->panel->mom_switch_pressed = p; + /* fallthrough */ + + case LP_SWITCH_OP_ON_OFF: + if (p->dataptr[p->state]) + switch (p->datatype) { + case LP_SWITCH_DATATYPE_UINT8: { + uint8_t *ptr, val; + + ptr = (uint8_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr | val; + } + break; + case LP_SWITCH_DATATYPE_UINT16: { + uint16_t *ptr, val; + + ptr = (uint16_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr | val; + } + break; + case LP_SWITCH_DATATYPE_UINT32: { + uint32_t *ptr, val; + + ptr = (uint32_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr | val; + } + break; + } + break; + + } + break; + + case 2: // release mom switch + + switch (p->operation) { + case LP_SWITCH_OP_MOM_OFF_MOM: + case LP_SWITCH_OP_OFF_MOM: + if (p->dataptr[p->state]) + switch (p->datatype) { + case LP_SWITCH_DATATYPE_UINT8: { + uint8_t *ptr, val; + + ptr = (uint8_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr & (~val); + } + break; + case LP_SWITCH_DATATYPE_UINT16: { + uint16_t *ptr, val; + + ptr = (uint16_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr & (~val); + } + break; + case LP_SWITCH_DATATYPE_UINT32: { + uint32_t *ptr, val; + + ptr = (uint32_t *) p->dataptr[p->state]; + val = 0x1 << p->bitnum; + *ptr = *ptr & (~val); + } + break; + } + p->panel->mom_switch_pressed = NULL; + p->state = LP_SWITCH_CENTER; + break; + + case LP_SWITCH_OP_ON_OFF: + break; + } + break; + + } + if (p->callback) + (*p->callback)(p->state, p->userdata); +} + +void lpSwitch_addCallback(lpSwitch_t *p, lp_switch_cbf_t cbfunc, int userval) +{ + p->callback = cbfunc; + p->userdata = userval; +} + +void lpSwitch_bindData8(lpSwitch_t *p, uint8_t *ptr_down, uint8_t *ptr_up, int bit_number) +{ + p->dataptr[LP_SWITCH_DOWN] = ptr_down; + p->dataptr[LP_SWITCH_UP] = ptr_up; + p->datatype = LP_SWITCH_DATATYPE_UINT8; + p->bitnum = bit_number; +} + +void lpSwitch_bindData16(lpSwitch_t *p, uint16_t *ptr_down, uint16_t *ptr_up, int bit_number) +{ + p->dataptr[LP_SWITCH_DOWN] = ptr_down; + p->dataptr[LP_SWITCH_UP] = ptr_up; + p->datatype = LP_SWITCH_DATATYPE_UINT16; + p->bitnum = bit_number; +} + +void lpSwitch_bindData32(lpSwitch_t *p, uint32_t *ptr_down, uint32_t *ptr_up, int bit_number) +{ + p->dataptr[LP_SWITCH_DOWN] = ptr_down; + p->dataptr[LP_SWITCH_UP] = ptr_up; + p->datatype = LP_SWITCH_DATATYPE_UINT32; + p->bitnum = bit_number; +} + +void lpSwitch_bindData64(lpSwitch_t *p, uint64_t *ptr_down, uint64_t *ptr_up, int bit_number) +{ + p->dataptr[LP_SWITCH_DOWN] = ptr_down; + p->dataptr[LP_SWITCH_UP] = ptr_up; + p->datatype = LP_SWITCH_DATATYPE_UINT64; + p->bitnum = bit_number; +} + +void lpSwitch_setName(lpSwitch_t *p, const char *name) +{ + int n; + + n = strlen(name); + p->name = (char *) malloc(n + 1); + strcpy(p->name, name); +} + +void lpSwitch_sampleData(lpSwitch_t *p) +{ + if (!p->dataptr[0]) + return; + if (p->operation != LP_SWITCH_OP_ON_OFF) + return; + + switch (p->datatype) { + case LP_SWITCH_DATATYPE_UINT8: { + uint8_t *ptr, bit; + + ptr = (uint8_t *) p->dataptr[0]; + bit = (1 << p->bitnum) & *ptr; + if (bit) + p->state = 1; + else + p->state = 0; + } + break; + + case LP_SWITCH_DATATYPE_UINT16: { + uint16_t *ptr, bit; + + ptr = (uint16_t *) p->dataptr[0]; + bit = (1 << p->bitnum) & *ptr; + if (bit) + p->state = 1; + else + p->state = 0; + } + break; + + case LP_SWITCH_DATATYPE_UINT32: { + uint32_t *ptr, bit; + + ptr = (uint32_t *) p->dataptr[0]; + bit = (1 << p->bitnum) & *ptr; + if (bit) + p->state = 1; + else + p->state = 0; + } + break; + } +} + +void lpSwitch_setupData(lpSwitch_t *p, int sw_num) +{ + int i; + + // resolve referenced graphics objects + + for (i = 0; i < p->num_object_refs; i++) { + if (!(p->object_refs[i] = Lpanel_findObjectByName(p->panel, + p->object_ref_names[i]))) { + fprintf(stderr, "error: switch %s references object %s which " + "cannot be found.\n", p->name, p->object_ref_names[i]); + } + } + + // set the drawfunc and pick targets + + switch (p->type) { + case LP_SWITCH_GFX_TOGGLE: + printf("setupData: toggle\n"); + break; + + case LP_SWITCH_GFX_PADDLE: + printf("setupData: paddle\n"); + break; + + case LP_SWITCH_GFX_OBJECT_REF: + p->drawFunc = lp_drawSwitchObject; + + if (p->object_refs[0]) { + p->up_target[0][0] = p->object_refs[0]->bbox.xyz_min[0]; + p->up_target[0][1] = p->object_refs[0]->bbox.center[1]; + p->up_target[0][2] = p->object_refs[0]->bbox.xyz_min[2]; + + p->up_target[1][0] = p->object_refs[0]->bbox.xyz_max[0]; + p->up_target[1][1] = p->object_refs[0]->bbox.center[1]; + p->up_target[1][2] = p->object_refs[0]->bbox.xyz_min[2]; + + p->up_target[2][0] = p->object_refs[0]->bbox.xyz_max[0]; + p->up_target[2][1] = p->object_refs[0]->bbox.xyz_max[1]; + p->up_target[2][2] = p->object_refs[0]->bbox.xyz_min[2]; + + p->up_target[3][0] = p->object_refs[0]->bbox.xyz_min[0]; + p->up_target[3][1] = p->object_refs[0]->bbox.xyz_max[1]; + p->up_target[3][2] = p->object_refs[0]->bbox.xyz_min[2]; + + p->down_target[0][0] = p->object_refs[0]->bbox.xyz_min[0]; + p->down_target[0][1] = p->object_refs[0]->bbox.xyz_min[1]; + p->down_target[0][2] = p->object_refs[0]->bbox.xyz_min[2]; + + p->down_target[1][0] = p->object_refs[0]->bbox.xyz_max[0]; + p->down_target[1][1] = p->object_refs[0]->bbox.xyz_min[1]; + p->down_target[1][2] = p->object_refs[0]->bbox.xyz_min[2]; + + p->down_target[2][0] = p->object_refs[0]->bbox.xyz_max[0]; + p->down_target[2][1] = p->object_refs[0]->bbox.center[1]; + p->down_target[2][2] = p->object_refs[0]->bbox.xyz_min[2]; + + p->down_target[3][0] = p->object_refs[0]->bbox.xyz_min[0]; + p->down_target[3][1] = p->object_refs[0]->bbox.center[1]; + p->down_target[3][2] = p->object_refs[0]->bbox.xyz_min[2]; + } else + p->drawFunc = lp_drawSwitchObjectDummy; + + break; + default: + printf("setupData: invalid switch type %d\n", p->type); + break; + } + + // set opengl name for mouse select + // the low order 31 bits are used to store the switch number (index within the array of + // switches). The high order bit indicates the target (1=up 0=down). + + p->select_up_name = ((uint32_t) sw_num & LP_SW_PICK_IDMASK) | LP_SW_PICK_UP_BIT; + p->select_dn_name = (uint32_t) sw_num & LP_SW_PICK_IDMASK; + + switch (p->type) { + case LP_SWITCH_OP_MOM_OFF_MOM: + case LP_SWITCH_OP_OFF_MOM: + break; + } +} + +int Lpanel_addSwitch(Lpanel_t *p, const char *name, lp_obj_parm_t *obj, const char *buff) +{ + int i, n; + lpSwitch_t *sw; + parser_result_t *result; + + // parse config file line values such as position, type etc. + // if n >= 0 it contains the char position in the line where an error + // ocurred + + if (p->num_switches + 1 > p->max_switches) + Lpanel_growSwitches(p); + + p->switches[p->num_switches] = sw = lpSwitch_new(); + sw->parms = obj; + lpSwitch_setName(p->switches[p->num_switches], name); + sw->panel = p; + p->num_switches++; + + Parser_setRules(&parser, switch_parse_rules); + Parser_setParseString(&parser, buff); + + // set reasonable defaults + + obj->scale[0] = 1.; + obj->scale[1] = 1.; + obj->scale[2] = 1.; + + obj->pos[0] = 0.; + obj->pos[1] = 0.; + obj->pos[2] = 0.; + + while ((n = Parser_parse(&parser, &result)) < 0) { + if (n != PARSER_DONE) { + // printf("\nresult %s\n", switch_parse_rules[result->cmd_idx]); + +#if 1 + if (!strcmp(switch_parse_rules[result->cmd_idx].cmd, "objects")) { + sw->object_ref_names = (char **) malloc(sizeof(char *) * + result->num_args); + + for (i = 0; i < result->num_args; i++) { + sw->object_ref_names[i] = + (char *) malloc(strlen(result->strings[i]) + 1); + strcpy(sw->object_ref_names[i], result->strings[i]); + } + sw->num_object_refs = result->num_args; + } else if (!strcmp(switch_parse_rules[result->cmd_idx].cmd, "operate")) { + if (!strcmp(result->strings[0], "toggle")) { + sw->operation = LP_SWITCH_OP_ON_OFF; + sw->state = LP_SWITCH_DOWN; // set to down + } else if (!strcmp(result->strings[0], "mom_off_mom")) { + sw->operation = LP_SWITCH_OP_MOM_OFF_MOM; + sw->state = LP_SWITCH_CENTER; // set to center + } else if (!strcmp(result->strings[0], "off_mom")) { + sw->operation = LP_SWITCH_OP_OFF_MOM; + sw->state = LP_SWITCH_CENTER; // to center (down) + } else { + printf("Invalid switch 'operation'. Should be one " + "of 'toggle' or 'mom_off_mom' or 'off_mom'\n"); + return result->var_pos; + } + } else if (!strcmp(switch_parse_rules[result->cmd_idx].cmd, "pos")) { + for (i = 0; i < result->num_args; i++) + sw->parms->pos[i] = result->floats[i]; + + } else if (!strcmp(switch_parse_rules[result->cmd_idx].cmd, "size")) { + for (i = 0; i < result->num_args; i++) + sw->parms->scale[i] = result->floats[i]; + + } else if (!strcmp(switch_parse_rules[result->cmd_idx].cmd, "type")) { + if (!strcmp(result->strings[0], "toggle")) { + sw->type = LP_SWITCH_GFX_TOGGLE; + } else if (!strcmp(result->strings[0], "paddle")) { + sw->type = LP_SWITCH_GFX_PADDLE; + } else if (!strcmp(result->strings[0], "object")) { + sw->type = LP_SWITCH_GFX_OBJECT_REF; + } else { + printf("Invalid switch 'type'. Should be one " + "of 'toggle, paddle, object'\n"); + return 0; + } + } +#endif + } + + if (n == PARSER_DONE) + break; + } + + if (n >= 0) { + printf("n=%d\n", n); + Parser_printError(&parser); + return n; + } + + return n; +} + +bool Lpanel_addSwitchCallback(Lpanel_t *p, const char *name, lp_switch_cbf_t cbfunc, int userval) +{ + char **namelist; + int num_names; + int i; + bool status = true; + lpSwitch_t *sw; + + num_names = xpand(name, &namelist); + + for (i = 0; i < num_names; i++) { + sw = Lpanel_findSwitchByName(p, namelist[i]); + + if (sw) { + lpSwitch_addCallback(sw, cbfunc, userval); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "addSwitchCallback: switch %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + } + free(namelist); + + return status; +} + +bool Lpanel_bindSwitch8(Lpanel_t *p, const char *name, void *loc_down, void *loc_up, + int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpSwitch_t *sw; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + // printf("name %d = %s bitnum=%d\n", i, namelist[i], bitnum); + + if (bitnum < 0) { + fprintf(stderr, "bindSwitch8: switch %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + sw = Lpanel_findSwitchByName(p, namelist[i]); + + if (sw) { + lpSwitch_bindData8(sw, (uint8_t *) loc_down, (uint8_t *) loc_up, + bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindSwitch8: switch %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindSwitch16(Lpanel_t *p, const char *name, void *loc_down, void *loc_up, + int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpSwitch_t *sw; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + // printf("name %d = %s bitnum=%d\n", i, namelist[i], bitnum); + + if (bitnum < 0) { + fprintf(stderr, "bindSwitch16: switch %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + sw = Lpanel_findSwitchByName(p, namelist[i]); + + if (sw) { + lpSwitch_bindData16(sw, (uint16_t *) loc_down, (uint16_t *) loc_up, + bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindSwitch16: switch %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindSwitch32(Lpanel_t *p, const char *name, void *loc_down, void *loc_up, + int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpSwitch_t *sw; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + // printf("name %d = %s bitnum=%d\n", i, namelist[i], bitnum); + + if (bitnum < 0) { + fprintf(stderr, "bindSwitch32: switch %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + sw = Lpanel_findSwitchByName(p, namelist[i]); + + if (sw) { + lpSwitch_bindData32(sw, (uint32_t *) loc_down, (uint32_t *) loc_up, + bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindSwitch32: switch %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindSwitch64(Lpanel_t *p, const char *name, void *loc_down, void *loc_up, + int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpSwitch_t *sw; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + // printf("name %d = %s bitnum=%d\n", i, namelist[i], bitnum); + + if (bitnum < 0) { + fprintf(stderr, "bindSwitch64: switch %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + sw = Lpanel_findSwitchByName(p, namelist[i]); + + if (sw) { + lpSwitch_bindData64(sw, (uint64_t *) loc_down, (uint64_t *) loc_up, + bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindSwitch64: switch %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +void lpSwitch_drawForPick(lpSwitch_t *p) +{ + int i; + + glPushMatrix(); + + glTranslatef(p->parms->pos[0], + p->parms->pos[1], + p->parms->pos[2]); + + glScalef(p->parms->scale[0], + p->parms->scale[1], + p->parms->scale[2]); + + glColor3f(1., 0., 0.); + + glLoadName(p->select_up_name); + glBegin(GL_POLYGON); + for (i = 0; i < 4; i++) + glVertex3fv(&p->up_target[i][0]); + glEnd(); + + glLoadName(p->select_dn_name); + glBegin(GL_POLYGON); + for (i = 0; i < 4; i++) + glVertex3fv(&p->down_target[i][0]); + glEnd(); + + glPopMatrix(); +} + +// +// findSwitchByName +// ---------------- + +lpSwitch_t *Lpanel_findSwitchByName(Lpanel_t *p, char *name) +{ + int i; + + for (i = 0; i < p->num_switches; i++) { + if (!strcmp(p->switches[i]->name, name)) + return p->switches[i]; + } + + return 0; +} + +void Lpanel_sampleSwitches(Lpanel_t *p) +{ + int i; + + for (i = 0; i < p->num_switches; i++) + lpSwitch_sampleData(p->switches[i]); +} diff --git a/frontpanel/lp_switch.cpp b/frontpanel/lp_switch.cpp deleted file mode 100644 index 0a419750..00000000 --- a/frontpanel/lp_switch.cpp +++ /dev/null @@ -1,978 +0,0 @@ -// lp_switch.cpp light panel switch class - - -/* Copyright (c) 2007-2008, John Kichury - - This software is freely distributable free of charge and without license fees with the - following conditions: - - 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 - JOHN KICHURY 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. - - The above copyright notice must be included in any copies of this software. - -*/ - -#include -#include -#include -#include "lpanel.h" -#include "lp_switch.h" -#include "lp_utils.h" - -#define UNUSED(x) (void) (x) - - -// parse rules for switches defined in the user configuration file - -static parser_rules_t switch_parse_rules[] = -{ - { "type", 1, 1, PARSER_STRING }, - { "operate", 1, 1, PARSER_STRING }, - { "pos", 2, 3, PARSER_FLOAT }, - { "size", 2, 3, PARSER_FLOAT }, - { "objects", 1, 3, PARSER_STRING }, - { NULL,0,0,0 } -}; - -Parser parser; // parser class for parsing config arguments -extern Parser parser; - -// supporting render functions - -void -lp_drawSwitchObjectDummy( Lpanel *p, lpSwitch *lpswitch) -{ - UNUSED(p); - UNUSED(lpswitch); - - // a stub function for switches that do not have a render object defined -} - -void -lp_drawSwitchObject( Lpanel *p, lpSwitch *lpswitch) -{ - int state = lpswitch->state; - - UNUSED(p); - - glPushMatrix(); - - glTranslatef( lpswitch->parms->pos[0], - lpswitch->parms->pos[1], - lpswitch->parms->pos[2]); - - glScalef( lpswitch->parms->scale[0], - lpswitch->parms->scale[1], - lpswitch->parms->scale[2]); - -#if 1 - lpswitch->object_refs[state]->draw(1); - -#else - int i; - int flag=0; - -if(!strcmp(lpswitch->name,"SW_11")) - flag = 1; - - glColor3f(1.,0.,0.); - glBegin(GL_POLYGON); - if(flag) - printf("sw_11 targ=\n"); - for(i=0;i<4;i++) - { - if(flag) - printf("= %f %f\n", - lpswitch->up_target[i][0], - lpswitch->up_target[i][1]); - glVertex3fv(&lpswitch->up_target[i][0]); - } - glEnd(); - - glColor3f(0.,1.,0.); - glBegin(GL_POLYGON); - for(i=0;i<4;i++) - glVertex3fv(&lpswitch->down_target[i][0]); - glEnd(); -#endif - - glPopMatrix(); -} - -void -lp_drawSwitchObject_rotated( Lpanel *p, lpSwitch *lpswitch) -{ - int state = lpswitch->state; - - UNUSED(p); - - glPushMatrix(); - - glTranslatef( lpswitch->parms->pos[0], lpswitch->parms->pos[1], lpswitch->parms->pos[2]); - - glScalef( lpswitch->parms->scale[0], - lpswitch->parms->scale[1], - lpswitch->parms->scale[2]); - - glRotatef(lpswitch->rotate[state][0], - lpswitch->rotate[state][1], - lpswitch->rotate[state][2], - lpswitch->rotate[state][3]); - - - lpswitch->object_refs[state]->draw(1); - - glPopMatrix(); -} - - -void -lp_drawSwitchPaddle( Lpanel *p, lpSwitch *lpswitch) -{ - int state = lpswitch->state; - - UNUSED(p); - - glPushMatrix(); - - glTranslatef( lpswitch->parms->pos[0], lpswitch->parms->pos[1], lpswitch->parms->pos[2]); - - glScalef( lpswitch->parms->scale[0], - lpswitch->parms->scale[1], - lpswitch->parms->scale[2]); - - glRotatef(lpswitch->rotate[state][0], - lpswitch->rotate[state][1], - lpswitch->rotate[state][2], - lpswitch->rotate[state][3]); - - //draw_paddle(); - - glPopMatrix(); -} - -void -lp_drawSwitchToggle( Lpanel *p, lpSwitch *lpswitch) -{ - int state = lpswitch->state; - - UNUSED(p); - - glPushMatrix(); - - glTranslatef( lpswitch->parms->pos[0], lpswitch->parms->pos[1], lpswitch->parms->pos[2]); - glScalef( lpswitch->parms->scale[0], - lpswitch->parms->scale[1], - lpswitch->parms->scale[2]); - glRotatef(lpswitch->rotate[state][0], - lpswitch->rotate[state][1], - lpswitch->rotate[state][2], - lpswitch->rotate[state][3]); - - //draw_toggle(); - - glPopMatrix(); -} - - - -// lpSwitch class -// -------------- - -lpSwitch::lpSwitch(void) -{ - name = NULL; - parms = NULL; - gfx_mode = LP_SWITCH_GFX_TOGGLE; - state = LP_SWITCH_DOWN; - operation = LP_SWITCH_OP_ON_OFF; - num_object_refs = 0; - drawFunc = NULL; - dataptr[0] = dataptr[1] = NULL; - object_ref_names = NULL; - select_up_name = select_dn_name = 0; - callback = NULL; - userdata = 0; -} - -lpSwitch::~lpSwitch(void) -{ - int i; - - if(name) delete[] name; - if(parms) delete parms; - - if(object_ref_names) - { - for(i=0; imom_switch_pressed = this; - - if(dataptr[state]) - switch(datatype) - { - case LP_SWITCH_DATATYPE_UINT8: - { - uint8_t *ptr, val; - ptr = (uint8_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr | val; - } - break; - - case LP_SWITCH_DATATYPE_UINT16: - { - uint16_t *ptr, val; - ptr = (uint16_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr | val; - } - break; - case LP_SWITCH_DATATYPE_UINT32: - { - uint32_t *ptr, val; - ptr = (uint32_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr | val; - } - break; - } - break; - - case LP_SWITCH_OP_ON_OFF: - if(dataptr[state]) - switch(datatype) - { - case LP_SWITCH_DATATYPE_UINT8: - { - uint8_t *ptr, val; - ptr = (uint8_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr & (~val); - } - break; - case LP_SWITCH_DATATYPE_UINT16: - { - uint16_t *ptr, val; - ptr = (uint16_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr & (~val); - } - break; - case LP_SWITCH_DATATYPE_UINT32: - { - uint32_t *ptr, val; - ptr = (uint32_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr & (~val); - } - break; - } - break; - - } - break; - - case 1: // up - - state = LP_SWITCH_UP; - - switch(operation) - { - case LP_SWITCH_OP_MOM_OFF_MOM: - case LP_SWITCH_OP_OFF_MOM: - panel->mom_switch_pressed = this; - /* fallthrough */ - - case LP_SWITCH_OP_ON_OFF: - if(dataptr[state]) - switch(datatype) - { - case LP_SWITCH_DATATYPE_UINT8: - { - uint8_t *ptr, val; - ptr = (uint8_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr | val; - } - break; - case LP_SWITCH_DATATYPE_UINT16: - { - uint16_t *ptr, val; - ptr = (uint16_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr | val; - } - break; - case LP_SWITCH_DATATYPE_UINT32: - { - uint32_t *ptr, val; - ptr = (uint32_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr | val; - } - break; - } - break; - - } - break; - - case 2: // release mom switch - - switch(operation) - { - case LP_SWITCH_OP_MOM_OFF_MOM: - case LP_SWITCH_OP_OFF_MOM: - if(dataptr[state]) - switch(datatype) - { - case LP_SWITCH_DATATYPE_UINT8: - { - uint8_t *ptr, val; - ptr = (uint8_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr & (~val); - } - break; - case LP_SWITCH_DATATYPE_UINT16: - { - uint16_t *ptr, val; - ptr = (uint16_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr & (~val); - } - break; - case LP_SWITCH_DATATYPE_UINT32: - { - uint32_t *ptr, val; - ptr = (uint32_t *) dataptr[state]; - val = 0x1 << bitnum; - *ptr = *ptr & (~val); - } - break; - } - panel->mom_switch_pressed = NULL; - state = LP_SWITCH_CENTER; - break; - - case LP_SWITCH_OP_ON_OFF: - break; - } - break; - - } - if(callback) (*callback)(state, userdata); -} - -void -lpSwitch::addCallback( void (*cbfunc)(int state, int val), int userval ) -{ - callback = cbfunc; - userdata = userval; -} - -void -lpSwitch::bindData8(uint8_t *ptr_down, uint8_t *ptr_up, int bit_number) -{ - dataptr[LP_SWITCH_DOWN] = ptr_down; - dataptr[LP_SWITCH_UP] = ptr_up; - datatype = LP_SWITCH_DATATYPE_UINT8; - bitnum = bit_number; -} - -void -lpSwitch::bindData16(uint16_t *ptr_down, uint16_t *ptr_up, int bit_number) -{ - dataptr[LP_SWITCH_DOWN] = ptr_down; - dataptr[LP_SWITCH_UP] = ptr_up; - datatype = LP_SWITCH_DATATYPE_UINT16; - bitnum = bit_number; -} - -void -lpSwitch::bindData32(uint32_t *ptr_down, uint32_t *ptr_up, int bit_number) -{ - dataptr[LP_SWITCH_DOWN] = ptr_down; - dataptr[LP_SWITCH_UP] = ptr_up; - datatype = LP_SWITCH_DATATYPE_UINT32; - bitnum = bit_number; -} - -void -lpSwitch::bindData64(uint64_t *ptr_down, uint64_t *ptr_up, int bit_number) -{ - dataptr[LP_SWITCH_DOWN] = ptr_down; - dataptr[LP_SWITCH_UP] = ptr_up; - datatype = LP_SWITCH_DATATYPE_UINT64; - bitnum = bit_number; -} - -void -lpSwitch::setName(const char *_name) -{ int n; - - n = strlen(_name); - name = new char[n+1]; - strcpy(name,_name); -} - -void -lpSwitch::sampleData(void) -{ - if(!dataptr[0]) return; - if(operation != LP_SWITCH_OP_ON_OFF) return; - - switch(datatype) - { - case LP_SWITCH_DATATYPE_UINT8: - { uint8_t *p, bit; - p = (uint8_t *) dataptr[0]; - bit = ( 1 << bitnum) & *p; - if(bit) state = 1; - else state = 0; - } - break; - - case LP_SWITCH_DATATYPE_UINT16: - { - uint16_t *p, bit; - p = (uint16_t *) dataptr[0]; - bit = ( 1 << bitnum) & *p; - if(bit) state = 1; - else state = 0; - } - break; - - case LP_SWITCH_DATATYPE_UINT32: - { - uint32_t *p, bit; - p = (uint32_t *) dataptr[0]; - bit = ( 1 << bitnum) & *p; - if(bit) state = 1; - else state = 0; - } - break; - } - -} - -void -lpSwitch::setupData(int sw_num) -{ - int i; - - // resolve referenced graphics objects - - for(i=0; ifindObjectByName(object_ref_names[i]))) - { - fprintf(stderr, "error: switch %s references object %s which cannot be found.\n", - name, object_ref_names[i]); - } - } - - // set the drawfunc and pick targets - - switch(type) - { - case LP_SWITCH_GFX_TOGGLE: -printf("setupData: toggle\n"); - break; - - case LP_SWITCH_GFX_PADDLE: -printf("setupData: paddle\n"); - break; - - case LP_SWITCH_GFX_OBJECT_REF: - - drawFunc = lp_drawSwitchObject; - - if(object_refs[0]) - { - up_target[0][0] = object_refs[0]->bbox.xyz_min[0]; - up_target[0][1] = object_refs[0]->bbox.center[1]; - up_target[0][2] = object_refs[0]->bbox.xyz_min[2]; - - up_target[1][0] = object_refs[0]->bbox.xyz_max[0]; - up_target[1][1] = object_refs[0]->bbox.center[1]; - up_target[1][2] = object_refs[0]->bbox.xyz_min[2]; - - up_target[2][0] = object_refs[0]->bbox.xyz_max[0]; - up_target[2][1] = object_refs[0]->bbox.xyz_max[1]; - up_target[2][2] = object_refs[0]->bbox.xyz_min[2]; - - up_target[3][0] = object_refs[0]->bbox.xyz_min[0]; - up_target[3][1] = object_refs[0]->bbox.xyz_max[1]; - up_target[3][2] = object_refs[0]->bbox.xyz_min[2]; - - - down_target[0][0] = object_refs[0]->bbox.xyz_min[0]; - down_target[0][1] = object_refs[0]->bbox.xyz_min[1]; - down_target[0][2] = object_refs[0]->bbox.xyz_min[2]; - - down_target[1][0] = object_refs[0]->bbox.xyz_max[0]; - down_target[1][1] = object_refs[0]->bbox.xyz_min[1]; - down_target[1][2] = object_refs[0]->bbox.xyz_min[2]; - - down_target[2][0] = object_refs[0]->bbox.xyz_max[0]; - down_target[2][1] = object_refs[0]->bbox.center[1]; - down_target[2][2] = object_refs[0]->bbox.xyz_min[2]; - - down_target[3][0] = object_refs[0]->bbox.xyz_min[0]; - down_target[3][1] = object_refs[0]->bbox.center[1]; - down_target[3][2] = object_refs[0]->bbox.xyz_min[2]; - } - else - drawFunc = lp_drawSwitchObjectDummy; - - break; - default: -printf("setupData: invalid switch type %d\n", type); - break; - } - -// set opengl name for mouse select -// the low order 31 bits are used to store the switch number (index within the array of -// switches). The high order bit indicates the target (1=up 0=down). - -select_up_name = ((uint32_t) sw_num & LP_SW_PICK_IDMASK) | LP_SW_PICK_UP_BIT; -select_dn_name = (uint32_t) sw_num & LP_SW_PICK_IDMASK; - - switch(type) - { - case LP_SWITCH_OP_MOM_OFF_MOM: - case LP_SWITCH_OP_OFF_MOM: - break; - } -} - -int -Lpanel::addSwitch(const char *name, lp_obj_parm_t *obj, const char *buff, Lpanel *_panel) -{ - int i,n; - lpSwitch *sw; - parser_result_t *result; - - // parse config file line values such as position, type etc. - // if n >= 0 it contains the char position in the line where an error - // ocurred - - - if(num_switches + 1 > max_switches) growSwitches(); - - switches[num_switches] = new lpSwitch; - switches[num_switches]->parms = obj; - switches[num_switches]->setName(name); - sw = switches[num_switches]; - sw->panel = _panel; - num_switches++; - - parser.setRules(switch_parse_rules); - parser.setParseString(buff); - - // set reasonable defaults - - obj->scale[0] = 1.; - obj->scale[1] = 1.; - obj->scale[2] = 1.; - - obj->pos[0] = 0.; - obj->pos[1] = 0.; - obj->pos[2] = 0.; - - while( (n = parser.parse(&result)) < 0 ) - { - if(n != PARSER_DONE) - { - // printf("\nresult %s\n", switch_parse_rules[result->cmd_idx]); - -#if 1 - if(!strcmp(switch_parse_rules[result->cmd_idx].cmd, "objects")) - { - sw->object_ref_names = new char *[result->num_args]; - - for(i=0;inum_args;i++) - { - sw->object_ref_names[i] = new char[strlen(result->strings[i])+1]; - strcpy(sw->object_ref_names[i], result->strings[i]); - } - sw->num_object_refs = result->num_args; - } - else if(!strcmp(switch_parse_rules[result->cmd_idx].cmd, "operate")) - { - if(!strcmp(result->strings[0], "toggle")) - { - sw->operation = LP_SWITCH_OP_ON_OFF; - sw->state = LP_SWITCH_DOWN; // set to down - } - else - if(!strcmp(result->strings[0], "mom_off_mom")) - { - sw->operation = LP_SWITCH_OP_MOM_OFF_MOM; - sw->state = LP_SWITCH_CENTER; // set to center - } - else - if(!strcmp(result->strings[0], "off_mom")) - { - sw->operation = LP_SWITCH_OP_OFF_MOM; - sw->state = LP_SWITCH_CENTER; // set to center (down) - } - else - { - printf("Invalid switch 'operation'. Should be one of 'toggle' or 'mom_off_mom' or 'off_mom'\n"); - return result->var_pos; - } - } - else if(!strcmp(switch_parse_rules[result->cmd_idx].cmd, "pos")) - { - for(i=0;inum_args;i++) - sw->parms->pos[i] = result->floats[i]; - - } - else if(!strcmp(switch_parse_rules[result->cmd_idx].cmd, "size")) - { - for(i=0;inum_args;i++) - sw->parms->scale[i] = result->floats[i]; - - } - else if(!strcmp(switch_parse_rules[result->cmd_idx].cmd, "type")) - { - if(!strcmp(result->strings[0], "toggle")) - { - sw->type = LP_SWITCH_GFX_TOGGLE; - } - else - if(!strcmp(result->strings[0], "paddle")) - { - sw->type = LP_SWITCH_GFX_PADDLE; - } - else - if(!strcmp(result->strings[0], "object")) - { - sw->type = LP_SWITCH_GFX_OBJECT_REF; - } - else - { - printf("Invalid switch 'type'. Should be one of 'toggle, paddle, object'\n"); - return 0; - } - } -#endif - } - - if( n == PARSER_DONE) break; - } - - if( n >= 0) - { printf("n=%d\n",n); - parser.printError(); - return n; - } - return n; - -} - -int -Lpanel::addSwitchCallback(const char *name, void (*cbfunc)(int state, int val), int userval) -{ - char **namelist; - int num_names; - int i, status = 1; - // int bitnum = 0, bit_inc = 1; - lpSwitch *sw; - - num_names = xpand(name, &namelist); - - for(i=0;iaddCallback( cbfunc, userval); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "addSwitchCallback: switch %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - // bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - - -int -Lpanel::bindSwitch8(const char *name, void *loc_down, void *loc_up, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpSwitch *sw; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData8( (uint8_t *) loc_down, (uint8_t *) loc_up, bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindSwitch8: switch %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - - -int -Lpanel::bindSwitch16(const char *name, void *loc_down, void *loc_up, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpSwitch *sw; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData16( (uint16_t *) loc_down, (uint16_t *) loc_up, bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindSwitch16: switch %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - - -int -Lpanel::bindSwitch32(const char *name, void *loc_down, void *loc_up, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpSwitch *sw; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData32( (uint32_t *) loc_down, (uint32_t *) loc_up, bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindSwitch32: switch %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -int -Lpanel::bindSwitch64(const char *name, void *loc_down, void *loc_up, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpSwitch *sw; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData64( (uint64_t *) loc_down, (uint64_t *) loc_up, bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindSwitch64: switch %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -void -lpSwitch::drawForPick(void) -{ - int i; - - glPushMatrix(); - - glTranslatef( parms->pos[0], - parms->pos[1], - parms->pos[2]); - - glScalef( parms->scale[0], - parms->scale[1], - parms->scale[2]); - - glColor3f(1.,0.,0.); - - glLoadName(select_up_name); - glBegin(GL_POLYGON); - for(i=0;i<4;i++) - glVertex3fv(&up_target[i][0]); - glEnd(); - - glLoadName(select_dn_name); - glBegin(GL_POLYGON); - for(i=0;i<4;i++) - glVertex3fv(&down_target[i][0]); - glEnd(); - - - glPopMatrix(); -} - - -// -// findSwitchByName -// ---------------- - -lpSwitch* -Lpanel::findSwitchByName(char *name) -{ int i; - - for(i=0;iname, name)) - return switches[i]; - } - -return 0; -} - - -void -Lpanel::sampleSwitches(void) -{ int i; - - for(i=0;isampleData(); - -} diff --git a/frontpanel/lp_switch.h b/frontpanel/lp_switch.h index c1887337..38b4e6b6 100644 --- a/frontpanel/lp_switch.h +++ b/frontpanel/lp_switch.h @@ -1,9 +1,9 @@ // lp_switch.h lightpanel switch class - /* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -20,99 +20,106 @@ #ifndef _LP_SWITCH_DEFS #define _LP_SWITCH_DEFS +#include +#ifdef WANT_SDL +#include +#else +#include +#endif + #include "lpanel.h" -enum lp_switch_states - { LP_SWITCH_DOWN = 0, // switch is down - LP_SWITCH_UP = 1, // switch is up - LP_SWITCH_CENTER = 2 // switch is centered (for momentary MOM_OFF_MOM - }; - -enum lp_switch_operation - { LP_SWITCH_OP_ON_OFF = 0, // on/off operation - LP_SWITCH_OP_MOM_OFF_MOM = 1, // momentary down, centered, momentary up - LP_SWITCH_OP_OFF_MOM = 2 // centered (down), momentary up - }; - -enum lp_switch_gfx_modes - { LP_SWITCH_GFX_TOGGLE = 0, // uses internal toggle switch graphics - LP_SWITCH_GFX_PADDLE = 1, // uses internal paddle switch graphics - LP_SWITCH_GFX_OBJECT_REF = 2 // uses a graphics 'object' from the config file - }; - -enum lp_switch_datatypes - { LP_SWITCH_DATATYPE_UINT8 = 8, - LP_SWITCH_DATATYPE_UINT16 = 16, - LP_SWITCH_DATATYPE_UINT32 = 32, - LP_SWITCH_DATATYPE_UINT64 = 64 - }; +enum lp_switch_states { + LP_SWITCH_DOWN = 0, // switch is down + LP_SWITCH_UP = 1, // switch is up + LP_SWITCH_CENTER = 2 // switch is centered (for momentary MOM_OFF_MOM +}; + +enum lp_switch_operation { + LP_SWITCH_OP_ON_OFF = 0, // on/off operation + LP_SWITCH_OP_MOM_OFF_MOM = 1, // momentary down, centered, momentary up + LP_SWITCH_OP_OFF_MOM = 2 // centered (down), momentary up +}; + +enum lp_switch_gfx_modes { + LP_SWITCH_GFX_TOGGLE = 0, // uses internal toggle switch graphics + LP_SWITCH_GFX_PADDLE = 1, // uses internal paddle switch graphics + LP_SWITCH_GFX_OBJECT_REF = 2 // uses a graphics 'object' from the config file +}; + +enum lp_switch_datatypes { + LP_SWITCH_DATATYPE_UINT8 = 8, + LP_SWITCH_DATATYPE_UINT16 = 16, + LP_SWITCH_DATATYPE_UINT32 = 32, + LP_SWITCH_DATATYPE_UINT64 = 64 +}; // High order bit in the OpenGL select name used to detect // the switch 'up_target' or 'down_target' being clicked with the mouse. // The low order 31 bits are used to store the switch number (index within the array of // switches). The high order bit indicates the target (1=up 0=down). - #define LP_SW_PICK_UP_BIT 0x80000000 #define LP_SW_PICK_IDMASK 0x0fffffff +typedef void (*lp_switch_cbf_t)(int state, int val); // switch callback function pointer +typedef void (*lp_switch_df_t)(struct lpSwitch *swtch); // switch draw function pointer -class lpSwitch +typedef struct lpSwitch { - - private: - - - public: - - lpSwitch(void); - ~lpSwitch(void); - - char *name; - - int type; // toggle/paddle/object_ref - uint8_t state, // 0=off 1=on 2=center(for mom-off-mom switches) - gfx_mode, // one of lp_switch_gfx_modes - operation, // one of lp_switch_operation - num_object_refs; // number of object references - - void *dataptr[2]; // pointer to data for up and down position - int datatype; // datatype dataptr points to - int bitnum; // bit in data controlling this light - void (*callback)(int state, int val); // user callback - int userdata; - - char **object_ref_names; - lpObject *object_refs[3]; // object references for gfx_mode=object - - lp_obj_parm_t *parms; - Lpanel *panel; - - // rotation values for 3 switch states (for 3D models) - - float rotate[3][4]; // ang, 3D unit vector for 3 switch states - - GLuint select_up_name, - select_dn_name; - - float up_target[4][3], // mouse pick targets for activation - down_target[4][3]; - - void action(int val); - void addCallback( void (*cbfunc)(int state, int val), int userval ); - void bindData64(uint64_t *ptr_down, uint64_t *ptr_up, int bit_number); - void bindData32(uint32_t *ptr_down, uint32_t *ptr_up, int bit_number); - void bindData16(uint16_t *ptr_down, uint16_t *ptr_up, int bit_number); - void bindData8(uint8_t *ptr_down, uint8_t *ptr_up, int bit_number); - void (*drawFunc)(Lpanel *p, lpSwitch *lpswitch); - void draw(void); - void drawForPick(void); - void sampleData(void); - - void setName(const char *_name); - void setupData(int sw_num); // resolve graphics references etc. - -}; - -#endif - + char *name; + + int type; // toggle/paddle/object_ref + uint8_t state, // 0=off 1=on 2=center(for mom-off-mom switches) + gfx_mode, // one of lp_switch_gfx_modes + operation, // one of lp_switch_operation + num_object_refs; // number of object references + + void *dataptr[2]; // pointer to data for up and down position + int datatype; // datatype dataptr points to + int bitnum; // bit in data controlling this light + lp_switch_cbf_t callback; // user callback + int userdata; + + char **object_ref_names; + lpObject_t *object_refs[3]; // object references for gfx_mode=object + + lp_obj_parm_t *parms; + struct Lpanel *panel; + + // rotation values for 3 switch states (for 3D models) + + float rotate[3][4]; // ang, 3D unit vector for 3 switch states + + GLuint select_up_name, + select_dn_name; + + float up_target[4][3], // mouse pick targets for activation + down_target[4][3]; + + lp_switch_df_t drawFunc; +} lpSwitch_t; + +extern lpSwitch_t *lpSwitch_new(void); +extern void lpSwitch_delete(lpSwitch_t *p); +extern void lpSwitch_init(lpSwitch_t *p); +extern void lpSwitch_fini(lpSwitch_t *p); + +extern void lpSwitch_action(lpSwitch_t *p, int val); +extern void lpSwitch_addCallback(lpSwitch_t *p, lp_switch_cbf_t cbfunc, int userval); +extern void lpSwitch_bindData64(lpSwitch_t *p, uint64_t *ptr_down, uint64_t *ptr_up, + int bit_number); +extern void lpSwitch_bindData32(lpSwitch_t *p, uint32_t *ptr_down, uint32_t *ptr_up, + int bit_number); +extern void lpSwitch_bindData16(lpSwitch_t *p, uint16_t *ptr_down, uint16_t *ptr_up, + int bit_number); +extern void lpSwitch_bindData8(lpSwitch_t *p, uint8_t *ptr_down, uint8_t *ptr_up, + int bit_number); +extern void lpSwitch_draw(lpSwitch_t *p); +extern void lpSwitch_drawForPick(lpSwitch_t *p); +extern void lpSwitch_sampleData(lpSwitch_t *p); + +extern void lpSwitch_setName(lpSwitch_t *p, const char *name); +extern void lpSwitch_setupData(lpSwitch_t *p, int sw_num); // resolve gfx refs etc. + +#endif /* !_LP_SWITCH_DEFS */ diff --git a/frontpanel/lp_utils.c b/frontpanel/lp_utils.c new file mode 100644 index 00000000..350b2c42 --- /dev/null +++ b/frontpanel/lp_utils.c @@ -0,0 +1,845 @@ +// lp_utils.c utility functions + +/* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt + + This software is freely distributable free of charge and without license fees with the + following conditions: + + 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 + JOHN KICHURY 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. + + The above copyright notice must be included in any copies of this software. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "lp_utils.h" + +#define UNUSED(x) (void) (x) + +/* --------------------- + gtoken - token parser + ---------------------*/ + +/* Token parser. Returns string tokens. + + + Gtoken scans the string argument starting at the character + position specified by the argument . The next token is returned + in the return argument string and the value of is updated + to reflect the current parsing position. The value of the function is + the integer character length of the returned token. + + Tokens are generated using the following rules: + + Delimiters: Space and Comma. + + A single space terminates a token. A multispace field is equivalent to + a single space. Leading spaces are ignored. + + A single comma terminates a token and is equivalent to a space. Two or + more commas in succession generates null tokens. + + Delimiters may be specified in a token by enclosing the token in single + quotes. Quotes are specified in a token if they are doubled. + + examples: 'this is one token' + 'this token string contains a ''quoted'' word'. + one, two, three are individual tokens. +*/ + +int gtoken(char *string, /* input character string */ + char *token, /* return token string */ + int maxlen, /* max token length */ + int *pos) /* starting char position to parse */ +{ + int toklen; /* token length in characters */ + bool qseen, /* quote (') seen flag */ + q2seen, /* 2nd quote seen flag */ + done, /* done with token flag */ + ignore_space; + char c; + + q2seen = qseen = done = false; + ignore_space = true; /* ignore leading spaces */ + toklen = 0; + + while ((c = string[*pos]) != '\0' && (toklen < maxlen) && !done) { + (*pos)++; + switch (c) { + case '\'': + ignore_space = false; + if (!qseen) { + qseen = true; + break; + } + if (!q2seen) { + q2seen = true; + break; + } + token[toklen++] = c; + q2seen = false; + break; + + case ',': + ignore_space = false; + if (qseen && !q2seen) + token[toklen++] = c; + else + done = true; + break; + + case ' ': + if (!ignore_space) { + if (qseen && !q2seen) + token[toklen++] = c; + else + done = true; + } + break; + + default: + ignore_space = false; + if (q2seen) { + done = true; + break; + } + token[toklen++] = c; + break; + + } /* end switch */ + } /* end while */ + + token[toklen] = '\0'; /* mark end of token */ + return toklen; + +} /* end of gtoken function */ + + +/* freadlin read line from file */ + +/* Read an ascii line from specified file (carret,lf or null signals end + of line) + + Returns line in "buffer" up to specified length terminated with a NULL. + + Value of function: 0=failure 1=success. + + usage: int freadlin(), i; + char buffer[]; + FILE *funit; + i = freadlin(funit, buffer, bufsize); +*/ + +#define CARRET '\015' /* carriage return */ +#define LF '\012' /* line feed */ +#define EOL '\0' /* end of line ("C" standard) */ + +int freadlin(FILE *funit, char *buffer, int bufsize) +{ + int i; + char c; + + i = 0; + + c = getc(funit); + + if (feof(funit)) + return 0; + + while (c != EOL && c != CARRET && c != LF) { + if (i < bufsize) + buffer[i++] = c; + c = getc(funit); + if (feof(funit)) + return 0; + } + buffer[i] = EOL; + return 1; +} /* end freadlin() */ + + +/* xpand */ + +enum xpnd_states { XPN_START, XPN_PREFIX, XPN_FRMVAL, XPN_TOVAL, XPN_INC, XPN_SUFFIX }; + +int xpand(const char *s, char **namelist[]) +{ + const char *cp = s, + *cp1 = NULL; + char c, + *prefix = NULL, + *suffix = NULL, + *from = NULL, + *to = NULL, + *inc = NULL; + int n, + // error = 0, + state = XPN_START; + + int ival, + from_ival = 0, + from_digits = 0, + to_ival = 0, + to_digits = 0, + inc_ival = 1, + ndigits = 0; + + char format[10], + dbuf[10], + obuf[100]; + + int max_names, // computed number of expanded names + num_names = 0; + char **new_namelist; + + while ((c = *cp)) { + + switch (state) { + case XPN_START: + if (c == '{') { + state = XPN_FRMVAL; + cp1 = cp + 1; + } else { + cp1 = cp; + state = XPN_PREFIX; + } + cp++; + break; + + case XPN_PREFIX: + if (c == '{') { + state = XPN_FRMVAL; + n = cp - cp1; + if (n > 0) { + prefix = (char *) malloc(n + 1); + strncpy(prefix, s, n); + prefix[n] = 0; + cp1 = cp + 1; + } + } + cp++; + break; + + case XPN_FRMVAL: + if (c == '-') { + state = XPN_TOVAL; + n = cp - cp1; + if (n > 0) { + from = (char *) malloc(n + 1); + strncpy(from, cp1, n); + from[n] = 0; + cp1 = cp + 1; + } + } else if (c == '}') { + state = XPN_SUFFIX; + n = cp - cp1; + if (n > 0) { + from = (char *) malloc(n + 1); + strncpy(from, cp1, n); + from[n] = 0; + } + cp1 = cp + 1; + } else if (c == '+') { + // error = 1; + } + cp++; + break; + + case XPN_TOVAL: + if (c == '+') { + state = XPN_INC; + n = cp - cp1; + if (n > 0) { + to = (char *) malloc(n + 1); + strncpy(to, cp1, n); + to[n] = 0; + cp1 = cp + 1; + } + } else if (c == '}') { + state = XPN_SUFFIX; + n = cp - cp1; + if (n > 0) { + to = (char *) malloc(n + 1); + strncpy(to, cp1, n); + to[n] = 0; + } + cp1 = cp + 1; + } + cp++; + break; + + case XPN_INC: + if (c == '}') { + state = XPN_SUFFIX; + n = cp - cp1; + if (n > 0) { + inc = (char *) malloc(n + 1); + strncpy(inc, cp1, n); + inc[n] = 0; + cp1 = cp + 1; + } + } + cp++; + break; + + case XPN_SUFFIX: + cp++; + break; + } /* end switch */ + + } /* end while */ + + switch (state) { + case XPN_START: + case XPN_PREFIX: + n = cp - cp1; + if (n > 0) { + prefix = (char *) malloc(n + 1); + strncpy(prefix, s, n); + prefix[n] = 0; + } + break; + case XPN_FRMVAL: + n = cp - cp1; + if (n > 0) { + from = (char *) malloc(n + 1); + strncpy(from, cp1, n); + from[n] = 0; + } + break; + case XPN_TOVAL: + n = cp - cp1; + if (n > 0) { + to = (char *) malloc(n + 1); + strncpy(to, cp1, n); + to[n] = 0; + } + break; + case XPN_INC: + n = cp - cp1; + if (n > 0) { + inc = (char *) malloc(n + 1); + strncpy(inc, cp1, n); + inc[n] = 0; + } + break; + case XPN_SUFFIX: + n = cp - cp1; + if (n > 0) { + suffix = (char *) malloc(n + 1); + strncpy(suffix, cp1, n); + suffix[n] = 0; + } + break; + } /* end switch(state) */ + + /* set up to iterate */ + + if (from && to) { + from_ival = atoi(from); + to_ival = atoi(to); + if (to_ival != from_ival) { + if (inc) + inc_ival = atoi(inc); + if (to_ival < from_ival) + inc_ival = -inc_ival; + + from_digits = strlen(from); + to_digits = strlen(to); + ndigits = max(from_digits, to_digits); + + ival = from_ival; + + snprintf(format, sizeof(format), "%%0%dd", ndigits); + + max_names = ((max(ival, to_ival)) - (min(ival, to_ival))) / + abs(inc_ival) + 1; + + new_namelist = (char **) malloc(sizeof(char *) * max_names); + *namelist = &new_namelist[0]; + num_names = 0; + + do { + obuf[0] = 0; + snprintf(dbuf, sizeof(dbuf), format, ival); + if (prefix) + strcpy(obuf, prefix); + strcat(obuf, dbuf); + if (suffix) + strcat(obuf, suffix); + + new_namelist[num_names] = (char *) malloc(strlen(obuf) + 1); + strcpy(new_namelist[num_names], obuf); + num_names++; + ival += inc_ival; + } while (ival != to_ival); + + snprintf(dbuf, sizeof(dbuf), format, ival); + obuf[0] = 0; + if (prefix) + strcpy(obuf, prefix); + strcat(obuf, dbuf); + if (suffix) + strcat(obuf, suffix); + new_namelist[num_names] = (char *) malloc(strlen(obuf) + 1); + strcpy(new_namelist[num_names], obuf); + num_names++; + } + } else { + obuf[0] = 0; + if (prefix) + strcpy(obuf, prefix); + if (from) + strcat(obuf, from); + if (suffix) + strcat(obuf, suffix); + + new_namelist = (char **) malloc(sizeof(char *)); + *namelist = &new_namelist[0]; + num_names = 0; + + new_namelist[num_names] = (char *) malloc(strlen(obuf) + 1); + strcpy(new_namelist[num_names], obuf); + num_names++; + } + + if (prefix) + free(prefix); + if (from) + free(from); + if (to) + free(to); + if (inc) + free(inc); + if (suffix) + free(suffix); + + return num_names; + +} /* end xpand() */ + + +/* framerate control */ + +/* + usage: + + init: + framerate_set(30.0); + framerate_start(); + + draw() + { + ... + + glFinish(); + framerate_wait(); + swapbuffers(); + framerate_start(); + } +*/ + +typedef struct frate { + double fps, + frametime, + start, + et; +} frate_t; + +static frate_t frate_parms = { 30.0, 1.0 / 30., 0., 0. }; + +double frate_gettime(void) +{ + struct timeval tp; + + gettimeofday(&tp, NULL); + return (double) tp.tv_sec + (double) tp.tv_usec / 1000000.0; +} + +/* funcs */ + +void framerate_set(double r) +{ + frate_parms.fps = r; + frate_parms.frametime = (float) 1.0 / frate_parms.fps; +} + +void framerate_start_frame(void) +{ + frate_parms.start = frate_gettime(); +} + +void framerate_wait(void) +{ + struct timespec ts, rem; + double delta; + double t; + + t = frate_gettime(); + + frate_parms.et = t - frate_parms.start; + + delta = frate_parms.frametime - frate_parms.et; + + // if (delta < 0.) + // printf("missed rendering frame\n"); + + if (delta > 0.0) { + delta = delta * 10e8; + ts.tv_sec = 0; + ts.tv_nsec = (long) delta; + + for (;;) + if (nanosleep(&ts, &rem) == -1 && errno == EINTR && rem.tv_nsec > 0L) { + ts = rem; + continue; + } else + break; + } +} + + +// parser class + +static const char *parser_errmsgs[] = { + "No error.", + "No variable", + "No value.", + "Bad Varable.", + "Bad value.", + "Too many values.", + "Too few values." +}; + +Parser_t *Parser_new(void) +{ + Parser_t *p = (Parser_t *) calloc(1, sizeof(Parser_t)); + + if (p) + Parser_init(p); + + return p; +} + +void Parser_delete(Parser_t *p) +{ + if (p) { + Parser_fini(p); + free(p); + } +} + +void Parser_init(Parser_t *p) +{ + parser_result_t *resp = &p->results; + + p->curr_arg = 0; + p->eol = 0; + resp->max_args = 0; + resp->strings = NULL; + resp->stringlengths = NULL; + resp->floats = NULL; + resp->ints = NULL; +} + +void Parser_fini(Parser_t *p) +{ + parser_result_t *resp = &p->results; + int i; + + if (resp->strings) { + for (i = 0; i < resp->max_args; i++) + if (resp->strings[i]) + free(resp->strings[i]); + } + + if (resp->strings) + free(resp->strings); + if (resp->stringlengths) + free(resp->stringlengths); + if (resp->floats) + free(resp->floats); + if (resp->ints) + free(resp->ints); +} + +int Parser_addArg(Parser_t *p, const char *s, const char *cpos1, const char *cpos2) +{ + parser_result_t *resp = &p->results; + int len; + float fval; + char *endptr; + + UNUSED(s); + + if (resp->num_args + 1 > resp->max_args) + Parser_growArgs(p, 4); + + if ((len = cpos2 - cpos1) > 0) { + + if (resp->stringlengths[resp->num_args] < len + 1) { + if (resp->strings[resp->num_args]) { + free(resp->strings[resp->num_args]); + resp->strings[resp->num_args] = NULL; + } + } + if (resp->strings[resp->num_args] == NULL) + resp->strings[resp->num_args] = (char *) malloc(len + 1); + resp->stringlengths[resp->num_args] = len + 1; + strncpy(resp->strings[resp->num_args], cpos1, len); + resp->strings[resp->num_args][len] = 0; + p->curr_arg = resp->num_args; + + // convert the string value to int/float if rules dictate it + + switch (p->rules[p->curr_rule].valtype) { + case PARSER_STRING: // no conversion, already a string + break; + + case PARSER_INT: + + fval = strtof(resp->strings[resp->num_args], &endptr); + + if (endptr == resp->strings[resp->num_args]) { + p->error = PARSER_ERR_BAD_VAL; + return cpos1 - p->buff; + } + + resp->ints[resp->num_args] = (int) fval; + break; + + case PARSER_FLOAT: + + fval = strtof(resp->strings[resp->num_args], &endptr); + resp->floats[resp->num_args] = fval; + if (endptr == resp->strings[resp->num_args]) { + p->error = PARSER_ERR_BAD_VAL; + return cpos1 - p->buff; + } + break; + } + + resp->num_args++; + } + return -1; +} + +int Parser_findCmd(Parser_t *p, const char *s) +{ + int i = 0; + + while (p->rules[i].cmd) { + if (!strcmp(s, p->rules[i].cmd)) + return i; + i++; + } + + return -1; // not found +} + +void Parser_growArgs(Parser_t *p, int n) +{ + parser_result_t *resp = &p->results; + char **new_strings; + float *new_floats; + int *new_ints; + int *new_stringlengths; + int i; + + new_strings = (char **) realloc(resp->strings, sizeof(char *) * (resp->max_args + n)); + new_stringlengths = (int *) realloc(resp->stringlengths, sizeof(int) * + (resp->max_args + n)); + new_floats = (float *) realloc(resp->floats, sizeof(float) * (resp->max_args + n)); + new_ints = (int *) realloc(resp->ints, sizeof(int) * (resp->max_args + n)); + + resp->max_args += n; + + for (i = resp->num_args; i < resp->max_args; i++) { + new_strings[i] = NULL; + new_stringlengths[i] = 0; + } + + resp->strings = new_strings; + resp->stringlengths = new_stringlengths; + resp->floats = new_floats; + resp->ints = new_ints; +} + +void Parser_setRules(Parser_t *p, parser_rules_t *rules) +{ + p->rules = rules; +} + +void Parser_printError(Parser_t *p) +{ + fprintf(stderr, "%s\n", parser_errmsgs[p->error]); +} + +void Parser_printRules(Parser_t *p) +{ + int i = 0; + + while (p->rules[i].cmd) { + printf("%s, %d, %d, %d\n", + p->rules[i].cmd, p->rules[i].minvals, + p->rules[i].maxvals, p->rules[i].valtype); + i++; + } +} + +void Parser_setParseString(Parser_t *p, const char *s) +{ + p->curr_arg = 0; + p->eol = 0; + p->cp = p->cp1 = p->cp2 = p->buff = s; + p->state = PARSER_GETVAR; +} + +int Parser_parse(Parser_t *p, parser_result_t **returned_result) +{ + parser_result_t *resp = &p->results; + int n, + leadspace = 1; + + resp->num_args = 0; + *returned_result = resp; + p->error = PARSER_ERR_NONE; + + // while ((p->c = *p->cp)) + while (!p->eol) { + p->c = *p->cp; + if (p->c == 0) { + p->eol = 1; + } + switch (p->state) { + case PARSER_GETVAR: + + if (leadspace) { + if (p->eol) + return PARSER_DONE; + if (p->c == ' ' || p->c == '\t') { + p->cp1 = p->cp + 1; + break; + } else + leadspace = 0; + } + + if (p->eol || p->c == '=') { + if ((n = (p->cp - p->cp1)) > 0) { + char *var; + + var = (char *) malloc(n + 1); + strncpy(var, p->cp1, n); + var[n] = 0; + p->curr_rule = resp->cmd_idx = Parser_findCmd(p, var); + free(var); + if (p->curr_rule < 0) { + p->error = PARSER_ERR_VAR_NOT_FOUND; + return p->cp1 - p->buff; + } + + resp->var_pos = p->cp1 - p->buff; + + if (p->eol) { + if (resp->num_args < + p->rules[p->curr_rule].minvals) { + p->error = PARSER_ERR_TOO_FEW_VALS; + return p->cp1 - p->buff; + } + return PARSER_OK; + } + + p->state = PARSER_GETVAL; + } else { + // null var + // return error pointing to position of bad var/val + p->error = PARSER_ERR_NO_VAR; + return p->cp1 - p->buff; + } + p->cp1 = p->cp + 1; + } else if (p->eol || p->c == ' ' || p->c == '\t') { + if ((n = (p->cp - p->cp1)) > 0) { + char *var; + + var = (char *) malloc(n + 1); + strncpy(var, p->cp1, n); + var[n] = 0; + p->curr_rule = resp->cmd_idx = Parser_findCmd(p, var); + free(var); + if (p->curr_rule < 0) { + p->error = PARSER_ERR_VAR_NOT_FOUND; + return p->cp1 - p->buff; + } + + // leadspace = 1; + if (resp->num_args < p->rules[p->curr_rule].minvals) { + p->error = PARSER_ERR_TOO_FEW_VALS; + return p->cp1 - p->buff; + } + return PARSER_OK; + } + } else if (p->c == ',') { + // error, var with no value, return pointing to char pos + p->error = PARSER_ERR_NO_VAL; + return p->cp - p->buff; + } + break; + + case PARSER_GETVAL: + if (p->c == ',') { + // got an argument + if (resp->num_args + 1 > p->rules[p->curr_rule].maxvals) { + p->error = PARSER_ERR_TOO_MANY_VALS; + return p->cp1 - p->buff; + } + + // copy value to string and convert to datatype + // dictated by the rule + + n = Parser_addArg(p, p->buff, p->cp1, p->cp); + + if (n >= 0) + return n; + p->cp1 = p->cp + 1; + } else if (p->eol || p->c == ' ' || p->c == '\t') { + // got an argument + if (resp->num_args + 1 > p->rules[p->curr_rule].maxvals) { + p->error = PARSER_ERR_TOO_MANY_VALS; + return p->cp1 - p->buff; + } + + // copy value to string and convert to datatype + // dictated by the rule + + n = Parser_addArg(p, p->buff, p->cp1, p->cp); + + if (n >= 0) + return n; + p->cp1 = p->cp + 1; + + p->state = PARSER_GETVAR; + // leadspace = 1; + p->cp1 = p->cp + 1; + p->cp2 = p->cp; + return PARSER_OK; + } + break; + } // end switch(p->state) + + p->cp++; + } + return PARSER_DONE; +} // end Parser_parse() diff --git a/frontpanel/lp_utils.cpp b/frontpanel/lp_utils.cpp deleted file mode 100644 index de7497bd..00000000 --- a/frontpanel/lp_utils.cpp +++ /dev/null @@ -1,1072 +0,0 @@ -// lp_utils.cpp utility functions - - -/* Copyright (c) 2007-2008, John Kichury - - This software is freely distributable free of charge and without license fees with the - following conditions: - - 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 - JOHN KICHURY 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. - - The above copyright notice must be included in any copies of this software. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lp_utils.h" - -#define TRUE 1 -#define FALSE 0 - -#ifndef max -#define max(a,b) (a) > (b) ? (a) : (b) -#endif -#ifndef min -#define min(a,b) (a) < (b) ? (a) : (b) -#endif - -#define UNUSED(x) (void) (x) - - -/* --------------------- - gtoken - token parser - ---------------------*/ - -/* Token parser. Returns string tokens. - - - Gtoken scans the string argument starting at the character - position specified by the argument . The next token is returned - in the return argument string and the value of is updated - to reflect the current parsing position. The value of the function is - the integer character length of the returned token. - - Tokens are generated using the following rules: - - Delimiters: Space and Comma. - - A single space terminates a token. A multispace field is equivalent to - a single space. Leading spaces are ignored. - - A single comma terminates a token and is equivalent to a space. Two or - more commas in succession generates null tokens. - - Delimiters may be specified in a token by enclosing the token in single - quotes. Quotes are specified in a token if they are doubled. - - examples: 'this is one token' - 'this token string contains a ''quoted'' word'. - one, two, three are individual tokens. -*/ - -int -gtoken(char *string,char *token,int maxlen,int *pos) - -#if 0 -char *string, /* input character string */ - *token; /* return token string */ - -int *pos, /* starting char position to parse */ - maxlen; /* max token length */ -#endif -{ - - - int qseen, /* quote (') seen flag */ - q2seen, /* 2nd quote seen flag */ - toklen, /* token length in characters */ - done, /* done with token flag */ - ignore_space; - - char c; - - q2seen = qseen = done = FALSE; - ignore_space = TRUE; /* ignore leading spaces */ - toklen = 0; - - while((c=string[*pos]) != '\0' && (toklen < maxlen) && !done) - { (*pos)++; - switch(c) - { case '\'': - ignore_space = FALSE; - if(!qseen) { qseen = TRUE; break; } - if(!q2seen) { q2seen = TRUE; break; } - token[toklen++] = c; - q2seen = FALSE; - break; - - case ',': - ignore_space = FALSE; - if(qseen && !q2seen) token[toklen++] = c; - else done = TRUE; - break; - - case ' ': - if(!ignore_space) - { if(qseen && !q2seen) token[toklen++] = c; - else done = TRUE; - } - break; - - default: - ignore_space = FALSE; - if(q2seen) - { done = TRUE; - break; - } - token[toklen++] = c; - break; - - } /* end switch */ - } /* end while */ - - token[toklen] = '\0'; /* mark end of token */ - return toklen; - -} /* end of gtoken function */ - - -/* ------------------------------- - case_a change string case - ------------------------------- - - Converts a character string from upper to lower or lower to upper case. - key; 0=conv to lower, 1= convert to upper case -*/ - - -void case_a(int key,char *string) -{ int i; - char c; - - i=0; - switch(key) - { case 0: while((c = string[i]) != '\0') string[i++] = tolower(c); - break; - case 1: while((c = string[i]) != '\0') string[i++] = toupper(c); - break; - default: break; - } - return; -} /* end case_a */ - -/* prefix.c test for string prefix */ - -/* Returns true (1) if string2 is a prefix of string1. - - usage: int prefix(); - char string1[LEN],string2[LEN]; - if(prefix(string1,string2)) ... - i = prefix("testing","test") -*/ - -int -prefix(char *str1,char *str2) -{ - int i; - char c; - - i=0; - while((c=str2[i]) != '\0') - if(c != str1[i++]) return 0; - - return 1; - -} - -/* freadlin.c read line from file */ - -/* Read an ascii line from specified file (carret,lf or null signals end - of line) - - Returns line in "buffer" up to specified length terminated with a NULL. - - Value of function: 0=failure 1=success. - - usage: int freadlin(), i; - char buffer[]; - FILE *funit; - i=freadlin(funit,buffer,bufsize); -*/ - -/* #include */ - -#define CARRET '\015' /* carriage return */ -#define LF '\012' /* line feed */ -#define EOL '\0' /* end of line ("C" standard) */ - -int -freadlin(FILE *funit,char *buffer,int bufsize) -{ - int i; - char c; - - i = 0; - - c = getc(funit); - - if(feof(funit)) return 0; - - while( c != EOL && c != CARRET && c != LF) - { if(i < bufsize) buffer[i++] = c; - c = getc(funit); - if(feof(funit)) return 0; - } - buffer[i] = EOL; - return 1; - -} /* end freadlin() */ - - - -/* strindex: return index of t in s, -1 if none */ - -int strindex(char s[], char t[]) -{ - int i,j,k; - - for(i=0; s[i] != '\0'; i++) - { - for (j=i, k=0; t[k] != '\0' && s[j]==t[k]; j++, k++) - ; - if(k>0 && t[k] == '\0') - return i; - - } - - return -1; -} - - -/* get power of 2 */ - -int -GetPowerOf2i(int n) -{ int result = 0x2; - - while(result < n) result = result << 1; - return result; -} - - - -/* xpand */ - - - -enum xpnd_states { XPN_START, XPN_PREFIX, XPN_FRMVAL, XPN_TOVAL, XPN_INC, XPN_SUFFIX }; - -#ifndef max - #define max( a, b ) ( ((a) > (b)) ? (a) : (b) ) -#endif - - -//int xpand(const char *s, int (*func)(char *m) ) - -//int xpand(const char *s, char ***namelist ) -int xpand(const char *s, char **namelist[] ) -{ - - const char *cp = s, - *cp1 = NULL; - char c, - *prefix = NULL, - *suffix = NULL, - *from = NULL, - *to = NULL, - *inc = NULL; - int n, - // error = 0, - state = XPN_START; - - int ival, - from_ival = 0, - from_digits = 0, - to_ival = 0, - to_digits = 0, - inc_ival = 1, - ndigits = 0; - - char format[10], - dbuf[10], - obuf[100]; - - int max_names, // computed number of expanded names - num_names = 0; - char **new_namelist; - - while ( (c = *cp) ) - { - - switch(state) - { - case XPN_START: - if( c == '{' ) - { - state = XPN_FRMVAL; - cp1 = cp + 1; - } - else - { - cp1 = cp; - state = XPN_PREFIX; - } - cp++; - break; - - case XPN_PREFIX: - if( c == '{' ) - { - state = XPN_FRMVAL; - n = cp - cp1; - if(n > 0) - { - //prefix = (char *) malloc(n+1); - prefix = new char[n+1]; - strncpy(prefix, s, n); - prefix[n] = 0; - cp1 = cp + 1; - } - } - cp++; - break; - - case XPN_FRMVAL: - - if( c == '-' ) - { - state = XPN_TOVAL; - n = cp - cp1; - if(n > 0) - { - //from = (char *) malloc(n+1); - from = new char[n+1]; - strncpy(from, cp1, n); - from[n] = 0; - cp1 = cp + 1; - } - } - else if( c == '}' ) - { - state = XPN_SUFFIX; - n = cp - cp1; - if(n > 0) - { - //from = (char *) malloc(n+1); - from = new char[n+1]; - strncpy(from, cp1, n); - from[n] = 0; - } - cp1 = cp + 1; - } - else if( c == '+' ) - { - // error = 1; - } - - cp++; - break; - - case XPN_TOVAL: - if( c == '+' ) - { - state = XPN_INC; - n = cp - cp1; - if(n > 0) - { - //to = (char *) malloc(n+1); - to = new char[n+1]; - strncpy(to, cp1, n); - to[n] = 0; - cp1 = cp + 1; - } - } - - else if( c == '}' ) - { - state = XPN_SUFFIX; - n = cp - cp1; - if(n > 0) - { - //to = (char *) malloc(n+1); - to = new char[n+1]; - strncpy(to, cp1, n); - to[n] = 0; - } - cp1 = cp + 1; - } - - cp++; - break; - - case XPN_INC: - if( c == '}' ) - { - state = XPN_SUFFIX; - n = cp - cp1; - if(n > 0) - { - //inc = (char *) malloc(n+1); - inc = new char[n+1]; - strncpy(inc, cp1, n); - inc[n] = 0; - cp1 = cp + 1; - } - } - - cp++; - break; - - case XPN_SUFFIX: - cp++; - break; - } /* end switch */ - - - } /* end while */ - - switch( state ) - { - case XPN_START: - case XPN_PREFIX: - n = cp - cp1; - //prefix = (char *) malloc(n+1); - //prefix = new char[n+1]; - if(n > 0) - { - //prefix = (char *) malloc(n+1); - prefix = new char[n+1]; - strncpy(prefix, s, n); - prefix[n] = 0; - } - break; - case XPN_FRMVAL: - n = cp - cp1; - if(n > 0) - { - //from = (char *) malloc(n+1); - from = new char[n+1]; - strncpy(from, cp1, n); - from[n] = 0; - } - break; - case XPN_TOVAL: - n = cp - cp1; - if(n > 0) - { - //to = (char *) malloc(n+1); - to = new char[n+1]; - strncpy(to, cp1, n); - to[n] = 0; - } - break; - case XPN_INC: - n = cp - cp1; - if(n > 0) - { - //inc = (char *) malloc(n+1); - inc = new char[n+1]; - strncpy(inc, cp1, n); - inc[n] = 0; - } - break; - case XPN_SUFFIX: - n = cp - cp1; - if(n > 0) - { - //suffix = (char *) malloc(n+1); - suffix = new char[n+1]; - strncpy(suffix, cp1, n); - suffix[n] = 0; - } - break; - - } /* end switch(state) */ - - - /* set up to iterate */ - - if(from && to) - { - from_ival = atoi(from); - to_ival = atoi(to); - if(to_ival != from_ival) - { - if(inc) inc_ival = atoi(inc); - if( to_ival < from_ival) inc_ival = -inc_ival; - - from_digits = strlen(from); - to_digits = strlen(to); - ndigits = max(from_digits, to_digits); - - ival = from_ival; - - snprintf(format, sizeof(format), "%%0%dd",ndigits); - - max_names = ( (max(ival, to_ival)) - (min(ival,to_ival))) / abs(inc_ival) + 1; - - new_namelist = new char *[max_names]; - *namelist = &new_namelist[0]; - num_names = 0; - - do - { - obuf[0]=0; - snprintf(dbuf,sizeof(dbuf),format,ival); - if(prefix) strcpy(obuf,prefix); - strcat(obuf,dbuf); - if(suffix) strcat(obuf,suffix); - - new_namelist[num_names] = new char[ strlen(obuf)+1]; - strcpy(new_namelist[num_names], obuf); - num_names++; - ival += inc_ival; - } while (ival != to_ival); - - snprintf(dbuf,sizeof(dbuf),format,ival); - obuf[0]=0; - if(prefix) strcpy(obuf,prefix); - strcat(obuf,dbuf); - if(suffix) strcat(obuf,suffix); - new_namelist[num_names] = new char[ strlen(obuf)+1]; - strcpy(new_namelist[num_names], obuf); - num_names++; - } - } - else - { - obuf[0]=0; - if(prefix) strcpy(obuf,prefix); - if(from ) strcat(obuf,from); - if(suffix) strcat(obuf,suffix); - - new_namelist = new char *[1]; - *namelist = &new_namelist[0]; - num_names = 0; - - new_namelist[num_names] = new char[ strlen(obuf)+1]; - strcpy(new_namelist[num_names], obuf); - num_names++; - } - - if(prefix) delete[] prefix; - if(from) delete[] from; - if(to) delete[] to; - if(inc) delete[] inc; - if(suffix) delete[] suffix; - - return num_names; - -} /* end xpand() */ - - -int check_glerror(void) -{ -int n = glGetError(); - if(n) - { printf("glError:%d %s\n",n, gluErrorString(n)); - } - return n; -} - - -/* framerate control */ - - -/* framerate.c */ - - -/* - - usage: - - init: - framerate_set(30.0); - framerate_start(); - - - draw() - { - ... - - glFinish(); - framerate_wait(); - swapbuffers(); - framerate_start(); - } - - -*/ - -typedef struct { - struct timeval bsdtime; - float dt; - int stopped; -} watch_t; - -typedef struct -{ - double fps, - frametime, - start, - et; -} frate_t; - -static frate_t frate_parms = {30.0, 1.0/30., 0., 0.}; - -static watch_t syswatch; - -double frate_gettime(void) -{ - struct timeval tp; - int sec; - int usec; - watch_t *t; - double secf, usecf, dt; - - t = &syswatch; - - gettimeofday(&tp, NULL); - sec = tp.tv_sec - t->bsdtime.tv_sec; - usec = tp.tv_usec - t->bsdtime.tv_usec; - if (usec < 0) - { - sec--; - usec += 1000000; - } - - secf = (double) sec; - usecf = (double) usec; - usecf = usecf / 1000000.0; - dt = secf + usecf; - return dt; -} - -/* funcs */ - -void framerate_set(double r) -{ - frate_parms.fps = r; - frate_parms.frametime = (float) 1.0 / frate_parms.fps; -} - -void framerate_start_frame(void) -{ - frate_parms.start = frate_gettime(); -} - -void framerate_wait(void) -{ - struct timespec ts, rem; - double delta; - double t; - - t = frate_gettime(); - - frate_parms.et = t - frate_parms.start; - - delta = frate_parms.frametime - frate_parms.et; - -// if(delta < 0.) printf("missed rendering frame\n"); - - if( delta > 0.0 ) - { - delta = delta * 10e8; - ts.tv_sec = 0; - ts.tv_nsec = (long) delta; - - for (;;) - if (nanosleep(&ts, &rem) == -1 && errno == EINTR && rem.tv_nsec > 0L) - { - ts = rem; - continue; - } - else - break; - } - -} - - -// parser class - - -// arg_parser.cpp argument parser class - - -#include -#include - -static const char *parser_errmsgs[] = { -"No error.", -"No variable", -"No value.", -"Bad Varable.", -"Bad value.", -"Too many values.", -"Too few values." -}; - - - -Parser::Parser(void) -{ - results.max_args = 0; - curr_arg = 0; - eol = 0; - results.strings = NULL; - results.stringlengths = NULL; - results.floats = NULL; - results.ints = NULL; -} - -Parser::~Parser(void) -{ - int i; - - if(results.strings) - { - for(i=0;i results.max_args) - growArgs(4); - - if((len = cpos2 - cpos1) > 0) - { - - if(results.stringlengths[results.num_args] < len+1) - { - if(results.strings[results.num_args]) - { - delete[] results.strings[results.num_args]; - results.strings[results.num_args] = NULL; - } - } - if (results.strings[results.num_args] == NULL) - results.strings[results.num_args] = new char[ len + 1]; - results.stringlengths[results.num_args] = len + 1; - strncpy(results.strings[results.num_args], cpos1,len); - results.strings[results.num_args][len] = 0; - curr_arg = results.num_args; - - - // convert the string value to int/float if rules dictate it - - switch(rules[curr_rule].valtype) - { - case PARSER_STRING: // no conversion, already a string - break; - - case PARSER_INT: - - fval = strtof(results.strings[results.num_args],&endptr); - - if(endptr == results.strings[results.num_args]) - { - error = PARSER_ERR_BAD_VAL; - return cpos1 - buff; - } - - results.ints[results.num_args] = (int) fval; - break; - - case PARSER_FLOAT: - - fval = strtof(results.strings[results.num_args],&endptr); - results.floats[results.num_args] = fval; - if(endptr == results.strings[results.num_args]) - { - error = PARSER_ERR_BAD_VAL; - return cpos1 - buff; - } - break; - } - - results.num_args++; - } - return -1; -} - -int -Parser::findCmd(char *s) -{ - int i = 0; - - while( rules[i].cmd ) - { - if(!strcmp(s, rules[i].cmd)) return i; - i++; - } - - return -1; // not found -} - -void Parser:: growArgs(int n) -{ - char **new_strings; - float *new_floats; - int *new_ints; - int *new_stringlengths; - int i; - - results.strings = results.strings; - results.floats = results.floats; - results.ints= results.ints; - results.stringlengths = results.stringlengths; - - new_strings = new char *[results.max_args + n]; - new_stringlengths = new int[results.max_args + n]; - new_floats = new float[results.max_args + n]; - new_ints = new int[results.max_args + n]; - - - for(i=0;i 0 ) - { - char *var; - var = new char[n+1]; - strncpy(var,cp1,n); - var[n]=0; - curr_rule= results.cmd_idx = findCmd(var); - delete[] var; - if(curr_rule < 0) - { - error = PARSER_ERR_VAR_NOT_FOUND; - return cp1-buff; - } - - // leadspace = 1; - if(results.num_args < rules[curr_rule].minvals) - { - error=PARSER_ERR_TOO_FEW_VALS; - return cp1-buff; - } - return PARSER_OK; - - } - } - else if( c == ',') - { - error = PARSER_ERR_NO_VAL; - return cp-buff; // error, var with no value, return pointing to char pos - } - break; - - case PARSER_GETVAL: - if( c == ',') - { - - // got an argument - if(results.num_args +1 > rules[curr_rule].maxvals) - { - error = PARSER_ERR_TOO_MANY_VALS; - return cp1-buff; - } - - // copy value to string and convert to datatype dictated by the rule - - n = addArg(buff, cp1, cp); - - if(n >= 0) return n; - cp1 = cp+1; - - } - else if(eol || c == ' ' || c == '\t') - { - // got an argument - if(results.num_args +1 > rules[curr_rule].maxvals) - { - error = PARSER_ERR_TOO_MANY_VALS; - return cp1-buff; - } - - // copy value to string and convert to datatype dictated by the rule - - n = addArg(buff, cp1, cp); - - if(n >= 0) return n; - cp1 = cp+1; - - state = PARSER_GETVAR; - // leadspace = 1; - cp1 = cp+1; - cp2 = cp; - return PARSER_OK; - } - - break; - } // end switch(state) - - cp++; - - } - return PARSER_DONE; - -} // end parse() - - - diff --git a/frontpanel/lp_utils.h b/frontpanel/lp_utils.h index 9360b5c0..cc0cc81e 100644 --- a/frontpanel/lp_utils.h +++ b/frontpanel/lp_utils.h @@ -1,8 +1,9 @@ // lp_utils.h /* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -16,111 +17,92 @@ */ +#ifndef _LP_UTILS_DEFS +#define _LP_UTILS_DEFS + +#include + #ifndef max -#define max(a,b) (a) > (b) ? (a) : (b) +#define max(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef min -#define min(a,b) (a) < (b) ? (a) : (b) +#define min(a,b) ((a) < (b) ? (a) : (b)) #endif +extern int gtoken(char *string, char *token, int maxlen, int *pos); +extern int freadlin(FILE *funit, char *buffer, int bufsize); +extern int xpand(const char *s, char ***namelist); -int gtoken(char *string,char *token,int maxlen,int *pos); -void case_a(int key,char *string); -int prefix(char *str1,char *str2); -int freadlin(FILE *funit,char *buffer,int bufsize); -int strindex(char s[], char t[]); - -int GetPowerOf2i(int n); -int xpand(const char *s, char ***namelist); - -int check_glerror(void); - - -/* framerate.h */ -double frate_gettime(void); -void framerate_set(double r); -void framerate_start_frame(void); -void framerate_wait(void); - - - - - -// arg_parser.h - -#ifndef _PARSER_DEFS -#define _PARSER_DEFS +extern double frate_gettime(void); +extern void framerate_set(double r); +extern void framerate_start_frame(void); +extern void framerate_wait(void); enum parser_rules_enums { PARSER_STRING, PARSER_INT, PARSER_FLOAT }; enum parser_state_enums { PARSER_GETVAR, PARSER_GETVAL }; -enum parser_error_nums_enums - { - PARSER_ERR_NONE, - PARSER_ERR_NO_VAR, - PARSER_ERR_NO_VAL, - PARSER_ERR_VAR_NOT_FOUND, - PARSER_ERR_BAD_VAL, - PARSER_ERR_TOO_MANY_VALS, - PARSER_ERR_TOO_FEW_VALS - }; - -#define PARSER_DONE -2 -#define PARSER_OK -1 - - -typedef struct -{ - const char *cmd; - int minvals, - maxvals, - valtype; -} parser_rules_t; - -typedef struct -{ - int cmd_idx, // command index within rules of found command string - var_pos, // position in parse string where the variable was found - num_args, // number of arguments found for current variable - max_args, // max args that can exist for current var - *stringlengths; // lengths of each argument in string form - char **strings; // array of text values for each argument - float *floats; - int *ints; - -} parser_result_t; - +enum parser_error_nums_enums { + PARSER_ERR_NONE, + PARSER_ERR_NO_VAR, + PARSER_ERR_NO_VAL, + PARSER_ERR_VAR_NOT_FOUND, + PARSER_ERR_BAD_VAL, + PARSER_ERR_TOO_MANY_VALS, + PARSER_ERR_TOO_FEW_VALS +}; -class Parser -{ - private: - parser_rules_t *rules; - int state, error, eol; - char c; - const char *cp, *cp1, *cp2, *buff; - int curr_rule, - curr_arg; - int addArg(const char *s, const char *cpos1, const char *cpos2); - int findCmd(char *s); - void growArgs(int n); - - public: - Parser(); - ~Parser(); - - parser_result_t results; - - void setParseString(const char *s); - void setRules(parser_rules_t *_rules); - void printError(void); - void printRules(void); - int parse(parser_result_t **returned_result); - int parse(); // continue with old parse +#define PARSER_DONE -2 +#define PARSER_OK -1 -}; +typedef struct parser_rules { + const char *cmd; + int minvals, + maxvals, + valtype; +} parser_rules_t; +typedef struct parser_result { + int cmd_idx, // command index within rules of found command string + var_pos, // position in parse string where the variable was found + num_args, // number of arguments found for current variable + max_args, // max args that can exist for current var + *stringlengths; // lengths of each argument in string form + char **strings; // array of text values for each argument + float *floats; + int *ints; -#endif +} parser_result_t; +typedef struct Parser { + // private variables + parser_rules_t *rules; + int state, error, eol; + char c; + const char *cp, *cp1, *cp2, *buff; + int curr_rule, + curr_arg; + + // public variables + parser_result_t results; +} Parser_t; + +extern Parser_t *Parser_new(void); +extern void Parser_delete(Parser_t *p); +extern void Parser_init(Parser_t *p); +extern void Parser_fini(Parser_t *p); + +/* private functions */ +extern int Parser_addArg(Parser_t *p, const char *s, const char *cpos1, const char *cpos2); +extern int Parser_findCmd(Parser_t *p, const char *s); +extern void Parser_growArgs(Parser_t *p, int n); + +/* public functions */ +extern void Parser_setParseString(Parser_t *p, const char *s); +extern void Parser_setRules(Parser_t *p, parser_rules_t *rules); +extern void Parser_printError(Parser_t *p); +extern void Parser_printRules(Parser_t *p); +extern int Parser_parse(Parser_t *p, parser_result_t **returned_result); + +#endif /* !_LP_UTILS_DEFS */ diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c new file mode 100644 index 00000000..a177bada --- /dev/null +++ b/frontpanel/lp_window.c @@ -0,0 +1,1247 @@ +// lp_window.c lightpanel window functions + +/* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt + + This software is freely distributable free of charge and without license fees with the + following conditions: + + 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 + JOHN KICHURY 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. + + The above copyright notice must be included in any copies of this software. + +*/ + +#include +#include +#include +#include +#ifdef WANT_SDL +#include +#include +#include +#else /* !WANT_SDL */ +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif +#endif /* !WANT_SDL */ + +#include "lpanel.h" +#include "lp_materials.h" +#include "lp_font.h" + +#define UNUSED(x) (void) (x) + +#ifndef WANT_SDL +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) +const char FPClassName[] = "FrontPanel 2.1"; +#else +static int RGBA_DB_attributes[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None +}; +#endif +#endif /* !WANT_SDL */ + +// OpenGL Light source + +static GLfloat light_pos0[] = { 0., 0.5, 1., 0.}; +// static GLfloat light_pos1[] = { 0.,-0.5,-1.,0.}; +static GLfloat light_diffuse[] = { 1., 1., 1., 1.}; +static GLfloat light_specular[] = { 1., 1., 1., 1.}; + +static GLfloat mtl_amb[] = { 0.2, 0.2, 0.2, 1.0 }; +static GLfloat mtl_dif[] = { 1.0, 1.0, 1.0, 1.0 }; +static GLfloat mtl_spec[] = { 0.0, 0.0, 0.0, 1.0 }; +static GLfloat mtl_shine[] = { 0.0 }; +static GLfloat mtl_emission[] = { 0.0, 0.0, 0.0, 1.0 }; + +static int mousex, mousey, omx, omy, lmouse; + +#ifdef WANT_SDL + +void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) +{ + switch (event->type) { + case SDL_WINDOWEVENT: + if (event->window.windowID != SDL_GetWindowID(p->window)) + break; + + Lpanel_resizeWindow(p); + break; + + case SDL_QUIT: + // call user quit callback if exists + if (p->quit_callbackfunc) + (*p->quit_callbackfunc)(); + break; + + case SDL_MOUSEBUTTONDOWN: + if (event->button.windowID != SDL_GetWindowID(p->window)) + break; + + SDL_GL_MakeCurrent(p->window, p->cx); + if (!Lpanel_pick(p, event->button.button - 1, 1, + event->button.x, event->button.y)) { + if (event->button.button == SDL_BUTTON_LEFT) { // left mousebutton ? + lmouse = 1; + mousex = event->button.x; + mousey = event->button.y; + } + } + break; + + case SDL_MOUSEBUTTONUP: + if (event->button.windowID != SDL_GetWindowID(p->window)) + break; + + SDL_GL_MakeCurrent(p->window, p->cx); + if (!Lpanel_pick(p, event->button.button - 1, 0, + event->button.x, event->button.y)) { + if (event->button.button == SDL_BUTTON_LEFT) + lmouse = 0; + } + break; + + case SDL_KEYUP: + if (event->key.windowID != SDL_GetWindowID(p->window)) + break; + + switch (event->key.keysym.sym) { + case SDLK_LSHIFT: + case SDLK_RSHIFT: + p->shift_key_pressed = false; + break; + + } + break; + + case SDL_KEYDOWN: + if (event->key.windowID != SDL_GetWindowID(p->window)) + break; + + switch (event->key.keysym.sym) { + case SDLK_ESCAPE: + // exit(EXIT_SUCCESS); + break; + + case SDLK_LSHIFT: + case SDLK_RSHIFT: + p->shift_key_pressed = true; + break; + + case SDLK_c: + p->do_cursor = !p->do_cursor; + break; + + case SDLK_d: + p->view.pan[1] -= 0.1; + p->view.redo_projections = true; + break; + + case SDLK_s: + p->do_stats = !p->do_stats; + break; + + case SDLK_l: + p->view.rot[1] += -1.; + p->view.redo_projections = true; + break; + + case SDLK_r: + p->view.rot[1] -= -1.; + p->view.redo_projections = true; + break; + + case SDLK_u: + p->view.pan[1] += 0.1; + p->view.redo_projections = true; + break; + + case SDLK_v: + if (p->view.projection == LP_ORTHO) + p->view.projection = LP_PERSPECTIVE; + else + p->view.projection = LP_ORTHO; + + p->view.redo_projections = true; + break; + + case SDLK_z: + if (p->shift_key_pressed) { + p->view.pan[2] += .1; + p->view.redo_projections = true; + } else { + p->view.pan[2] -= .1; + p->view.redo_projections = true; + } + break; + + case SDLK_UP: + if (p->do_cursor) + Lpanel_inc_cursor(p, 0., p->cursor_inc); + else { + if (p->shift_key_pressed) + p->view.pan[1] += -0.1; + else + p->view.rot[0] += -1.; + + p->view.redo_projections = true; + } + break; + + case SDLK_DOWN: + if (p->do_cursor) + Lpanel_inc_cursor(p, 0., -p->cursor_inc); + else { + if (p->shift_key_pressed) + p->view.pan[1] += 0.1; + else + p->view.rot[0] += 1.; + + p->view.redo_projections = true; + } + break; + + case SDLK_RIGHT: + if (p->do_cursor) + Lpanel_inc_cursor(p, p->cursor_inc, 0.); + else { + if (p->shift_key_pressed) + p->view.pan[0] += -.1; + else + p->view.rot[1] += 1.; + + p->view.redo_projections = true; + } + break; + + case SDLK_LEFT: + if (p->do_cursor) + Lpanel_inc_cursor(p, -p->cursor_inc, 0.); + else { + if (p->shift_key_pressed) + p->view.pan[0] += .1; + else + p->view.rot[1] += -1.; + + p->view.redo_projections = true; + } + break; + + case SDLK_1: + case SDLK_KP_1: + break; + + default: + break; + } + /* fallthrough */ + + case SDL_MOUSEMOTION: + if (event->motion.windowID != SDL_GetWindowID(p->window)) + break; + + if (lmouse) { + omx = mousex; + omy = mousey; + + if (p->shift_key_pressed) { + p->view.pan[0] += ((float) event->motion.x - (float) omx) * .02; + p->view.pan[1] -= ((float) event->motion.y - (float) omy) * .02; + } else { + p->view.rot[1] += ((float) event->motion.x - (float) omx) * .2; + p->view.rot[0] += ((float) event->motion.y - (float) omy) * .2; + } + + mousex = event->motion.x; + mousey = event->motion.y; + p->view.redo_projections = true; + } + break; + + default: + break; + } +} // end Lpanel_procEvent() + +#else /* !WANT_SDL */ + +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + +static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + LONG_PTR user_data = GetWindowLongPtr(hWnd, GWLP_USERDATA); + + if (user_data) + return Lpanel_WndProc((Lpanel_t *) user_data, Msg, wParam, lParam); + else + return DefWindowProc(hWnd, Msg, wParam, lParam); +} + +LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT msg, WPARAM wParam, LPARAM lParam) +{ + unsigned int kcode; + + switch(msg) { + case WM_KEYUP: + if (LOWORD(wParam) == VK_SHIFT) { + p->shift_key_pressed = false; + return 0; + } + return 0; + + case WM_KEYDOWN: + kcode = LOWORD(wParam); + switch(kcode) { + case VK_SHIFT: + p->shift_key_pressed = true; + return 0; + + case VK_UP: + if (p->do_cursor) + Lpanel_inc_cursor(p, 0., p->cursor_inc); + else { + if (p->shift_key_pressed) + p->view.pan[1] += -0.1; + else + p->view.rot[0] += -1.; + + p->view.redo_projections = true; + } + break; + + case VK_DOWN: + if (p->do_cursor) + Lpanel_inc_cursor(p, 0., -cursor_inc); + else { + if (p->shift_key_pressed) + p->view.pan[1] += 0.1; + else + p->view.rot[0] += 1.; + + p->view.redo_projections = true; + } + break; + + case VK_RIGHT: + if (p->do_cursor) + Lpanel_inc_cursor(p, p->cursor_inc, 0.); + else { + if (p->shift_key_pressed) + p->view.pan[0] += -.1; + else + p->view.rot[1] += 1.; + + p->view.redo_projections = true; + } + break; + + case VK_LEFT: + if (p->do_cursor) + Lpanel_inc_cursor(p, -p->cursor_inc, 0.); + else { + if (p->shift_key_pressed) + p->view.pan[0] += .1; + else + p->view.rot[1] += -1.; + + p->view.redo_projections = true; + } + break; + } + return 0; + + case WM_CHAR: + kcode = LOWORD(wParam); + + switch (kcode) { + case VK_ESCAPE: + // exit(EXIT_SUCCESS); + break; + + case 'c': + case 'C': + p->do_cursor = !p->do_cursor; + break; + + case 'd': + case 'D': + p->view.pan[1] -= 0.1; + p->view.redo_projections = true; + break; + + case 's': + case 'S': + p->do_stats = !p->do_stats; + break; + + case 'l': + case 'L': + p->view.rot[1] += -1.; + p->view.redo_projections = true; + break; + + case 'r': + case 'R': + p->view.rot[1] -= -1.; + p->view.redo_projections = true; + break; + + case 'u': + case 'U': + p->view.pan[1] += 0.1; + p->view.redo_projections = true; + break; + + case 'v': + case 'V': + if (p->view.projection == LP_ORTHO) + view.projection = LP_PERSPECTIVE; + else + view.projection = LP_ORTHO; + + view.redo_projections = true; + break; + + case 'z': + view.pan[2] -= .1; + view.redo_projections = true; + break; + + case 'Z': + view.pan[2] += .1; + view.redo_projections = true; + break; + + case '1': + break; + } + break; + + case WM_MOUSEWHEEL: + p->view.pan[2] += (float) GET_WHEEL_DELTA_WPARAM(wParam) / 250.0; + p->view.redo_projections = true; + return 0; + + case WM_LBUTTONDOWN: + if (!Lpanel_pick(p, 0, 1, LOWORD(lParam), HIWORD(lParam))) { + mousex = LOWORD(lParam); + mousey = HIWORD(lParam); + lmouse = true; + } + return 0; + + case WM_LBUTTONUP: + if(!Lpanel_pick(p, 0, 0, LOWORD(lParam), HIWORD(lParam))) + lmouse = false; + return 0; + + case WM_MOUSEMOVE: + if (lmouse) { + omx = mousex; + omy = mousey; + + if (p->shift_key_pressed) { + p->view.pan[0] += ((float) LOWORD(lParam) - (float) omx) * .02; + p->view.pan[1] -= ((float) HIWORD(lParam) - (float) omy) * .02; + } else { + view.rot[1] += ((float) LOWORD(lParam) - (float) omx) * .2; + view.rot[0] += ((float) HIWORD(lParam) - (float) omy) * .2; + } + + mousex = LOWORD(lParam); + mousey = HIWORD(lParam); + p->view.redo_projections = true; + } + return 0; + + case WM_SIZE: + p->window_xsize = (GLsizei) LOWORD(lParam); + p->window_ysize = (GLsizei) HIWORD(lParam); + p->view.aspect = (GLdouble) p->window_xsize / (GLdouble) p->window_ysize; + + glViewport(0, 0, p->window_xsize, p->window_ysize); + glGetIntegerv(GL_VIEWPORT, p->viewport); + setProjection(false); + setModelview(false); + + return 0; + + case WM_QUIT: + case WM_CLOSE: + if (p->hRC) { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(p->hRC); + } + if (p->hDC) { + ReleaseDC(p->hWnd, p->hDC); + } + DestroyWindow(p->hWnd); + return 0; + + case WM_DESTROY: + UnregisterClass(FPClassName, p->hInstance); + PostQuitMessage(0); + if(quit_callbackfunc) + (*quit_callbackfunc)(); + else + exit(EXIT_SUCCESS); + return 0; + + default: + return DefWindowProc(p->hWnd, msg, wParam, lParam); + } +} + +void Lpanel_procEvents(Lpanel_t *p) +{ + MSG msg; + + if (PeekMessage(&msg, p->hWnd, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +#else /* !__MINGW32__ && !_WIN32 && !_WIN32_ && !__WIN32__ */ + +void Lpanel_procEvents(Lpanel_t *p) +{ + XEvent event; + char buffer[5]; + int bufsize = 5; + KeySym key; + XComposeStatus compose; + + while (XPending(p->dpy)) { + XNextEvent(p->dpy, &event); + + switch (event.type) { + case ConfigureNotify: + Lpanel_resizeWindow(p); + break; + + case ClientMessage: + if ((Atom) event.xclient.data.l[0] == p->wmDeleteMessage) { + // call user quit callback if exists + if (p->quit_callbackfunc) { + (*p->quit_callbackfunc)(); + } else { + XCloseDisplay(p->dpy); + exit(EXIT_SUCCESS); + } + } + break; + + case UnmapNotify: + break; + + case DestroyNotify: + break; + + case ButtonPress: + if (!Lpanel_pick(p, event.xbutton.button - 1, 1, + event.xbutton.x, event.xbutton.y)) { + if (event.xbutton.button == 1) { // left mousebutton ? + lmouse = 1; + mousex = event.xbutton.x; + mousey = event.xbutton.y; + } + } + break; + + case ButtonRelease: + if (!Lpanel_pick(p, event.xbutton.button - 1, 0, + event.xbutton.x, event.xbutton.y)) { + if (event.xbutton.button == 1) + lmouse = 0; + } + break; + + case KeyRelease: + XLookupString(&event.xkey, buffer, bufsize, &key, &compose); + + switch (key) { + case XK_Shift_L: + case XK_Shift_R: + p->shift_key_pressed = false; + break; + + } + break; + + case KeyPress: + XLookupString(&event.xkey, buffer, bufsize, &key, &compose); + + switch (key) { + case XK_Escape: + // exit(EXIT_SUCCESS); + break; + + case XK_Shift_L: + case XK_Shift_R: + p->shift_key_pressed = true; + break; + + case XK_c: + case XK_C: + p->do_cursor = !p->do_cursor; + break; + + case XK_d: + case XK_D: + p->view.pan[1] -= 0.1; + p->view.redo_projections = true; + break; + + case XK_s: + case XK_S: + p->do_stats = !p->do_stats; + break; + + case XK_l: + case XK_L: + p->view.rot[1] += -1.; + p->view.redo_projections = true; + break; + + case XK_r: + case XK_R: + p->view.rot[1] -= -1.; + p->view.redo_projections = true; + break; + + case XK_u: + case XK_U: + p->view.pan[1] += 0.1; + p->view.redo_projections = true; + break; + + case XK_v: + case XK_V: + if (p->view.projection == LP_ORTHO) + p->view.projection = LP_PERSPECTIVE; + else + p->view.projection = LP_ORTHO; + + p->view.redo_projections = true; + break; + + case XK_z: + p->view.pan[2] -= .1; + p->view.redo_projections = true; + break; + + case XK_Z: + p->view.pan[2] += .1; + p->view.redo_projections = true; + break; + + case XK_Up: + if (p->do_cursor) + Lpanel_inc_cursor(p, 0., p->cursor_inc); + else { + if (p->shift_key_pressed) + p->view.pan[1] += -0.1; + else + p->view.rot[0] += -1.; + + p->view.redo_projections = true; + } + break; + + case XK_Down: + if (p->do_cursor) + Lpanel_inc_cursor(p, 0., -p->cursor_inc); + else { + if (p->shift_key_pressed) + p->view.pan[1] += 0.1; + else + p->view.rot[0] += 1.; + + p->view.redo_projections = true; + } + break; + + case XK_Right: + if (p->do_cursor) + Lpanel_inc_cursor(p, p->cursor_inc, 0.); + else { + if (p->shift_key_pressed) + p->view.pan[0] += -.1; + else + p->view.rot[1] += 1.; + + p->view.redo_projections = true; + } + break; + + case XK_Left: + if (p->do_cursor) + Lpanel_inc_cursor(p, -p->cursor_inc, 0.); + else { + if (p->shift_key_pressed) + p->view.pan[0] += .1; + else + p->view.rot[1] += -1.; + + p->view.redo_projections = true; + } + break; + + case XK_1: + case XK_KP_1: + break; + + default: + break; + } + /* fallthrough */ + + case MotionNotify: + if (lmouse) { + omx = mousex; + omy = mousey; + + if (p->shift_key_pressed) { + p->view.pan[0] += ((float) event.xmotion.x - + (float) omx) * .02; + p->view.pan[1] -= ((float) event.xmotion.y - + (float) omy) * .02; + } else { + p->view.rot[1] += ((float) event.xmotion.x - + (float) omx) * .2; + p->view.rot[0] += ((float) event.xmotion.y - + (float) omy) * .2; + } + + mousex = event.xmotion.x; + mousey = event.xmotion.y; + p->view.redo_projections = true; + } + break; + + default: + break; + } + } // end while +} // end Lpanel_procEvents() + +static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) +{ + UNUSED(d); + + if ((e->type == MapNotify) && (e->xmap.window == (Window) arg)) { + return GL_TRUE; + } + return GL_FALSE; +} + +#endif /* !__MINGW32__ && !_WIN32 && !_WIN32_ && !__WIN32__ */ + +#endif /* !WANT_SDL */ + +int Lpanel_openWindow(Lpanel_t *p, const char *title) +{ + float geom_aspect = (p->bbox.xyz_max[0] - p->bbox.xyz_min[0]) / + (p->bbox.xyz_max[1] - p->bbox.xyz_min[1]); + p->window_ysize = (int) ((float) p->window_xsize / geom_aspect); + p->view.aspect = (GLdouble) p->window_xsize / (GLdouble) p->window_ysize; + +#ifdef WANT_SDL + + if (IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG) == 0) { + fprintf(stderr, "Can't initialize SDL_image: %s\n", IMG_GetError()); + return 0; + } + + p->window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + p->window_xsize, p->window_ysize, + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + if (p->window == NULL) { + fprintf(stderr, "Can't create window: %s\n", SDL_GetError()); + return 0; + } + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); + if ((p->cx = SDL_GL_CreateContext(p->window)) == NULL) { + fprintf(stderr, "Can't create context: %s\n", SDL_GetError()); + return 0; + } + if (SDL_GL_MakeCurrent(p->window, p->cx) < 0) { + fprintf(stderr, "Can't make window current to context: %s\n", SDL_GetError()); + return 0; + } + /* First try adaptive vsync, than vsync */ + if (SDL_GL_SetSwapInterval(-1) < 0) + SDL_GL_SetSwapInterval(1); + + Lpanel_resizeWindow(p); + Lpanel_initGraphics(p); + +#else /* !WANT_SDL */ + +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + + BOOL err; + + p->hInstance = GetModuleHandle(NULL); + + p->wc.cbSize = sizeof(WNDCLASSEX); + p->wc.style = 0; + p->wc.lpfnWndProc = StaticWndProc; + p->wc.cbClsExtra = 0; + p->wc.cbWndExtra = 0; + p->wc.hInstance = p->hInstance; + p->wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + p->wc.hCursor = LoadCursor(NULL, IDC_HAND); + // p->wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE); + p->wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); + p->wc.lpszMenuName = NULL; + p->wc.lpszClassName = FPClassName; + p->wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + if (!RegisterClassEx(&p->wc)) { + MessageBox(NULL, "Window registration failed!", "Error!", + MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + p->hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, FPClassName, title, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, p->window_xsize, p->window_ysize, + NULL, NULL, p->hInstance, NULL); + if (p->hWnd == NULL) { + MessageBox(NULL, "Window creation failed!", "Error!", + MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + // We put in the window user data area a pointer to the windowproc for its instance + SetWindowLongPtr(p->hWnd, GWLP_USERDATA, (LONG_PTR) p); + + p->hDC = GetDC(p->hWnd); + + memset(&p->pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + p->pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + p->pfd.nVersion = 1; + p->pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + p->pfd.iPixelType = PFD_TYPE_RGBA; + p->pfd.cColorBits = 24; + p->pfd.cDepthBits = 32; + p->pfd.iLayerType = PFD_MAIN_PLANE; + + int pixelFormat = ChoosePixelFormat(p->hDC, &p->pfd); + if (pixelFormat == 0) { + return 0; + } + + err = SetPixelFormat(p->hDC, pixelFormat, &p->pfd); + if (!err) { + return 0; + } + + p->hRC = wglCreateContext(p->hDC); + if (!p->hRC) { + MessageBox(NULL, "lightpanel: Can't create window context", "Error!", + MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + err = wglMakeCurrent(p->hDC, p->hRC); + if (!err) { + MessageBox(NULL, "lightpanel: Can't make window current to context", "Error!", + MB_ICONEXCLAMATION | MB_OK); + // ReleaseDC(p->hWnd, p->hDC); + return 0; + } + + ShowWindow(p->hWnd, SW_SHOWNORMAL); + + SetForegroundWindow(p->hWnd); + SetFocus(p->hWnd); + Lpanel_initGraphics(p); + UpdateWindow(p->hWnd); + +#else /* !__MINGW32__ && !_WIN32 && !_WIN32_ && !__WIN32__ */ + + int status; + XSetWindowAttributes swa; + XSizeHints hints; + XEvent ev; + + p->dpy = XOpenDisplay(0); + if (p->dpy == NULL) { + fprintf(stderr, "Can't connect to display \"%s\"\n", getenv("DISPLAY")); + return 0; + } + + p->vi = glXChooseVisual(p->dpy, DefaultScreen(p->dpy), RGBA_DB_attributes); + if (p->vi == NULL) { + fprintf(stderr, "Can't find visual\n"); + return 0; + } + + glXGetConfig(p->dpy, p->vi, GLX_USE_GL, &status); + if (!status) { + printf("Your system must support OpenGL to run FrontPanel\n"); + return 0; + } + + swa.border_pixel = 0; + swa.colormap = XCreateColormap(p->dpy, RootWindow(p->dpy, p->vi->screen), + p->vi->visual, AllocNone); + swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | PointerMotionMask; + + p->window = XCreateWindow(p->dpy, RootWindow(p->dpy, p->vi->screen), 500, 500, + p->window_xsize, p->window_ysize, + 0, p->vi->depth, InputOutput, p->vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &swa); + + p->wmDeleteMessage = XInternAtom(p->dpy, "WM_DELETE_WINDOW", False); + XSetWMProtocols(p->dpy, p->window, &p->wmDeleteMessage, 1); + + XStoreName(p->dpy, p->window, title); + + hints.width = 500; + hints.height = 125; + hints.min_aspect.x = p->window_xsize; + hints.min_aspect.y = p->window_ysize; + hints.max_aspect.x = p->window_xsize; + hints.max_aspect.y = p->window_ysize; + hints.flags = PSize | PAspect; + XSetNormalHints(p->dpy, p->window, &hints); + + XMapWindow(p->dpy, p->window); + XIfEvent(p->dpy, &ev, WaitForMapNotify, (char *) p->window); + + if ((p->cx = glXCreateContext(p->dpy, p->vi, 0, GL_TRUE)) == NULL) { + printf("lightpanel: Can't create context\n"); + return 0; + } + if (!glXMakeCurrent(p->dpy, p->window, p->cx)) { + printf("lightpanel: Can't make window current to context\n"); + return 0; + } + + Lpanel_resizeWindow(p); + Lpanel_initGraphics(p); + +#endif /* !__MINGW32__ && !_WIN32 && !_WIN32_ && !__WIN32__ */ + +#endif /* !WANT_SDL */ + + p->cursor[0] = (p->bbox.xyz_max[0] + p->bbox.xyz_min[0]) * .5; + p->cursor[1] = (p->bbox.xyz_max[1] + p->bbox.xyz_min[1]) * .5; + makeRasterFont(); + Lpanel_make_cursor_text(p); + + return 1; +} + +void Lpanel_destroyWindow(Lpanel_t *p) +{ + glFlush(); + glFinish(); + +#ifdef WANT_SDL + if (SDL_GL_MakeCurrent(NULL, NULL) < 0) { + printf("lightpanel: destroyWindow: Can't release context\n"); + } + SDL_GL_DeleteContext(p->cx); + SDL_DestroyWindow(p->window); + IMG_Quit(); + p->cx = NULL; + p->window = NULL; +#else /* !WANT_SDL */ +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + wglMakeCurrent(NULL, NULL); + ReleaseDC(p->hWnd, p->hDC); +#else + if (!glXMakeCurrent(p->dpy, None, None)) { + printf("lightpanel: destroyWindow: Can't release context\n"); + } + + glXDestroyContext(p->dpy, p->cx); + XDestroyWindow(p->dpy, p->window); + XFree(p->vi); + XCloseDisplay(p->dpy); + p->dpy = NULL; + p->cx = NULL; + p->vi = NULL; + p->window = 0; +#endif +#endif /* !WANT_SDL */ +} + +void Lpanel_setModelview(Lpanel_t *p, bool dopick) +{ + float x, y; + + if (!dopick) + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + switch (p->view.projection) { + case LP_ORTHO: + glTranslatef(0., 0., -10.); // so objects at z=0 don't get clipped + break; + + case LP_PERSPECTIVE: + x = -((p->bbox.xyz_min[0] + p->bbox.xyz_max[0]) * 0.5 - p->view.pan[0]); + y = -((p->bbox.xyz_min[1] + p->bbox.xyz_max[1]) * 0.5 - p->view.pan[1]); + + glTranslatef(x, y, p->view.pan[2]); + + glTranslatef(p->bbox.center[0], p->bbox.center[1], p->bbox.center[2]); + glRotatef(p->view.rot[2], 0., 0., 1.); + glRotatef(p->view.rot[0], 1., 0., 0.); + glRotatef(p->view.rot[1], 0., 1., 0.); + glTranslatef(-p->bbox.center[0], -p->bbox.center[1], -p->bbox.center[2]); + break; + } +} + +void Lpanel_setProjection(Lpanel_t *p, bool dopick) +{ + switch (p->view.projection) { + case LP_ORTHO: + if (!dopick) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + } + + glOrtho(p->bbox.xyz_min[0], p->bbox.xyz_max[0], + p->bbox.xyz_min[1], p->bbox.xyz_max[1], + .1, 1000.); + + if (!dopick) + glMatrixMode(GL_MODELVIEW); + break; + + case LP_PERSPECTIVE: + if (!dopick) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + } + + // gluPerspective(p->view.fovy, p->view.aspect, p->view.znear, p->view.zfar); + double deltaz = p->view.zfar - p->view.znear; + double cotangent = 1 / tan(p->view.fovy / 2 * M_PI / 180); + GLdouble m[16] = { + cotangent / p->view.aspect, 0, 0, 0, + 0, cotangent, 0, 0, + 0, 0, -(p->view.zfar + p->view.znear) / deltaz, -1, + 0, 0, -2 * p->view.znear *p->view.zfar / deltaz, 0 + }; + glMultMatrixd(m); + + if (!dopick) + glMatrixMode(GL_MODELVIEW); + break; + } +} + +#if !defined(__MINGW32__) && !defined(_WIN32) && !defined(_WIN32_) && !defined(__WIN32__) +void Lpanel_resizeWindow(Lpanel_t *p) +{ +#ifdef WANT_SDL + int width, height; + + SDL_GL_MakeCurrent(p->window, p->cx); + SDL_GL_GetDrawableSize(p->window, &width, &height); + p->window_xsize = width; + p->window_ysize = height; +#else /* !WANT_SDL */ + XWindowAttributes windowattr; + + XGetWindowAttributes(p->dpy, p->window, &windowattr); + p->window_xsize = windowattr.width; + p->window_ysize = windowattr.height; +#endif /* !WANT_SDL */ + + p->view.aspect = (double) p->window_xsize / (double) p->window_ysize; + glViewport(0, 0, p->window_xsize, p->window_ysize); + glGetIntegerv(GL_VIEWPORT, p->viewport); + + Lpanel_setProjection(p, false); + + Lpanel_setModelview(p, false); +} +#endif /* !__MINGW32__ && !_WIN32 && !_WIN32_ && !__WIN32__ */ + +void Lpanel_doPickProjection(Lpanel_t *p) +{ + // glOrtho(p->bbox.xyz_min[0], p->bbox.xyz_max[0], + // p->bbox.xyz_min[1], p->bbox.xyz_max[1], + // .1, 1000.); + Lpanel_setProjection(p, 1); +} + +void Lpanel_doPickModelview(Lpanel_t *p) +{ + Lpanel_setModelview(p, 1); + // glTranslatef(0., 0., -10.); // so objects at z=0 don't get clipped +} + +void Lpanel_initGraphics(Lpanel_t *p) +{ + // initialize materials + + lp_init_materials_dlist(); + + // define lights in case we use them + + glLoadIdentity(); + glLightfv(GL_LIGHT0, GL_POSITION, light_pos0); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_specular); + + // glLightfv(GL_LIGHT1, GL_POSITION, light_pos1); + // glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); + // glLightfv(GL_LIGHT1, GL_DIFFUSE, light_specular); + + glEnable(GL_LIGHT0); + if (p->view.do_depthtest) + glEnable(GL_DEPTH_TEST); + glPolygonOffset(0., -10.); + // glEnable(GL_LIGHT1); + + glDisable(GL_LIGHTING); + // glEnable(GL_LIGHTING); + glClearColor(0., 0., 0., 1.); + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mtl_amb); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mtl_dif); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mtl_spec); + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mtl_shine); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mtl_emission); + + glEnable(GL_NORMALIZE); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +#ifdef WANT_SDL + SDL_GL_SwapWindow(p->window); +#else +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + SwapBuffers(p->hDC); + // UpdateWindow(p->hWnd); + // Sleep(100); +#else + glXSwapBuffers(p->dpy, p->window); +#endif +#endif + + // download any textures that may have been read in + + lpTextures_downloadTextures(&p->textures); + + if (p->envmap_detected) { + glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + } + + p->cursor[0] = (p->bbox.xyz_max[0] + p->bbox.xyz_min[0]) * .5; + p->cursor[1] = (p->bbox.xyz_max[1] + p->bbox.xyz_min[1]) * .5; + makeRasterFont(); + Lpanel_make_cursor_text(p); +} + +void Lpanel_draw_stats(Lpanel_t *p) +{ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0., p->window_xsize, 0., p->window_ysize, .1, 1000.); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(0., 0., -10.); + glDisable(GL_DEPTH_TEST); + + glColor3f(1., 1., 0.); + snprintf(p->perf_txt, sizeof(p->perf_txt), "fps:%d sps:%d", + p->frames_per_second, p->samples_per_second); + printStringAt(p->perf_txt, p->bbox.xyz_min[0] + .2, p->bbox.xyz_min[1] + .2); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glEnable(GL_DEPTH_TEST); +} + +void Lpanel_draw_cursor(Lpanel_t *p) +{ + float size = 0.1; + + glColor3f(1., 1., 0.); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + glVertex3f(p->cursor[0] - size, p->cursor[1] - size, p->cursor[2]); + glVertex3f(p->cursor[0] + size, p->cursor[1] + size, p->cursor[2]); + + glVertex3f(p->cursor[0] - size, p->cursor[1] + size, p->cursor[2]); + glVertex3f(p->cursor[0] + size, p->cursor[1] - size, p->cursor[2]); + + glEnd(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0., p->window_xsize, 0., p->window_ysize, .1, 1000.); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(0., 0., -10.); + + printStringAt(p->cursor_txt, p->cursor_textpos[0], p->cursor_textpos[1]); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glEnable(GL_DEPTH_TEST); +} + +void Lpanel_inc_cursor(Lpanel_t *p, float x, float y) +{ + if (p->shift_key_pressed) { + x *= 10.; + y *= 10.; + } + p->cursor[0] += x; + p->cursor[1] += y; + Lpanel_make_cursor_text(p); +} + +void Lpanel_make_cursor_text(Lpanel_t *p) +{ + p->cursor_textpos[0] = (p->bbox.xyz_max[0] + p->bbox.xyz_min[0]) * .5; + p->cursor_textpos[1] = p->bbox.xyz_min[1] + .1; + snprintf(p->cursor_txt, sizeof(p->cursor_txt), "cursor position=%7.3f,%7.3f", + p->cursor[0], p->cursor[1]); +} diff --git a/frontpanel/lp_window.cpp b/frontpanel/lp_window.cpp deleted file mode 100644 index 8beedcc9..00000000 --- a/frontpanel/lp_window.cpp +++ /dev/null @@ -1,1049 +0,0 @@ -// lp_window.cpp lightpanel window functions - - -/* Copyright (c) 2007-2008, John Kichury - - This software is freely distributable free of charge and without license fees with the - following conditions: - - 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 - JOHN KICHURY 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. - - The above copyright notice must be included in any copies of this software. - -*/ - -#include -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -#include -#include -#include -#else -#include -#include -#include -#include -#endif -#include -#include -#include - -#include "lpanel.h" -#include "lp_materials.h" -#include "lp_font.h" - -#define UNUSED(x) (void) (x) - - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -const char FPClassName[] = "FrontPanel 2.1"; - -#else -static int RGBA_DB_attributes[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 1, - None, -}; -#endif - -// OpenGL Light source - -static GLfloat light_pos0[] = { 0.,0.5,1.,0.}; -// static GLfloat light_pos1[] = { 0.,-0.5,-1.,0.}; -static GLfloat light_diffuse[] = { 1.,1.,1.,1.}; -static GLfloat light_specular[] = { 1.,1.,1.,1.}; - -static GLfloat mtl_amb[] = { 0.2, 0.2, 0.2, 1.0 }; -static GLfloat mtl_dif[] = { 1.0, 1.0, 1.0, 1.0 }; -static GLfloat mtl_spec[] = { 0.0, 0.0, 0.0, 1.0 }; -static GLfloat mtl_shine[] = { 0.0 }; -static GLfloat mtl_emission[] = { 0.0, 0.0, 0.0, 1.0 }; - -static int mousex, mousey, omx, omy, lmouse; // mmouse, rmouse; - - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - - -static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - - if (LONG_PTR user_data = GetWindowLongPtr(hWnd, GWLP_USERDATA)) { - Lpanel * this_window = reinterpret_cast(user_data); - return this_window->WndProc(hWnd, Msg, wParam, lParam); - } - return DefWindowProc(hWnd, Msg, wParam, lParam); -} - - -// -LRESULT CALLBACK -Lpanel::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - unsigned int kcode; - - switch(msg) - { - - case WM_KEYUP: - if (LOWORD (wParam) == VK_SHIFT) { - shift_key_pressed=0; - return 0; - } - return 0; - break; - - - case WM_KEYDOWN: - kcode=LOWORD (wParam); - switch(kcode) - { - case VK_SHIFT: - shift_key_pressed=1; - return 0; - break; - - case VK_UP: - if(do_cursor) - inc_cursor(0.,cursor_inc ); - else - { - if(shift_key_pressed) - view.pan[1] += -0.1; - else - view.rot[0] += -1.; - - view.redo_projections = 1; - } - break; - case VK_DOWN: - if(do_cursor) - inc_cursor(0.,-cursor_inc ); - else - { - if(shift_key_pressed) - view.pan[1] += 0.1; - else - view.rot[0] += 1.; - - view.redo_projections = 1; - } - break; - case VK_RIGHT: - if(do_cursor) - inc_cursor(cursor_inc, 0.); - else - { - if(shift_key_pressed) - view.pan[0] += -.1; - else - view.rot[1] += 1.; - - view.redo_projections = 1; - } - break; - case VK_LEFT: - if(do_cursor) - inc_cursor(-cursor_inc, 0.); - else - { - if(shift_key_pressed) - view.pan[0] += .1; - else - view.rot[1] += -1.; - - view.redo_projections = 1; - } - break; - } - return 0; - break; - - - case WM_CHAR: - kcode=LOWORD (wParam); - - switch (kcode) - { - case VK_ESCAPE: - //exit(EXIT_SUCCESS); - break; - case 'c': - case 'C': - do_cursor = !do_cursor; - break; - case 'd': - case 'D': - view.pan[1] -= 0.1; - view.redo_projections = 1; - break; - case 's': - case 'S': - do_stats = !do_stats ; - break; - - case 'l': - case 'L': - view.rot[1] += -1.; - view.redo_projections = 1; - break; - - case 'r': - case 'R': - view.rot[1] -= -1.; - view.redo_projections = 1; - break; - - case 'u': - case 'U': - view.pan[1] += 0.1; - view.redo_projections = 1; - break; - - case 'v': - case 'V': - if( view.projection == LP_ORTHO) - view.projection = LP_PERSPECTIVE; - else - view.projection = LP_ORTHO; - - view.redo_projections = 1; - break; - - case 'z': - view.pan[2] -= .1; - view.redo_projections = 1; - break; - - case 'Z': - view.pan[2] += .1; - view.redo_projections = 1; - break; - //// - case '1': - break; - } - return 0; - break; - - - case WM_MOUSEWHEEL: - view.pan[2] += (float)GET_WHEEL_DELTA_WPARAM(wParam)/250.0; - view.redo_projections = 1; - return 0; - break; - - - case WM_LBUTTONDOWN: - if(!pick(0, 1, LOWORD (lParam), HIWORD (lParam))) - { - mousex = LOWORD (lParam); - mousey = HIWORD (lParam); - lmouse = 1; - } - return 0; - break; - - - case WM_LBUTTONUP: - if(!pick(0, 0, LOWORD (lParam), HIWORD (lParam))) - lmouse = 0; - return 0; - break; - - - case WM_MOUSEMOVE: - if(lmouse) - { - omx = mousex; - omy = mousey; - - if(shift_key_pressed) - { - view.pan[0] += ((float) LOWORD (lParam) - (float) omx) *.02; - view.pan[1] -= ((float) HIWORD (lParam) - (float) omy) *.02; - - } - else - { - view.rot[1] += ((float) LOWORD (lParam) - (float) omx) *.2; - view.rot[0] += ((float) HIWORD (lParam) - (float) omy) *.2; - } - - mousex = LOWORD (lParam); - mousey = HIWORD (lParam); - view.redo_projections = 1; - } - return 0; - break; - - - case WM_SIZE: - window_xsize = (GLsizei) LOWORD (lParam); - window_ysize = (GLsizei) HIWORD (lParam); - view.aspect = (GLdouble)window_xsize/(GLdouble)window_ysize; - - glViewport( 0, 0, window_xsize, window_ysize ); - glGetIntegerv (GL_VIEWPORT, viewport); - setProjection(0); - setModelview(0); - - return 0; - break; - - case WM_QUIT: - case WM_CLOSE: - if (hRC) { - wglMakeCurrent(NULL,NULL); - wglDeleteContext( hRC ); - } - if (hDC) { - ReleaseDC(hWnd,hDC); - } - DestroyWindow(hWnd); - return 0; - break; - - case WM_DESTROY: - UnregisterClass(FPClassName,hInstance); - PostQuitMessage( 0 ); - if(quit_callbackfunc) - (*quit_callbackfunc)(); - else - exit(EXIT_SUCCESS); - return 0; - break; - - default: - return DefWindowProc( hWnd, msg, wParam, lParam ); - } -} - - -#else -static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) -{ - UNUSED(d); - - if ((e->type == MapNotify) && (e->xmap.window == (Window)arg)) { - return GL_TRUE; - } - return GL_FALSE; -} -#endif - -void -Lpanel::procEvents(void) -{ - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - -MSG msg; - - if ( PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE) ) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - -#else - - XEvent event; - char buffer[5]; - int bufsize = 5; - KeySym key; - XComposeStatus compose; - - - while(XPending(dpy)) - { - XNextEvent(dpy, &event); - - switch(event.type) - { - case ConfigureNotify: - - resizeWindow(); - break; - case ClientMessage: - if((Atom)event.xclient.data.l[0] == wmDeleteMessage) - { - // call user quit callback if exists - if(quit_callbackfunc) - { (*quit_callbackfunc)(); - } - else - { XCloseDisplay(dpy); - exit(EXIT_SUCCESS); - } - } - break; - case UnmapNotify: - - break; - case DestroyNotify: - - - break; - - case ButtonPress: - - if(!pick(event.xbutton.button-1, 1, event.xbutton.x, event.xbutton.y)) - { - if(event.xbutton.button == 1) // left mousebutton ? - { lmouse = 1; - mousex = event.xbutton.x; - mousey = event.xbutton.y; - } - } - - break; - - case ButtonRelease: - - if(!pick(event.xbutton.button-1, 0, event.xbutton.x, event.xbutton.y)) - { - if(event.xbutton.button == 1) lmouse = 0; - } - break; - - case KeyRelease: - - XLookupString(&event.xkey, buffer, bufsize, &key, &compose); - switch (key) - { - case XK_Shift_L: - case XK_Shift_R: - shift_key_pressed = 0; - break; - - } - break; - - case KeyPress: - - XLookupString(&event.xkey, buffer, bufsize, &key, &compose); - - switch (key) - { - case XK_Escape: - //exit(EXIT_SUCCESS); - break; - case XK_Shift_L: - case XK_Shift_R: - shift_key_pressed = 1; - break; - case XK_c: - case XK_C: - do_cursor = !do_cursor; - break; - case XK_d: - case XK_D: - view.pan[1] -= 0.1; - view.redo_projections = 1; - break; - case XK_s: - case XK_S: - do_stats = !do_stats ; - break; - - case XK_l: - case XK_L: - view.rot[1] += -1.; - view.redo_projections = 1; - break; - - case XK_r: - case XK_R: - view.rot[1] -= -1.; - view.redo_projections = 1; - break; - - case XK_u: - case XK_U: - view.pan[1] += 0.1; - view.redo_projections = 1; - break; - - case XK_v: - case XK_V: - if( view.projection == LP_ORTHO) - view.projection = LP_PERSPECTIVE; - else - view.projection = LP_ORTHO; - - view.redo_projections = 1; - break; - - case XK_z: - view.pan[2] -= .1; - view.redo_projections = 1; - break; - - case XK_Z: - view.pan[2] += .1; - view.redo_projections = 1; - break; - - case XK_Up: - if(do_cursor) - inc_cursor(0.,cursor_inc ); - else - { - if(shift_key_pressed) - view.pan[1] += -0.1; - else - view.rot[0] += -1.; - - view.redo_projections = 1; - } - break; - case XK_Down: - if(do_cursor) - inc_cursor(0.,-cursor_inc ); - else - { - if(shift_key_pressed) - view.pan[1] += 0.1; - else - view.rot[0] += 1.; - - view.redo_projections = 1; - } - break; - case XK_Right: - if(do_cursor) - inc_cursor(cursor_inc, 0.); - else - { - if(shift_key_pressed) - view.pan[0] += -.1; - else - view.rot[1] += 1.; - - view.redo_projections = 1; - } - break; - case XK_Left: - if(do_cursor) - inc_cursor(-cursor_inc, 0.); - else - { - if(shift_key_pressed) - view.pan[0] += .1; - else - view.rot[1] += -1.; - - view.redo_projections = 1; - } - break; - - case XK_1: - case XK_KP_1: - break; - - default: - break; - } - /* fallthrough */ - - case MotionNotify: - - if(lmouse) - { - omx = mousex; - omy = mousey; - - if(shift_key_pressed) - { - view.pan[0] += ((float) event.xbutton.x - (float) omx) *.02; - view.pan[1] -= ((float) event.xbutton.y - (float) omy) *.02; - - } - else - { - view.rot[1] += ((float) event.xbutton.x - (float) omx) *.2; - view.rot[0] += ((float) event.xbutton.y - (float) omy) *.2; - } - - mousex = event.xbutton.x; - mousey = event.xbutton.y; - view.redo_projections = 1; - } - break; - default: - break; - } - - } // end while -#endif -} // end procEvents() - -int -Lpanel::openWindow(const char *title) -{ - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - - BOOL err; - - float geom_aspect = (bbox.xyz_max[0] - bbox.xyz_min[0]) / (bbox.xyz_max[1] - bbox.xyz_min[1]); - window_ysize = (int) ( (float) window_xsize / geom_aspect); - view.aspect = (GLdouble)window_xsize/(GLdouble)window_ysize; - - hInstance = GetModuleHandle( NULL ); - - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = 0; - wc.lpfnWndProc = StaticWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_HAND); - //wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); - wc.lpszMenuName = NULL; - wc.lpszClassName = FPClassName; - wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - if(!RegisterClassEx(&wc)) - { - MessageBox(NULL, "Window registration failed!", "Error!", - MB_ICONEXCLAMATION | MB_OK); - return 0; - } - - hWnd = CreateWindowEx( - WS_EX_CLIENTEDGE, - FPClassName, - title, - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, window_xsize, window_ysize, - NULL, NULL, hInstance, NULL); - - if(hWnd == NULL) - { - MessageBox(NULL, "Window creation failed!", "Error!", - MB_ICONEXCLAMATION | MB_OK); - return 0; - } - - // We put in the window user data area a ponter to the windowproc for its instance - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)reinterpret_cast(this)); - - hDC = GetDC (hWnd); - - memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cDepthBits = 32; - pfd.iLayerType = PFD_MAIN_PLANE; - - int pixelFormat = ChoosePixelFormat(hDC, &pfd); - if (pixelFormat == 0) { - return 0; - } - - err = SetPixelFormat (hDC, pixelFormat, &pfd); - if (!err) { - return 0; - } - - hRC = wglCreateContext(hDC); - if (!hRC) { - MessageBox(NULL, "lightpanel: Can't create window context", "Error!", - MB_ICONEXCLAMATION | MB_OK); - return 0; - } - - err = wglMakeCurrent(hDC, hRC); - if (!err) { - MessageBox(NULL, "lightpanel: Can't make window current to context", "Error!", - MB_ICONEXCLAMATION | MB_OK); - //ReleaseDC (hWnd, hDC); - return 0; - } - - ShowWindow(hWnd, SW_SHOWNORMAL ); - - SetForegroundWindow(hWnd); - SetFocus(hWnd); - initGraphics(); - UpdateWindow(hWnd); - - cursor[0] = (bbox.xyz_max[0] + bbox.xyz_min[0]) * .5; - cursor[1] = (bbox.xyz_max[1] + bbox.xyz_min[1]) * .5; - makeRasterFont(); - make_cursor_text(); - -// -#else - - int status; - - XSetWindowAttributes swa; - XSizeHints hints; - XEvent ev; - - int *attr; - - dpy = XOpenDisplay(0); - if (dpy == NULL) - { - fprintf(stderr, "Can't connect to display \"%s\"\n", getenv("DISPLAY")); - return 0; - } - - attr = RGBA_DB_attributes; - vi = glXChooseVisual(dpy, DefaultScreen(dpy), attr); - if (vi == NULL) - { - fprintf(stderr, "Can't find visual\n"); - return 0; - } - - - glXGetConfig(dpy, vi, GLX_USE_GL, &status); - if (!status) - { - printf("Your system must support OpenGL to run FrontPanel\n"); - return 0; - } - - swa.border_pixel = 0; - swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), - vi->visual, AllocNone); - swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask | PointerMotionMask ; - - float geom_aspect = (bbox.xyz_max[0] - bbox.xyz_min[0]) / (bbox.xyz_max[1] - bbox.xyz_min[1]); - window_ysize = (int) ( (float) window_xsize / geom_aspect); - - window = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 500, 500, window_xsize, window_ysize, - 0, vi->depth, InputOutput, vi->visual, - CWBorderPixel | CWColormap | CWEventMask, &swa); - - wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dpy, window, &wmDeleteMessage, 1); - - XStoreName(dpy, window, title); - - hints.width = 500; - hints.height = 125; - hints.min_aspect.x = window_xsize; - hints.min_aspect.y = window_ysize; - hints.max_aspect.x = window_xsize; - hints.max_aspect.y = window_ysize; - hints.flags = PSize | PAspect; - XSetNormalHints(dpy, window, &hints); - - XMapWindow(dpy, window); - XIfEvent(dpy, &ev, WaitForMapNotify, (char *)window); - - if ((cx = glXCreateContext(dpy, vi, 0, GL_TRUE)) == NULL) { - printf("lightpanel: Can't create context\n"); - return 0; - } - if (!glXMakeCurrent(dpy, window, cx)) { - printf("lightpanel: Can't make window current to context\n"); - return 0; - } - - resizeWindow(); - initGraphics(); - - cursor[0] = (bbox.xyz_max[0] + bbox.xyz_min[0]) * .5; - cursor[1] = (bbox.xyz_max[1] + bbox.xyz_min[1]) * .5; - makeRasterFont(); - make_cursor_text(); - -#endif - return 1; -} - -void -Lpanel::destroyWindow(void) -{ - - glFlush(); - glFinish(); - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -// - wglMakeCurrent(NULL,NULL); - ReleaseDC (hWnd, hDC); - -#else - - if (!glXMakeCurrent(dpy, None, None)) { - printf("lightpanel: destroyWindow: Can't release context\n"); - } - - glXDestroyContext(dpy,cx); - XDestroyWindow(dpy, window); - XFree(vi); - XCloseDisplay(dpy); - dpy = 0; - cx = 0; - vi = NULL; - window = 0; - -#endif - - -} - -void -Lpanel::setModelview(int dopick) -{ - float x,y; - - if(!dopick) - { - glMatrixMode(GL_MODELVIEW); - } - glLoadIdentity(); - - switch(view.projection) - { - case LP_ORTHO: - glTranslatef(0.,0.,-10.); // so objects at z=0 don't get clipped - break; - - case LP_PERSPECTIVE: - x = -(( bbox.xyz_min[0] + bbox.xyz_max[0]) * 0.5 - view.pan[0]); - y = -(( bbox.xyz_min[1] + bbox.xyz_max[1]) * 0.5 - view.pan[1]); - - glTranslatef(x,y,view.pan[2]); - - glTranslatef(bbox.center[0], bbox.center[1], bbox.center[2]); - glRotatef(view.rot[2],0.,0.,1.); - glRotatef(view.rot[0],1.,0.,0.); - glRotatef(view.rot[1],0.,1.,0.); - glTranslatef(-bbox.center[0], -bbox.center[1], -bbox.center[2]); - - break; - } - -} - -void -Lpanel::setProjection(int dopick) -{ - - switch(view.projection) - { - case LP_ORTHO: - - if(!dopick) - { glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - } - - glOrtho(bbox.xyz_min[0], bbox.xyz_max[0], bbox.xyz_min[1], bbox.xyz_max[1], .1, 1000.); - if(!dopick) glMatrixMode(GL_MODELVIEW); - break; - - case LP_PERSPECTIVE: - - if(!dopick) - { glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - } - - gluPerspective(view.fovy, view.aspect, view.znear, view.zfar); - if(!dopick) glMatrixMode(GL_MODELVIEW); - - - break; - - } - -} - - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -// -#else -void -Lpanel::resizeWindow(void) -{ - XWindowAttributes windowattr; - - XGetWindowAttributes(dpy, window, &windowattr); - - window_xsize = windowattr.width; - window_ysize = windowattr.height; - view.aspect = (double) window_xsize / (double) window_ysize; - glViewport(0, 0, windowattr.width, windowattr.height); - glGetIntegerv (GL_VIEWPORT, viewport); - - setProjection(0); - - setModelview(0); - -} -#endif - -void -Lpanel::doPickProjection(void) -{ -// glOrtho(bbox.xyz_min[0], bbox.xyz_max[0], bbox.xyz_min[1], bbox.xyz_max[1], .1, 1000.); - setProjection(1); - -} - -void -Lpanel::doPickModelview(void) -{ - setModelview(1); - //glTranslatef(0.,0.,-10.); // so objects at z=0 don't get clipped -} - -void -Lpanel::initGraphics(void) -{ - // initialize materials - - lp_init_materials_dlist(); - - // define lights in case we use them - - glLoadIdentity(); - glLightfv(GL_LIGHT0,GL_POSITION,light_pos0); - glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); - glLightfv(GL_LIGHT0,GL_DIFFUSE,light_specular); - -// glLightfv(GL_LIGHT1,GL_POSITION,light_pos1); -// glLightfv(GL_LIGHT1,GL_DIFFUSE,light_diffuse); - //glLightfv(GL_LIGHT1,GL_DIFFUSE,light_specular); - - glEnable(GL_LIGHT0); - if(view.do_depthtest) glEnable(GL_DEPTH_TEST); - glPolygonOffset(0.,-10.); - //glEnable(GL_LIGHT1); - - glDisable(GL_LIGHTING); - //glEnable(GL_LIGHTING); - glClearColor(0.,0.,0.,1.); - - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mtl_amb); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mtl_dif); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mtl_spec); - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mtl_shine); - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mtl_emission); - - - glEnable(GL_NORMALIZE); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -// -//UpdateWindow(hWnd); -//Sleep(100); - SwapBuffers(hDC); -#else - glXSwapBuffers(dpy, window); -#endif - - // download any textures that may have been read in - - textures.downloadTextures(); - - if(envmap_detected) - { - glTexGenf(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); - glTexGenf(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); - } - -} - -void -Lpanel::draw_stats(void) -{ - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.,window_xsize, 0., window_ysize, .1, 1000.); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glTranslatef(0.,0.,-10.); - glDisable(GL_DEPTH_TEST); - - glColor3f(1.,1.,0.); - snprintf(perf_txt,sizeof(perf_txt),"fps:%d sps:%d",frames_per_second, samples_per_second); - printStringAt(perf_txt, bbox.xyz_min[0] + .2, bbox.xyz_min[1] + .2); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glEnable(GL_DEPTH_TEST); -} - -void -Lpanel::draw_cursor(void) -{ float size = 0.1; - glColor3f(1.,1.,0.); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glBegin(GL_LINES); - glVertex3f( cursor[0] - size , cursor[1] - size, cursor[2]); - glVertex3f( cursor[0] + size , cursor[1] + size, cursor[2]); - - glVertex3f( cursor[0] - size , cursor[1] + size, cursor[2]); - glVertex3f( cursor[0] + size , cursor[1] - size, cursor[2]); - - glEnd(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.,window_xsize, 0., window_ysize, .1, 1000.); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glTranslatef(0.,0.,-10.); - - printStringAt(cursor_txt, cursor_textpos[0], cursor_textpos[1]); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - glEnable(GL_DEPTH_TEST); -} - - -void -Lpanel::inc_cursor(float x, float y) -{ - if(shift_key_pressed) - { x *= 10.; - y *= 10.; - } - cursor[0] += x; - cursor[1] += y; - make_cursor_text(); -} - -void -Lpanel::make_cursor_text(void) -{ - cursor_textpos[0] = (bbox.xyz_max[0] + bbox.xyz_min[0]) * .5; - cursor_textpos[1] = bbox.xyz_min[1] + .1; - snprintf(cursor_txt,sizeof(cursor_txt),"cursor position=%7.3f,%7.3f", cursor[0], cursor[1]); -} - diff --git a/frontpanel/lpanel.c b/frontpanel/lpanel.c new file mode 100644 index 00000000..55b59a92 --- /dev/null +++ b/frontpanel/lpanel.c @@ -0,0 +1,2067 @@ +// lpanel.c lightpanel class + +/* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt + + This software is freely distributable free of charge and without license fees with the + following conditions: + + 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 + JOHN KICHURY 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. + + The above copyright notice must be included in any copies of this software. + +*/ + +#define DEBUG 0 + +#include +#include +#include +#include +#include +#ifdef WANT_SDL +#include +#include +#else /* !WANT_SDL */ +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) +#include +#include +#else +#include +#include +#endif +#endif /* !WANT_SDL */ + +#include "lp_utils.h" +#include "lp_materials.h" +#include "lpanel.h" + +#include "lpanel_data.h" + +#define UNUSED(x) (void) (x) + +static parser_rules_t light_parse_rules[] = { + { "color", 3, 3, PARSER_FLOAT }, + { "group", 1, 1, PARSER_INT }, + { "object", 1, 1, PARSER_STRING }, + { "pos", 2, 3, PARSER_FLOAT }, + { "size", 2, 3, PARSER_FLOAT }, + { NULL, 0, 0, 0 } +}; + +extern Parser_t parser; + +static void drawLightObject(lpLight_t *p) +{ + lpObject_draw_refoverride(p->obj_ref, 2); +} + +static void drawLightGraphics(lpLight_t *p) +{ + int i; + int lod = 1; + + for (i = 0; i < 3; i++) { + if (p->color[i] < 0. || p->color[i] > 1.) + printf("drawLight: color out of range color[%d] = %f\n", i, p->color[i]); + } + + // glColor3f(0., 0., 0.); + glBegin(GL_POLYGON); + + for (i = 0; i < cir2d_nverts - 1; i += lod) + glVertex2fv(&cir2d_data2[i][0]); + + glEnd(); + + glBegin(GL_TRIANGLE_STRIP); + + for (i = 0; i < cir2d_nverts - 1; i += lod) { + glColor3fv(&p->color[0]); + glVertex2fv(&cir2d_data2[i][0]); + glColor3f(0., 0., 0.); + glVertex2fv(&cir2d_data[i][0]); + } + + glColor3fv(&p->color[0]); + glVertex2fv(&cir2d_data2[0][0]); + glColor3f(0., 0., 0.); + glVertex2fv(&cir2d_data[0][0]); + glEnd(); +} + +static void sampleData8_error(lpLight_t *p) +{ + UNUSED(p); + +#if 0 + static bool flag = false; + + if (!flag) { + printf("sampleData8: light %s has no data bound to it.\n", p->name); + flag = true; + } +#endif +} + +static void sampleData8(lpLight_t *p) +{ + unsigned char bit; + uint8_t *ptr = (uint8_t *) p->dataptr; + + bit = (int) (*ptr >> p->bitnum) & 0x01; + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + +static void sampleData8invert(lpLight_t *p) +{ + unsigned char bit; + uint8_t *ptr = (uint8_t *) p->dataptr; + + bit = (int) ~(*ptr >> p->bitnum) & 0x01; + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + +static void sampleData16(lpLight_t *p) +{ + unsigned char bit; + uint16_t *ptr = (uint16_t *) p->dataptr; +#if 0 + uint64_t on_time_inc = 0; +#endif + bit = (int) (*ptr >> p->bitnum) & 0x01; + +#if 0 + if (bit) { +#if 0 + p->on_time += (*p->simclock - p->old_clock); +#endif + on_time_inc = (*p->simclock - p->old_clock); + } + + if (bit != p->state) { + on_time_inc = on_time_inc >> 1; + } + p->on_time += on_time_inc; +#endif + + // if (p->old_clock > *p->simclock) + // printf("sampleData16: clock stepped backward\n"); + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + +static void sampleDatafv(lpLight_t *p) +{ + float *ptr = (float *) p->dataptr; + + if (p->smoothing > 0) { + p->intense_curr = p->intensity; + p->intense_samples[p->intense_curr_idx] = ptr[p->bitnum]; + + if (p->intense_samples[p->intense_curr_idx] > 1.0) + p->intense_samples[p->intense_curr_idx] = 1.0; + else if (p->intense_samples[p->intense_curr_idx] < 0.0) + p->intense_samples[p->intense_curr_idx] = 0.0; + + p->intense_incr = (p->intense_samples[p->intense_curr_idx] - + p->intense_samples[!p->intense_curr_idx]) / + (float) p->smoothing; + } else + p->intensity = ptr[p->bitnum]; +} + +static void sampleData16invert(lpLight_t *p) +{ + unsigned char bit; + uint16_t *ptr = (uint16_t *) p->dataptr; + + bit = (int) ~(*ptr >> p->bitnum) & 0x01; + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + +static void sampleData32(lpLight_t *p) +{ + unsigned char bit; + uint32_t *ptr = (uint32_t *) p->dataptr; + + bit = (int) (*ptr >> p->bitnum) & 0x01; + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + +static void sampleData32invert(lpLight_t *p) +{ + unsigned char bit; + uint32_t *ptr = (uint32_t *) p->dataptr; + + bit = (int) ~(*ptr >> p->bitnum) & 0x01; + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + +static void sampleData64(lpLight_t *p) +{ + unsigned char bit; + uint64_t *ptr = (uint64_t *) p->dataptr; + + bit = (int) (*ptr >> p->bitnum) & 0x01; + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + +static void sampleData64invert(lpLight_t *p) +{ + unsigned char bit; + uint64_t *ptr = (uint64_t *) p->dataptr; + + bit = (int) ~(*ptr >> p->bitnum) & 0x01; + + if (bit) { + p->on_time += (*p->simclock - p->old_clock); + } + p->old_clock = *p->simclock; + p->dirty = true; + p->state = bit; +} + + +Lpanel_t *Lpanel_new(void) +{ + Lpanel_t *p = (Lpanel_t *) calloc(1, sizeof(Lpanel_t)); + + if (p) + Lpanel_init(p); + + return p; +} + +void Lpanel_delete(Lpanel_t *p) +{ + if (p) { + Lpanel_fini(p); + free(p); + } +} + +void Lpanel_init(Lpanel_t *p) // initializer +{ + int i; + +#ifdef WANT_SDL + p->window = NULL; + p->cx = NULL; +#else +#if !defined(__MINGW32__) && !defined(_WIN32) && !defined(_WIN32_) && !defined(__WIN32__) + p->window = 0; + p->vi = NULL; + p->cx = 0; + p->dpy = 0; +#endif +#endif + + p->num_lights = 0; + p->max_lights = 0; + p->lights = NULL; + + p->num_switches = p->max_switches = 0; + p->switches = NULL; + p->mom_switch_pressed = NULL; + + p->default_clock = 0; + p->old_clock = 0; + p->simclock = &p->default_clock; + p->clock_warp = 0; + + p->default_runflag = 0; + p->runflag = &p->default_runflag; + + // init light groups + + for (i = 0; i < LP_MAX_LIGHT_GROUPS; i++) { + p->light_groups[i].num_items = 0; + p->light_groups[i].max_items = 0; + p->light_groups[i].list = NULL; + } + + // init light graphics + + p->lightcolor[0] = 1.; + p->lightcolor[1] = 0.; + p->lightcolor[2] = 0.; + p->lightsize[0] = 0.1875; + p->lightsize[1] = 0.1875; + p->lightsize[2] = 0.1875; + + for (i = 0; i < cir2d_nverts; i++) { + cir2d_data2[i][0] = cir2d_data[i][0] * .4; + cir2d_data2[i][1] = cir2d_data[i][1] * .4; + } + + // init config root path + + p->config_root_path = NULL; + Lpanel_setConfigRootPath(p, "."); + + lpTextures_init(&p->textures); + + // init graphics objects + + p->envmap_detected = false; + p->num_objects = 0; + p->max_objects = 0; + p->objects = NULL; + + p->num_alpha_objects = 0; + p->max_alpha_objects = 0; + p->alpha_objects = NULL; + + p->curr_object = NULL; + p->curr_element = NULL; + p->curr_vertex = NULL; + + lpBBox_init(&p->bbox); + + // use this for small displays like notebooks etc. + p->window_xsize = 800; + p->window_ysize = 325; + + // use this for Desktops/Workstations with good graphics + // p->window_xsize = 1600; + // p->window_ysize = 650; + + p->cursor[0] = 0.; + p->cursor[1] = 0.; + p->cursor[2] = 0.0; + p->cursor_inc = .01; + p->do_cursor = false; + p->do_stats = false; + p->shift_key_pressed = false; + + // graphics view parms + + p->view.rot[0] = 0.; + p->view.rot[1] = 0.; + p->view.rot[2] = 0.; + + p->view.pan[0] = 0.; + p->view.pan[1] = -0.0; + p->view.pan[2] = -16.0; + + p->view.znear = 0.01; + p->view.zfar = 1000.0; + p->view.fovy = 25.0; + p->view.projection = LP_ORTHO; + p->view.redo_projections = true; + p->view.do_depthtest = false; // default to no zbuffer + + p->quit_callbackfunc = NULL; +} // end initializer + +void Lpanel_fini(Lpanel_t *p) // finalizer +{ + int i; + + for (i = 0; i < p->num_lights; i++) + if (p->lights[i]) + lpLight_delete(p->lights[i]); + p->num_lights = p->max_lights = 0; + + for (i = 0; i < p->num_objects; i++) + if (p->objects[i]) + lpObject_delete(p->objects[i]); + p->num_objects = p->max_objects = 0; + + for (i = 0; i < p->num_switches; i++) + if (p->switches[i]) + lpSwitch_delete(p->switches[i]); + p->num_switches = p->max_switches = 0; + + for (i = 0; i < LP_MAX_LIGHT_GROUPS; i++) { + if (p->light_groups[i].list) { + free(p->light_groups[i].list); + p->light_groups[i].list = NULL; + } + p->light_groups[i].num_items = 0; + p->light_groups[i].max_items = 0; + } + + lpTextures_fini(&p->textures); + lpBBox_fini(&p->bbox); +} // end finalizer + +int Lpanel_test(Lpanel_t *p, int n) +{ + UNUSED(p); + + printf("panel test %d\n", n); + + switch (n) { + case 0: + break; + case 1: + break; + default: + break; + } + + return 1; +} + +void Lpanel_addQuitCallback(Lpanel_t *p, lp_quit_cbf_t cbfunc) +{ + p->quit_callbackfunc = cbfunc; +} + +int Lpanel_addLight(Lpanel_t *p, const char *name, lp_obj_parm_t *obj, const char *buff) +{ + int i, n; + parser_result_t *result; + lpLight_t *light; + + if (p->num_lights + 1 > p->max_lights) + Lpanel_growLights(p); + + p->lights[p->num_lights] = light = lpLight_new(); + light->parms = obj; + lpLight_setName(light, name); + lpLight_bindSimclock(light, p->simclock, &p->clock_warp); + light->panel = p; + + Parser_setRules(&parser, light_parse_rules); + Parser_setParseString(&parser, buff); + + // parse config file line values such has position, color etc. + // if n >= 0 it contains the char position in the line where an error + // ocurred + + while ((n = Parser_parse(&parser, &result)) < 0) { + if (n != PARSER_DONE) { + + if (!strcmp(light_parse_rules[result->cmd_idx].cmd, "color")) { + for (i = 0; i < result->num_args; i++) + light->parms->color[i] = result->floats[i]; + } else if (!strcmp(light_parse_rules[result->cmd_idx].cmd, "group")) { + light->parms->group = result->ints[0]; + } else if (!strcmp(light_parse_rules[result->cmd_idx].cmd, "object")) { + light->obj_refname = + (char *) malloc(strlen(result->strings[0]) + 1); + strcpy(light->obj_refname, result->strings[0]); + } else if (!strcmp(light_parse_rules[result->cmd_idx].cmd, "pos")) { + for (i = 0; i < result->num_args; i++) + light->parms->pos[i] = result->floats[i]; + } else if (!strcmp(light_parse_rules[result->cmd_idx].cmd, "size")) { + for (i = 0; i < result->num_args; i++) + light->parms->scale[i] = result->floats[i]; + } + } // end if (n != PARSER_DONE) + + if (n == PARSER_DONE) + break; + } + + if (n >= 0) { + printf("n=%d\n", n); + Parser_printError(&parser); + return n; + } + + if (obj->group >= 0) { + Lpanel_addLightToGroup(p, p->num_lights, obj->group); + } + + p->num_lights++; + + return -1; +} + +int Lpanel_addLightToGroup(Lpanel_t *p, int lightnum, int groupnum) +{ + if (groupnum >= LP_MAX_LIGHT_GROUPS) { + fprintf(stderr, "error: light %s invalid group number (%d)\n", + p->lights[lightnum]->name, groupnum); + return 0; + } + + if (p->light_groups[groupnum].num_items + 1 > p->light_groups[groupnum].max_items) { + int *new_list; + + new_list = (int *) realloc(p->light_groups[groupnum].list, + sizeof(int) * + (p->light_groups[groupnum].max_items + 1)); + p->light_groups[groupnum].max_items += 1; + p->light_groups[groupnum].list = new_list; + } + p->light_groups[groupnum].list[p->light_groups[groupnum].num_items] = lightnum; + p->light_groups[groupnum].num_items++; + return 1; +} + +bool Lpanel_bindLight8(Lpanel_t *p, const char *name, void *loc, int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight8: light %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + lpLight_bindData8(light, (uint8_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight8: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +// bind light and invert logic according to mask + +bool Lpanel_bindLight8invert(Lpanel_t *p, const char *name, void *loc, int start_bit_number, + uint8_t mask) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight8invert: light %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + if (mask & (0x1 << (bitnum - 1))) + lpLight_bindData8invert(light, (uint8_t *) loc); + else + lpLight_bindData8(light, (uint8_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight8invert: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindLight16(Lpanel_t *p, const char *name, void *loc, int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight16: light %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + lpLight_bindData16(light, (uint16_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight16: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +// bindLightfv +// bind to an array of float values +// subsequent sampling will use the bit number as an index into the array of float values +// instead of a single bit + +bool Lpanel_bindLightfv(Lpanel_t *p, const char *name, void *loc) +{ + char **namelist; + int num_names; + int i; + bool status = true; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + for (i = 0; i < num_names; i++) { + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + lpLight_bindDatafv(light, (float *) loc); + lpLight_setBitNumber(light, i); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLightfv: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + } + free(namelist); + + return status; +} + +bool Lpanel_bindLight16invert(Lpanel_t *p, const char *name, void *loc, int start_bit_number, + uint16_t mask) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight16invert: light %s bad bitnum %d\n", + namelist[i], + bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + if (mask & (0x1 << (bitnum - 1))) + lpLight_bindData16invert(light, (uint16_t *) loc); + else + lpLight_bindData16(light, (uint16_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight16invert: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindLight32(Lpanel_t *p, const char *name, void *loc, int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight16: light %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + lpLight_bindData32(light, (uint32_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight32: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindLight32invert(Lpanel_t *p, const char *name, void *loc, int start_bit_number, + uint32_t mask) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight32invert: light %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + if (mask & (0x1 << (bitnum - 1))) + lpLight_bindData32invert(light, (uint32_t *) loc); + else + lpLight_bindData32(light, (uint32_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight32invert: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindLight64(Lpanel_t *p, const char *name, void *loc, int start_bit_number) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight64: light %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + lpLight_bindData64(light, (uint64_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight64: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +bool Lpanel_bindLight64invert(Lpanel_t *p, const char *name, void *loc, int start_bit_number, + uint64_t mask) +{ + char **namelist; + int num_names; + int i; + bool status = true; + int bitnum, bit_inc; + lpLight_t *light; + + num_names = xpand(name, &namelist); + + bitnum = abs(start_bit_number); + if (start_bit_number > 0) + bit_inc = 1; + else + bit_inc = -1; + + for (i = 0; i < num_names; i++) { + if (bitnum <= 0) { + fprintf(stderr, "bindLight64invert: light %s bad bitnum %d\n", + namelist[i], bitnum); + bitnum = 1; + } + + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + if (mask & (0x1 << (bitnum - 1))) + lpLight_bindData64invert(light, (uint64_t *) loc); + else + lpLight_bindData64(light, (uint64_t *) loc); + lpLight_setBitNumber(light, bitnum - 1); + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "bindLight64invert: light %s not found\n", + namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + bitnum += bit_inc; + } + free(namelist); + + return status; +} + +void Lpanel_bindRunFlag(Lpanel_t *p, uint8_t *addr) +{ + int i; + + p->runflag = (uint8_t *) addr; + + for (i = 0; i < p->num_lights; i++) + lpLight_bindRunFlag(p->lights[i], (uint8_t *) addr); +} + +void Lpanel_bindSimclock(Lpanel_t *p, uint64_t *addr) +{ + int i; + + p->simclock = (uint64_t *) addr; + + for (i = 0; i < p->num_lights; i++) + lpLight_bindSimclock(p->lights[i], (uint64_t *) addr, &p->clock_warp); + +} + +void Lpanel_draw(Lpanel_t *p) +{ + int i; + +#ifdef WANT_SDL + SDL_GL_MakeCurrent(p->window, p->cx); +#endif + + if (p->view.redo_projections) { + Lpanel_setProjection(p, 0); + Lpanel_setModelview(p, 0); + p->view.redo_projections = false; + } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // draw graphics objects + + // glEnable(GL_LIGHTING); + + for (i = 0; i < p->num_objects; i++) { + if (p->objects[i]->is_alpha) + continue; + + if (p->objects[i]->texture_num) { + lpTextures_bindTexture(&p->textures, p->objects[i]->texture_num); + } + if (p->objects[i]->have_normals) + glEnable(GL_LIGHTING); + lpObject_draw(p->objects[i]); + } + + // draw lights + + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0., -10.); + + for (i = 0; i < p->num_lights; i++) + lpLight_draw(p->lights[i]); + + // draw switches + + for (i = 0; i < p->num_switches; i++) + p->switches[i]->drawFunc(p->switches[i]); + + if (p->alpha_objects) { + // glDisable(GL_DEPTH_TEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + for (i = 0; i < p->num_alpha_objects; i++) { + if (p->alpha_objects[i]->texture_num) { + lpTextures_bindTexture(&p->textures, + p->alpha_objects[i]->texture_num); + } + if (p->alpha_objects[i]->have_normals) + glEnable(GL_LIGHTING); + lpObject_draw(p->alpha_objects[i]); + } + // glEnable(GL_DEPTH_TEST); + } + + glDisable(GL_TEXTURE_2D); + glDisable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + if (p->do_cursor) { + glEnable(GL_POLYGON_OFFSET_LINE); + Lpanel_draw_cursor(p); + glDisable(GL_POLYGON_OFFSET_LINE); + } + if (p->do_stats) + Lpanel_draw_stats(p); +#ifdef WANT_SDL + SDL_GL_SwapWindow(p->window); +#else +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + SwapBuffers(p->hDC); + // UpdateWindow(p->hWnd); +#else + glXSwapBuffers(p->dpy, p->window); +#endif +#endif +} + +void Lpanel_growLights(Lpanel_t *p) +{ + lpLight_t **new_lights; + + new_lights = (lpLight_t **) realloc(p->lights, + sizeof(lpLight_t *) * (p->num_lights + 8)); + p->max_lights += 8; + p->lights = new_lights; +} + +void Lpanel_growSwitches(Lpanel_t *p) +{ + lpSwitch_t **new_switches; + + new_switches = (lpSwitch_t **) realloc(p->switches, + sizeof(lpSwitch_t *) * (p->num_switches + 1)); + p->max_switches += 1; + p->switches = new_switches; +} + +int Lpanel_pick(Lpanel_t *p, int button, int state, int x, int y) +{ + GLuint namebuf[500], *ptr; + int i, + num_picked = 0, + switch_dir; + uint32_t switch_num; + + UNUSED(button); + + if (state == 0) { + if (p->mom_switch_pressed) + lpSwitch_action(p->mom_switch_pressed, 2); + return num_picked; + } + + namebuf[0] = 0; + glSelectBuffer(500, &namebuf[0]); + glRenderMode(GL_SELECT); + glInitNames(); + glPushName(0); + glGetIntegerv(GL_VIEWPORT, p->viewport); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + // gluPickMatrix ((GLdouble) x, (GLdouble) (window_ysize - y), 1.0, 1.0, viewport); + glTranslatef(p->viewport[2] - 2 * (x - p->viewport[0]), + p->viewport[3] - 2 * (p->window_ysize - y - p->viewport[1]), 0); + glScalef(p->viewport[2], p->viewport[3], 1.0); + + Lpanel_doPickProjection(p); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + Lpanel_doPickModelview(p); + + // draw switches + + for (i = 0; i < p->num_switches; i++) + lpSwitch_drawForPick(p->switches[i]); + + num_picked = glRenderMode(GL_RENDER); + + if (num_picked) { + uint32_t n; + + ptr = (GLuint *) namebuf; + n = ptr[3]; + + switch_num = n & LP_SW_PICK_IDMASK; // decode the switch number + switch_dir = ((n & LP_SW_PICK_UP_BIT) != 0); + // printf("pick: switch_num=%d dir=%d\n", switch_num, switch_dir); + + lpSwitch_action(p->switches[switch_num], switch_dir); + } + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glRenderMode(GL_RENDER); + + return num_picked; +} + +#define BUFSIZE 256 +#define TOKENSIZE 80 + +bool Lpanel_readConfig(Lpanel_t *p, const char *_fname) +{ + FILE *fd; + int i, n; + char buffer[BUFSIZE], token[TOKENSIZE]; + int pos, lineno = 0; + bool bailout = false; + lp_obj_parm_t *obj; + char *fname; + + fname = (char *) malloc(strlen(p->config_root_path) + 1 + strlen(_fname) + 1); + strcpy(fname, p->config_root_path); + strcat(fname, "/"); + strcat(fname, _fname); + + if ((fd = fopen(fname, "r")) == 0) { + fprintf(stderr, "readFile: could not open file %s\n", fname); + free(fname); + return 0; + } + + lp_init_materials(); + + while (!feof(fd) && !bailout) { + lineno++; + if (!freadlin(fd, buffer, BUFSIZE)) + continue; + pos = 0; + if (!gtoken(buffer, token, TOKENSIZE, &pos)) // blank line + continue; + if (token[0] == '#') // comment + continue; + + if (!strcmp(token, "color")) { // color + int n; + + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("color defined outside of an object\n"); + bailout = true; + } else { + n = sscanf(&buffer[pos], "%f %f %f", + &p->curr_object->color[0], + &p->curr_object->color[1], + &p->curr_object->color[2]); + + if (n < 3) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("color must have 3 (r g b) values in the " + "range of 0.0 - 1.0.\n"); + bailout = true; + } + } + } else if (!strcmp(token, "zbuffer")) { + p->view.do_depthtest = true; + } else if (!strcmp(token, "envmap")) { // environment mapped reflection + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("envmap defined outside of an object\n"); + bailout = true; + } else { + p->envmap_detected = true; + p->curr_object->envmapped = true; + } + } else if (!strcmp(token, "instance")) { + char s[100]; + + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("instance defined outside of an object\n"); + bailout = true; + } else { + if (!gtoken(buffer, s, 100, &pos)) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("instance with no object name.\n"); + bailout = true; + } else + lpObject_setInstanceName(p->curr_object, s); + } + } else if (!strcmp(token, "light")) { + obj = (lp_obj_parm_t *) malloc(sizeof(lp_obj_parm_t)); + obj->type = LP_LED; + obj->subtype = LP_LED_3D; + obj->group = -1; // does not belong to group + obj->pos[0] = 0.; + obj->pos[1] = 0.; + obj->pos[2] = 0.; + obj->color[0] = p->lightcolor[0]; + obj->color[1] = p->lightcolor[1]; + obj->color[2] = p->lightcolor[2]; + obj->scale[0] = p->lightsize[0]; + obj->scale[1] = p->lightsize[1]; + obj->scale[2] = p->lightsize[2]; + + gtoken(buffer, token, TOKENSIZE, &pos); // get name + + n = Lpanel_addLight(p, token, obj, &buffer[pos]); + if (n >= 0) { + bailout = true; + n += pos; + printf("Error on line %d of config file %s\n", lineno, fname); + + printf("%s\n", buffer); + for (i = 0; i < n; i++) + putchar(' '); + printf("^\n"); + } + } else if (!strcmp(token, "lightcolor")) { // default light size + int n; + + n = sscanf(&buffer[pos], "%f %f %f", + &p->lightcolor[0], + &p->lightcolor[1], + &p->lightcolor[2]); + + if (n < 3) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("lightcolor must have 3 (r g b) values in the " + "range of 0.0 - 1.0.\n"); + bailout = true; + } + } else if (!strcmp(token, "lightsize")) { // default light size + int n; + + n = sscanf(&buffer[pos], "%f %f %f", + &p->lightsize[0], + &p->lightsize[1], + &p->lightsize[2]); + + if (n < 1) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("lightsize must have 1, 2, or 3 values (x y z).\n"); + bailout = true; + } + + if (n == 1) + p->lightsize[1] = p->lightsize[2] = p->lightsize[0]; + else if (n == 2) + p->lightsize[2] = p->lightsize[0]; + } else if (!strcmp(token, "line")) { + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("line defined outside of an object\n"); + bailout = true; + } else { + if (!(p->curr_element = lpObject_addElement(p->curr_object, + p->curr_object))) { + printf("could not allocate memory for line.\n"); + bailout = true; + } else { + p->curr_element->type = LP_LINE; + lpElement_setTextureManager(p->curr_element, &p->textures); + } + } + } else if (!strcmp(token, "material")) { // material reference or definition + int n, matnum; + float Ar, Ag, Ab, Aa, // Ambient rgba + Dr, Dg, Db, Da, // Diffuse rgba + Sr, Sg, Sb, Sa, // Specular rgba + shine, // shinyness + Er, Eg, Eb, Ea; // emission rgba + + if (p->curr_object) { // material reference + n = sscanf(&buffer[pos], "%d", &p->curr_object->material); + + if (n != 1) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("material within an object definition must have " + "one integer value.\n"); + bailout = true; + } + p->curr_object->is_alpha = + lp_is_material_alpha(p->curr_object->material); + } else { // material definition + + n = sscanf(&buffer[pos], + "%d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", + &matnum, &Ar, &Ag, &Ab, &Aa, &Dr, &Dg, &Db, &Da, + &Sr, &Sg, &Sb, &Sa, &shine, &Er, &Eg, &Eb, &Ea); + + if (n < 18) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("material definition must have 18 values.\n"); + bailout = true; + } else + lp_set_material_params(matnum, Ar, Ag, Ab, Aa, + Dr, Dg, Db, Da, + Sr, Sg, Sb, Sa, + shine, Er, Eg, Eb, Ea); + } + } else if (!strcmp(token, "message")) { // message + printf("%s\n", &buffer[pos]); + } else if (!strcmp(token, "n")) { // vertex normal vector + int n; + + if (!p->curr_element || !p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("normal defined outside of a polygon or line\n"); + bailout = true; + } else { + if (!p->curr_vertex) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("normal defined before a vertex definition\n"); + bailout = true; + } + + n = sscanf(&buffer[pos], "%f %f %f", + &p->curr_vertex->norm[0], + &p->curr_vertex->norm[1], + &p->curr_vertex->norm[2]); + + if (n < 3) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("normal must have 3 values.\n"); + bailout = true; + } else + p->curr_object->have_normals = true; + } + } else if (!strcmp(token, "object")) { + p->curr_object = Lpanel_addObject(p); + lpObject_setTextureManager(p->curr_object, &p->textures); + if (gtoken(buffer, token, TOKENSIZE, &pos)) + lpObject_setName(p->curr_object, token); + p->curr_element = NULL; + p->curr_vertex = NULL; + } else if (!strcmp(token, "perspective")) { + p->view.projection = LP_PERSPECTIVE; + } else if (!strcmp(token, "polygon")) { + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("polygon defined outside of an object\n"); + bailout = true; + } else { + if (!(p->curr_element = lpObject_addElement(p->curr_object, + p->curr_object))) { + printf("could not allocate memory for polygon.\n"); + bailout = true; + } else { + p->curr_element->type = LP_POLYGON; + lpElement_setTextureManager(p->curr_element, &p->textures); + } + } + } else if (!strcmp(token, "referenced")) { // referenced + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("color defined outside of an object\n"); + bailout = true; + } else + p->curr_object->referenced = true; + } else if (!strcmp(token, "rotate")) { // rotate hpr + int n; + + if (!p->curr_object) { + n = sscanf(&buffer[pos], "%f %f", + &p->view.rot[0], + &p->view.rot[1]); + + if (n < 2) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("scene rotate must have 2 values.\n"); + bailout = true; + } + } else { + n = sscanf(&buffer[pos], "%f %f %f", + &p->curr_object->rotate[0], + &p->curr_object->rotate[1], + &p->curr_object->rotate[2]); + + if (n < 3) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("object rotate must have 3 values.\n"); + bailout = true; + } + } + } else if (!strcmp(token, "switch")) { + obj = (lp_obj_parm_t *) malloc(sizeof(lp_obj_parm_t)); + obj->group = -1; // does not belong to group + obj->pos[0] = 0.; + obj->pos[1] = 0.; + obj->pos[2] = 0.; + obj->color[0] = 1.; + obj->color[1] = 0.; + obj->color[2] = 0.; + obj->scale[0] = 0.1875; + obj->scale[1] = 0.1875; + obj->scale[2] = 0.1875; + + gtoken(buffer, token, TOKENSIZE, &pos); // get name + + n = Lpanel_addSwitch(p, token, obj, &buffer[pos]); + if (n >= 0) { + bailout = true; + n += pos; + printf("Error on line %d of config file %s\n", lineno, fname); + + printf("%s\n", buffer); + for (i = 0; i < n; i++) + putchar(' '); + printf("^\n"); + } + } else if (!strcmp(token, "t")) { // texture coordinate + int n; + + if (!p->curr_element || !p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("texture coord defined outside of a polygon or line\n"); + bailout = true; + break; + } else { + if (!p->curr_vertex) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("texture coord defined before a vertex coordinate " + "was defined.\n"); + bailout = true; + break; + } + + n = sscanf(&buffer[pos], "%f %f", + &p->curr_vertex->st[0], + &p->curr_vertex->st[1]); + + if (n < 2) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("texture coordinate must have 2 coordinates " + "(e.g. t ).\n"); + bailout = true; + break; + } + p->curr_element->have_tcoords = true; + } + } else if (!strcmp(token, "texture")) { // texture + char *texture_path = NULL; + int len; + + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("texture defined outside of an object.\n"); + bailout = true; + break; + } + + if (!gtoken(buffer, token, TOKENSIZE, &pos)) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("texture with no path to jpeg file defined.\n"); + bailout = true; + break; + } + + len = strlen(p->config_root_path) + strlen(token) + 1; + + texture_path = (char *) malloc(len + 1); + strcpy(texture_path, p->config_root_path); + strcat(texture_path, "/"); + strcat(texture_path, token); + texture_path[len] = 0; + + if (!(p->curr_object->texture_num = lpTextures_addTexture(&p->textures, + texture_path))) { + printf("Error on line %d of config file %s\n", + lineno, texture_path); + printf("could not load texture '%s'.\n", texture_path); + bailout = true; + break; + } + + free(texture_path); + } else if (!strcmp(token, "texture_scale")) { + int n; + + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("texture_scale defined outside of an object\n"); + bailout = true; + } else { + n = sscanf(&buffer[pos], "%f %f", + &p->curr_object->texture_scale[0], + &p->curr_object->texture_scale[1]); + + if (n < 2) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("texture_scale must have 2 (x y) values.\n"); + bailout = true; + } + } + } else if (!strcmp(token, "texture_translate")) { + int n; + + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("texture_translate defined outside of an object\n"); + bailout = true; + } else { + n = sscanf(&buffer[pos], "%f %f", + &p->curr_object->texture_translate[0], + &p->curr_object->texture_translate[1]); + + if (n < 2) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("texture_translate must have 2 (x y) values.\n"); + bailout = true; + } + } + } else if (!strcmp(token, "translate")) { + int n; + + if (!p->curr_object) { + n = sscanf(&buffer[pos], "%f %f %f", + &p->view.pan[0], + &p->view.pan[1], + &p->view.pan[2]); + + if (n < 3) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("scene translate must have 3 values.\n"); + bailout = true; + } + } + } else if (!strcmp(token, "tristrip")) { + if (!p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("tristrip defined outside of an object\n"); + bailout = true; + } else { + if (!(p->curr_element = lpObject_addElement(p->curr_object, + p->curr_object))) { + printf("could not allocate memory for tristrip.\n"); + bailout = true; + } else { + p->curr_element->type = LP_TRISTRIP; + lpElement_setTextureManager(p->curr_element, &p->textures); + } + } + } else if (!strcmp(token, "v")) { // vertex + int n; + + if (!p->curr_element || !p->curr_object) { + printf("Error on line %d of config file %s\n", lineno, fname); + printf("vertex defined outside of a polygon or line\n"); + bailout = true; + } else { + if (!(p->curr_vertex = lpElement_addVertex(p->curr_element))) { + printf("could not allocate memory for vertex.\n"); + bailout = true; + } + + n = sscanf(&buffer[pos], "%f %f %f", + &p->curr_vertex->xyz[0], + &p->curr_vertex->xyz[1], + &p->curr_vertex->xyz[2]); + + if (n < 2) { + printf("Error on line %d of config file %s\n", + lineno, fname); + printf("vertex must have 2 or 3 coordinates.\n"); + bailout = true; + } + } + } else { + printf("Error: unknown statement on line %d of config file %s\n", + lineno, fname); + bailout = true; + + } + } // end while(!feof) + + free(fname); + fclose(fd); + + if (!bailout) { + Lpanel_genGraphicsData(p); + Lpanel_resolveObjectInstances(p); + + for (i = 0; i < p->num_lights; i++) + lpLight_setupData(p->lights[i]); + + for (i = 0; i < p->num_switches; i++) + lpSwitch_setupData(p->switches[i], i); + } + return !bailout; +} // end Lpanel_readConfig() + +lpLight_t *Lpanel_findLightByName(Lpanel_t *p, char *name) +{ + int i; + + for (i = 0; i < p->num_lights; i++) { + if (!strcmp(p->lights[i]->name, name)) + return p->lights[i]; + } + + return NULL; +} + +void Lpanel_printLights(Lpanel_t *p) +{ + int i; + + printf("lights:\n"); + for (i = 0; i < p->num_lights; i++) + lpLight_print(p->lights[i]); +} + +void Lpanel_resolveObjectInstances(Lpanel_t *p) +{ + int i, j; + lpObject_t *obj; + + for (i = 0; i < p->num_objects; i++) { + if (p->objects[i]->instance_name) { + if ((obj = Lpanel_findObjectByName(p, p->objects[i]->instance_name))) + p->objects[i]->instance_object = obj; + else + fprintf(stderr, "Error: object %s instances object %s which " + "cannot be found.\n", + p->objects[i]->name, p->objects[i]->instance_name); + } + } + + for (i = 0; i < p->num_objects; i++) { + obj = p->objects[i]->instance_object; + while (obj) { + for (j = 0; j < 3; j++) { + p->objects[i]->bbox.xyz_min[j] = + min(p->objects[i]->bbox.xyz_min[j], obj->bbox.xyz_min[j]); + p->objects[i]->bbox.xyz_max[j] = + max(p->objects[i]->bbox.xyz_max[j], obj->bbox.xyz_max[j]); + } + obj = obj->instance_object; + } + } +} + +void Lpanel_sampleData(Lpanel_t *p) +{ + int i; + + if (*p->simclock < p->old_clock) { + fprintf(stderr, "libfrontpanel: Warning clock went backwards (current=%" PRIu64 + " previous=%" PRIu64 ".\n", *p->simclock, p->old_clock); + + } + p->old_clock = *p->simclock; + + for (i = 0; i < p->num_lights; i++) + lpLight_sampleData(p->lights[i]); +} + +void Lpanel_sampleDataWarp(Lpanel_t *p, int clockwarp) +{ + int i; + + p->clock_warp = clockwarp; + + for (i = 0; i < p->num_lights; i++) + lpLight_sampleData(p->lights[i]); + + p->clock_warp = 0; +} + +void Lpanel_sampleLightGroup(Lpanel_t *p, int groupnum, int clockval) +{ + int i; + + if (groupnum < 0 || groupnum >= LP_MAX_LIGHT_GROUPS) { + fprintf(stderr, "sampleLightGroup: groupnum (%d) must be in the " + "range of (0-%d).\n", groupnum, LP_MAX_LIGHT_GROUPS - 1); + } + + p->clock_warp = clockval; + + for (i = 0; i < p->light_groups[groupnum].num_items; i++) + lpLight_sampleData(p->lights[p->light_groups[groupnum].list[i]]); + + p->clock_warp = 0; +} + +void Lpanel_setConfigRootPath(Lpanel_t *p, const char *path) +{ + if (p->config_root_path) + free(p->config_root_path); + p->config_root_path = (char *) malloc(strlen(path) + 1); + strcpy(p->config_root_path, path); +} + +void Lpanel_framerate_set(Lpanel_t *p, float n) +{ + p->framerate = n; + p->frametime = 1. / n; +}; + +void Lpanel_ignoreBindErrors(Lpanel_t *p, bool f) +{ + p->ignore_bind_errors = f; +}; + + +// ------------- +// lpLight class +// ------------- + +lpLight_t *lpLight_new(void) +{ + lpLight_t *p = (lpLight_t *) calloc(1, sizeof(lpLight_t)); + + if (p) + lpLight_init(p); + + return p; +} + +void lpLight_delete(lpLight_t *p) +{ + if (p) { + lpLight_fini(p); + free(p); + } +} + +void lpLight_init(lpLight_t *p) +{ + p->bindtype = LBINDTYPE_BIT; // default to bind to bit + p->parms = NULL; + p->name = NULL; + p->obj_refname = NULL; + p->obj_ref = NULL; + p->sampleDataFunc = sampleData8_error; + p->drawFunc = drawLightGraphics; + p->t1 = p->t2 = p->on_time = 1; + p->start_clock = 0; + p->old_clock = 0; + p->dirty = false; + p->state = 0; + p->old_state = 0; + p->intensity = 1.; + + p->smoothing = 0; // no intensity smoothing for bindtype of FLOATV + p->intense_curr_idx = 0; + p->intense_samples[0] = 0.; + p->intense_samples[1] = 0.; + p->color[0] = 0.2; + p->color[1] = 0.; + p->color[2] = 0.; + p->default_runflag = 0; + p->runflag = &p->default_runflag; +} + +void lpLight_fini(lpLight_t *p) +{ + if (p->name) + free(p->name); + if (p->obj_refname) + free(p->obj_refname); + if (p->parms) + free(p->parms); +} + +void lpLight_bindRunFlag(lpLight_t *p, uint8_t *addr) +{ + p->runflag = (uint8_t *) addr; +} + +void lpLight_bindSimclock(lpLight_t *p, uint64_t *addr, int *clockwarp) +{ + p->simclock = addr; + p->clock_warp = clockwarp; +} + +void lpLight_draw(lpLight_t *p) +{ + int i; + // float *fp; + + switch (p->bindtype) { + + case LBINDTYPE_BIT: + if (*p->runflag) { + if (p->dirty) + lpLight_calcIntensity(p); + } else { + for (i = 0; i < 3; i++) { + p->color[i] = p->parms->color[i] * (float) p->state + + (p->parms->color[i] * .2); + p->color[i] = min(p->color[i], 1.0); + } + } + break; + + case LBINDTYPE_FLOATV: + // fp = (float *) p->dataptr; + // p->intensity = fp[p->bitnum]; + // if (p->intensity > 1.0) + // p->intensity = 1.0; + + if (p->smoothing) { + p->intense_curr += p->intense_incr; + if (p->intense_curr > 1.0) + p->intense_curr = 1.0; + else if (p->intense_curr < 0.0) + p->intense_curr = 0.0; + p->intensity = p->intense_curr; + } + + for (i = 0; i < 3; i++) { + p->color[i] = p->parms->color[i] * p->intensity + + (p->parms->color[i] * .2); + p->color[i] = min(p->color[i], 1.0); + } + // printf("xyzzy: intense=%f bitnum=%d\n", p->intensity, p->bitnum); + break; + } + +#if DEBUG +#if 0 + if (!strcmp(p->name, "LED_ADDR_00") || + !strcmp(p->name, "LED_ADDR_01") || + !strcmp(p->name, "LED_ADDR_10")) +#endif + if (!strcmp(p->name, "LED_ADDR_15")) { + fprintf(stderr, "draw: %s %f\n", p->name, p->intensity); + } +#endif + + glPushMatrix(); + glTranslatef(p->parms->pos[0], p->parms->pos[1], p->parms->pos[2]); + glScalef(p->parms->scale[0], p->parms->scale[1], p->parms->scale[2]); + + glColor3fv(&p->color[0]); + + (*p->drawFunc)(p); + + glPopMatrix(); +} + +void lpLight_print(lpLight_t *p) +{ + printf("light: name=%s\n", p->name); + + printf("obj: pos=%f %f %f size=%f %f %f color=%f %f %f\n", + p->parms->pos[0], + p->parms->pos[1], + p->parms->pos[2], + p->parms->scale[0], + p->parms->scale[1], + p->parms->scale[2], + p->parms->color[0], + p->parms->color[1], + p->parms->color[2]); +} + +void lpLight_bindData8(lpLight_t *p, uint8_t *ptr) +{ + p->sampleDataFunc = sampleData8; + p->dataptr = (uint8_t *) ptr; +} + +void lpLight_bindData8invert(lpLight_t *p, uint8_t *ptr) +{ + p->sampleDataFunc = sampleData8invert; + p->dataptr = (uint8_t *) ptr; +} + +void lpLight_bindData16(lpLight_t *p, uint16_t *ptr) +{ + // xyzzy + p->sampleDataFunc = sampleData16; + p->dataptr = (uint16_t *) ptr; +} + +void lpLight_bindDatafv(lpLight_t *p, float *ptr) +{ + p->sampleDataFunc = sampleDatafv; + p->dataptr = (float *) ptr; + p->bindtype = LBINDTYPE_FLOATV; +} + +void lpLight_bindData16invert(lpLight_t *p, uint16_t *ptr) +{ + p->sampleDataFunc = sampleData16invert; + p->dataptr = (uint16_t *) ptr; +} + +void lpLight_bindData32(lpLight_t *p, uint32_t *ptr) +{ + p->sampleDataFunc = sampleData32; + p->dataptr = (uint32_t *) ptr; +} + +void lpLight_bindData32invert(lpLight_t *p, uint32_t *ptr) +{ + p->sampleDataFunc = sampleData32invert; + p->dataptr = (uint32_t *) ptr; +} + +void lpLight_bindData64(lpLight_t *p, uint64_t *ptr) +{ + p->sampleDataFunc = sampleData64; + p->dataptr = (uint64_t *) ptr; +} + +void lpLight_bindData64invert(lpLight_t *p, uint64_t *ptr) +{ + p->sampleDataFunc = sampleData64invert; + p->dataptr = (uint64_t *) ptr; +} + +void lpLight_calcIntensity(lpLight_t *p) +{ + int i; + // unsigned int dt; + uint64_t clock_delta; + + clock_delta = p->old_clock - p->start_clock; + if (clock_delta == 0) { + // p->intensity = 0.; + return; + } else + p->intensity = (float) ((double) p->on_time / (double) clock_delta * 2.0); + if (p->intensity > 1.0) + p->intensity = 1.0; + +#if 0 + // printf("calcIntensity runflag = %d\n", *p->runflag); + if (*p->runflag) + // if (!strcmp(p->name, "LED_ADDR_15") && p->intensity > .2) + if (!strcmp(p->name, "LED_ADDR_15")) { + fprintf(stderr, "dbg: draw: %s intense=%f on_time=%d old_clock=%d " + "start_clock=%d old-start=%d\n", + p->name, p->intensity, p->on_time, p->old_clock, + p->start_clock, p->old_clock - p->start_clock); + } +#endif + + p->start_clock = *p->simclock; + p->on_time = 0; + p->dirty = false; + + for (i = 0; i < 3; i++) { + p->color[i] = p->parms->color[i] * p->intensity + p->parms->color[i] * .2; + // p->color[i] = min(p->color[i], 1.0); + if (p->color[i] > 1.0) + p->color[i] = 1.0; + } +} + +void lpLight_sampleData(lpLight_t *p) +{ + (*p->sampleDataFunc)(p); +} + +void lpLight_setupData(lpLight_t *p) +{ + if (p->obj_refname) { + if (!(p->obj_ref = Lpanel_findObjectByName(p->panel, p->obj_refname))) { + fprintf(stderr, "error: light %s references object %s which " + "cannot be found.\n", p->name, p->obj_refname); + return; + } + + p->drawFunc = drawLightObject; + } +} + +void lpLight_setName(lpLight_t *p, const char *name) +{ + int n; + + n = strlen(name); + p->name = (char *) malloc(n + 1); + strcpy(p->name, name); +} + +void lpLight_setBitNumber(lpLight_t *p, int bitnum) +{ + p->bitnum = bitnum; +}; + +bool Lpanel_smoothLight(Lpanel_t *p, const char *name, int nframes) +{ + char **namelist; + int num_names; + int i; + bool status = true; + lpLight_t *light; + + if (nframes < 0) { + fprintf(stderr, "smoothLight: light %s error. nframes = %d must be >=0 \n", + name, nframes); + return false; + } + + num_names = xpand(name, &namelist); + + for (i = 0; i < num_names; i++) { + light = Lpanel_findLightByName(p, namelist[i]); + + if (light) { + light->smoothing = nframes; + } else { + if (!p->ignore_bind_errors) + fprintf(stderr, "smoothLight: light %s not found\n", namelist[i]); + status = false; + } + if (namelist[i]) + free(namelist[i]); + } + free(namelist); + + return status; +} diff --git a/frontpanel/lpanel.cpp b/frontpanel/lpanel.cpp deleted file mode 100644 index 0eebf6b9..00000000 --- a/frontpanel/lpanel.cpp +++ /dev/null @@ -1,2188 +0,0 @@ -// lpanel.cpp lightpanel class - -#define DEBUG 0 - -/* Copyright (c) 2007-2008, John Kichury - - This software is freely distributable free of charge and without license fees with the - following conditions: - - 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 - JOHN KICHURY 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. - - The above copyright notice must be included in any copies of this software. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lp_utils.h" -#include "lp_materials.h" -#include "lpanel.h" - -#include "lpanel_data.h" - -#define UNUSED(x) (void) (x) - -extern pthread_mutex_t data_sample_lock; - -static parser_rules_t light_parse_rules[] = -{ - { "color", 3, 3, PARSER_FLOAT }, - { "group", 1, 1, PARSER_INT }, - { "object", 1, 1, PARSER_STRING }, - { "pos", 2, 3, PARSER_FLOAT }, - { "size", 2, 3, PARSER_FLOAT }, - { NULL,0,0,0 } -}; - -extern Parser parser; - - -void drawLightObject(lpLight *lp) -{ - lp->obj_ref->draw(2); -} - -void drawLightGraphics(lpLight *lp) -{ - int i; - int lod=1; - -for(i=0;i<3;i++) - { - if( lp->color[i] < 0. || - lp->color[i] > 1. ) - printf("drawLight: color out of range color[%d] = %f\n", i, lp->color[i]); - } - - //glColor3f(0.,0.,0.); - glBegin(GL_POLYGON); - - for(i=0;icolor[0]); - glVertex2fv(&cir2d_data2[i][0]); - glColor3f(0.,0.,0.); - glVertex2fv(&cir2d_data[i][0]); - } - - glColor3fv(&lp->color[0]); - glVertex2fv(&cir2d_data2[0][0]); - glColor3f(0.,0.,0.); - glVertex2fv(&cir2d_data[0][0]); - glEnd(); - -} - -void -sampleData8_error(lpLight *p) -{ - UNUSED(p); - -#if 0 -static int flag = 0; - if(!flag) - { - printf("sampleData8: light %s has no data bound to it. \n", p->name); - flag = 1; - } -#endif -} - -void -sampleData8(lpLight *p) -{ - unsigned char bit; - uint8_t *ptr = (uint8_t *) p->dataptr; - - bit = (int) (*ptr >> p->bitnum) & 0x01; - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - - -void -sampleData8invert(lpLight *p) -{ - unsigned char bit; - uint8_t *ptr = (uint8_t *) p->dataptr; - - bit = (int) ~(*ptr >> p->bitnum) & 0x01; - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - -void -sampleData16(lpLight *p) -{ - unsigned char bit; - uint16_t *ptr = (uint16_t *) p->dataptr; -#if 0 - uint64_t on_time_inc = 0; -#endif - // int logit = 0; - - bit = (int) (*ptr >> p->bitnum) & 0x01; - -#if 0 - if(bit) - { -#if 0 - p->on_time += ( *p->simclock - p->old_clock ); -#endif - on_time_inc = ( *p->simclock - p->old_clock ); - } - - if( bit != p->state) - { - on_time_inc = on_time_inc >> 1; - } - p->on_time += on_time_inc; -#endif - - //if(p->old_clock > *p->simclock) printf("sampleData16: clock stepped backward\n"); - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - -void -sampleDatafv(lpLight *p) -{ - float *ptr = (float *) p->dataptr; - // int logit = 0; - - if(p->smoothing > 0) - { - p->intense_curr = p->intensity; - p->intense_samples[p->intense_curr_idx] = ptr[p->bitnum]; - - if(p->intense_samples[p->intense_curr_idx] > 1.0) p->intense_samples[p->intense_curr_idx] = 1.0; - else if(p->intense_samples[p->intense_curr_idx] < 0.0) p->intense_samples[p->intense_curr_idx] = 0.0; - - p->intense_incr = ( p->intense_samples[p->intense_curr_idx] - - p->intense_samples[!p->intense_curr_idx]) / (float) p->smoothing; - - } - else - p->intensity = ptr[p->bitnum]; - -} - - - -void -sampleData16invert(lpLight *p) -{ - unsigned char bit; - uint16_t *ptr = (uint16_t *) p->dataptr; - - bit = (int) ~(*ptr >> p->bitnum) & 0x01; - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - -void -sampleData32(lpLight *p) -{ - unsigned char bit; - uint32_t *ptr = (uint32_t *) p->dataptr; - - bit = (int) (*ptr >> p->bitnum) & 0x01; - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - - -void -sampleData32invert(lpLight *p) -{ - unsigned char bit; - uint32_t *ptr = (uint32_t *) p->dataptr; - - bit = (int) ~(*ptr >> p->bitnum) & 0x01; - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - -void -sampleData64(lpLight *p) -{ - unsigned char bit; - uint64_t *ptr = (uint64_t *) p->dataptr; - - bit = (int) (*ptr >> p->bitnum) & 0x01; - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - -void -sampleData64invert(lpLight *p) -{ - unsigned char bit; - uint64_t *ptr = (uint64_t *) p->dataptr; - - bit = (int) ~(*ptr >> p->bitnum) & 0x01; - - if(bit) - { - p->on_time += ( *p->simclock - p->old_clock ); - } - p->old_clock = *p->simclock; - p->dirty = 1; - p->state = bit; - -} - - -Lpanel::Lpanel(void) // constructor -{ - int i; - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -#else - window = 0; - vi = NULL; - cx = 0; - dpy = 0; -#endif - - num_lights = 0; - max_lights = 0; - lights = NULL; - - num_switches = max_switches = 0; - switches = NULL; - mom_switch_pressed = NULL; - - default_clock = 0; - old_clock = 0; - simclock = &default_clock; - clock_warp = 0; - - default_runflag = 0; - runflag = &default_runflag; - - // init light groups - - for(i=0;i max_lights) growLights(); - - lights[num_lights] = new lpLight; - light = lights[num_lights]; - lights[num_lights]->parms = obj; - lights[num_lights]->setName(name); - lights[num_lights]->bindSimclock(simclock, &clock_warp); - lights[num_lights]->panel = this; - - parser.setRules(light_parse_rules); - parser.setParseString(buff); - - // parse config file line values such has position, color etc. - // if n >= 0 it contains the char position in the line where an error - // ocurred - - while( (n = parser.parse(&result)) < 0 ) - { - if(n != PARSER_DONE) - { - - if(!strcmp(light_parse_rules[result->cmd_idx].cmd, "color")) - { - for(i=0;inum_args;i++) - light->parms->color[i] = result->floats[i]; - } - else if(!strcmp(light_parse_rules[result->cmd_idx].cmd, "group")) - { - light->parms->group = result->ints[0]; - } - else if(!strcmp(light_parse_rules[result->cmd_idx].cmd, "object")) - { - light->obj_refname = new char[strlen(result->strings[0])+1]; - strcpy(light->obj_refname, result->strings[0]); - } - else if(!strcmp(light_parse_rules[result->cmd_idx].cmd, "pos")) - { - for(i=0;inum_args;i++) - light->parms->pos[i] = result->floats[i]; - } - else if(!strcmp(light_parse_rules[result->cmd_idx].cmd, "size")) - { - for(i=0;inum_args;i++) - light->parms->scale[i] = result->floats[i]; - } - } // end if(n != PARSER_DONE) - - if( n == PARSER_DONE) break; - } - - if( n >= 0) - { printf("n=%d\n",n); - parser.printError(); - return n; - } - - - if(obj->group >=0) - { - addLightToGroup(num_lights, obj->group); - } - - num_lights++; - - return -1; - -} - -int -Lpanel::addLightToGroup( int lightnum, int groupnum) -{ - - if(groupnum >= LP_MAX_LIGHT_GROUPS) - { - fprintf(stderr, "error: light %s invalid group number (%d)\n", lights[lightnum]->name, groupnum); - return 0; - } - - if( light_groups[groupnum].num_items + 1 > light_groups[groupnum].max_items) - { - int *new_list, - i; - - new_list = new int[light_groups[groupnum].max_items + 1]; - - if(light_groups[groupnum].list) - { for(i=0; i < light_groups[groupnum].max_items;i++) - new_list[i] = light_groups[groupnum].list[i]; - delete[] light_groups[groupnum].list; - } - light_groups[groupnum].list = new_list; - } - light_groups[groupnum].max_items += 1; - light_groups[groupnum].list[light_groups[groupnum].num_items] = lightnum; - light_groups[groupnum].num_items++; - return 1; -} - -int -Lpanel::bindLight8(const char *name, void *loc, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData8( (uint8_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight8: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -// bind light and invert logic according to mask - -int -Lpanel::bindLight8invert(const char *name, void *loc, int start_bit_number, uint8_t mask) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; // bit_inv; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData8invert( (uint8_t *) loc); - else - light->bindData8( (uint8_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight8invert: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -int -Lpanel::bindLight16(const char *name, void *loc, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData16( (uint16_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight16: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - - -// bindLightfv -// bind to an array of float values -// subsequent sampling will use the bit number as an index into the array of float values -// instead of a single bit - -int -Lpanel::bindLightfv(const char *name, void *loc) -{ - char **namelist; - int num_names; - int i, status = 1; - // int bitnum, bit_inc; - lpLight *light; - - num_names = xpand(name, &namelist); - - for(i=0;ibindDatafv( (float *) loc); - light->setBitNumber(i); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLightfv: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - // bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -int -Lpanel::bindLight16invert(const char *name, void *loc, int start_bit_number, uint16_t mask) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; // bit_inv; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData16invert( (uint16_t *) loc); - else - light->bindData16( (uint16_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight16invert: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - - - -int -Lpanel::bindLight32(const char *name, void *loc, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData32( (uint32_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight32: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -int -Lpanel::bindLight32invert(const char *name, void *loc, int start_bit_number, uint32_t mask) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; // bit_inv; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData32invert( (uint32_t *) loc); - else - light->bindData32( (uint32_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight32invert: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - - -int -Lpanel::bindLight64(const char *name, void *loc, int start_bit_number) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData64( (uint64_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight64: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -int -Lpanel::bindLight64invert(const char *name, void *loc, int start_bit_number, uint64_t mask) -{ - char **namelist; - int num_names; - int i, status = 1; - int bitnum, bit_inc; // bit_inv; - lpLight *light; - - num_names = xpand(name, &namelist); - - bitnum = abs(start_bit_number); - if(start_bit_number > 0) bit_inc = 1; - else bit_inc = -1; - - for(i=0;ibindData64invert( (uint64_t *) loc); - else - light->bindData64( (uint64_t *) loc); - light->setBitNumber(bitnum-1); - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "bindLight64invert: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete[] namelist[i]; - bitnum += bit_inc; - } - delete[] namelist; - - return status; -} - -void -Lpanel::bindRunFlag(uint8_t *addr) -{ - int i; - - runflag = (uint8_t *) addr; - - for(i=0;ibindRunFlag((uint8_t *)addr); -} - -void -Lpanel::bindSimclock(uint64_t *addr) -{ - int i; - simclock = (uint64_t *) addr; - - for(i=0;ibindSimclock((uint64_t *) addr, &clock_warp); - -} - - -void -Lpanel::draw(void) -{ int i; - - if(view.redo_projections) - { - setProjection(0); - setModelview(0); - view.redo_projections = 0; - } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - // draw graphics objects - - //glEnable(GL_LIGHTING); - - for(i=0;iis_alpha) continue; - - if(objects[i]->texture_num) - { - textures.bindTexture(objects[i]->texture_num); - } - if(objects[i]->have_normals) glEnable(GL_LIGHTING); - objects[i]->draw(); - } - - // draw lights - - glDisable(GL_TEXTURE_2D); - glDisable(GL_LIGHTING); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.,-10.); - - for(i=0;idraw(); - - // draw switches - - for(i=0;idrawFunc(this, switches[i]); - - if(alpha_objects) - { -// glDisable(GL_DEPTH_TEST); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - for(i=0;itexture_num) - { - textures.bindTexture(alpha_objects[i]->texture_num); - } - if(alpha_objects[i]->have_normals) glEnable(GL_LIGHTING); - alpha_objects[i]->draw(); - } - // glEnable(GL_DEPTH_TEST); - } - - glDisable(GL_TEXTURE_2D); - glDisable(GL_POLYGON_OFFSET_FILL); - glEnable(GL_POLYGON_OFFSET_LINE); - if(do_cursor) - { - glEnable(GL_POLYGON_OFFSET_LINE); - draw_cursor(); - glDisable(GL_POLYGON_OFFSET_LINE); - } - if(do_stats) draw_stats(); -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - SwapBuffers(hDC); - //UpdateWindow(hWnd); -#else - glXSwapBuffers(dpy, window); -#endif -} - - -void -Lpanel::growLights(void) -{ - int i; - lpLight **new_lights; - - new_lights = new lpLight * [num_lights + 8]; - for(i=0;iaction(2); - return num_picked; - } - - - namebuf[0]=0; - glSelectBuffer(500,&namebuf[0]); - glRenderMode(GL_SELECT); - glInitNames(); - glPushName(0); - glGetIntegerv (GL_VIEWPORT, viewport); - glMatrixMode (GL_PROJECTION); - glPushMatrix (); - glLoadIdentity (); - - gluPickMatrix ((GLdouble) x, (GLdouble) (window_ysize - y), 1.0, 1.0, viewport); - doPickProjection(); - glMatrixMode (GL_MODELVIEW); - glPushMatrix(); - doPickModelview(); - - // draw switches - - for(i=0;idrawForPick(); - - num_picked = glRenderMode(GL_RENDER); - - if( num_picked) - { - uint32_t n; - ptr = (GLuint *) namebuf; - n = ptr[3]; - - switch_num = n & LP_SW_PICK_IDMASK; // decode the switch number - switch_dir = ((n & LP_SW_PICK_UP_BIT) != 0); -//printf("pick: switch_num=%d dir=%d\n", switch_num, switch_dir); - - switches[switch_num]->action(switch_dir); - } - - glPopMatrix(); - glMatrixMode (GL_PROJECTION); - glPopMatrix(); - glMatrixMode (GL_MODELVIEW); - glPopMatrix(); - glRenderMode(GL_RENDER); - - return num_picked; - -} - - -int -Lpanel::readConfig(const char *_fname) -{ - FILE *fd; - int i,n; - -#define BUFSIZE 256 -#define TOKENSIZE 80 - - char buffer[BUFSIZE], token[TOKENSIZE]; - int pos, lineno=0, bailout=0; - lp_obj_parm_t *obj; - - char *fname; - - fname = new char[strlen(config_root_path) + 1 + strlen(_fname) + 1]; - strcpy(fname, config_root_path); - strcat(fname, "/"); - strcat(fname, _fname); - - if( (fd=fopen(fname,"r")) == 0) - { - fprintf(stderr,"readFile: could not open file %s\n",fname); - delete[] fname; - return 0; - } - - lp_init_materials(); - - while(!feof(fd) && !bailout) - { - lineno++; - if(!freadlin(fd,buffer,BUFSIZE)) continue; - pos = 0; - if(!gtoken(buffer,token,TOKENSIZE,&pos)) continue; // blank line - if(token[0] == '#') continue; // comment - - if(!strcmp(token, "color")) // color - { int n; - - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("color defined outside of an object\n"); - bailout = 1; - } - else - { - n = sscanf(&buffer[pos],"%f %f %f", - &curr_object->color[0], - &curr_object->color[1], - &curr_object->color[2]); - - if(n < 3) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("color must have 3 (r g b) values in the range of 0.0 - 1.0.\n"); - bailout = 1; - } - - } - } - else if(!strcmp(token, "zbuffer")) - { - view.do_depthtest = 1; - } - else - if(!strcmp(token, "envmap")) // environment mapped reflection - { - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("envmap defined outside of an object\n"); - bailout = 1; - } - else - { - envmap_detected = 1; - curr_object->envmapped = 1; - } - } - else if(!strcmp(token, "instance")) - { - char s[100]; - - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("instance defined outside of an object\n"); - bailout = 1; - } - else - { - if(!gtoken(buffer,s,100,&pos)) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("instance with no object name.\n"); - bailout = 1; - } - else - curr_object->setInstanceName(s); - } - } - else if(!strcmp(token, "light")) - { - obj = new lp_obj_parm_t; - obj->type = LP_LED; - obj->subtype = LP_LED_3D; - obj->group = -1; // does not belong to group - obj->pos[0] = 0.; - obj->pos[1] = 0.; - obj->pos[2] = 0.; - obj->color[0] = lightcolor[0]; - obj->color[1] = lightcolor[1]; - obj->color[2] = lightcolor[2]; - obj->scale[0] = lightsize[0]; - obj->scale[1] = lightsize[1]; - obj->scale[2] = lightsize[2]; - - gtoken(buffer,token,TOKENSIZE,&pos); // get name - - n = addLight(token, obj, &buffer[pos]); - if(n >= 0) - { bailout = 1; - n += pos; - printf("Error on line %d of config file %s\n",lineno, fname); - - printf("%s\n",buffer); - for(i=0;iaddElement(curr_object))) - { printf("could not allocate memory for line.\n"); - bailout = 1; - } - else - { curr_element->type = LP_LINE; - curr_element->setTextureManager(&textures); - } - } - } - else if(!strcmp(token, "material")) // material reference or definition - { int n, matnum; - float Ar, Ag, Ab, Aa, // Ambient rgba - Dr, Dg, Db, Da, // Diffuse rgba - Sr, Sg, Sb, Sa, // Specular rgba - shine, // shinyness - Er, Eg, Eb, Ea; // emission rgba - - if(curr_object) // material reference - { - n = sscanf(&buffer[pos],"%d",&curr_object->material); - - if(n != 1) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("material within an object definition must have one integer value.\n"); - bailout = 1; - } - curr_object->is_alpha = lp_is_material_alpha(curr_object->material); - } - else // material definition - { - - n = sscanf(&buffer[pos],"%d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", - &matnum, &Ar,&Ag,&Ab,&Aa, &Dr,&Dg,&Db,&Da, &Sr,&Sg,&Sb,&Sa, &shine, &Er,&Eg,&Eb,&Ea); - - if(n < 18) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("material definition must have 18 values.\n"); - bailout = 1; - } - else - lp_set_material_params(matnum, Ar,Ag,Ab,Aa, Dr,Dg,Db,Da, Sr,Sg,Sb,Sa, shine, Er,Eg,Eb,Ea); - - } - } - else if(!strcmp(token, "message")) // message - { - printf("%s\n", &buffer[pos]); - } - else if(!strcmp(token, "n")) // vertex normal vector - { int n; - - if(!curr_element || !curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("normal defined outside of a polygon or line\n"); - bailout = 1; - } - else - { - if(!curr_vertex) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("normal defined before a vertex definition\n"); - bailout = 1; - } - - n = sscanf(&buffer[pos],"%f %f %f", - &curr_vertex->norm[0], - &curr_vertex->norm[1], - &curr_vertex->norm[2]); - - if(n < 3) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("normal must have 3 values.\n"); - bailout = 1; - } - else - curr_object->have_normals = 1; - } - } - else if(!strcmp(token, "object")) - { - curr_object = addObject(); - curr_object->setTextureManager(&textures); - if( gtoken(buffer,token,TOKENSIZE,&pos)) - curr_object->setName(token); - curr_element = NULL; - curr_vertex = NULL; - } - else if(!strcmp(token, "perspective")) - { - view.projection = LP_PERSPECTIVE; - } - else if(!strcmp(token, "polygon")) - { - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("polygon defined outside of an object\n"); - bailout = 1; - } - else - { - if(!(curr_element = curr_object->addElement(curr_object))) - { printf("could not allocate memory for polygon.\n"); - bailout = 1; - } - else - { curr_element->type = LP_POLYGON; - curr_element->setTextureManager(&textures); - } - } - } - else if(!strcmp(token, "referenced")) // referenced - { - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("color defined outside of an object\n"); - bailout = 1; - } - else - curr_object->referenced = 1; - } - else if(!strcmp(token, "rotate")) // rotate hpr - { int n; - - if(!curr_object) - { - n = sscanf(&buffer[pos],"%f %f", - &view.rot[0], - &view.rot[1]); - - if(n < 2) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("scene rotate must have 2 values.\n"); - bailout = 1; - } - - } - else - { - n = sscanf(&buffer[pos],"%f %f %f", - &curr_object->rotate[0], - &curr_object->rotate[1], - &curr_object->rotate[2]); - - if(n < 3) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("object rotate must have 3 values.\n"); - bailout = 1; - } - } - } - else if(!strcmp(token, "switch")) - { - obj = new lp_obj_parm_t; - obj->group = -1; // does not belong to group - obj->pos[0] = 0.; - obj->pos[1] = 0.; - obj->pos[2] = 0.; - obj->color[0] = 1.; - obj->color[1] = 0.; - obj->color[2] = 0.; - obj->scale[0] = 0.1875; - obj->scale[1] = 0.1875; - obj->scale[2] = 0.1875; - - gtoken(buffer,token,TOKENSIZE,&pos); // get name - - n = addSwitch(token, obj, &buffer[pos], this); - if(n >= 0) - { bailout = 1; - n += pos; - printf("Error on line %d of config file %s\n",lineno, fname); - - printf("%s\n",buffer); - for(i=0;ist[0], - &curr_vertex->st[1]); - - if(n < 2) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("texture coordinate must have 2 coordinates (e.g. t ).\n"); - bailout = 1; - break; - } - curr_element->have_tcoords = 1; - } - } - else if(!strcmp(token, "texture")) // texture - { - char *texture_path = NULL; - int len; - - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("texture defined outside of an object.\n"); - bailout = 1; - break; - } - - if(!gtoken(buffer,token,TOKENSIZE,&pos)) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("texture with no path to jpeg file defined.\n"); - bailout = 1; - break; - } - - len = strlen(config_root_path) + strlen(token) + 1; - - texture_path = new char[len+1]; - strcpy(texture_path, config_root_path); - strcat(texture_path, "/"); - strcat(texture_path, token); - texture_path[len] = 0; - - - if( !(curr_object->texture_num = textures.addTexture(texture_path))) - { printf("Error on line %d of config file %s\n",lineno, texture_path); - printf("could not load texture '%s'.\n", texture_path); - bailout = 1; - break; - } - - delete[] texture_path; - - } - else if(!strcmp(token, "texture_scale")) - { int n; - - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("texture_scale defined outside of an object\n"); - bailout = 1; - } - else - { - n = sscanf(&buffer[pos],"%f %f", - &curr_object->texture_scale[0], - &curr_object->texture_scale[1]); - - if(n < 2) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("texture_scale must have 2 (x y) values.\n"); - bailout = 1; - } - - } - } - else if(!strcmp(token, "texture_translate")) - { int n; - - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("texture_translate defined outside of an object\n"); - bailout = 1; - } - else - { - n = sscanf(&buffer[pos],"%f %f", - &curr_object->texture_translate[0], - &curr_object->texture_translate[1]); - - if(n < 2) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("texture_translate must have 2 (x y) values.\n"); - bailout = 1; - } - - } - } - else if(!strcmp(token, "translate")) - { int n; - - if(!curr_object) - { - n = sscanf(&buffer[pos],"%f %f %f", - &view.pan[0], - &view.pan[1], - &view.pan[2]); - - if(n < 3) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("scene translate must have 3 values.\n"); - bailout = 1; - } - - } - } - else if(!strcmp(token, "tristrip")) - { - if(!curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("tristrip defined outside of an object\n"); - bailout = 1; - } - else - { - if(!(curr_element = curr_object->addElement(curr_object))) - { printf("could not allocate memory for tristrip.\n"); - bailout = 1; - } - else - { curr_element->type = LP_TRISTRIP; - curr_element->setTextureManager(&textures); - } - } - } - else if(!strcmp(token, "v")) // vertex - { int n; - - if(!curr_element || !curr_object) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("vertex defined outside of a polygon or line\n"); - bailout = 1; - } - else - { - if(!(curr_vertex = curr_element->addVertex())) - { printf("could not allocate memory for vertex.\n"); - bailout = 1; - } - - n = sscanf(&buffer[pos],"%f %f %f", - &curr_vertex->xyz[0], - &curr_vertex->xyz[1], - &curr_vertex->xyz[2]); - - if(n < 2) - { printf("Error on line %d of config file %s\n",lineno, fname); - printf("vertex must have 2 or 3 coordinates.\n"); - bailout = 1; - } - - } - } - else - { - printf("Error: unknown statement on line %d of config file %s\n",lineno, fname); - bailout = 1; - - } - } // end while(!feof) - - delete[] fname; - fclose(fd); - - if(!bailout) - { - genGraphicsData(); - resolveObjectInstances(); - - for(i=0;isetupData(); - - for(i=0;isetupData(i); - } - return !bailout; -} // end readConfig() - -lpLight * -Lpanel::findLightByName(char *name) -{ int i; - - for(i=0;iname, name)) - return lights[i]; - } - -return 0; -} - -// parse var=v,v,v - - enum parse_states { GET_VAR, GET_VAL }; - - - -void -Lpanel::printLights(void) -{ int i; - - printf("lights:\n"); - for(i=0;iprint(); - -} - -void -Lpanel::resolveObjectInstances(void) -{ - int i,j; - lpObject *p; - - for(i=0;iinstance_name) - { if( (p = findObjectByName(objects[i]->instance_name))) - objects[i]->instance_object = p; - else - fprintf(stderr,"Error: object %s instances object %s which cannot be found.\n", - objects[i]->name, objects[i]->instance_name); - } - } - - for(i=0;iinstance_object; - while(p) - { - for(j=0;j<3;j++) - { - objects[i]->bbox.xyz_min[j] = min(objects[i]->bbox.xyz_min[j], p->bbox.xyz_min[j]); - objects[i]->bbox.xyz_max[j] = max(objects[i]->bbox.xyz_max[j], p->bbox.xyz_max[j]); - } - p = p->instance_object; - } - - } -} - -void -Lpanel::sampleData(void) -{ int i; - - // mutex lock - pthread_mutex_lock(&data_sample_lock); - -if( *simclock < old_clock ) -{ - fprintf(stderr,"libfrontpanel: Warning clock went backwards (current=%" PRIu64 " previous=%" PRIu64 ".\n", *simclock, old_clock); - -} - old_clock = *simclock; - - for(i=0;isampleData(); - // mutex unlock -pthread_mutex_unlock(&data_sample_lock); - -} - -void -Lpanel::sampleDataWarp(int clockwarp) -{ int i; - - clock_warp = clockwarp; - - for(i=0;isampleData(); - - clock_warp = 0; -} - -void -Lpanel::sampleLightGroup(int groupnum, int clockval) -{ int i; - - if(groupnum < 0 || groupnum >= LP_MAX_LIGHT_GROUPS) - { - fprintf(stderr, "sampleLightGroup: groupnum (%d) must be in the range of (0-%d). \n", - groupnum, LP_MAX_LIGHT_GROUPS-1); - } - - clock_warp = clockval; - - for(i=0;isampleData(); - - clock_warp = 0; -} - -void -Lpanel::setConfigRootPath(const char *path) -{ - if(config_root_path) delete[] config_root_path; - config_root_path = new char [strlen(path) + 1]; - strcpy(config_root_path,path); - -} - -// ------------- -// lpLight class -// ------------- - -lpLight::lpLight(void) -{ - bindtype = LBINDTYPE_BIT; // default to bind to bit - parms = NULL; - name = NULL; - obj_refname = NULL; - obj_ref = NULL; - sampleDataFunc = sampleData8_error; - drawFunc = drawLightGraphics; - t1 = t2 = on_time = 1; - start_clock = 0; - old_clock = 0; - dirty = 0; - state = 0; - old_state = 0; - intensity = 1.; - - smoothing = 0; // no intensity smoothing for bindtype of FLOATV - intense_curr_idx = 0; - intense_samples[0] = 0.; - intense_samples[1] = 0.; - color[0] = 0.2; - color[1] = 0.; - color[2] = 0.; - default_runflag = 0; - runflag = &default_runflag; -} - -lpLight::~lpLight(void) -{ - if(name) delete[] name; - if(obj_refname) delete[] obj_refname; - if(parms) delete parms; -} - -void -lpLight::bindRunFlag(uint8_t *addr) -{ - runflag = (uint8_t *) addr; -} - -void -lpLight::bindSimclock(uint64_t *addr, int *clockwarp) -{ - - simclock = addr; - clock_warp = clockwarp; -} - - -void -lpLight::draw(void) -{ - int i; - // float *fp; - - switch(bindtype) - { - - case LBINDTYPE_BIT: - - if(*runflag) - { if(dirty) calcIntensity(); - } - else - { - for(i=0;i<3;i++) - { color[i] = parms->color[i] * (float) state + (parms->color[i] * .2); - color[i] = min(color[i],1.0); - } - } - break; - - case LBINDTYPE_FLOATV: - - // fp = (float *) dataptr; - - //intensity = fp[bitnum]; - - //if(intensity > 1.0) intensity = 1.0; - - if(smoothing) - { intense_curr += intense_incr; - if(intense_curr > 1.0) intense_curr = 1.0; - else if(intense_curr < 0.0) intense_curr = 0.0; - intensity = intense_curr; - } - - for(i=0;i<3;i++) - { color[i] = parms->color[i] * intensity + (parms->color[i] * .2); - color[i] = min(color[i],1.0); - } -//printf("xyzzy: intense=%f bitnum=%d\n",intensity, bitnum); - break; - - } - -#if DEBUG -#if 0 - if(!strcmp(name,"LED_ADDR_00") || - !strcmp(name,"LED_ADDR_01") || - !strcmp(name,"LED_ADDR_10") ) -#endif - - - if(!strcmp(name,"LED_ADDR_15")) - { - fprintf(stderr, "draw: %s %f\n",name, intensity); - } -#endif - - glPushMatrix(); - glTranslatef(parms->pos[0], parms->pos[1], parms->pos[2]); - glScalef(parms->scale[0], parms->scale[1], parms->scale[2]); - - - glColor3fv(&color[0]); - - (*drawFunc)(this); - - glPopMatrix(); -} - -void -lpLight::print(void) -{ - printf("light: name=%s\n", name); - - printf("obj: pos=%f %f %f size=%f %f %f color=%f %f %f\n", - parms->pos[0], - parms->pos[1], - parms->pos[2], - parms->scale[0], - parms->scale[1], - parms->scale[2], - parms->color[0], - parms->color[1], - parms->color[2]); -} - -void -lpLight::bindData8(uint8_t *ptr) -{ - sampleDataFunc = sampleData8; - dataptr = (uint8_t *) ptr; -} -void -lpLight::bindData8invert(uint8_t *ptr) -{ - sampleDataFunc = sampleData8invert; - dataptr = (uint8_t *) ptr; -} - -void -lpLight::bindData16(uint16_t *ptr) -{ -// xyzzy - sampleDataFunc = sampleData16; - dataptr = (uint16_t *) ptr; -} - -void -lpLight::bindDatafv(float *ptr) -{ - sampleDataFunc = sampleDatafv; - dataptr = (float *) ptr; - bindtype = LBINDTYPE_FLOATV; -} - -void -lpLight::bindData16invert(uint16_t *ptr) -{ - sampleDataFunc = sampleData16invert; - dataptr = (uint16_t *) ptr; -} - -void -lpLight::bindData32(uint32_t *ptr) -{ - sampleDataFunc = sampleData32; - dataptr = (uint32_t *) ptr; -} - -void -lpLight::bindData32invert(uint32_t *ptr) -{ - sampleDataFunc = sampleData32invert; - dataptr = (uint32_t *) ptr; -} - -void -lpLight::bindData64(uint64_t *ptr) -{ - sampleDataFunc = sampleData64; - dataptr = (uint64_t *) ptr; -} - -void -lpLight::bindData64invert(uint64_t *ptr) -{ - sampleDataFunc = sampleData64invert; - dataptr = (uint64_t *) ptr; -} - - -void -lpLight::calcIntensity(void) -{ - int i; - // unsigned int dt; - uint64_t clock_delta; - - // int logit = 0; - - clock_delta = old_clock - start_clock; - if(clock_delta == 0) - {// intensity = 0.; - return; - } - else - intensity = (float) ((double) on_time / (double) (clock_delta) * 2.0); - if(intensity > 1.0) intensity = 1.0; - -#if 0 -//printf("calcIntensity runflag = %d\n",*runflag); - if(*runflag) - //if(!strcmp(name,"LED_ADDR_15") && intensity > .2) - if(!strcmp(name,"LED_ADDR_15") ) - { - - fprintf(stderr, "dbg: draw: %s intense=%f on_time=%d old_clock=%d start_clock=%d old-start=%d\n",name, intensity, on_time, old_clock, start_clock,old_clock-start_clock); - } -#endif - - start_clock = *simclock; - on_time = 0; - dirty = 0; - - - - for(i=0;i<3;i++) - { color[i] = parms->color[i] * intensity + parms->color[i] * .2; - // color[i] = min(color[i],1.0); - if(color[i] > 1.0) color[i] = 1.0; - } - - -} - - -void -lpLight::sampleData(void) -{ - (*sampleDataFunc)(this); -} - -void -lpLight::setupData(void) -{ - - - if(obj_refname) - { if( !( obj_ref = panel->findObjectByName(obj_refname))) - { - fprintf(stderr, "error: light %s references object %s which cannot be found.\n", - name, obj_refname); - return; - } - - drawFunc = drawLightObject; - } - -} - -void -lpLight::setName(const char *_name) -{ int n; - - n = strlen(_name); - name = new char[n+1]; - strcpy(name,_name); -} - - -int -Lpanel::smoothLight(const char *name, int nframes) -{ - char **namelist; - int num_names; - int i, status = 1; - lpLight *light; - - if( nframes <0) - { - fprintf(stderr, "smoothLight: light %s error. nframes = %d must be >=0 \n", name, nframes); - return 0; - } - - num_names = xpand(name, &namelist); - - for(i=0;ismoothing = nframes; - } - else - { - if(!ignore_bind_errors) fprintf(stderr, "smoothLight: light %s not found\n", namelist[i]); - status = 0; - } - if(namelist[i]) delete namelist[i]; - } - delete[] namelist; - - return status; -} - diff --git a/frontpanel/lpanel.h b/frontpanel/lpanel.h index 256f03ec..d2e5fd19 100644 --- a/frontpanel/lpanel.h +++ b/frontpanel/lpanel.h @@ -1,9 +1,9 @@ -// lpanel.h lightpanel - +// lpanel.h lightpanel /* Copyright (c) 2007-2008, John Kichury + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -17,30 +17,34 @@ */ -#ifndef __LPANEL_DEFS -#define __LPANEL_DEFS - +#ifndef _LPANEL_DEFS +#define _LPANEL_DEFS +#include #include -#include -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -#include +#ifdef WANT_SDL +#include +#include +#else /* !WANT_SDL */ +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) #include +#include #else +#include #include #include #include #endif +#endif /* !WANT_SDL */ #define LP_MAX_LIGHT_GROUPS 10 - // forward references -class lpLight; -class lpSwitch; -class Lpanel; +struct lpLight; +struct lpSwitch; +struct Lpanel; enum obj_types { LP_NULL, LP_LED }; @@ -49,328 +53,332 @@ enum gfx_projection { LP_ORTHO, LP_PERSPECTIVE }; // light sampling datatypes -enum light_bindtypes { - LBINDTYPE_NULL, - LBINDTYPE_BIT, // data pointer points to a single word of bits (bitnum is used as a bit number) - LBINDTYPE_FLOATV // data pointer points to an array (bitnum is used as an index) - }; +enum light_bindtypes { + LBINDTYPE_NULL, + LBINDTYPE_BIT, // data pointer points to a single word of bits + // (bitnum is used as a bit number) + LBINDTYPE_FLOATV // data pointer points to an array + // (bitnum is used as an index) +}; // view structure // -typedef struct -{ - int projection, // ortho, perspective - do_depthtest; // true = enable depth test - float rot[3], - pan[3]; - double aspect, fovy, znear, zfar; - - int redo_projections; +typedef struct view { + int projection; // ortho, perspective + bool do_depthtest; // true = enable depth test + float rot[3], + pan[3]; + double aspect, fovy, znear, zfar; + bool redo_projections; } view_t; -// object parm structure +// object parm structure // --------------------- -typedef struct -{ - int type, // LP_LIGHT, LP_SWITCH etc. - subtype, // LP_LED - group; +typedef struct lp_obj_parm { + int type, // LP_LIGHT, LP_SWITCH etc. + subtype, // LP_LED + group; - float pos[3], // xyz position - color[3], // rgb color - scale[3]; + float pos[3], // xyz position + color[3], // rgb color + scale[3]; } lp_obj_parm_t; - -typedef struct -{ - int num_items, - max_items, - *list; - -} lp_light_group; - +typedef struct lp_light_group { + int num_items, + max_items, + *list; +} lp_light_group_t; #include "lp_gfx.h" #include "lp_switch.h" -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) -static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); -#endif - -// light panel class -// ----------------- +// lightpanel class +// ---------------- -class Lpanel -{ +typedef void (*lp_quit_cbf_t)(void); - private: +typedef struct Lpanel { + // private variables + int num_lights, + max_lights; - int num_lights, - max_lights; + struct lpLight **lights; - lpLight **lights; + lp_light_group_t light_groups[LP_MAX_LIGHT_GROUPS]; - lp_light_group light_groups[LP_MAX_LIGHT_GROUPS]; + lpSwitch_t **switches; - lpSwitch **switches; + int num_switches, + max_switches; - int num_switches, - max_switches; - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - HINSTANCE hInstance; - HWND hWnd; - WNDCLASSEX wc; - HDC hDC; - HGLRC hRC; - PIXELFORMATDESCRIPTOR pfd; +#ifdef WANT_SDL + SDL_Window *window; // SDL window + SDL_GLContext cx; +#else /* !WANT_SDL */ +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + HINSTANCE hInstance; + HWND hWnd; + WNDCLASSEX wc; + HDC hDC; + HGLRC hRC; + PIXELFORMATDESCRIPTOR pfd; #else - Display *dpy; // Xwindows display - Window window; // Xwindows window - XVisualInfo *vi; - GLXContext cx; - Atom wmDeleteMessage; // for processing window close event + Display *dpy; // Xwindows display + Window window; // Xwindows window + XVisualInfo *vi; + GLXContext cx; + Atom wmDeleteMessage; // for processing window close event #endif - - view_t view; - - lpElement *curr_element; - vertex_t *curr_vertex; - int envmap_detected; - - char *config_root_path; // pathname to configuration root (default is ./) - - // internal methods - - int parseConfigParms(const char *buff, lp_obj_parm_t *obj); - void genGraphicsData(void); - void growLights(void); - void growObjects(void); - void growAlphaObjects(void); - void growSwitches(void); - lpObject *addObject(void); - void addAlphaObject(lpObject *p); - lpTextures textures; - int pick(int button, int state, int x, int y); // mouse pick function - void setProjection(int forpick); - void setModelview(int eye); - - public: - - Lpanel(void); - ~Lpanel(void); - - uint64_t default_clock, - *simclock, - old_clock; - int clock_warp; - int ignore_bind_errors; - uint8_t default_runflag, - *runflag; - lpSwitch *mom_switch_pressed, - *findSwitchByName(char *name); - - float lightcolor[3], // default light color - lightsize[3]; // default light size - - void (*quit_callbackfunc)(void); - - int test(int n); // general test function - - int addLight(const char *name, lp_obj_parm_t *obj, const char *buff); - int addLightToGroup( int lightnum, int groupnum); - - int addSwitch(const char *name, lp_obj_parm_t *obj, const char *buff, Lpanel *p); - int addSwitchCallback(const char *name, void (*cbfunc)(int state, int val), int userval); - void addQuitCallback(void (*cbfunc)(void)); - -// void bindSimclock(const uint64_t *addr); -// void bindRunFlag(const uint8_t *addr); - - void bindSimclock(uint64_t *addr); - void bindRunFlag(uint8_t *addr); - - void draw(void); - lpLight *findLightByName(char *name); - lpObject *findObjectByName(char *name); - - void framerate_set(float n) { framerate = n; frametime=1./n; }; - void ignoreBindErrors(int n) { ignore_bind_errors = n; }; - void printLights(void); - void Quit(void); - int readConfig(const char *fname); - //int readConfig(const char *cfg_rootpath, const char *fname); - void sampleData(void); - void sampleDataWarp(int clockwarp); - void sampleLightGroup(int groupnum, int clockval); - void sampleSwitches(void); - void setConfigRootPath(const char *path); - int bindLight8(const char *name, void *loc, int start_bit_number); - int bindLight16(const char *name, void *loc, int start_bit_number); - int bindLightfv(const char *name, void *loc); - int bindLight32(const char *name, void *loc, int start_bit_number); - int bindLight64(const char *name, void *loc, int start_bit_number); - - int bindLight8invert(const char *name, void *loc, int start_bit_number, uint8_t mask); - int bindLight16invert(const char *name, void *loc, int start_bit_number, uint16_t mask); - int bindLight32invert(const char *name, void *loc, int start_bit_number, uint32_t mask); - int bindLight64invert(const char *name, void *loc, int start_bit_number, uint64_t mask); - - int bindSwitch8(const char *name, void *loc_down, void *loc_up, int start_bit_number); - int bindSwitch16(const char *name, void *loc_down, void *loc_up, int start_bit_number); - int bindSwitch32(const char *name, void *loc_down, void *loc_up, int start_bit_number); - int bindSwitch64(const char *name, void *loc_down, void *loc_up, int start_bit_number); - int smoothLight(const char *name, int nframes); - - int num_objects, - max_objects, - num_alpha_objects, - max_alpha_objects; - - lpObject **objects, - *curr_object, - **alpha_objects; - - lpBBox bbox; - - // window methods - - int openWindow(const char *title); - void destroyWindow(void); - void doPickProjection(void); - void doPickModelview(void); - -#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) - - LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); - +#endif /* !WANT_SDL */ + + view_t view; + + lpElement_t *curr_element; + vertex_t *curr_vertex; + bool envmap_detected; + + char *config_root_path; // pathname to configuration root (default is ./) + + lpTextures_t textures; + + // public variables + uint64_t default_clock, + *simclock, + old_clock; + int clock_warp; + bool ignore_bind_errors; + uint8_t default_runflag, + *runflag; + lpSwitch_t *mom_switch_pressed; + + float lightcolor[3], // default light color + lightsize[3]; // default light size + + lp_quit_cbf_t quit_callbackfunc; + + int num_objects, + max_objects, + num_alpha_objects, + max_alpha_objects; + + lpObject_t **objects, + *curr_object, + **alpha_objects; + + lpBBox_t bbox; + + GLint viewport[4]; + int window_xsize, + window_ysize; + + // dev vars + + // performance measurement vars + + float framerate, frametime; + int frames_per_second, + samples_per_second; + char perf_txt[30]; + + char cursor_txt[60]; + float cursor_textpos[2]; + bool do_cursor, do_stats; + float cursor[3], cursor_inc; + bool shift_key_pressed; +} Lpanel_t; // end Lpanel_t + +extern Lpanel_t *Lpanel_new(void); +extern void Lpanel_delete(Lpanel_t *p); +extern void Lpanel_init(Lpanel_t *p); +extern void Lpanel_fini(Lpanel_t *p); + +// internal functions + +extern void Lpanel_genGraphicsData(Lpanel_t *p); +extern void Lpanel_growLights(Lpanel_t *p); +extern void Lpanel_growObjects(Lpanel_t *p); +extern void Lpanel_growAlphaObjects(Lpanel_t *p); +extern void Lpanel_growSwitches(Lpanel_t *p); +extern lpObject_t *Lpanel_addObject(Lpanel_t *p); +extern void Lpanel_addAlphaObject(Lpanel_t *p, lpObject_t *obj); +extern int Lpanel_pick(Lpanel_t *p, int button, int state, // mouse pick function + int x, int y); +extern void Lpanel_setProjection(Lpanel_t *p, bool dopick); +extern void Lpanel_setModelview(Lpanel_t *p, bool dopick); + +// public funcions + +extern lpSwitch_t *Lpanel_findSwitchByName(Lpanel_t *p, char *name); +extern int Lpanel_test(Lpanel_t *p, int n); // general test function +extern int Lpanel_addLight(Lpanel_t *p, const char *name, lp_obj_parm_t *obj, + const char *buff); +extern int Lpanel_addLightToGroup(Lpanel_t *p, int lightnum, int groupnum); + +extern int Lpanel_addSwitch(Lpanel_t *p, const char *name, lp_obj_parm_t *obj, + const char *buff); +extern bool Lpanel_addSwitchCallback(Lpanel_t *p, const char *name, + lp_switch_cbf_t cbfunc, int userval); +extern void Lpanel_addQuitCallback(Lpanel_t *p, lp_quit_cbf_t cbfunc); + +extern void Lpanel_bindSimclock(Lpanel_t *p, uint64_t *addr); +extern void Lpanel_bindRunFlag(Lpanel_t *p, uint8_t *addr); + +extern void Lpanel_draw(Lpanel_t *p); +extern struct lpLight *Lpanel_findLightByName(Lpanel_t *p, char *name); +extern lpObject_t *Lpanel_findObjectByName(Lpanel_t *p, char *name); + +extern void Lpanel_framerate_set(Lpanel_t *p, float n); +extern void Lpanel_ignoreBindErrors(Lpanel_t *p, bool f); +extern void Lpanel_printLights(Lpanel_t *p); +extern bool Lpanel_readConfig(Lpanel_t *p, const char *fname); +extern void Lpanel_sampleData(Lpanel_t *p); +extern void Lpanel_sampleDataWarp(Lpanel_t *p, int clockwarp); +extern void Lpanel_sampleLightGroup(Lpanel_t *p, int groupnum, int clockval); +extern void Lpanel_sampleSwitches(Lpanel_t *p); +extern void Lpanel_setConfigRootPath(Lpanel_t *p, const char *path); +extern bool Lpanel_bindLight8(Lpanel_t *p, const char *name, void *loc, + int start_bit_number); +extern bool Lpanel_bindLight16(Lpanel_t *p, const char *name, void *loc, + int start_bit_number); +extern bool Lpanel_bindLightfv(Lpanel_t *p, const char *name, void *loc); +extern bool Lpanel_bindLight32(Lpanel_t *p, const char *name, void *loc, + int start_bit_number); +extern bool Lpanel_bindLight64(Lpanel_t *p, const char *name, void *loc, + int start_bit_number); + +extern bool Lpanel_bindLight8invert(Lpanel_t *p, const char *name, void *loc, + int start_bit_number, uint8_t mask); +extern bool Lpanel_bindLight16invert(Lpanel_t *p, const char *name, void *loc, + int start_bit_number, uint16_t mask); +extern bool Lpanel_bindLight32invert(Lpanel_t *p, const char *name, void *loc, + int start_bit_number, uint32_t mask); +extern bool Lpanel_bindLight64invert(Lpanel_t *p, const char *name, void *loc, + int start_bit_number, uint64_t mask); + +extern bool Lpanel_bindSwitch8(Lpanel_t *p, const char *name, void *loc_down, + void *loc_up, int start_bit_number); +extern bool Lpanel_bindSwitch16(Lpanel_t *p, const char *name, void *loc_down, + void *loc_up, int start_bit_number); +extern bool Lpanel_bindSwitch32(Lpanel_t *p, const char *name, void *loc_down, + void *loc_up, int start_bit_number); +extern bool Lpanel_bindSwitch64(Lpanel_t *p, const char *name, void *loc_down, + void *loc_up, int start_bit_number); +extern bool Lpanel_smoothLight(Lpanel_t *p, const char *name, int nframes); + +// window functions + +extern int Lpanel_openWindow(Lpanel_t *p, const char *title); +extern void Lpanel_destroyWindow(Lpanel_t *p); +extern void Lpanel_doPickProjection(Lpanel_t *p); +extern void Lpanel_doPickModelview(Lpanel_t *p); + +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) +extern LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT Msg, WPARAM wParam, LPARAM lParam); #else - void resizeWindow(void); +extern void Lpanel_resizeWindow(Lpanel_t *p); #endif - void initGraphics(); - void procEvents(void); - void resolveObjectInstances(void); - - GLint viewport[4]; - int window_xsize, - window_ysize; - - // dev vars and methods - - // performance measurement vars - - float framerate, frametime; - int frames_per_second, - samples_per_second; - char perf_txt[30]; - - char cursor_txt[60]; - float cursor_textpos[2]; - int do_cursor, do_stats; - float cursor[3], cursor_inc; - int shift_key_pressed; - void draw_cursor(void); - void inc_cursor(float x, float y); - void make_cursor_text(void); +extern void Lpanel_initGraphics(Lpanel_t *p); +#ifdef WANT_SDL +extern void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event); +#else +extern void Lpanel_procEvents(Lpanel_t *p); +#endif +extern void Lpanel_resolveObjectInstances(Lpanel_t *p); - void draw_stats(void); +// dev functions -}; // end Lpanel +extern void Lpanel_draw_cursor(Lpanel_t *p); +extern void Lpanel_inc_cursor(Lpanel_t *p, float x, float y); +extern void Lpanel_make_cursor_text(Lpanel_t *p); +extern void Lpanel_draw_stats(Lpanel_t *p); // class lpLight // ------------- +typedef void (*lp_light_df_t)(struct lpLight *p); // light draw function pointer +typedef void (*lp_light_sdf_t)(struct lpLight *p); // light sample data function pointer -class lpLight -{ - private: +typedef struct lpLight { + Lpanel_t *panel; + int bindtype; // bound to bit or array of floats - public: + int smoothing; // 0= no intensity transition smoothing + // >0 = number of frames to transition. - lpLight(void); - ~lpLight(void); + uint64_t *simclock; + int *clock_warp; - Lpanel *panel; + uint8_t default_runflag, + *runflag; - int bindtype; // bound to bit or array of floats + char *name; + void *dataptr; // pointer to data to sample + int datatype; // datatype dataptr points to + int bitnum; // bit in data controlling this light - int smoothing; // 0= no intensity transition smoothing, >0 = number of frames to transition. + char *obj_refname; // name of object if this light references one. + lpObject_t *obj_ref; // pointer to object if this light references one. - uint64_t *simclock; - int *clock_warp; + uint64_t t1, t2, + on_time; - uint8_t default_runflag, - *runflag; - //void bindRunFlag(const uint8_t *addr); - void bindRunFlag(uint8_t *addr); + uint64_t start_clock, + old_clock; - char *name; - void *dataptr; // pointer to data to sample - int datatype; // datatype dataptr points to - int bitnum; // bit in data controlling this light + float intensity, + intense_samples[2], // for smoothing if enabled + intense_incr, // increment value for smoothing transitions + intense_curr; // current intensity for smoothing + int intense_curr_idx; // index for intense_samples[] - char *obj_refname; // name of object if this light references one. - lpObject *obj_ref; // pointer to object if this light references one. - -#if 0 - unsigned long t1, t2, - on_time; -#endif - uint64_t t1, t2, - on_time; + float color[3]; // adjusted color + unsigned char state, + old_state; + bool dirty; + lp_obj_parm_t *parms; - uint64_t start_clock, - old_clock; + lp_light_df_t drawFunc; + lp_light_sdf_t sampleDataFunc; +} lpLight_t; - float intensity, - intense_samples[2], // for smoothing if enabled - intense_incr, // increment value for smoothing transitions - intense_curr; // current intensity for smoothing - int intense_curr_idx; // index for intense_samples[] +extern lpLight_t *lpLight_new(void); +extern void lpLight_delete(lpLight_t *p); +extern void lpLight_init(lpLight_t *p); +extern void lpLight_fini(lpLight_t *p); - float color[3]; // adjusted color - unsigned char state, - old_state, - dirty; +extern void lpLight_bindRunFlag(lpLight_t *p, uint8_t *addr); - lp_obj_parm_t *parms; +extern void lpLight_bindData8(lpLight_t *p, uint8_t *ptr); +extern void lpLight_bindData8invert(lpLight_t *p, uint8_t *ptr); - void bindData8(uint8_t *ptr); - void bindData8invert(uint8_t *ptr); +extern void lpLight_bindData16(lpLight_t *p, uint16_t *ptr); +extern void lpLight_bindDatafv(lpLight_t *p, float *ptr); - void bindData16(uint16_t *ptr); - void bindDatafv(float *ptr); +extern void lpLight_bindData16invert(lpLight_t *p, uint16_t *ptr); +extern void lpLight_bindData32(lpLight_t *p, uint32_t *ptr); +extern void lpLight_bindData32invert(lpLight_t *p, uint32_t *ptr); +extern void lpLight_bindData64(lpLight_t *p, uint64_t *ptr); +extern void lpLight_bindData64invert(lpLight_t *p, uint64_t *ptr); - void bindData16invert(uint16_t *ptr); - void bindData32(uint32_t *ptr); - void bindData32invert(uint32_t *ptr); - void bindData64(uint64_t *ptr); - void bindData64invert(uint64_t *ptr); +extern void lpLight_bindSimclock(lpLight_t *p, uint64_t *addr, int *clockwarp); - void bindSimclock(uint64_t *addr, int *clockwarp); +extern void lpLight_calcIntensity(lpLight_t *p); +extern void lpLight_draw(lpLight_t *p); +extern void lpLight_print(lpLight_t *p); - void calcIntensity(void); - void draw(void); - void (*drawFunc)(lpLight *lp); - void print(void); +extern void lpLight_setupData(lpLight_t *p); +extern void lpLight_sampleData(lpLight_t *p); - void setupData(void); - void (*sampleDataFunc)(lpLight *p); - void sampleData(void); - - void setName(const char *name); - void setBitNumber(int _bitnum) { bitnum = _bitnum; }; -}; +extern void lpLight_setName(lpLight_t *p, const char *name); +extern void lpLight_setBitNumber(lpLight_t *p, int bitnum); - - -#endif +#endif /* !_LPANEL_DEFS */ diff --git a/frontpanel/lpanel_data.h b/frontpanel/lpanel_data.h index c19e94a9..ac437bbb 100644 --- a/frontpanel/lpanel_data.h +++ b/frontpanel/lpanel_data.h @@ -1,9 +1,8 @@ // lpanel_data.h - /* Copyright (c) 2007-2008, John Kichury - This software is freely distributable free of charge and without license fees with the + This software is freely distributable free of charge and without license fees with the following conditions: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -17,36 +16,38 @@ */ -// graphics data for light panel +#ifndef _LPANEL_DATA_DEFS +#define _LPANEL_DATA_DEFS +// graphics data for lightpanel // 2d circle for lights - static float cir2d_data[20][2] = - { - { 0., 1. }, - { -0.309017, 0.951057 }, - { -0.587785, 0.809017 }, - { -0.809017, 0.587785 }, - { -0.951057, 0.309017 }, - { -1., 0. }, - { -0.951057, -0.309017 }, - { -0.809017, -0.587785 }, - { -0.587785, -0.809017 }, - { -0.309017, -0.951057 }, - { 0., -1. } , - { 0.309017, -0.951057 }, - { 0.587785, -0.809017 }, - { 0.809017, -0.587785 }, - { 0.951057, -0.309017 }, - { 1., 0. }, - { 0.951057, 0.309017 }, - { 0.809017, 0.587785 }, - { 0.587785, 0.809017 }, - { 0.309017, 0.951057 } +static float cir2d_data[20][2] = { + { 0., 1. }, + { -0.309017, 0.951057 }, + { -0.587785, 0.809017 }, + { -0.809017, 0.587785 }, + { -0.951057, 0.309017 }, + { -1., 0. }, + { -0.951057, -0.309017 }, + { -0.809017, -0.587785 }, + { -0.587785, -0.809017 }, + { -0.309017, -0.951057 }, + { 0., -1. }, + { 0.309017, -0.951057 }, + { 0.587785, -0.809017 }, + { 0.809017, -0.587785 }, + { 0.951057, -0.309017 }, + { 1., 0. }, + { 0.951057, 0.309017 }, + { 0.809017, 0.587785 }, + { 0.587785, 0.809017 }, + { 0.309017, 0.951057 } }; - static int cir2d_nverts = 20; +static int cir2d_nverts = 20; - static float cir2d_data2[20][2]; +static float cir2d_data2[20][2]; +#endif /* !_LPANEL_DATA_DEFS */ diff --git a/imsaisim/conf_2d/system.conf b/imsaisim/conf_2d/system.conf index 70216d11..b462570e 100644 --- a/imsaisim/conf_2d/system.conf +++ b/imsaisim/conf_2d/system.conf @@ -40,14 +40,14 @@ ns_port 8080 # VIO background and foreground colors in hex RGB format # white Monitor -vio_bg 303030 -vio_fg FFFFFF +vio_bg 48,48,48 +vio_fg 255,255,255 # green Monitor -#vio_bg 002000 -#vio_fg 00BF00 +#vio_bg 0,32,0 +#vio_fg 0,191,0 # amber Monitor -#vio_bg 202000 -#vio_fg FFBF00 +#vio_bg 32,32,0 +#vio_fg 255,191,0 # add scanlines to VIO monitor, 0 = no scanlines vio_scanlines 1 diff --git a/imsaisim/conf_3d/system.conf b/imsaisim/conf_3d/system.conf index 70216d11..b462570e 100644 --- a/imsaisim/conf_3d/system.conf +++ b/imsaisim/conf_3d/system.conf @@ -40,14 +40,14 @@ ns_port 8080 # VIO background and foreground colors in hex RGB format # white Monitor -vio_bg 303030 -vio_fg FFFFFF +vio_bg 48,48,48 +vio_fg 255,255,255 # green Monitor -#vio_bg 002000 -#vio_fg 00BF00 +#vio_bg 0,32,0 +#vio_fg 0,191,0 # amber Monitor -#vio_bg 202000 -#vio_fg FFBF00 +#vio_bg 32,32,0 +#vio_fg 255,191,0 # add scanlines to VIO monitor, 0 = no scanlines vio_scanlines 1 diff --git a/imsaisim/srcsim/Makefile b/imsaisim/srcsim/Makefile index 67f99314..8579d951 100644 --- a/imsaisim/srcsim/Makefile +++ b/imsaisim/srcsim/Makefile @@ -5,7 +5,9 @@ # and the executable saved as '../machinesim' MACHINE = imsai # emulate a machine's frontpanel -FRONTPANEL = YES +FRONTPANEL ?= YES +# use SDL2 instead of X11 +WANT_SDL ?= NO # machine specific system source files MACHINE_SRCS = simcfg.c simio.c simmem.c simctl.c # machine specific I/O source files @@ -40,28 +42,6 @@ DOCROOT_DIR = $(DATADIR)/www ### END MACHINE DEPENDENT VARIABLES ### -### -### FRONTPANEL VARIABLES -### -ifeq ($(FRONTPANEL),YES) -FP_SRCS = fpmain.cpp -FP_DEFS = -DFRONTPANEL -FP_LIB = $(FP_DIR)/libfrontpanel.a -FP_LDLIBS = -lfrontpanel -ljpeg -lGL -lGLU -LINK = $(CXX) -LINKFLAGS = $(CXXFLAGS) -else -FP_SRCS = -FP_DEFS = -FP_LIB = -FP_LDLIBS = -LINK = $(CC) -LINKFLAGS = $(CFLAGS) -endif -### -### END FRONTPANEL VARIABLES -### - SIM = ../$(MACHINE)sim CORE_DIR = ../../z80core @@ -72,59 +52,88 @@ CIV_DIR = $(NET_DIR)/civetweb VPATH = $(CORE_DIR) $(IO_DIR) $(IO_DIR)/apu $(FP_DIR) $(NET_DIR) $(CIV_DIR) -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os +### +### SDL2/X11 PLATFORM VARIABLES +### +ifeq ($(WANT_SDL),YES) +PLAT_DEFS = -DWANT_SDL +ifeq ($(TARGET_OS),BSD) +PLAT_INCS = -I/usr/local/include/SDL2 +PLAT_LDFLAGS = -L/usr/local/lib +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),LINUX) +PLAT_INCS = -I/usr/include/SDL2 +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDLIBS = -framework SDL2 +endif +else ifeq ($(TARGET_OS),BSD) PLAT_INCS = -I/usr/local/include PLAT_LDFLAGS = -L/usr/local/lib -PLAT_LDLIBS = -lthr -lm +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),LINUX) +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include +PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib +PLAT_LDLIBS = -LX11 endif -ifeq ($(TARGET_OS),LINUX) -PLAT_LDLIBS = -lm -lpthread endif +### +### END SDL2/X11 PLATFORM VARIABLES +### + +### +### FRONTPANEL VARIABLES +### +ifeq ($(FRONTPANEL),YES) +FP_DEFS = -DFRONTPANEL +FP_LIB = $(FP_DIR)/libfrontpanel.a +ifeq ($(WANT_SDL),YES) ifeq ($(TARGET_OS),OSX) -PLAT_INCS = -I/opt/X11/include -PLAT_LDFLAGS = -L/usr/local/lib -L/opt/X11/lib +FP_LDLIBS = -lfrontpanel -framework SDL2_image -framework OpenGL +else +FP_LDLIBS = -lfrontpanel -lSDL2_image -lGL +endif +else +FP_LDLIBS = -lfrontpanel -ljpeg -lGL +endif endif ### -### END O/S DEPENDENT VARIABLES +### END FRONTPANEL VARIABLES ### DEFS = -DCONFDIR=\"$(CONF_DIR)\" -DDISKSDIR=\"$(DISKS_DIR)\" \ - -DBOOTROM=\"$(ROMS_DIR)\" -DSYSDOCROOT=\"$(DOCROOT_DIR)\" $(FP_DEFS) + -DBOOTROM=\"$(ROMS_DIR)\" -DSYSDOCROOT=\"$(DOCROOT_DIR)\" $(FP_DEFS) \ + $(PLAT_DEFS) INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) -I$(FP_DIR) -I$(NET_DIR) \ -I$(CIV_DIR)/include $(PLAT_INCS) CPPFLAGS = $(DEFS) $(INCS) CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L CWARNS = -Wall -Wextra -Wwrite-strings -CXXSTDS = -std=c++03 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L -CXXWARNS = -Wall -Wextra # Production - the default COPTS = -O3 -U_FORTIFY_SOURCE -CXXOPTS = -O3 -U_FORTIFY_SOURCE # Development - use `MODE=DEV make build` ifeq ($(MODE),DEV) COPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 -CXXOPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 endif # Debug - use `DEBUG=1 make build` ifneq ($(DEBUG),) COPTS = -O -g -CXXOPTS = -O -g endif -CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) $(PLAT_CFLAGS) -CXXFLAGS = $(CXXSTDS) $(CXXOPTS) $(CXXWARNS) $(PLAT_CXXFLAGS) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) LDFLAGS = -L$(FP_DIR) -L$(CIV_DIR) $(PLAT_LDFLAGS) -LDLIBS = $(CIV_LDLIBS) $(FP_LDLIBS) -lX11 $(PLAT_LDLIBS) +LDLIBS = $(CIV_LDLIBS) $(FP_LDLIBS) $(PLAT_LDLIBS) -lm -lpthread INSTALL = install INSTALL_PROGRAM = $(INSTALL) @@ -132,26 +141,22 @@ INSTALL_DATA = $(INSTALL) -m 644 # core system source files for the CPU simulation CORE_SRCS = sim8080.c simcore.c simdis.c simfun.c simglb.c simice.c simint.c \ - simmain.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c simz80-ed.c \ - simz80-fd.c simz80-fdcb.c + simmain.c simsdl.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c \ + simz80-ed.c simz80-fd.c simz80-fdcb.c SRCS = $(CORE_SRCS) $(MACHINE_SRCS) $(IO_SRCS) -XXSRCS = $(FP_SRCS) -OBJS = $(SRCS:.c=.o) $(XXSRCS:.cpp=.o) -DEPS = $(SRCS:.c=.d) $(XXSRCS:.cpp=.d) +OBJS = $(SRCS:.c=.o) +DEPS = $(SRCS:.c=.d) all: $(SIM) $(SIM): $(OBJS) $(CIV_LIB) $(FP_LIB) - $(LINK) $(LINKFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ $(DEPS): sim.h %.d: %.c @$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< > $@ -%.d: %.cpp - @$(CXX) -MM $(CXXFLAGS) $(CPPFLAGS) $< > $@ - -include $(DEPS) $(CIV_LIB): FORCE diff --git a/imsaisim/srcsim/simcfg.c b/imsaisim/srcsim/simcfg.c index 1bf96edd..8cb4d32f 100644 --- a/imsaisim/srcsim/simcfg.c +++ b/imsaisim/srcsim/simcfg.c @@ -3,6 +3,7 @@ * * Copyright (C) 2008-2021 Udo Munk * Copyright (C) 2021 David McNaughton + * Copyright (C) 2025 by Thomas Eberhardt * * This module reads the system configuration file and sets * global variables, so that the system can be configured. @@ -33,6 +34,7 @@ * 20-JUL-2021 log banked memory * 05-AUG-2021 add boot config for machine without frontpanel * 29-AUG-2021 new memory configuration sections + * 03-JAN-2025 changed colors configuration to RGB-triple */ #include @@ -64,7 +66,7 @@ void config(void) FILE *fp; char buf[BUFSIZE]; char *s, *t1, *t2, *t3, *t4; - int v1, v2; + int v1, v2, v3; char fn[MAX_LFN - 1]; int num_segs = 0; @@ -262,9 +264,53 @@ void config(void) } #endif } else if (!strcmp(t1, "vio_bg")) { - strncpy(&bg_color[1], t2, 6); + if ((t3 = strtok(NULL, " \t,")) == NULL || + (t4 = strtok(NULL, " \t,")) == NULL) { + LOGW(TAG, "missing parameter for %s", t1); + continue; + } + v1 = strtol(t2, NULL, 0); + if (v1 < 0 || v1 > 255) { + LOGW(TAG, "invalid red component %d", v1); + continue; + } + v2 = strtol(t3, NULL, 0); + if (v2 < 0 || v2 > 255) { + LOGW(TAG, "invalid green component %d", v2); + continue; + } + v3 = strtol(t4, NULL, 0); + if (v3 < 0 || v3 > 255) { + LOGW(TAG, "invalid blue component %d", v3); + continue; + } + bg_color[0] = v1; + bg_color[1] = v2; + bg_color[2] = v3; } else if (!strcmp(t1, "vio_fg")) { - strncpy(&fg_color[1], t2, 6); + if ((t3 = strtok(NULL, " \t,")) == NULL || + (t4 = strtok(NULL, " \t,")) == NULL) { + LOGW(TAG, "missing parameter for %s", t1); + continue; + } + v1 = strtol(t2, NULL, 0); + if (v1 < 0 || v1 > 255) { + LOGW(TAG, "invalid red component %d", v1); + continue; + } + v2 = strtol(t3, NULL, 0); + if (v2 < 0 || v2 > 255) { + LOGW(TAG, "invalid green component %d", v2); + continue; + } + v3 = strtol(t4, NULL, 0); + if (v3 < 0 || v3 > 255) { + LOGW(TAG, "invalid blue component %d", v3); + continue; + } + fg_color[0] = v1; + fg_color[1] = v2; + fg_color[2] = v3; } else if (!strcmp(t1, "vio_scanlines")) { if (*t2 != '0') slf = 2; diff --git a/imsaisim/srcsim/simctl.c b/imsaisim/srcsim/simctl.c index 982ddc27..937a6569 100644 --- a/imsaisim/srcsim/simctl.c +++ b/imsaisim/srcsim/simctl.c @@ -4,6 +4,7 @@ * This module allows operation of the system from an IMSAI 8080 front panel * * Copyright (C) 2008-2024 by Udo Munk + * Copyright (C) 2025 by Thomas Eberhardt * * History: * 20-OCT-2008 first version finished @@ -30,6 +31,7 @@ * 06-NOV-2019 use correct memory access functions * 14-AUG-2020 allow building machine without frontpanel * 29-APR-2024 added CPU execution statistics + * 04-JAN-2025 add SDL2 support */ #include @@ -57,7 +59,11 @@ #endif #ifdef FRONTPANEL +#ifdef WANT_SDL +#include "simsdl.h" +#else #include +#endif #include "frontpanel.h" #include "log.h" static const char *TAG = "system"; @@ -73,6 +79,16 @@ static void examine_clicked(int state, int val); static void deposit_clicked(int state, int val); static void power_clicked(int state, int val); static void quit_callback(void); + +#ifdef WANT_SDL +static int fp_win_id; /* frontpanel window id */ +static win_funcs_t fp_win_funcs = { + fp_openWindow, + fp_quit, + fp_procEvent, + fp_draw +}; +#endif #endif /* FRONTPANEL */ /* @@ -92,14 +108,18 @@ void mon(void) #ifdef FRONTPANEL if (F_flag) { - /* initialize front panel */ +#ifndef WANT_SDL XInitThreads(); - +#endif + /* initialize front panel */ putchar('\n'); if (!fp_init2(&confdir[0], "panel.conf", fp_size)) { LOGE(TAG, "frontpanel error"); exit(EXIT_FAILURE); } +#ifdef WANT_SDL + fp_win_id = simsdl_create(&fp_win_funcs); +#endif fp_addQuitCallback(quit_callback); fp_framerate(fp_fps); @@ -232,7 +252,11 @@ void mon(void) sleep_for_ms(999); /* stop frontpanel */ +#ifdef WANT_SDL + simsdl_destroy(fp_win_id); +#else fp_quit(); +#endif } #endif diff --git a/intelmdssim/srcsim/Makefile b/intelmdssim/srcsim/Makefile index ae1e6f1d..7b0eb493 100644 --- a/intelmdssim/srcsim/Makefile +++ b/intelmdssim/srcsim/Makefile @@ -5,7 +5,9 @@ # and the executable saved as '../machinesim' MACHINE = intelmds # emulate a machine's frontpanel -FRONTPANEL = YES +FRONTPANEL ?= YES +# use SDL2 instead of X11 +WANT_SDL ?= NO # machine specific system source files MACHINE_SRCS = simcfg.c simio.c simmem.c simctl.c # machine specific I/O source files @@ -33,28 +35,6 @@ ROMS_DIR = $(DATADIR)/roms ### END MACHINE DEPENDENT VARIABLES ### -### -### FRONTPANEL VARIABLES -### -ifeq ($(FRONTPANEL),YES) -FP_SRCS = fpmain.cpp -FP_DEFS = -DFRONTPANEL -FP_LIB = $(FP_DIR)/libfrontpanel.a -FP_LDLIBS = -lfrontpanel -ljpeg -lGL -lGLU -LINK = $(CXX) -LINKFLAGS = $(CXXFLAGS) -else -FP_SRCS = -FP_DEFS = -FP_LIB = -FP_LDLIBS = -LINK = $(CC) -LINKFLAGS = $(CFLAGS) -endif -### -### END FRONTPANEL VARIABLES -### - SIM = ../$(MACHINE)sim CORE_DIR = ../../z80core @@ -63,58 +43,86 @@ FP_DIR = ../../frontpanel VPATH = $(CORE_DIR) $(IO_DIR) $(FP_DIR) -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os +### +### SDL2/X11 PLATFORM VARIABLES +### +ifeq ($(WANT_SDL),YES) +PLAT_DEFS = -DWANT_SDL +ifeq ($(TARGET_OS),BSD) +PLAT_INCS = -I/usr/local/include/SDL2 +PLAT_LDFLAGS = -L/usr/local/lib +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),LINUX) +PLAT_INCS = -I/usr/include/SDL2 +PLAT_LDLIBS = -lSDL2 -lSDL2main +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDLIBS = -framework SDL2 +endif +else ifeq ($(TARGET_OS),BSD) PLAT_INCS = -I/usr/local/include PLAT_LDFLAGS = -L/usr/local/lib -PLAT_LDLIBS = -lthr -lm +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),LINUX) +PLAT_LDLIBS = -lX11 +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include +PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib +PLAT_LDLIBS = -LX11 endif -ifeq ($(TARGET_OS),LINUX) -PLAT_LDLIBS = -lm -lpthread endif +### +### END SDL2/X11 PLATFORM VARIABLES +### + +### +### FRONTPANEL VARIABLES +### +ifeq ($(FRONTPANEL),YES) +FP_DEFS = -DFRONTPANEL +FP_LIB = $(FP_DIR)/libfrontpanel.a +ifeq ($(WANT_SDL),YES) ifeq ($(TARGET_OS),OSX) -PLAT_INCS = -I/opt/X11/include -PLAT_LDFLAGS = -L/usr/local/lib -L/opt/X11/lib +FP_LDLIBS = -lfrontpanel -framework SDL2_image -framework OpenGL +else +FP_LDLIBS = -lfrontpanel -lSDL2_image -lGL +endif +else +FP_LDLIBS = -lfrontpanel -ljpeg -lGL +endif endif ### -### END O/S DEPENDENT VARIABLES +### END FRONTPANEL VARIABLES ### DEFS = -DCONFDIR=\"$(CONF_DIR)\" -DDISKSDIR=\"$(DISKS_DIR)\" \ - -DBOOTROM=\"$(ROMS_DIR)\" $(FP_DEFS) + -DBOOTROM=\"$(ROMS_DIR)\" $(FP_DEFS) $(PLAT_DEFS) INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) -I$(FP_DIR) $(PLAT_INCS) CPPFLAGS = $(DEFS) $(INCS) CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L CWARNS = -Wall -Wextra -Wwrite-strings -CXXSTDS = -std=c++03 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L -CXXWARNS = -Wall -Wextra # Production - the default COPTS = -O3 -U_FORTIFY_SOURCE -CXXOPTS = -O3 -U_FORTIFY_SOURCE # Development - use `MODE=DEV make build` ifeq ($(MODE),DEV) COPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 -CXXOPTS = -O3 -fstack-protector-all -D_FORTIFY_SOURCE=2 endif # Debug - use `DEBUG=1 make build` ifneq ($(DEBUG),) COPTS = -O -g -CXXOPTS = -O -g endif -CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) $(PLAT_CFLAGS) -CXXFLAGS = $(CXXSTDS) $(CXXOPTS) $(CXXWARNS) $(PLAT_CXXFLAGS) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) LDFLAGS = -L$(FP_DIR) $(PLAT_LDFLAGS) -LDLIBS = $(FP_LDLIBS) -lX11 $(PLAT_LDLIBS) +LDLIBS = $(FP_LDLIBS) $(PLAT_LDLIBS) -lm -lpthread INSTALL = install INSTALL_PROGRAM = $(INSTALL) @@ -122,26 +130,22 @@ INSTALL_DATA = $(INSTALL) -m 644 # core system source files for the CPU simulation CORE_SRCS = sim8080.c simcore.c simdis.c simfun.c simglb.c simice.c simint.c \ - simmain.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c simz80-ed.c \ - simz80-fd.c simz80-fdcb.c + simmain.c simsdl.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c \ + simz80-ed.c simz80-fd.c simz80-fdcb.c SRCS = $(CORE_SRCS) $(MACHINE_SRCS) $(IO_SRCS) -XXSRCS = $(FP_SRCS) -OBJS = $(SRCS:.c=.o) $(XXSRCS:.cpp=.o) -DEPS = $(SRCS:.c=.d) $(XXSRCS:.cpp=.d) +OBJS = $(SRCS:.c=.o) +DEPS = $(SRCS:.c=.d) all: $(SIM) $(SIM): $(OBJS) $(FP_LIB) - $(LINK) $(LINKFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ $(DEPS): sim.h %.d: %.c @$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< > $@ -%.d: %.cpp - @$(CXX) -MM $(CXXFLAGS) $(CPPFLAGS) $< > $@ - -include $(DEPS) $(FP_LIB): FORCE diff --git a/intelmdssim/srcsim/simctl.c b/intelmdssim/srcsim/simctl.c index c6457cc4..f93a4378 100644 --- a/intelmdssim/srcsim/simctl.c +++ b/intelmdssim/srcsim/simctl.c @@ -2,13 +2,14 @@ * Z80SIM - a Z80-CPU simulator * * Copyright (C) 2008-2024 by Udo Munk - * Copyright (C) 2024 by Thomas Eberhardt + * Copyright (C) 2024-2025 by Thomas Eberhardt * * This module contains the user interface an Intel Intellec MDS-800 system * * History: * 03-JUN-2024 first version * 07-JUN-2024 rewrite of the monitor ports and the timing thread + * 04-JAN-2025 add SDL2 support */ #include @@ -31,7 +32,11 @@ #include "unix_terminal.h" #ifdef FRONTPANEL +#ifdef WANT_SDL +#include "simsdl.h" +#else #include +#endif #include "frontpanel.h" #include "log.h" static const char *TAG = "system"; @@ -44,6 +49,16 @@ static void power_clicked(int state, int val); static void quit_callback(void); static int cpu_wait; /* CPU wait flag */ + +#ifdef WANT_SDL +static int fp_win_id; /* frontpanel window id */ +static win_funcs_t fp_win_funcs = { + fp_openWindow, + fp_quit, + fp_procEvent, + fp_draw +}; +#endif #endif /* FRONTPANEL */ BYTE boot_switch; /* status of boot switch */ @@ -60,13 +75,18 @@ void mon(void) { #ifdef FRONTPANEL if (F_flag) { - /* initialize frontpanel */ +#ifndef WANT_SDL XInitThreads(); +#endif + /* initialize frontpanel */ if (!fp_init2(&confdir[0], "panel.conf", fp_size)) { LOGE(TAG, "frontpanel error"); exit(EXIT_FAILURE); } +#ifdef WANT_SDL + fp_win_id = simsdl_create(&fp_win_funcs); +#endif fp_addQuitCallback(quit_callback); fp_framerate(fp_fps); @@ -163,7 +183,11 @@ void mon(void) sleep_for_ms(999); /* shutdown frontpanel */ +#ifdef WANT_SDL + simsdl_destroy(fp_win_id); +#else fp_quit(); +#endif } #endif diff --git a/iodevices/cromemco-dazzler.c b/iodevices/cromemco-dazzler.c index 2796875c..ea36b08b 100644 --- a/iodevices/cromemco-dazzler.c +++ b/iodevices/cromemco-dazzler.c @@ -5,6 +5,7 @@ * * Copyright (C) 2015-2019 by Udo Munk * Copyright (C) 2018 David McNaughton + * Copyright (C) 2025 by Thomas Eberhardt * * Emulation of a Cromemco DAZZLER S100 board * @@ -23,17 +24,20 @@ * 15-JUL-2018 use logging * 19-JUL-2018 integrate webfrontend * 04-NOV-2019 remove fake DMA bus request + * 04-JAN-2025 add SDL2 support */ #include +#include +#include +#ifdef WANT_SDL +#include +#include +#else #include #include #include -#include -#include -#include -#include - +#endif #include "sim.h" #ifdef HAS_DAZZLER @@ -43,19 +47,68 @@ #include "simcfg.h" #include "simmem.h" #include "simport.h" +#ifdef WANT_SDL +#include "simsdl.h" +#endif #ifdef HAS_NETSERVER #include "netsrv.h" #endif -#include "cromemco-dazzler.h" + +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) +#include /* #define LOG_LOCAL_LEVEL LOG_DEBUG */ #include "log.h" static const char *TAG = "DAZZLER"; +#endif -/* X11 stuff */ +#include "cromemco-dazzler.h" + +/* SDL2/X11 stuff */ #define WSIZE 512 static int size = WSIZE; +#ifdef WANT_SDL +static SDL_Window *window; +static SDL_Renderer *renderer; +static int dazzler_win_id = -1; +static uint8_t colors[16][3] = { + { 0x00, 0x00, 0x00 }, + { 0x80, 0x00, 0x00 }, + { 0x00, 0x80, 0x00 }, + { 0x80, 0x80, 0x00 }, + { 0x00, 0x00, 0x80 }, + { 0x80, 0x00, 0x80 }, + { 0x00, 0x80, 0x80 }, + { 0x80, 0x80, 0x80 }, + { 0x00, 0x00, 0x00 }, + { 0xFF, 0x00, 0x00 }, + { 0x00, 0xFF, 0x00 }, + { 0xFF, 0xFF, 0x00 }, + { 0x00, 0x00, 0xFF }, + { 0xFF, 0x00, 0xFF }, + { 0x00, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF } +}; +static uint8_t grays[16][3] = { + { 0x00, 0x00, 0x00 }, + { 0x11, 0x11, 0x11 }, + { 0x22, 0x22, 0x22 }, + { 0x33, 0x33, 0x33 }, + { 0x44, 0x44, 0x44 }, + { 0x55, 0x55, 0x55 }, + { 0x66, 0x66, 0x66 }, + { 0x77, 0x77, 0x77 }, + { 0x88, 0x88, 0x88 }, + { 0x99, 0x99, 0x99 }, + { 0xAA, 0xAA, 0xAA }, + { 0xBB, 0xBB, 0xBB }, + { 0xCC, 0xCC, 0xCC }, + { 0xDD, 0xDD, 0xDD }, + { 0xEE, 0xEE, 0xEE }, + { 0xFF, 0xFF, 0xFF } +}; +#else /* !WANT_SDL */ static Display *display; static Window window; static int screen; @@ -97,6 +150,7 @@ static char gray12[] = "#CCCCCC"; static char gray13[] = "#DDDDDD"; static char gray14[] = "#EEEEEE"; static char gray15[] = "#FFFFFF"; +#endif /* !WANT_SDL */ /* DAZZLER stuff */ static int state; @@ -104,17 +158,27 @@ static WORD dma_addr; static BYTE flags = 64; static BYTE format; +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) /* UNIX stuff */ static pthread_t thread; +#endif #ifdef HAS_NETSERVER static void ws_clear(void); static BYTE formatBuf = 0; #endif -/* create the X11 window for DAZZLER display */ +/* create the SDL2 or X11 window for DAZZLER display */ static void open_display(void) { +#ifdef WANT_SDL + window = SDL_CreateWindow("Cromemco DAzzLER", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + size, size, 0); + renderer = SDL_CreateRenderer(window, -1, (SDL_RENDERER_ACCELERATED | + SDL_RENDERER_PRESENTVSYNC)); +#else /* !WANT_SDL */ Window rootwindow; XSizeHints *size_hints = XAllocSizeHints(); Atom wm_delete_window; @@ -212,35 +276,117 @@ static void open_display(void) XMapWindow(display, window); XUnlockDisplay(display); +#endif /* !WANT_SDL */ } -/* switch DAZZLER off from front panel */ -void cromemco_dazzler_off(void) +/* close the SDL or X11 window for DAZZLER display */ +static void close_display(void) { - state = 0; - sleep_for_ms(50); +#ifdef WANT_SDL + SDL_DestroyRenderer(renderer); + renderer = NULL; + SDL_DestroyWindow(window); + window = NULL; +#else + XLockDisplay(display); + XFreePixmap(display, pixmap); + XFreeGC(display, gc); + XUnlockDisplay(display); + XCloseDisplay(display); + display = NULL; +#endif +} +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) +static void kill_thread(void) +{ if (thread != 0) { + sleep_for_ms(50); pthread_cancel(thread); pthread_join(thread, NULL); thread = 0; } +} +#endif - if (display != NULL) { - XLockDisplay(display); - XFreePixmap(display, pixmap); - XFreeGC(display, gc); - XUnlockDisplay(display); - XCloseDisplay(display); - display = NULL; - } +/* switch DAZZLER off from front panel */ +void cromemco_dazzler_off(void) +{ + state = 0; +#ifdef WANT_SDL +#ifdef HAS_NETSERVER + if (!n_flag) { +#endif + if (dazzler_win_id >= 0) { + simsdl_destroy(dazzler_win_id); + dazzler_win_id = -1; + } +#ifdef HAS_NETSERVER + } else { + kill_thread(); + ws_clear(); + } +#endif +#else /* !WANT_SDL */ + kill_thread(); + if (display != NULL) + close_display(); #ifdef HAS_NETSERVER if (n_flag) ws_clear(); #endif +#endif /* !WANT_SDL */ +} + +#ifdef WANT_SDL + +/* process SDL event */ +static void proc_event(SDL_Event *event) +{ + UNUSED(event); +} + +static inline void set_fg_color(int i) +{ + SDL_SetRenderDrawColor(renderer, + colors[i][0], colors[i][1], colors[i][2], + SDL_ALPHA_OPAQUE); +} + +static inline void set_fg_gray(int i) +{ + SDL_SetRenderDrawColor(renderer, + grays[i][0], grays[i][1], grays[i][2], + SDL_ALPHA_OPAQUE); } +static inline void fill_rect(int x, int y, int w, int h) +{ + SDL_Rect r = {x, y, w, h}; + + SDL_RenderFillRect(renderer, &r); +} + +#else /* !WANT_SDL */ + +static inline void set_fg_color(int i) +{ + XSetForeground(display, gc, colors[i].pixel); +} + +static inline void set_fg_gray(int i) +{ + XSetForeground(display, gc, grays[i].pixel); +} + +static inline void fill_rect(int x, int y, int w, int h) +{ + XFillRectangle(display, pixmap, gc, x, y, w, h); +} + +#endif /* !WANT_SDL */ + /* draw pixels for one frame in hires */ static void draw_hires(void) { @@ -250,55 +396,30 @@ static void draw_hires(void) /* set color or grayscale from lower nibble in graphics format */ i = format & 0x0f; if (format & 16) - XSetForeground(display, gc, colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, grays[i].pixel); - + set_fg_gray(i); if (format & 32) { /* 2048 bytes memory */ psize = size / 128; /* size of one pixel for 128x128 */ for (y = 0; y < 64; y += 2) { for (x = 0; x < 64;) { i = dma_read(addr); if (i & 1) - XFillRectangle(display, pixmap, gc, - x * psize, - y * psize, - psize, psize); + fill_rect(x * psize, y * psize, psize, psize); if (i & 2) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - y * psize, - psize, psize); + fill_rect((x + 1) * psize, y * psize, psize, psize); if (i & 4) - XFillRectangle(display, pixmap, gc, - x * psize, - (y + 1) * psize, - psize, psize); + fill_rect(x * psize, (y + 1) * psize, psize, psize); if (i & 8) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 1) * psize, (y + 1) * psize, psize, psize); if (i & 16) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - y * psize, - psize, psize); + fill_rect((x + 2) * psize, y * psize, psize, psize); if (i & 32) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - y * psize, - psize, psize); + fill_rect((x + 3) * psize, y * psize, psize, psize); if (i & 64) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 2) * psize, (y + 1) * psize, psize, psize); if (i & 128) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 3) * psize, (y + 1) * psize, psize, psize); x += 4; addr++; } @@ -307,45 +428,21 @@ static void draw_hires(void) for (x = 64; x < 128;) { i = dma_read(addr); if (i & 1) - XFillRectangle(display, pixmap, gc, - x * psize, - y * psize, - psize, psize); + fill_rect(x * psize, y * psize, psize, psize); if (i & 2) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - y * psize, - psize, psize); + fill_rect((x + 1) * psize, y * psize, psize, psize); if (i & 4) - XFillRectangle(display, pixmap, gc, - x * psize, - (y + 1) * psize, - psize, psize); + fill_rect(x * psize, (y + 1) * psize, psize, psize); if (i & 8) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 1) * psize, (y + 1) * psize, psize, psize); if (i & 16) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - y * psize, - psize, psize); + fill_rect((x + 2) * psize, y * psize, psize, psize); if (i & 32) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - y * psize, - psize, psize); + fill_rect((x + 3) * psize, y * psize, psize, psize); if (i & 64) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 2) * psize, (y + 1) * psize, psize, psize); if (i & 128) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 3) * psize, (y + 1) * psize, psize, psize); x += 4; addr++; } @@ -354,45 +451,21 @@ static void draw_hires(void) for (x = 0; x < 64;) { i = dma_read(addr); if (i & 1) - XFillRectangle(display, pixmap, gc, - x * psize, - y * psize, - psize, psize); + fill_rect(x * psize, y * psize, psize, psize); if (i & 2) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - y * psize, - psize, psize); + fill_rect((x + 1) * psize, y * psize, psize, psize); if (i & 4) - XFillRectangle(display, pixmap, gc, - x * psize, - (y + 1) * psize, - psize, psize); + fill_rect(x * psize, (y + 1) * psize, psize, psize); if (i & 8) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 1) * psize, (y + 1) * psize, psize, psize); if (i & 16) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - y * psize, - psize, psize); + fill_rect((x + 2) * psize, y * psize, psize, psize); if (i & 32) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - y * psize, - psize, psize); + fill_rect((x + 3) * psize, y * psize, psize, psize); if (i & 64) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 2) * psize, (y + 1) * psize, psize, psize); if (i & 128) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 3) * psize, (y + 1) * psize, psize, psize); x += 4; addr++; } @@ -401,45 +474,21 @@ static void draw_hires(void) for (x = 64; x < 128;) { i = dma_read(addr); if (i & 1) - XFillRectangle(display, pixmap, gc, - x * psize, - y * psize, - psize, psize); + fill_rect(x * psize, y * psize, psize, psize); if (i & 2) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - y * psize, - psize, psize); + fill_rect((x + 1) * psize, y * psize, psize, psize); if (i & 4) - XFillRectangle(display, pixmap, gc, - x * psize, - (y + 1) * psize, - psize, psize); + fill_rect(x * psize, (y + 1) * psize, psize, psize); if (i & 8) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 1) * psize, (y + 1) * psize, psize, psize); if (i & 16) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - y * psize, - psize, psize); + fill_rect((x + 2) * psize, y * psize, psize, psize); if (i & 32) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - y * psize, - psize, psize); + fill_rect((x + 3) * psize, y * psize, psize, psize); if (i & 64) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 2) * psize, (y + 1) * psize, psize, psize); if (i & 128) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 3) * psize, (y + 1) * psize, psize, psize); x += 4; addr++; } @@ -450,45 +499,21 @@ static void draw_hires(void) for (x = 0; x < 64;) { i = dma_read(addr); if (i & 1) - XFillRectangle(display, pixmap, gc, - x * psize, - y * psize, - psize, psize); + fill_rect(x * psize, y * psize, psize, psize); if (i & 2) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - y * psize, - psize, psize); + fill_rect((x + 1) * psize, y * psize, psize, psize); if (i & 4) - XFillRectangle(display, pixmap, gc, - x * psize, - (y + 1) * psize, - psize, psize); + fill_rect(x * psize, (y + 1) * psize, psize, psize); if (i & 8) - XFillRectangle(display, pixmap, gc, - (x + 1) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 1) * psize, (y + 1) * psize, psize, psize); if (i & 16) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - y * psize, - psize, psize); + fill_rect((x + 2) * psize, y * psize, psize, psize); if (i & 32) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - y * psize, - psize, psize); + fill_rect((x + 3) * psize, y * psize, psize, psize); if (i & 64) - XFillRectangle(display, pixmap, gc, - (x + 2) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 2) * psize, (y + 1) * psize, psize, psize); if (i & 128) - XFillRectangle(display, pixmap, gc, - (x + 3) * psize, - (y + 1) * psize, - psize, psize); + fill_rect((x + 3) * psize, (y + 1) * psize, psize, psize); x += 4; addr++; } @@ -509,25 +534,17 @@ static void draw_lowres(void) for (x = 0; x < 32;) { i = dma_read(addr) & 0x0f; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; i = (dma_read(addr) & 0xf0) >> 4; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; addr++; } @@ -536,25 +553,17 @@ static void draw_lowres(void) for (x = 32; x < 64;) { i = dma_read(addr) & 0x0f; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; i = (dma_read(addr) & 0xf0) >> 4; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; addr++; } @@ -563,25 +572,17 @@ static void draw_lowres(void) for (x = 0; x < 32;) { i = dma_read(addr) & 0x0f; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; i = (dma_read(addr) & 0xf0) >> 4; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; addr++; } @@ -590,25 +591,17 @@ static void draw_lowres(void) for (x = 32; x < 64;) { i = dma_read(addr) & 0x0f; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; i = (dma_read(addr) & 0xf0) >> 4; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; addr++; } @@ -619,25 +612,17 @@ static void draw_lowres(void) for (x = 0; x < 32;) { i = dma_read(addr) & 0x0f; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; i = (dma_read(addr) & 0xf0) >> 4; if (format & 16) - XSetForeground(display, gc, - colors[i].pixel); + set_fg_color(i); else - XSetForeground(display, gc, - grays[i].pixel); - XFillRectangle(display, pixmap, gc, - x * psize, y * psize, - psize, psize); + set_fg_gray(i); + fill_rect(x * psize, y * psize, psize, psize); x++; addr++; } @@ -668,7 +653,6 @@ static void ws_clear(void) static void ws_refresh(void) { - int len = (format & 32) ? 2048 : 512; int addr; int i, n, x, la_count; @@ -721,10 +705,43 @@ static void ws_refresh(void) } } } +#endif /* HAS_NETSERVER */ + +#ifdef WANT_SDL +/* function for updating the display */ +static void update_display(bool tick) +{ + UNUSED(tick); + + /* draw one frame dependent on graphics format */ + set_fg_color(0); + SDL_RenderClear(renderer); + if (state == 1) { /* draw frame if on */ + if (format & 64) + draw_hires(); + else + draw_lowres(); + SDL_RenderPresent(renderer); + + /* frame done, set frame flag for 4ms */ + flags = 0; + sleep_for_ms(4); + flags = 64; + } else + SDL_RenderPresent(renderer); +} + +static win_funcs_t dazzler_funcs = { + open_display, + close_display, + proc_event, + update_display +}; #endif -/* thread for updating the display */ -static void *update_display(void *arg) +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) +/* thread for updating the X11 display or web server */ +static void *update_thread(void *arg) { uint64_t t1, t2; int tdiff; @@ -740,9 +757,10 @@ static void *update_display(void *arg) #ifdef HAS_NETSERVER if (!n_flag) { #endif +#ifndef WANT_SDL XLockDisplay(display); - XSetForeground(display, gc, colors[0].pixel); - XFillRectangle(display, pixmap, gc, 0, 0, size, size); + set_fg_color(0); + fill_rect(0, 0, size, size); if (format & 64) draw_hires(); else @@ -751,6 +769,7 @@ static void *update_display(void *arg) size, size, 0, 0); XSync(display, True); XUnlockDisplay(display); +#endif #ifdef HAS_NETSERVER } else { if (net_device_alive(DEV_DZLR)) { @@ -782,6 +801,7 @@ static void *update_display(void *arg) /* just in case it ever gets here */ pthread_exit(NULL); } +#endif /* !WANT_SDL || !HAS_NETSERVER */ void cromemco_dazzler_ctl_out(BYTE data) { @@ -793,10 +813,14 @@ void cromemco_dazzler_ctl_out(BYTE data) #ifdef HAS_NETSERVER if (!n_flag) { #endif - state = 1; - if (display == NULL) { +#ifdef WANT_SDL + if (dazzler_win_id < 0) + dazzler_win_id = simsdl_create(&dazzler_funcs); +#else + if (display == NULL) open_display(); - } +#endif + state = 1; #ifdef HAS_NETSERVER } else { if (state == 0) @@ -804,24 +828,34 @@ void cromemco_dazzler_ctl_out(BYTE data) state = 1; } #endif - if (thread == 0) { - if (pthread_create(&thread, NULL, update_display, - (void *) NULL)) { - LOGE(TAG, "can't create thread"); - exit(EXIT_FAILURE); +#if defined(WANT_SDL) && defined(HAS_NETSERVER) + if (n_flag) { +#endif +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) + if (thread == 0) { + if (pthread_create(&thread, NULL, update_thread, + NULL)) { + LOGE(TAG, "can't create thread"); + exit(EXIT_FAILURE); + } } +#endif +#if defined(WANT_SDL) && defined(HAS_NETSERVER) } +#endif } else { if (state == 1) { state = 0; sleep_for_ms(50); #ifdef HAS_NETSERVER if (!n_flag) { -#endif +#ifndef WANT_SDL XLockDisplay(display); XClearWindow(display, window); XSync(display, True); XUnlockDisplay(display); +#endif +#endif #ifdef HAS_NETSERVER } else ws_clear(); @@ -832,10 +866,26 @@ void cromemco_dazzler_ctl_out(BYTE data) BYTE cromemco_dazzler_flags_in(void) { + BYTE data = 0xff; + +#ifdef WANT_SDL +#ifdef HAS_NETSERVER + if (!n_flag) { +#endif + if (dazzler_win_id >= 0) + data = flags; +#ifdef HAS_NETSERVER + } else { + if (thread != 0) + data = flags; + } +#endif +#else /* !WANT_SDL */ if (thread != 0) - return flags; - else - return (BYTE) 0xff; + data = flags; +#endif /* !WANT_SDL */ + + return data; } void cromemco_dazzler_format_out(BYTE data) diff --git a/iodevices/cromemco-dazzler.h b/iodevices/cromemco-dazzler.h index dbfbfcff..9da544f6 100644 --- a/iodevices/cromemco-dazzler.h +++ b/iodevices/cromemco-dazzler.h @@ -5,6 +5,7 @@ * * Copyright (C) 2015-2019 by Udo Munk * Copyright (C) 2018 David McNaughton + * Copyright (C) 2025 by Thomas Eberhardt * * Emulation of a Cromemco DAZZLER S100 board * @@ -23,6 +24,7 @@ * 15-JUL-2018 use logging * 19-JUL-2018 integrate webfrontend * 04-NOV-2019 remove fake DMA bus request + * 04-JAN-2025 add SDL2 support */ #ifndef CROMEMCO_DAZZLER_INC diff --git a/iodevices/imsai-vio.c b/iodevices/imsai-vio.c index d78889fe..dc2b14f6 100644 --- a/iodevices/imsai-vio.c +++ b/iodevices/imsai-vio.c @@ -5,6 +5,7 @@ * * Copyright (C) 2017-2019 by Udo Munk * Copyright (C) 2018 David McNaughton + * Copyright (C) 2025 by Thomas Eberhardt * * Emulation of an IMSAI VIO S100 board * @@ -19,39 +20,54 @@ * 12-JUL-2018 use logging * 14-JUL-2018 integrate webfrontend * 05-NOV-2019 use correct memory access function + * 04-JAN-2025 add SDL2 support */ #include +#include +#include +#ifdef WANT_SDL +#include +#include +#else #include #include #include -#include -#include -#include +#endif #include "sim.h" #include "simdefs.h" #include "simglb.h" #include "simmem.h" #include "simport.h" +#include "simsdl.h" #ifdef HAS_NETSERVER #include "netsrv.h" #endif -#include "imsai-vio-charset.h" -#include "imsai-vio.h" +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) +#include #include "log.h" static const char *TAG = "VIO"; +#endif + +#include "imsai-vio-charset.h" +#include "imsai-vio.h" #define XOFF 10 /* use some offset inside the window */ #define YOFF 15 /* for the drawing area */ -/* X11 stuff */ +/* SDL2/X11 stuff */ int slf = 1; /* scanlines factor, default no lines */ static int xsize, ysize; /* window size */ static int xscale, yscale; static int sx, sy; +#ifdef WANT_SDL +static SDL_Window *window; +static SDL_Renderer *renderer; +static int vio_win_id = -1; +#else /* !WANT_SDL */ static Display *display; static Window window; static int screen; @@ -61,11 +77,12 @@ static Pixmap pixmap; static Colormap colormap; static XColor black, bg, fg; static char black_color[] = "#000000"; /* black */ - char bg_color[] = "#303030"; /* default background color */ - char fg_color[] = "#FFFFFF"; /* default foreground color */ static XEvent event; static KeySym key; static char text[10]; +#endif /* !WANT_SDL */ + uint8_t bg_color[3] = {48, 48, 48}; /* default background color */ + uint8_t fg_color[3] = {255, 255, 255}; /* default foreground color */ /* VIO stuff */ static int state; /* state on/off for refresh thread */ @@ -74,18 +91,33 @@ static int modebuf; /* and double buffer for it */ static int vmode, res, inv; /* video mode, resolution & inverse */ int imsai_kbd_status, imsai_kbd_data; /* keyboard status & data */ +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) /* UNIX stuff */ static pthread_t thread; +#endif -/* create the X11 window for VIO display */ +/* create the SDL2 or X11 window for VIO display */ static void open_display(void) { + xsize = 560 + (XOFF * 2); + ysize = (240 * slf) + (YOFF * 2); + +#ifdef WANT_SDL + window = SDL_CreateWindow("IMSAI VIO", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + xsize, ysize, 0); + renderer = SDL_CreateRenderer(window, -1, (SDL_RENDERER_ACCELERATED | + SDL_RENDERER_PRESENTVSYNC)); + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); + SDL_RenderPresent(renderer); +#else /* !WANT_SDL */ Window rootwindow; XSizeHints *size_hints = XAllocSizeHints(); Atom wm_delete_window; - - xsize = 560 + (XOFF * 2); - ysize = (240 * slf) + (YOFF * 2); + char buf[8]; display = XOpenDisplay(NULL); XLockDisplay(display); @@ -113,37 +145,112 @@ static void open_display(void) XParseColor(display, colormap, black_color, &black); XAllocColor(display, colormap, &black); - XParseColor(display, colormap, bg_color, &bg); + sprintf(buf, "#%02X%02X%02X", bg_color[0], bg_color[1], bg_color[2]); + XParseColor(display, colormap, buf, &bg); XAllocColor(display, colormap, &bg); - XParseColor(display, colormap, fg_color, &fg); + sprintf(buf, "#%02X%02X%02X", fg_color[0], fg_color[1], fg_color[2]); + XParseColor(display, colormap, buf, &fg); XAllocColor(display, colormap, &fg); XMapWindow(display, window); XSync(display, True); XUnlockDisplay(display); +#endif /* !WANT_SDL */ } -/* shutdown VIO thread and window */ -void imsai_vio_off(void) +/* close the SDL2 or X11 window for VIO display */ +static void close_display(void) { - state = 0; /* tell refresh thread to stop */ - sleep_for_ms(50); /* and wait a bit */ +#ifdef WANT_SDL + SDL_DestroyRenderer(renderer); + renderer = NULL; + SDL_DestroyWindow(window); + window = NULL; +#else + XLockDisplay(display); + XFreePixmap(display, pixmap); + XFreeGC(display, gc); + XUnlockDisplay(display); + XCloseDisplay(display); +#endif +} - /* works if X11 with posix threads implemented correct, but ... */ +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) +static void kill_thread(void) +{ if (thread != 0) { + sleep_for_ms(50); /* wait a bit for thread to stop */ pthread_cancel(thread); pthread_join(thread, NULL); + thread = 0; } +} +#endif - if (display != NULL) { - XLockDisplay(display); - XFreePixmap(display, pixmap); - XFreeGC(display, gc); - XUnlockDisplay(display); - XCloseDisplay(display); - } +/* shutdown VIO thread and window */ +void imsai_vio_off(void) +{ + state = 0; /* tell web refresh thread to stop */ + +#ifdef WANT_SDL +#ifdef HAS_NETSERVER + if (!n_flag) { +#endif + if (vio_win_id >= 0) { + simsdl_destroy(vio_win_id); + vio_win_id = -1; + } +#ifdef HAS_NETSERVER + } else + kill_thread(); +#endif +#else /* !WANT_SDL */ + kill_thread(); + if (display != NULL) + close_display(); +#endif /* !WANT_SDL */ +} + +#ifdef WANT_SDL + +static inline void set_fg_color(void) +{ + SDL_SetRenderDrawColor(renderer, + fg_color[0], fg_color[1], fg_color[2], + SDL_ALPHA_OPAQUE); +} + +static inline void set_bg_color(void) +{ + SDL_SetRenderDrawColor(renderer, + bg_color[0], bg_color[1], bg_color[2], + SDL_ALPHA_OPAQUE); +} + +static inline void draw_point(int x, int y) +{ + SDL_RenderDrawPoint(renderer, x, y); +} + +#else /* !WANT_SDL */ + +static inline void set_fg_color(void) +{ + XSetForeground(display, gc, fg.pixel); +} + +static inline void set_bg_color(void) +{ + XSetForeground(display, gc, bg.pixel); } +static inline void draw_point(int x, int y) +{ + XDrawPoint(display, pixmap, gc, x, y); +} + +#endif /* !WANT_SDL */ + /* display characters 80-FF from bits 0-6, bit 7 = inverse video */ static void dc1(BYTE c) { @@ -154,28 +261,24 @@ static void dc1(BYTE c) for (y = 0; y < 10; y++) { if (charset[(c << 1) & 0xff][y][x] == 1) { if ((cinv ^ inv) == 0) - XSetForeground(display, gc, fg.pixel); + set_fg_color(); else - XSetForeground(display, gc, bg.pixel); + set_bg_color(); } else { if ((cinv ^ inv) == 0) - XSetForeground(display, gc, bg.pixel); + set_bg_color(); else - XSetForeground(display, gc, fg.pixel); + set_fg_color(); } - XDrawPoint(display, pixmap, gc, sx + (x * xscale), - sy + (y * yscale * slf)); + draw_point(sx + (x * xscale), sy + (y * yscale * slf)); if (res & 1) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale) + 1, + draw_point(sx + (x * xscale) + 1, sy + (y * yscale * slf)); if (res & 2) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale), + draw_point(sx + (x * xscale), sy + (y * yscale * slf) + (1 * slf)); if ((res & 3) == 3) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale) + 1, + draw_point(sx + (x * xscale) + 1, sy + (y * yscale * slf) + (1 * slf)); } } @@ -191,28 +294,24 @@ static void dc2(BYTE c) for (y = 0; y < 10; y++) { if (charset[c & 0x7f][y][x] == 1) { if ((cinv ^ inv) == 0) - XSetForeground(display, gc, fg.pixel); + set_fg_color(); else - XSetForeground(display, gc, bg.pixel); + set_bg_color(); } else { if ((cinv ^ inv) == 0) - XSetForeground(display, gc, bg.pixel); + set_bg_color(); else - XSetForeground(display, gc, fg.pixel); + set_fg_color(); } - XDrawPoint(display, pixmap, gc, sx + (x * xscale), - sy + (y * yscale * slf)); + draw_point(sx + (x * xscale), sy + (y * yscale * slf)); if (res & 1) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale) + 1, + draw_point(sx + (x * xscale) + 1, sy + (y * yscale * slf)); if (res & 2) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale), + draw_point(sx + (x * xscale), sy + (y * yscale * slf) + (1 * slf)); if ((res & 3) == 3) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale) + 1, + draw_point(sx + (x * xscale) + 1, sy + (y * yscale * slf) + (1 * slf)); } } @@ -227,33 +326,96 @@ static void dc3(BYTE c) for (y = 0; y < 10; y++) { if (charset[c][y][x] == 1) { if (inv == 0) - XSetForeground(display, gc, fg.pixel); + set_fg_color(); else - XSetForeground(display, gc, bg.pixel); + set_bg_color(); } else { if (inv == 0) - XSetForeground(display, gc, bg.pixel); + set_bg_color(); else - XSetForeground(display, gc, fg.pixel); + set_fg_color(); } - XDrawPoint(display, pixmap, gc, sx + (x * xscale), - sy + (y * yscale * slf)); + draw_point(sx + (x * xscale), sy + (y * yscale * slf)); if (res & 1) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale) + 1, + draw_point(sx + (x * xscale) + 1, sy + (y * yscale * slf)); if (res & 2) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale), + draw_point(sx + (x * xscale), sy + (y * yscale * slf) + (1 * slf)); if ((res & 3) == 3) - XDrawPoint(display, pixmap, gc, - sx + (x * xscale) + 1, + draw_point(sx + (x * xscale) + 1, sy + (y * yscale * slf) + (1 * slf)); } } } +#ifdef WANT_SDL + +/* + * Process a SDL2 event, we are only interested in keyboard input. + * Note that I'm using the event queue as typeahead buffer, saves to + * implement one self. + */ +static void event_handler(SDL_Event *event) +{ + /* if there is a keyboard event get it and convert to ASCII */ + switch (event->type) { + case SDL_WINDOWEVENT: + if (event->window.windowID == SDL_GetWindowID(window)) { + switch (event->window.event) { + case SDL_WINDOWEVENT_FOCUS_GAINED: + SDL_StartTextInput(); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + SDL_StopTextInput(); + break; + default: + break; + } + } + break; + case SDL_TEXTINPUT: + if (event->text.windowID == SDL_GetWindowID(window)) { + /* if the last character wasn't processed already do nothing */ + /* keep event in queue until the CPU emulation got current one */ + if (imsai_kbd_status != 0) + return; + + imsai_kbd_data = event->text.text[0]; + imsai_kbd_status = 0; + } + break; + case SDL_KEYDOWN: + if (event->key.windowID == SDL_GetWindowID(window)) { + /* if the last character wasn't processed already do nothing */ + /* keep event in queue until the CPU emulation got current one */ + if (imsai_kbd_status != 0) + return; + + if (!(event->key.keysym.sym & SDLK_SCANCODE_MASK) && + ((event->key.keysym.mod & KMOD_CTRL) || + (event->key.keysym.sym < 32))) { + imsai_kbd_data = event->key.keysym.sym & 0x1f; + imsai_kbd_status = 0; + } + } + break; + default: + break; + } +#ifdef HAS_NETSERVER + if (n_flag) { + int res = net_device_get(DEV_VIO); + if (res >= 0) { + imsai_kbd_data = res; + imsai_kbd_status = 2; + } + } +#endif +} + +#else /* !WANT_SDL */ + /* * Check the X11 event queue, we are only interested in keyboard input. * Note that I'm using the event queue as typeahead buffer, saves to @@ -286,6 +448,8 @@ static inline void event_handler(void) #endif } +#endif /* !WANT_SDL */ + /* refresh the display buffer dependent on video mode */ static void refresh(void) { @@ -323,15 +487,22 @@ static void refresh(void) switch (vmode) { case 0: /* Video mode 0: video off, screen blanked */ +#ifdef WANT_SDL + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); +#else event_handler(); XSetForeground(display, gc, black.pixel); XFillRectangle(display, pixmap, gc, 0, 0, xsize, ysize); +#endif break; case 1: /* Video mode 1: display character codes 80-FF */ for (y = 0; y < rows; y++) { sx = XOFF; +#ifndef WANT_SDL event_handler(); +#endif for (x = 0; x < cols; x++) { c = getmem(0xf000 + (y * cols) + x); dc1(c); @@ -344,7 +515,9 @@ static void refresh(void) case 2: /* Video mode 2: display character codes 00-7F */ for (y = 0; y < rows; y++) { sx = XOFF; +#ifndef WANT_SDL event_handler(); +#endif for (x = 0; x < cols; x++) { c = getmem(0xf000 + (y * cols) + x); dc2(c); @@ -357,7 +530,9 @@ static void refresh(void) case 3: /* Video mode 3: display character codes 00-FF */ for (y = 0; y < rows; y++) { sx = XOFF; +#ifndef WANT_SDL event_handler(); +#endif for (x = 0; x < cols; x++) { c = getmem(0xf000 + (y * cols) + x); dc3(c); @@ -410,7 +585,9 @@ static void ws_refresh(void) LOGD(__func__, "MODE change"); } +#ifndef WANT_SDL event_handler(); +#endif int len = rows * cols; int addr; @@ -457,10 +634,30 @@ static void ws_refresh(void) } } } -#endif +#endif /* HAS_NETSERVER */ -/* thread for updating the display */ -static void *update_display(void *arg) +#ifdef WANT_SDL +/* function for updating the display */ +static void update_display(bool tick) +{ + UNUSED(tick); + + /* update display window */ + refresh(); + SDL_RenderPresent(renderer); +} + +static win_funcs_t vio_funcs = { + open_display, + close_display, + event_handler, + update_display +}; +#endif /* !WANT_SDL */ + +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) +/* thread for updating the X11 display or web server */ +static void *update_thread(void *arg) { uint64_t t1, t2; int tdiff; @@ -473,6 +670,7 @@ static void *update_display(void *arg) #ifdef HAS_NETSERVER if (!n_flag) { #endif +#ifndef WANT_SDL /* lock display, don't cancel thread while locked */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); XLockDisplay(display); @@ -486,6 +684,7 @@ static void *update_display(void *arg) /* unlock display, thread can be canceled again */ XUnlockDisplay(display); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); +#endif #ifdef HAS_NETSERVER } else ws_refresh(); @@ -502,21 +701,39 @@ static void *update_display(void *arg) pthread_exit(NULL); } +#endif /* !WANT_SDL || HAS_NETSERVER */ -/* create the X11 window and start display refresh thread */ +/* create the SDL window and start display refresh thread */ void imsai_vio_init(void) { #ifdef HAS_NETSERVER - if (!n_flag) + if (!n_flag) { +#endif +#ifdef WANT_SDL + if (vio_win_id < 0) + vio_win_id = simsdl_create(&vio_funcs); +#else + if (display == NULL) + open_display(); +#endif +#ifdef HAS_NETSERVER + } #endif - open_display(); state = 1; modebuf = -1; putmem(0xf7ff, 0x00); - if (pthread_create(&thread, NULL, update_display, (void *) NULL)) { - LOGE(TAG, "can't create thread"); - exit(EXIT_FAILURE); +#if defined(WANT_SDL) && defined(HAS_NETSERVER) + if (n_flag) { +#endif +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) + if (pthread_create(&thread, NULL, update_thread, (void *) NULL)) { + LOGE(TAG, "can't create thread"); + exit(EXIT_FAILURE); + } +#endif +#if defined(WANT_SDL) && defined(HAS_NETSERVER) } +#endif } diff --git a/iodevices/imsai-vio.h b/iodevices/imsai-vio.h index eb12eda0..44c9a869 100644 --- a/iodevices/imsai-vio.h +++ b/iodevices/imsai-vio.h @@ -5,6 +5,7 @@ * * Copyright (C) 2017-2019 by Udo Munk * Copyright (C) 2018 David McNaughton + * Copyright (C) 2025 by Thomas Eberhardt * * Emulation of an IMSAI VIO S100 board * @@ -19,14 +20,17 @@ * 12-JUL-2018 use logging * 14-JUL-2018 integrate webfrontend * 05-NOV-2019 use correct memory access function + * 04-JAN-2025 add SDL2 support */ #ifndef IMSAI_VIO_INC #define IMSAI_VIO_INC +#include + extern int slf; /* VIO scanlines factor */ -extern char bg_color[]; /* VIO background color */ -extern char fg_color[]; /* VIO foreground color */ +extern uint8_t bg_color[3]; /* VIO background color */ +extern uint8_t fg_color[3]; /* VIO foreground color */ extern int imsai_kbd_status, imsai_kbd_data; diff --git a/iodevices/proctec-vdm.c b/iodevices/proctec-vdm.c index c86f07ae..d2f6d253 100644 --- a/iodevices/proctec-vdm.c +++ b/iodevices/proctec-vdm.c @@ -4,6 +4,7 @@ * Common I/O devices used by various simulated machines * * Copyright (C) 2017-2019 by Udo Munk + * Copyright (C) 2025 by Thomas Eberhardt * * Emulation of a Processor Technology VDM-1 S100 board * @@ -13,36 +14,50 @@ * 20-APR-2018 avoid thread deadlock on Windows/Cygwin * 15-JUL-2018 use logging * 04-NOV-2019 eliminate usage of mem_base() + * 03-JAN-2025 use SDL2 instead of X11 */ #include #include +#include +#include +#ifdef WANT_SDL +#include +#include +#else #include #include #include #include -#include -#include +#endif #include "sim.h" #include "simdefs.h" #include "simglb.h" #include "simmem.h" #include "simport.h" +#include "simsdl.h" #include "proctec-vdm-charset.h" #include "proctec-vdm.h" +#ifndef WANT_SDL #include "log.h" static const char *TAG = "VDM"; +#endif #define XOFF 10 /* use some offset inside the window */ #define YOFF 15 /* for the drawing area */ -/* X11 stuff */ +/* SDL2/X11 stuff */ int slf = 1; /* scanlines factor, default no lines */ static int xsize, ysize; /* window size */ static int sx, sy; +#ifdef WANT_SDL +static SDL_Window *window; +static SDL_Renderer *renderer; +static int proctec_win_id = -1; +#else static Display *display; static Window window; static int screen; @@ -52,11 +67,12 @@ static Pixmap pixmap; static Colormap colormap; static XColor black, bg, fg; static char black_color[] = "#000000"; /* black */ - char bg_color[] = "#303030"; /* default background color */ - char fg_color[] = "#FFFFFF"; /* default foreground color */ static XEvent event; static KeySym key; static char text[10]; +#endif + uint8_t bg_color[3] = {48, 48, 48}; /* default background color */ + uint8_t fg_color[3] = {255, 255, 255}; /* default foreground color */ /* VDM stuff */ static int state; /* state on/off for refresh thread */ @@ -66,18 +82,33 @@ int proctec_kbd_data = -1; /* keyboard data */ static int first; /* first displayed screen position */ static int beg; /* beginning display line address */ +#ifndef WANT_SDL /* UNIX stuff */ static pthread_t thread; +#endif -/* create the X11 window for VDM display */ +/* create the SDL window for VDM display */ static void open_display(void) { + xsize = 576 + (XOFF * 2); + ysize = (208 * slf) + (YOFF * 2); + +#ifdef WANT_SDL + window = SDL_CreateWindow("Processor Technology VDM-1", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + xsize, ysize, 0); + renderer = SDL_CreateRenderer(window, -1, (SDL_RENDERER_ACCELERATED | + SDL_RENDERER_PRESENTVSYNC)); + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); + SDL_RenderPresent(renderer); +#else /* !WANT_SDL */ Window rootwindow; XSizeHints *size_hints = XAllocSizeHints(); Atom wm_delete_window; - - xsize = 576 + (XOFF * 2); - ysize = (208 * slf) + (YOFF * 2); + char buf[8]; display = XOpenDisplay(NULL); XLockDisplay(display); @@ -105,9 +136,11 @@ static void open_display(void) XParseColor(display, colormap, black_color, &black); XAllocColor(display, colormap, &black); - XParseColor(display, colormap, bg_color, &bg); + sprintf(buf, "#%02X%02X%02X", bg_color[0], bg_color[1], bg_color[2]); + XParseColor(display, colormap, buf, &bg); XAllocColor(display, colormap, &bg); - XParseColor(display, colormap, fg_color, &fg); + sprintf(buf, "#%02X%02X%02X", fg_color[0], fg_color[1], fg_color[2]); + XParseColor(display, colormap, buf, &fg); XAllocColor(display, colormap, &fg); XMapWindow(display, window); @@ -115,29 +148,126 @@ static void open_display(void) XFillRectangle(display, pixmap, gc, 0, 0, xsize, ysize); XSync(display, True); XUnlockDisplay(display); +#endif /* !WANT_SDL */ } -/* shutdown VDM thread and window */ +/* close the SDL window for VDM display */ +static void close_display(void) +{ +#ifdef WANT_SDL + SDL_DestroyRenderer(renderer); + renderer = NULL; + SDL_DestroyWindow(window); + window = NULL; +#else + XLockDisplay(display); + XFreePixmap(display, pixmap); + XFreeGC(display, gc); + XUnlockDisplay(display); + XCloseDisplay(display); +#endif +} + +/* shutdown VDM window */ void proctec_vdm_off(void) { state = 0; /* tell refresh thread to stop */ - sleep_for_ms(50); /* and wait a bit */ +#ifdef WANT_SDL + if (proctec_win_id >= 0) { + simsdl_destroy(proctec_win_id); + proctec_win_id = -1; + } +#else /* !WANT_SDL */ /* works if X11 with posix threads implemented correct, but ... */ if (thread != 0) { + sleep_for_ms(50); /* wait a bit for thread to stop */ pthread_cancel(thread); pthread_join(thread, NULL); } - if (display != NULL) { - XLockDisplay(display); - XFreePixmap(display, pixmap); - XFreeGC(display, gc); - XUnlockDisplay(display); - XCloseDisplay(display); + if (display != NULL) + close_display(); +#endif /* !WANT_SDL */ +} + +#ifdef WANT_SDL + +/* + * Process a SDL event, we are only interested in keyboard input. + * Note that I'm using the event queue as typeahead buffer, saves to + * implement one self. + */ +static void event_handler(SDL_Event *event) +{ + /* if there is a keyboard event get it and convert to ASCII */ + switch (event->type) { + case SDL_WINDOWEVENT: + if (event->window.windowID == SDL_GetWindowID(window)) { + switch (event->window.event) { + case SDL_WINDOWEVENT_FOCUS_GAINED: + SDL_StartTextInput(); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + SDL_StopTextInput(); + break; + default: + break; + } + } + break; + case SDL_TEXTINPUT: + if (event->text.windowID == SDL_GetWindowID(window)) { + /* if the last character wasn't processed already do nothing */ + /* keep event in queue until the CPU emulation got current one */ + if (proctec_kbd_status == 0) + return; + + proctec_kbd_data = event->text.text[0]; + proctec_kbd_status = 0; + } + break; + case SDL_KEYDOWN: + if (event->key.windowID == SDL_GetWindowID(window)) { + /* if the last character wasn't processed already do nothing */ + /* keep event in queue until the CPU emulation got current one */ + if (proctec_kbd_status == 0) + return; + + if (!(event->key.keysym.sym & SDLK_SCANCODE_MASK) && + ((event->key.keysym.mod & KMOD_CTRL) || + (event->key.keysym.sym < 32))) { + proctec_kbd_data = event->key.keysym.sym & 0x1f; + proctec_kbd_status = 0; + } + } + break; + default: + break; } } +static inline void set_fg_color(void) +{ + SDL_SetRenderDrawColor(renderer, + fg_color[0], fg_color[1], fg_color[2], + SDL_ALPHA_OPAQUE); +} + +static inline void set_bg_color(void) +{ + SDL_SetRenderDrawColor(renderer, + bg_color[0], bg_color[1], bg_color[2], + SDL_ALPHA_OPAQUE); +} + +static inline void draw_point(int x, int y) +{ + SDL_RenderDrawPoint(renderer, x, y); +} + +#else /* !WANT_SDL */ + /* * Check the X11 event queue, we are only interested in keyboard input. * Note that I'm using the event queue as typeahead buffer, saves to @@ -161,6 +291,23 @@ static inline void event_handler(void) } } +static inline void set_fg_color(void) +{ + XSetForeground(display, gc, fg.pixel); +} + +static inline void set_bg_color(void) +{ + XSetForeground(display, gc, bg.pixel); +} + +static inline void draw_point(int x, int y) +{ + XDrawPoint(display, pixmap, gc, x, y); +} + +#endif /* !WANT_SDL */ + /* display characters, bit 7 = inverse video */ static void dc(BYTE c) { @@ -171,16 +318,16 @@ static void dc(BYTE c) for (y = 0; y < 13; y++) { if (charset[c & 0x7f][y][x] == 1) { if (!inv) - XSetForeground(display, gc, fg.pixel); + set_fg_color(); else - XSetForeground(display, gc, bg.pixel); + set_bg_color(); } else { if (!inv) - XSetForeground(display, gc, bg.pixel); + set_bg_color(); else - XSetForeground(display, gc, fg.pixel); + set_fg_color(); } - XDrawPoint(display, pixmap, gc, sx + x, sy + (y * slf)); + draw_point(sx + x, sy + (y * slf)); } } } @@ -197,7 +344,9 @@ static void refresh(void) for (y = 0; y < 16; y++) { sx = XOFF; +#ifndef WANT_SDL event_handler(); +#endif for (x = 0; x < 64; x++) { if (y >= first) { c = getmem(addr + x); @@ -213,6 +362,29 @@ static void refresh(void) } } +#ifdef WANT_SDL + +/* function for updating the display */ +static void update_display(bool tick) +{ + UNUSED(tick); + + if (state) { + /* update display window */ + refresh(); + SDL_RenderPresent(renderer); + } +} + +static win_funcs_t proctec_funcs = { + open_display, + close_display, + event_handler, + update_display +}; + +#else /* !WANT_SDL */ + /* thread for updating the display */ static void *update_display(void *arg) { @@ -251,18 +423,7 @@ static void *update_display(void *arg) pthread_exit(NULL); } -/* create the X11 window and start display refresh thread */ -static void vdm_init(void) -{ - open_display(); - - state = 1; - - if (pthread_create(&thread, NULL, update_display, (void *) NULL)) { - LOGE(TAG, "can't create thread"); - exit(EXIT_FAILURE); - } -} +#endif /* !WANT_SDL */ /* I/O port for the VDM */ void proctec_vdm_out(BYTE data) @@ -271,7 +432,19 @@ void proctec_vdm_out(BYTE data) first = (data & 0xf0) >> 4; beg = data & 0x0f; - if (display == 0) - vdm_init(); + state = 1; + +#ifdef WANT_SDL + if (proctec_win_id < 0) + proctec_win_id = simsdl_create(&proctec_funcs); +#else + if (display == 0) { + open_display(); + if (pthread_create(&thread, NULL, update_display, (void *) NULL)) { + LOGE(TAG, "can't create thread"); + exit(EXIT_FAILURE); + } + } +#endif } diff --git a/iodevices/proctec-vdm.h b/iodevices/proctec-vdm.h index 69d73334..5ff7a03e 100644 --- a/iodevices/proctec-vdm.h +++ b/iodevices/proctec-vdm.h @@ -4,6 +4,7 @@ * Common I/O devices used by various simulated machines * * Copyright (C) 2017-2018 by Udo Munk + * Copyright (C) 2025 by Thomas Eberhardt * * Emulation of a Processor Technology VDM-1 S100 board * @@ -12,17 +13,20 @@ * 21-JUN-2017 don't use dma_read(), switches Tarbell ROM off * 20-APR-2018 avoid thread deadlock on Windows/Cygwin * 15-JUL-2018 use logging + * 04-JAN-2025 add SDL2 support */ #ifndef PROCTEC_VDM_INC #define PROCTEC_VDM_INC +#include + #include "sim.h" #include "simdefs.h" extern int slf; /* VDM scanlines factor */ -extern char bg_color[]; /* VDM background color */ -extern char fg_color[]; /* VDM foreground color */ +extern uint8_t bg_color[3]; /* VDM background color */ +extern uint8_t fg_color[3]; /* VDM foreground color */ extern int proctec_kbd_status; extern int proctec_kbd_data; diff --git a/mosteksim/srcsim/Makefile b/mosteksim/srcsim/Makefile index d061524d..c8049cd5 100644 --- a/mosteksim/srcsim/Makefile +++ b/mosteksim/srcsim/Makefile @@ -37,24 +37,11 @@ IO_DIR = ../../iodevices VPATH = $(CORE_DIR) $(IO_DIR) -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os -ifeq ($(TARGET_OS),BSD) -endif -ifeq ($(TARGET_OS),LINUX) -endif -ifeq ($(TARGET_OS),OSX) -endif -### -### END O/S DEPENDENT VARIABLES -### - DEFS = -DCONFDIR=\"$(CONF_DIR)\" -DDISKSDIR=\"$(DISKS_DIR)\" \ -DBOOTROM=\"$(ROMS_DIR)\" -INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) $(PLAT_INCS) +INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) CPPFLAGS = $(DEFS) $(INCS) CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L @@ -73,11 +60,10 @@ ifneq ($(DEBUG),) COPTS = -O -g endif -CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) $(PLAT_CFLAGS) -CXXFLAGS = $(CXXSTDS) $(CXXOPTS) $(CXXWARNS) $(PLAT_CXXFLAGS) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) -LDFLAGS = $(PLAT_LDFLAGS) -LDLIBS = $(PLAT_LDLIBS) +LDFLAGS = +LDLIBS = INSTALL = install INSTALL_PROGRAM = $(INSTALL) @@ -85,8 +71,8 @@ INSTALL_DATA = $(INSTALL) -m 644 # core system source files for the CPU simulation CORE_SRCS = sim8080.c simcore.c simdis.c simfun.c simglb.c simice.c simint.c \ - simmain.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c simz80-ed.c \ - simz80-fd.c simz80-fdcb.c + simmain.c simsdl.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c \ + simz80-ed.c simz80-fd.c simz80-fdcb.c SRCS = $(CORE_SRCS) $(MACHINE_SRCS) $(IO_SRCS) OBJS = $(SRCS:.c=.o) DEPS = $(SRCS:.c=.d) diff --git a/z80core/fpmain.cpp b/z80core/fpmain.cpp deleted file mode 100644 index d6d0811e..00000000 --- a/z80core/fpmain.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Z80SIM - a Z80-CPU simulator - C++ main() - * - * Copyright (C) 2022 Thomas Eberhardt - * - * History: - * 19-OCT-2022 add C++ main() for linking with the C++ frontpanel library - */ - -#include "simmain.h" - -int main(int argc, char *argv[]) -{ - return sim_main(argc, argv); -} diff --git a/z80core/simmain.c b/z80core/simmain.c index 3bcefc4a..5e1c6e24 100644 --- a/z80core/simmain.c +++ b/z80core/simmain.c @@ -37,12 +37,11 @@ #include "simport.h" #include "simfun.h" #include "simint.h" -#include "simmain.h" static void save_core(void); static int load_core(void); -#ifdef FRONTPANEL +#ifdef WANT_SDL int sim_main(int argc, char *argv[]) #else int main(int argc, char *argv[]) @@ -332,7 +331,7 @@ int main(int argc, char *argv[]) #ifdef HAS_NETSERVER puts("\t-n = enable web-based frontend"); #endif - exit(EXIT_FAILURE); + return EXIT_FAILURE; } putchar('\n'); diff --git a/z80core/simmain.h b/z80core/simmain.h index be6c9c7f..5f4bfc30 100644 --- a/z80core/simmain.h +++ b/z80core/simmain.h @@ -3,24 +3,14 @@ * * Copyright (C) 1987-2024 Udo Munk * Copyright (C) 2021 David McNaughton - * Copyright (C) 2022-2024 Thomas Eberhardt + * Copyright (C) 2022-2025 Thomas Eberhardt */ #ifndef SIMMAIN_INC #define SIMMAIN_INC -#include "sim.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef FRONTPANEL +#ifdef WANT_SDL extern int sim_main(int argc, char *argv[]); #endif -#ifdef __cplusplus -} -#endif - #endif /* !SIMMAIN_INC */ diff --git a/z80core/simsdl.c b/z80core/simsdl.c new file mode 100644 index 00000000..e8022282 --- /dev/null +++ b/z80core/simsdl.c @@ -0,0 +1,154 @@ +/* + * Z80SIM - a Z80-CPU simulator + * + * Copyright (C) 2025 Thomas Eberhardt + */ + +/* + * This module contains the SDL2 integration for the simulator. + */ + +#ifdef WANT_SDL + +#include +#include +#include +#include + +#include "simsdl.h" +#include "simmain.h" + +#define MAX_WINDOWS 5 + +static int sim_thread_func(void *data); + +typedef struct args { + int argc; + char **argv; +} args_t; + +typedef struct window { + bool in_use; + bool is_new; + bool quit; + win_funcs_t *funcs; +} window_t; + +static window_t win[MAX_WINDOWS]; +static bool sim_finished; /* simulator thread finished flag */ + +int main(int argc, char *argv[]) +{ + SDL_Event event; + bool quit = false, tick; + SDL_Thread *sim_thread; + uint64_t t1, t2; + int i, status; + args_t args = {argc, argv}; + + if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { + fprintf(stderr, "Can't initialize SDL: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + + sim_finished = false; + sim_thread = SDL_CreateThread(sim_thread_func, "Simulator", &args); + if (sim_thread == NULL) { + fprintf(stderr, "Can't create simulator thread: %s\n", SDL_GetError()); + SDL_Quit(); + return EXIT_FAILURE; + } + + tick = false; + t1 = SDL_GetTicks64() + 1000; + while (!quit) { + /* process event queue */ + while (SDL_PollEvent(&event) != 0) { + if (event.type == SDL_QUIT) + quit = true; + + for (i = 0; i < MAX_WINDOWS; i++) + if (win[i].in_use) + (*win[i].funcs->event)(&event); + } + + /* open/close/draw windows */ + for (i = 0; i < MAX_WINDOWS; i++) + if (win[i].in_use) { + if (win[i].quit) { + (*win[i].funcs->close)(); + win[i].in_use = false; + } else { + if (win[i].is_new) { + (*win[i].funcs->open)(); + win[i].is_new = false; + } + (*win[i].funcs->draw)(tick); + } + } + + /* update seconds tick */ + tick = false; + t2 = SDL_GetTicks64(); + if (t2 >= t1) { + tick = true; + t1 = t2 + 1000; + } + + if (sim_finished) + quit = true; + } + + SDL_WaitThread(sim_thread, &status); + + for (i = 0; i < MAX_WINDOWS; i++) + if (win[i].in_use) + (*win[i].funcs->close)(); + + SDL_Quit(); + + return status; +} + +/* this is called from the simulator thread */ +int simsdl_create(win_funcs_t *funcs) +{ + int i; + + for (i = 0; i < MAX_WINDOWS; i++) + if (!win[i].in_use) { + win[i].is_new = true; + win[i].quit = false; + win[i].funcs = funcs; + win[i].in_use = true; + break; + } + + if (i == MAX_WINDOWS) { + fprintf(stderr, "No more window slots left\n"); + i = -1; + } + + return i; +} + +/* this is called from the simulator thread */ +void simsdl_destroy(int i) +{ + if (i >= 0 && i < MAX_WINDOWS) + win[i].quit = true; +} + +/* this thread runs the simulator */ +static int sim_thread_func(void *data) +{ + args_t *args = (args_t *) data; + int status; + + status = sim_main(args->argc, args->argv); + sim_finished = true; + + return status; +} + +#endif /* WANT_SDL */ diff --git a/z80core/simsdl.h b/z80core/simsdl.h new file mode 100644 index 00000000..e3a0e5d6 --- /dev/null +++ b/z80core/simsdl.h @@ -0,0 +1,27 @@ +/* + * Z80SIM - a Z80-CPU simulator + * + * Copyright (C) 2025 Thomas Eberhardt + */ + +#ifndef SIMSDL_INC +#define SIMSDL_INC + +#ifdef WANT_SDL + +#include +#include + +typedef struct win_funcs { + void (*open)(void); + void (*close)(void); + void (*event)(SDL_Event *e); + void (*draw)(bool tick); +} win_funcs_t; + +extern int simsdl_create(win_funcs_t *funcs); +extern void simsdl_destroy(int i); + +#endif /* WANT_SDL */ + +#endif /* !SIMSDL_INC */ diff --git a/z80sim/srcsim/Makefile b/z80sim/srcsim/Makefile index f40f7eb3..f0a4060a 100644 --- a/z80sim/srcsim/Makefile +++ b/z80sim/srcsim/Makefile @@ -30,23 +30,10 @@ IO_DIR = ../../iodevices VPATH = $(CORE_DIR) $(IO_DIR) -### -### START O/S PLATFORM DEPENDENT VARIABLES -### include $(CORE_DIR)/Makefile.in-os -ifeq ($(TARGET_OS),BSD) -endif -ifeq ($(TARGET_OS),LINUX) -endif -ifeq ($(TARGET_OS),OSX) -endif -### -### END O/S DEPENDENT VARIABLES -### - DEFS = -INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) $(PLAT_INCS) +INCS = -I. -I$(CORE_DIR) -I$(IO_DIR) CPPFLAGS = $(DEFS) $(INCS) CSTDS = -std=c99 -D_DEFAULT_SOURCE # -D_XOPEN_SOURCE=700L @@ -65,11 +52,10 @@ ifneq ($(DEBUG),) COPTS = -O -g endif -CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) $(PLAT_CFLAGS) -CXXFLAGS = $(CXXSTDS) $(CXXOPTS) $(CXXWARNS) $(PLAT_CXXFLAGS) +CFLAGS = $(CSTDS) $(COPTS) $(CWARNS) -LDFLAGS = $(PLAT_LDFLAGS) -LDLIBS = $(PLAT_LDLIBS) +LDFLAGS = +LDLIBS = INSTALL = install INSTALL_PROGRAM = $(INSTALL) @@ -77,8 +63,8 @@ INSTALL_DATA = $(INSTALL) -m 644 # core system source files for the CPU simulation CORE_SRCS = sim8080.c simcore.c simdis.c simfun.c simglb.c simice.c simint.c \ - simmain.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c simz80-ed.c \ - simz80-fd.c simz80-fdcb.c + simmain.c simsdl.c simz80.c simz80-cb.c simz80-dd.c simz80-ddcb.c \ + simz80-ed.c simz80-fd.c simz80-fdcb.c SRCS = $(CORE_SRCS) $(MACHINE_SRCS) $(IO_SRCS) OBJS = $(SRCS:.c=.o) DEPS = $(SRCS:.c=.d) From 6fe43c80b4f597f4b9671773d877f32e6badd420 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Mon, 6 Jan 2025 09:39:12 +0100 Subject: [PATCH 02/15] frontpanel formating --- frontpanel/frontpanel.h | 2 +- frontpanel/lp_gfx.c | 12 ++-- frontpanel/lp_gfx.h | 5 -- frontpanel/lp_main.c | 6 +- frontpanel/lp_switch.c | 1 - frontpanel/lp_switch.h | 3 +- frontpanel/lp_utils.c | 8 +-- frontpanel/lp_utils.h | 1 - frontpanel/lp_window.c | 153 ++++++++++++++++++++-------------------- frontpanel/lpanel.c | 12 ++-- frontpanel/lpanel.h | 3 - 11 files changed, 93 insertions(+), 113 deletions(-) diff --git a/frontpanel/frontpanel.h b/frontpanel/frontpanel.h index 7cc4b72e..c35a7f8a 100644 --- a/frontpanel/frontpanel.h +++ b/frontpanel/frontpanel.h @@ -62,7 +62,7 @@ extern int fp_bindLight32(const char *name, uint32_t *bits, int bitnum); extern int fp_bindLight16(const char *name, uint16_t *bits, int bitnum); extern int fp_bindLightfv(const char *name, float *bits); extern int fp_bindLight8(const char *name, uint8_t *bits, int bitnum); -extern int fp_bindLight8invert(const char *name, uint8_t *bits, int bitnum,uint8_t mask); +extern int fp_bindLight8invert(const char *name, uint8_t *bits, int bitnum, uint8_t mask); extern int fp_bindLight16invert(const char *name, uint16_t *bits, int bitnum, uint16_t mask); extern int fp_bindLight32invert(const char *name, uint32_t *bits, int bitnum, uint32_t mask); extern int fp_bindLight64invert(const char *name, uint64_t *bits, int bitnum, uint64_t mask); diff --git a/frontpanel/lp_gfx.c b/frontpanel/lp_gfx.c index cd3cc59f..b7c203a6 100644 --- a/frontpanel/lp_gfx.c +++ b/frontpanel/lp_gfx.c @@ -147,7 +147,6 @@ void Lpanel_growAlphaObjects(Lpanel_t *p) p->alpha_objects = new_alpha_objects; } - // --------------------- // object class @@ -424,7 +423,6 @@ void lpObject_setTextureManager(lpObject_t *p, lpTextures_t *textures) p->textures = textures; }; - lpElement_t *lpElement_new(void) { lpElement_t *p = (lpElement_t *) calloc(1, sizeof(lpElement_t)); @@ -586,13 +584,13 @@ void lpElement_genTextureCoords(lpElement_t *p, lpObject_t *obj, lpBBox_t *bbox) for (j = 0; j < 2; j++) { vp->st[j] = (1.0 / (bbox->xyz_max[j] - bbox->xyz_min[j])) * - (vp->xyz[j] - bbox->xyz_min[j]); + (vp->xyz[j] - bbox->xyz_min[j]); vp->st[j] *= 1.0 / obj->texture_scale[j]; vp->st[j] -= obj->texture_translate[j]; } } // vp->st[j] = (1.0 / (bbox->xyz_max[j] - bbox->xyz_min[j])) * - // (vp->xyz[j] - bbox->xyz_min[j]); + // (vp->xyz[j] - bbox->xyz_min[j]); p->have_tcoords = true; } @@ -612,7 +610,6 @@ void lpElement_setTextureManager(lpElement_t *p, lpTextures_t *textures) p->textures = textures; }; - // texture class lpTextures_t *lpTextures_new(void) @@ -782,7 +779,7 @@ int lpTextures_downloadTextures(lpTextures_t *p) // position after last row of pixels rsrc = (unsigned char *) tp->surface->pixels + - tp->surface->pitch * tp->imgYsize; + tp->surface->pitch * tp->imgYsize; tp->texels = (unsigned char *) malloc(tp->texSsize * tp->texTsize * tp->imgZsize); @@ -810,7 +807,7 @@ int lpTextures_downloadTextures(lpTextures_t *p) // copy image pixel data to texel data unsigned char *src, *dst; - int x,y,z; + int x, y, z; src = tp->pixels; @@ -890,7 +887,6 @@ void lpTextures_TexCoord2fv(lpTextures_t *p, float *st) st[1] * p->tex[p->last_accessed]->texTmax); } - // Bbox class lpBBox_t *lpBBox_new(void) diff --git a/frontpanel/lp_gfx.h b/frontpanel/lp_gfx.h index c1cf456e..e00dc669 100644 --- a/frontpanel/lp_gfx.h +++ b/frontpanel/lp_gfx.h @@ -41,7 +41,6 @@ typedef struct { struct lpElement; struct lpTextures; - typedef struct lpBBox { float xyz_min[3], xyz_max[3], @@ -53,7 +52,6 @@ extern void lpBBox_delete(lpBBox_t *p); extern void lpBBox_init(lpBBox_t *p); extern void lpBBox_fini(lpBBox_t *p); - typedef struct lpObject { int num_elements, max_elements; @@ -101,7 +99,6 @@ extern void lpObject_draw_refoverride(lpObject_t *p, int refoverride); extern void lpObject_setTextureManager(lpObject_t *p, struct lpTextures *textures); extern void lpObject_genGraphicsData(lpObject_t *p); - typedef struct lpElement { int type, // LP_POLYGON, LP_LINE num_verts, @@ -135,7 +132,6 @@ extern void lpElement_genTextureCoords(lpElement_t *p, lpObject_t *obj, lpBBox_t *bbox); extern void lpElement_setTextureManager(lpElement_t *p, struct lpTextures *textures); - // texture class for managing graphics textures typedef struct texture { @@ -173,7 +169,6 @@ typedef struct texture { texCropTmax; } texture_t; - typedef struct lpTextures { int num_textures, max_textures, diff --git a/frontpanel/lp_main.c b/frontpanel/lp_main.c index f662a544..1b2988ed 100644 --- a/frontpanel/lp_main.c +++ b/frontpanel/lp_main.c @@ -70,7 +70,7 @@ static void *lp_mainloop_thread(void *n) t1 = frate_gettime(); framerate_start_frame(); - while(!quit) { + while (!quit) { // lock pthread_mutex_lock(&data_lock); @@ -123,7 +123,7 @@ static int start_threads(void) n = pthread_create(&thread_info.thread_id, NULL, lp_mainloop_thread, &thread_info.thread_no); if (n) { - fprintf(stderr, "error %d starting mainloop thread\n",n); + fprintf(stderr, "error %d starting mainloop thread\n", n); return 0; } @@ -393,7 +393,7 @@ void fp_quit(void) for (i = 0; i < 10; i++) { pthread_mutex_lock(&data_lock); - if(thread_info.running == 0) { + if (thread_info.running == 0) { okay = true; break; } diff --git a/frontpanel/lp_switch.c b/frontpanel/lp_switch.c index 5dd651e0..3841d267 100644 --- a/frontpanel/lp_switch.c +++ b/frontpanel/lp_switch.c @@ -159,7 +159,6 @@ static void lp_drawSwitchToggle(lpSwitch_t *p) } #endif - // lpSwitch class // -------------- diff --git a/frontpanel/lp_switch.h b/frontpanel/lp_switch.h index 38b4e6b6..a963b659 100644 --- a/frontpanel/lp_switch.h +++ b/frontpanel/lp_switch.h @@ -65,8 +65,7 @@ enum lp_switch_datatypes { typedef void (*lp_switch_cbf_t)(int state, int val); // switch callback function pointer typedef void (*lp_switch_df_t)(struct lpSwitch *swtch); // switch draw function pointer -typedef struct lpSwitch -{ +typedef struct lpSwitch { char *name; int type; // toggle/paddle/object_ref diff --git a/frontpanel/lp_utils.c b/frontpanel/lp_utils.c index 350b2c42..b8d94a29 100644 --- a/frontpanel/lp_utils.c +++ b/frontpanel/lp_utils.c @@ -127,7 +127,6 @@ int gtoken(char *string, /* input character string */ } /* end of gtoken function */ - /* freadlin read line from file */ /* Read an ascii line from specified file (carret,lf or null signals end @@ -170,7 +169,6 @@ int freadlin(FILE *funit, char *buffer, int bufsize) return 1; } /* end freadlin() */ - /* xpand */ enum xpnd_states { XPN_START, XPN_PREFIX, XPN_FRMVAL, XPN_TOVAL, XPN_INC, XPN_SUFFIX }; @@ -366,7 +364,7 @@ int xpand(const char *s, char **namelist[]) snprintf(format, sizeof(format), "%%0%dd", ndigits); max_names = ((max(ival, to_ival)) - (min(ival, to_ival))) / - abs(inc_ival) + 1; + abs(inc_ival) + 1; new_namelist = (char **) malloc(sizeof(char *) * max_names); *namelist = &new_namelist[0]; @@ -417,7 +415,7 @@ int xpand(const char *s, char **namelist[]) } if (prefix) - free(prefix); + free(prefix); if (from) free(from); if (to) @@ -431,7 +429,6 @@ int xpand(const char *s, char **namelist[]) } /* end xpand() */ - /* framerate control */ /* @@ -511,7 +508,6 @@ void framerate_wait(void) } } - // parser class static const char *parser_errmsgs[] = { diff --git a/frontpanel/lp_utils.h b/frontpanel/lp_utils.h index cc0cc81e..8abc25c2 100644 --- a/frontpanel/lp_utils.h +++ b/frontpanel/lp_utils.h @@ -39,7 +39,6 @@ extern void framerate_set(double r); extern void framerate_start_frame(void); extern void framerate_wait(void); - enum parser_rules_enums { PARSER_STRING, PARSER_INT, PARSER_FLOAT }; enum parser_state_enums { PARSER_GETVAR, PARSER_GETVAL }; diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c index a177bada..f554a006 100644 --- a/frontpanel/lp_window.c +++ b/frontpanel/lp_window.c @@ -287,7 +287,8 @@ void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) #if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) -static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { +static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ LONG_PTR user_data = GetWindowLongPtr(hWnd, GWLP_USERDATA); if (user_data) @@ -300,7 +301,7 @@ LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT msg, WPARAM wParam, LPARAM lPa { unsigned int kcode; - switch(msg) { + switch (msg) { case WM_KEYUP: if (LOWORD(wParam) == VK_SHIFT) { p->shift_key_pressed = false; @@ -310,7 +311,7 @@ LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT msg, WPARAM wParam, LPARAM lPa case WM_KEYDOWN: kcode = LOWORD(wParam); - switch(kcode) { + switch (kcode) { case VK_SHIFT: p->shift_key_pressed = true; return 0; @@ -436,78 +437,78 @@ LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT msg, WPARAM wParam, LPARAM lPa } break; - case WM_MOUSEWHEEL: - p->view.pan[2] += (float) GET_WHEEL_DELTA_WPARAM(wParam) / 250.0; - p->view.redo_projections = true; - return 0; - - case WM_LBUTTONDOWN: - if (!Lpanel_pick(p, 0, 1, LOWORD(lParam), HIWORD(lParam))) { - mousex = LOWORD(lParam); - mousey = HIWORD(lParam); - lmouse = true; - } - return 0; - - case WM_LBUTTONUP: - if(!Lpanel_pick(p, 0, 0, LOWORD(lParam), HIWORD(lParam))) - lmouse = false; - return 0; - - case WM_MOUSEMOVE: - if (lmouse) { - omx = mousex; - omy = mousey; - - if (p->shift_key_pressed) { - p->view.pan[0] += ((float) LOWORD(lParam) - (float) omx) * .02; - p->view.pan[1] -= ((float) HIWORD(lParam) - (float) omy) * .02; - } else { - view.rot[1] += ((float) LOWORD(lParam) - (float) omx) * .2; - view.rot[0] += ((float) HIWORD(lParam) - (float) omy) * .2; - } - - mousex = LOWORD(lParam); - mousey = HIWORD(lParam); - p->view.redo_projections = true; - } - return 0; - - case WM_SIZE: - p->window_xsize = (GLsizei) LOWORD(lParam); - p->window_ysize = (GLsizei) HIWORD(lParam); - p->view.aspect = (GLdouble) p->window_xsize / (GLdouble) p->window_ysize; - - glViewport(0, 0, p->window_xsize, p->window_ysize); - glGetIntegerv(GL_VIEWPORT, p->viewport); - setProjection(false); - setModelview(false); - - return 0; - - case WM_QUIT: - case WM_CLOSE: - if (p->hRC) { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(p->hRC); - } - if (p->hDC) { - ReleaseDC(p->hWnd, p->hDC); - } - DestroyWindow(p->hWnd); - return 0; - - case WM_DESTROY: - UnregisterClass(FPClassName, p->hInstance); - PostQuitMessage(0); - if(quit_callbackfunc) - (*quit_callbackfunc)(); - else - exit(EXIT_SUCCESS); - return 0; - - default: - return DefWindowProc(p->hWnd, msg, wParam, lParam); + case WM_MOUSEWHEEL: + p->view.pan[2] += (float) GET_WHEEL_DELTA_WPARAM(wParam) / 250.0; + p->view.redo_projections = true; + return 0; + + case WM_LBUTTONDOWN: + if (!Lpanel_pick(p, 0, 1, LOWORD(lParam), HIWORD(lParam))) { + mousex = LOWORD(lParam); + mousey = HIWORD(lParam); + lmouse = true; + } + return 0; + + case WM_LBUTTONUP: + if (!Lpanel_pick(p, 0, 0, LOWORD(lParam), HIWORD(lParam))) + lmouse = false; + return 0; + + case WM_MOUSEMOVE: + if (lmouse) { + omx = mousex; + omy = mousey; + + if (p->shift_key_pressed) { + p->view.pan[0] += ((float) LOWORD(lParam) - (float) omx) * .02; + p->view.pan[1] -= ((float) HIWORD(lParam) - (float) omy) * .02; + } else { + view.rot[1] += ((float) LOWORD(lParam) - (float) omx) * .2; + view.rot[0] += ((float) HIWORD(lParam) - (float) omy) * .2; + } + + mousex = LOWORD(lParam); + mousey = HIWORD(lParam); + p->view.redo_projections = true; + } + return 0; + + case WM_SIZE: + p->window_xsize = (GLsizei) LOWORD(lParam); + p->window_ysize = (GLsizei) HIWORD(lParam); + p->view.aspect = (GLdouble) p->window_xsize / (GLdouble) p->window_ysize; + + glViewport(0, 0, p->window_xsize, p->window_ysize); + glGetIntegerv(GL_VIEWPORT, p->viewport); + setProjection(false); + setModelview(false); + + return 0; + + case WM_QUIT: + case WM_CLOSE: + if (p->hRC) { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(p->hRC); + } + if (p->hDC) { + ReleaseDC(p->hWnd, p->hDC); + } + DestroyWindow(p->hWnd); + return 0; + + case WM_DESTROY: + UnregisterClass(FPClassName, p->hInstance); + PostQuitMessage(0); + if (quit_callbackfunc) + (*quit_callbackfunc)(); + else + exit(EXIT_SUCCESS); + return 0; + + default: + return DefWindowProc(p->hWnd, msg, wParam, lParam); } } @@ -912,7 +913,7 @@ int Lpanel_openWindow(Lpanel_t *p, const char *title) swa.colormap = XCreateColormap(p->dpy, RootWindow(p->dpy, p->vi->screen), p->vi->visual, AllocNone); swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask | PointerMotionMask; + ButtonPressMask | ButtonReleaseMask | PointerMotionMask; p->window = XCreateWindow(p->dpy, RootWindow(p->dpy, p->vi->screen), 500, 500, p->window_xsize, p->window_ysize, diff --git a/frontpanel/lpanel.c b/frontpanel/lpanel.c index 55b59a92..bd2dd4e3 100644 --- a/frontpanel/lpanel.c +++ b/frontpanel/lpanel.c @@ -189,7 +189,7 @@ static void sampleDatafv(lpLight_t *p) p->intense_incr = (p->intense_samples[p->intense_curr_idx] - p->intense_samples[!p->intense_curr_idx]) / - (float) p->smoothing; + (float) p->smoothing; } else p->intensity = ptr[p->bitnum]; } @@ -269,7 +269,6 @@ static void sampleData64invert(lpLight_t *p) p->state = bit; } - Lpanel_t *Lpanel_new(void) { Lpanel_t *p = (Lpanel_t *) calloc(1, sizeof(Lpanel_t)); @@ -523,7 +522,7 @@ int Lpanel_addLightToGroup(Lpanel_t *p, int lightnum, int groupnum) { if (groupnum >= LP_MAX_LIGHT_GROUPS) { fprintf(stderr, "error: light %s invalid group number (%d)\n", - p->lights[lightnum]->name, groupnum); + p->lights[lightnum]->name, groupnum); return 0; } @@ -1477,7 +1476,7 @@ bool Lpanel_readConfig(Lpanel_t *p, const char *_fname) printf("Error on line %d of config file %s\n", lineno, fname); printf("texture coordinate must have 2 coordinates " - "(e.g. t ).\n"); + "(e.g. t ).\n"); bailout = true; break; } @@ -1751,7 +1750,6 @@ void Lpanel_ignoreBindErrors(Lpanel_t *p, bool f) p->ignore_bind_errors = f; }; - // ------------- // lpLight class // ------------- @@ -1837,7 +1835,7 @@ void lpLight_draw(lpLight_t *p) } else { for (i = 0; i < 3; i++) { p->color[i] = p->parms->color[i] * (float) p->state + - (p->parms->color[i] * .2); + (p->parms->color[i] * .2); p->color[i] = min(p->color[i], 1.0); } } @@ -1860,7 +1858,7 @@ void lpLight_draw(lpLight_t *p) for (i = 0; i < 3; i++) { p->color[i] = p->parms->color[i] * p->intensity + - (p->parms->color[i] * .2); + (p->parms->color[i] * .2); p->color[i] = min(p->color[i], 1.0); } // printf("xyzzy: intense=%f bitnum=%d\n", p->intensity, p->bitnum); diff --git a/frontpanel/lpanel.h b/frontpanel/lpanel.h index d2e5fd19..9674e519 100644 --- a/frontpanel/lpanel.h +++ b/frontpanel/lpanel.h @@ -37,7 +37,6 @@ #endif #endif /* !WANT_SDL */ - #define LP_MAX_LIGHT_GROUPS 10 // forward references @@ -46,7 +45,6 @@ struct lpLight; struct lpSwitch; struct Lpanel; - enum obj_types { LP_NULL, LP_LED }; enum obj_subtypes { LP_SUBTYPE_NULL, LP_LED_3D, LP_LED_2D }; enum gfx_projection { LP_ORTHO, LP_PERSPECTIVE }; @@ -298,7 +296,6 @@ extern void Lpanel_make_cursor_text(Lpanel_t *p); extern void Lpanel_draw_stats(Lpanel_t *p); - // class lpLight // ------------- From e0d0aac244fb334b87d8fc68a89fbf69c9660b13 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Mon, 6 Jan 2025 15:52:28 +0100 Subject: [PATCH 03/15] make frontpanel window close button work --- frontpanel/lp_window.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c index f554a006..5c82c506 100644 --- a/frontpanel/lp_window.c +++ b/frontpanel/lp_window.c @@ -85,7 +85,21 @@ void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) if (event->window.windowID != SDL_GetWindowID(p->window)) break; - Lpanel_resizeWindow(p); + switch (event->window.event) { + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: + case SDL_WINDOWEVENT_MAXIMIZED: + case SDL_WINDOWEVENT_RESTORED: + Lpanel_resizeWindow(p); + break; + case SDL_WINDOWEVENT_CLOSE: + // call user quit callback if exists + if (p->quit_callbackfunc) + (*p->quit_callbackfunc)(); + break; + default: + break; + } break; case SDL_QUIT: From b558bf02b781981870f43bdcdcaa4d68504c190d Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Tue, 7 Jan 2025 02:25:47 +0100 Subject: [PATCH 04/15] add typeahead buffer for SDL --- altairsim/srcsim/simio.c | 33 +------- iodevices/cromemco-dazzler.c | 4 +- iodevices/imsai-hal.c | 14 +--- iodevices/imsai-vio.c | 150 ++++++++++++++++++++++++----------- iodevices/imsai-vio.h | 4 +- iodevices/proctec-vdm.c | 134 ++++++++++++++++++++++--------- iodevices/proctec-vdm.h | 7 +- 7 files changed, 210 insertions(+), 136 deletions(-) diff --git a/altairsim/srcsim/simio.c b/altairsim/srcsim/simio.c index 09c19e68..3ee97493 100644 --- a/altairsim/srcsim/simio.c +++ b/altairsim/srcsim/simio.c @@ -72,7 +72,6 @@ static BYTE hwctl_in(void), fp_in(void); static void hwctl_out(BYTE), fp_out(BYTE data); static BYTE lpt_status_in(void), lpt_data_in(void); static void lpt_status_out(BYTE), lpt_data_out(BYTE data); -static BYTE kbd_status_in(void), kbd_data_in(void); static void io_no_card_out(BYTE data); #if 0 /* currently not used */ @@ -93,8 +92,8 @@ BYTE (*const port_in[256])(void) = { [ 1] = altair_sio0_data_in, /* " */ [ 2] = lpt_status_in, /* printer status */ [ 3] = lpt_data_in, /* printer data */ - [ 4] = kbd_status_in, /* status VDM keyboard */ - [ 5] = kbd_data_in, /* data VDM keyboard */ + [ 4] = proctec_vdm_kbd_status_in, /* status VDM keyboard */ + [ 5] = proctec_vdm_kbd_in, /* data VDM keyboard */ [ 6] = altair_sio3_status_in, /* SIO 3 connected to socket */ [ 7] = altair_sio3_data_in, /* " */ [ 8] = altair_dsk_status_in, /* MITS 88-DCDD status */ @@ -138,7 +137,7 @@ void (*const port_out[256])(BYTE data) = { [ 19] = altair_sio2_data_out, /* " */ [160] = hwctl_out, /* virtual hardware control */ [161] = host_bdos_out, /* host file I/O hook */ - [200] = proctec_vdm_out, /* Processor Technology VDM */ + [200] = proctec_vdm_ctl_out, /* Processor Technology VDM */ [248] = tarbell_cmd_out, /* Tarbell 1011D command */ [249] = tarbell_track_out, /* Tarbell 1011D track */ [250] = tarbell_sec_out, /* Tarbell 1011D sector */ @@ -384,29 +383,3 @@ static void lpt_status_out(BYTE data) { UNUSED(data); } - -/* - * Return status of the VDM keyboard - */ -static BYTE kbd_status_in(void) -{ - return (BYTE) proctec_kbd_status; -} - -/* - * Return next data byte from the VDM keyboard - */ -static BYTE kbd_data_in(void) -{ - int data; - - if (proctec_kbd_data == -1) - return (BYTE) 0; - - /* take over data and reset status */ - data = proctec_kbd_data; - proctec_kbd_data = -1; - proctec_kbd_status = 1; - - return (BYTE) data; -} diff --git a/iodevices/cromemco-dazzler.c b/iodevices/cromemco-dazzler.c index ea36b08b..86097e61 100644 --- a/iodevices/cromemco-dazzler.c +++ b/iodevices/cromemco-dazzler.c @@ -342,7 +342,7 @@ void cromemco_dazzler_off(void) #ifdef WANT_SDL /* process SDL event */ -static void proc_event(SDL_Event *event) +static void process_event(SDL_Event *event) { UNUSED(event); } @@ -734,7 +734,7 @@ static void update_display(bool tick) static win_funcs_t dazzler_funcs = { open_display, close_display, - proc_event, + process_event, update_display }; #endif diff --git a/iodevices/imsai-hal.c b/iodevices/imsai-hal.c index dc8e7fe0..a974de9d 100644 --- a/iodevices/imsai-hal.c +++ b/iodevices/imsai-hal.c @@ -83,21 +83,11 @@ static int vio_kbd_alive(void) { } static void vio_kbd_status(BYTE *stat) { - *stat = imsai_kbd_status; + *stat = imsai_vio_kbd_status_in(); } static int vio_kbd_in(void) { - int data; - - if (imsai_kbd_data == -1) - return -1; - - /* take over data and reset */ - data = imsai_kbd_data; - imsai_kbd_data = -1; - imsai_kbd_status = 0; - - return data; + return imsai_vio_kbd_in(); } static void vio_kbd_out(BYTE data) { UNUSED(data); diff --git a/iodevices/imsai-vio.c b/iodevices/imsai-vio.c index dc2b14f6..48209213 100644 --- a/iodevices/imsai-vio.c +++ b/iodevices/imsai-vio.c @@ -40,7 +40,9 @@ #include "simglb.h" #include "simmem.h" #include "simport.h" +#ifdef WANT_SDL #include "simsdl.h" +#endif #ifdef HAS_NETSERVER #include "netsrv.h" @@ -55,11 +57,16 @@ static const char *TAG = "VIO"; #include "imsai-vio-charset.h" #include "imsai-vio.h" -#define XOFF 10 /* use some offset inside the window */ -#define YOFF 15 /* for the drawing area */ +#define XOFF 10 /* use some offset inside the window */ +#define YOFF 15 /* for the drawing area */ +#ifdef WANT_SDL +#define KEYBUF_LEN 20 +#endif /* SDL2/X11 stuff */ - int slf = 1; /* scanlines factor, default no lines */ +int slf = 1; /* scanlines factor, default no lines */ +uint8_t bg_color[3] = {48, 48, 48}; /* default background color */ +uint8_t fg_color[3] = {255, 255, 255}; /* default foreground color */ static int xsize, ysize; /* window size */ static int xscale, yscale; static int sx, sy; @@ -67,6 +74,9 @@ static int sx, sy; static SDL_Window *window; static SDL_Renderer *renderer; static int vio_win_id = -1; +static char keybuf[KEYBUF_LEN]; /* typeahead buffer */ +static int keyn, keyin, keyout; +static SDL_mutex *keybuf_mutex; #else /* !WANT_SDL */ static Display *display; static Window window; @@ -81,17 +91,15 @@ static XEvent event; static KeySym key; static char text[10]; #endif /* !WANT_SDL */ - uint8_t bg_color[3] = {48, 48, 48}; /* default background color */ - uint8_t fg_color[3] = {255, 255, 255}; /* default foreground color */ /* VIO stuff */ static int state; /* state on/off for refresh thread */ static int mode; /* video mode written to command port memory */ static int modebuf; /* and double buffer for it */ static int vmode, res, inv; /* video mode, resolution & inverse */ -int imsai_kbd_status, imsai_kbd_data; /* keyboard status & data */ - #if !defined(WANT_SDL) || defined(HAS_NETSERVER) +static int kbd_status, kbd_data; /* keyboard status & data */ + /* UNIX stuff */ static pthread_t thread; #endif @@ -110,6 +118,7 @@ static void open_display(void) renderer = SDL_CreateRenderer(window, -1, (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)); + keybuf_mutex = SDL_CreateMutex(); SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); SDL_RenderClear(renderer); SDL_RenderPresent(renderer); @@ -163,9 +172,8 @@ static void close_display(void) { #ifdef WANT_SDL SDL_DestroyRenderer(renderer); - renderer = NULL; SDL_DestroyWindow(window); - window = NULL; + SDL_DestroyMutex(keybuf_mutex); #else XLockDisplay(display); XFreePixmap(display, pixmap); @@ -352,12 +360,29 @@ static void dc3(BYTE c) #ifdef WANT_SDL /* - * Process a SDL2 event, we are only interested in keyboard input. - * Note that I'm using the event queue as typeahead buffer, saves to - * implement one self. + * Enqueue a keyboard character + */ +static void enqueue_key(char c) +{ + if (keyn == KEYBUF_LEN) + fprintf(stderr, "VIO typeahead buffer full\r\n"); + else { + SDL_LockMutex(keybuf_mutex); + keyn++; + keybuf[keyin++] = c; + if (keyin == KEYBUF_LEN) + keyin = 0; + SDL_UnlockMutex(keybuf_mutex); + } +} + +/* + * Process a SDL2 event */ -static void event_handler(SDL_Event *event) +static void process_event(SDL_Event *event) { + char *p; + /* if there is a keyboard event get it and convert to ASCII */ switch (event->type) { case SDL_WINDOWEVENT: @@ -375,44 +400,34 @@ static void event_handler(SDL_Event *event) } break; case SDL_TEXTINPUT: - if (event->text.windowID == SDL_GetWindowID(window)) { - /* if the last character wasn't processed already do nothing */ - /* keep event in queue until the CPU emulation got current one */ - if (imsai_kbd_status != 0) - return; - - imsai_kbd_data = event->text.text[0]; - imsai_kbd_status = 0; - } + if (event->text.windowID == SDL_GetWindowID(window)) + for (p = event->text.text; *p; p++) + enqueue_key(*p); break; case SDL_KEYDOWN: - if (event->key.windowID == SDL_GetWindowID(window)) { - /* if the last character wasn't processed already do nothing */ - /* keep event in queue until the CPU emulation got current one */ - if (imsai_kbd_status != 0) - return; - + if (event->key.windowID == SDL_GetWindowID(window)) if (!(event->key.keysym.sym & SDLK_SCANCODE_MASK) && ((event->key.keysym.mod & KMOD_CTRL) || - (event->key.keysym.sym < 32))) { - imsai_kbd_data = event->key.keysym.sym & 0x1f; - imsai_kbd_status = 0; - } - } + (event->key.keysym.sym < 32))) + enqueue_key(event->key.keysym.sym & 0x1f); break; default: break; } +} + #ifdef HAS_NETSERVER +static inline void event_handler(void) +{ if (n_flag) { int res = net_device_get(DEV_VIO); if (res >= 0) { - imsai_kbd_data = res; - imsai_kbd_status = 2; + kbd_data = res; + kbd_status = 2; } } -#endif } +#endif #else /* !WANT_SDL */ @@ -425,7 +440,7 @@ static inline void event_handler(void) { /* if the last character wasn't processed already do nothing */ /* keep event in queue until the CPU emulation got current one */ - if (imsai_kbd_status != 0) + if (kbd_status != 0) return; /* if there is a keyboard event get it and convert with keymap */ @@ -433,16 +448,16 @@ static inline void event_handler(void) XNextEvent(display, &event); if ((event.type == KeyPress) && XLookupString(&event.xkey, text, 1, &key, 0) == 1) { - imsai_kbd_data = text[0]; - imsai_kbd_status = 2; + kbd_data = text[0]; + kbd_status = 2; } } #ifdef HAS_NETSERVER if (n_flag) { int res = net_device_get(DEV_VIO); if (res >= 0) { - imsai_kbd_data = res; - imsai_kbd_status = 2; + kbd_data = res; + kbd_status = 2; } } #endif @@ -487,11 +502,13 @@ static void refresh(void) switch (vmode) { case 0: /* Video mode 0: video off, screen blanked */ +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) + event_handler(); +#endif #ifdef WANT_SDL SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); SDL_RenderClear(renderer); #else - event_handler(); XSetForeground(display, gc, black.pixel); XFillRectangle(display, pixmap, gc, 0, 0, xsize, ysize); #endif @@ -500,7 +517,7 @@ static void refresh(void) case 1: /* Video mode 1: display character codes 80-FF */ for (y = 0; y < rows; y++) { sx = XOFF; -#ifndef WANT_SDL +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) event_handler(); #endif for (x = 0; x < cols; x++) { @@ -515,7 +532,7 @@ static void refresh(void) case 2: /* Video mode 2: display character codes 00-7F */ for (y = 0; y < rows; y++) { sx = XOFF; -#ifndef WANT_SDL +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) event_handler(); #endif for (x = 0; x < cols; x++) { @@ -530,7 +547,7 @@ static void refresh(void) case 3: /* Video mode 3: display character codes 00-FF */ for (y = 0; y < rows; y++) { sx = XOFF; -#ifndef WANT_SDL +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) event_handler(); #endif for (x = 0; x < cols; x++) { @@ -585,9 +602,7 @@ static void ws_refresh(void) LOGD(__func__, "MODE change"); } -#ifndef WANT_SDL event_handler(); -#endif int len = rows * cols; int addr; @@ -650,7 +665,7 @@ static void update_display(bool tick) static win_funcs_t vio_funcs = { open_display, close_display, - event_handler, + process_event, update_display }; #endif /* !WANT_SDL */ @@ -737,3 +752,42 @@ void imsai_vio_init(void) } #endif } + +BYTE imsai_vio_kbd_status_in(void) +{ + BYTE data; + +#ifdef WANT_SDL + data = keyn ? 2 : 0; +#else + data = (BYTE) kbd_status; +#endif + + return data; +} + +int imsai_vio_kbd_in(void) +{ + int data; + +#ifdef WANT_SDL + if (keyn) { + SDL_LockMutex(keybuf_mutex); + keyn--; + data = (BYTE) keybuf[keyout++]; + if (keyout == KEYBUF_LEN) + keyout = 0; + SDL_UnlockMutex(keybuf_mutex); + } else + data = -1; +#else + if (kbd_status != 0) { + /* take over data and reset status */ + data = (BYTE) kbd_data; + kbd_status = 0; + } else + data = -1; +#endif + + return data; +} diff --git a/iodevices/imsai-vio.h b/iodevices/imsai-vio.h index 44c9a869..9e92558d 100644 --- a/iodevices/imsai-vio.h +++ b/iodevices/imsai-vio.h @@ -32,8 +32,8 @@ extern int slf; /* VIO scanlines factor */ extern uint8_t bg_color[3]; /* VIO background color */ extern uint8_t fg_color[3]; /* VIO foreground color */ -extern int imsai_kbd_status, imsai_kbd_data; - extern void imsai_vio_init(void), imsai_vio_off(void); +extern BYTE imsai_vio_kbd_status_in(void); +extern int imsai_vio_kbd_in(void); #endif /* !IMSAI_VIO_INC */ diff --git a/iodevices/proctec-vdm.c b/iodevices/proctec-vdm.c index d2f6d253..fed80e9b 100644 --- a/iodevices/proctec-vdm.c +++ b/iodevices/proctec-vdm.c @@ -36,7 +36,9 @@ #include "simglb.h" #include "simmem.h" #include "simport.h" +#ifdef WANT_SDL #include "simsdl.h" +#endif #include "proctec-vdm-charset.h" #include "proctec-vdm.h" @@ -46,17 +48,25 @@ static const char *TAG = "VDM"; #endif -#define XOFF 10 /* use some offset inside the window */ -#define YOFF 15 /* for the drawing area */ +#define XOFF 10 /* use some offset inside the window */ +#define YOFF 15 /* for the drawing area */ +#ifdef WANT_SDL +#define KEYBUF_LEN 20 /* typeahead buffer size */ +#endif /* SDL2/X11 stuff */ - int slf = 1; /* scanlines factor, default no lines */ +int slf = 1; /* scanlines factor, default no lines */ +uint8_t bg_color[3] = {48, 48, 48}; /* default background color */ +uint8_t fg_color[3] = {255, 255, 255}; /* default foreground color */ static int xsize, ysize; /* window size */ static int sx, sy; #ifdef WANT_SDL static SDL_Window *window; static SDL_Renderer *renderer; static int proctec_win_id = -1; +static char keybuf[KEYBUF_LEN]; /* typeahead buffer */ +static int keyn, keyin, keyout; +static SDL_mutex *keybuf_mutex; #else static Display *display; static Window window; @@ -71,14 +81,14 @@ static XEvent event; static KeySym key; static char text[10]; #endif - uint8_t bg_color[3] = {48, 48, 48}; /* default background color */ - uint8_t fg_color[3] = {255, 255, 255}; /* default foreground color */ /* VDM stuff */ static int state; /* state on/off for refresh thread */ static int mode; /* video mode from I/O port */ -int proctec_kbd_status = 1; /* keyboard status */ -int proctec_kbd_data = -1; /* keyboard data */ +#ifndef WANT_SDL +static int kbd_status = 1; /* keyboard status */ +static int kbd_data; /* keyboard data */ +#endif static int first; /* first displayed screen position */ static int beg; /* beginning display line address */ @@ -101,6 +111,7 @@ static void open_display(void) renderer = SDL_CreateRenderer(window, -1, (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)); + keybuf_mutex = SDL_CreateMutex(); SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); SDL_RenderClear(renderer); SDL_RenderPresent(renderer); @@ -156,9 +167,8 @@ static void close_display(void) { #ifdef WANT_SDL SDL_DestroyRenderer(renderer); - renderer = NULL; SDL_DestroyWindow(window); - window = NULL; + SDL_DestroyMutex(keybuf_mutex); #else XLockDisplay(display); XFreePixmap(display, pixmap); @@ -194,12 +204,29 @@ void proctec_vdm_off(void) #ifdef WANT_SDL /* - * Process a SDL event, we are only interested in keyboard input. - * Note that I'm using the event queue as typeahead buffer, saves to - * implement one self. + * Enqueue a keyboard character + */ +static void enqueue_key(char c) +{ + if (keyn == KEYBUF_LEN) + fprintf(stderr, "VDM typeahead buffer full\r\n"); + else { + SDL_LockMutex(keybuf_mutex); + keyn++; + keybuf[keyin++] = c; + if (keyin == KEYBUF_LEN) + keyin = 0; + SDL_UnlockMutex(keybuf_mutex); + } +} + +/* + * Process a SDL event */ -static void event_handler(SDL_Event *event) +static void process_event(SDL_Event *event) { + char *p; + /* if there is a keyboard event get it and convert to ASCII */ switch (event->type) { case SDL_WINDOWEVENT: @@ -217,30 +244,16 @@ static void event_handler(SDL_Event *event) } break; case SDL_TEXTINPUT: - if (event->text.windowID == SDL_GetWindowID(window)) { - /* if the last character wasn't processed already do nothing */ - /* keep event in queue until the CPU emulation got current one */ - if (proctec_kbd_status == 0) - return; - - proctec_kbd_data = event->text.text[0]; - proctec_kbd_status = 0; - } + if (event->text.windowID == SDL_GetWindowID(window)) + for (p = event->text.text; *p; p++) + enqueue_key(*p); break; case SDL_KEYDOWN: - if (event->key.windowID == SDL_GetWindowID(window)) { - /* if the last character wasn't processed already do nothing */ - /* keep event in queue until the CPU emulation got current one */ - if (proctec_kbd_status == 0) - return; - + if (event->key.windowID == SDL_GetWindowID(window)) if (!(event->key.keysym.sym & SDLK_SCANCODE_MASK) && ((event->key.keysym.mod & KMOD_CTRL) || - (event->key.keysym.sym < 32))) { - proctec_kbd_data = event->key.keysym.sym & 0x1f; - proctec_kbd_status = 0; - } - } + (event->key.keysym.sym < 32))) + enqueue_key(event->key.keysym.sym & 0x1f); break; default: break; @@ -277,7 +290,7 @@ static inline void event_handler(void) { /* if the last character wasn't processed already do nothing */ /* keep event in queue until the CPU emulation got current one */ - if (proctec_kbd_status == 0) + if (kbd_status == 0) return; /* if there is a keyboard event get it and convert with keymap */ @@ -285,8 +298,8 @@ static inline void event_handler(void) XNextEvent(display, &event); if ((event.type == KeyPress) && XLookupString(&event.xkey, text, 1, &key, 0) == 1) { - proctec_kbd_data = text[0]; - proctec_kbd_status = 0; + kbd_data = text[0]; + kbd_status = 0; } } } @@ -379,7 +392,7 @@ static void update_display(bool tick) static win_funcs_t proctec_funcs = { open_display, close_display, - event_handler, + process_event, update_display }; @@ -426,7 +439,7 @@ static void *update_display(void *arg) #endif /* !WANT_SDL */ /* I/O port for the VDM */ -void proctec_vdm_out(BYTE data) +void proctec_vdm_ctl_out(BYTE data) { mode = data; first = (data & 0xf0) >> 4; @@ -448,3 +461,48 @@ void proctec_vdm_out(BYTE data) } #endif } + +/* + * Return status of the VDM keyboard + */ +BYTE proctec_vdm_kbd_status_in(void) +{ + BYTE data; + +#ifdef WANT_SDL + data = keyn ? 0 : 1; +#else + data = (BYTE) kbd_status; +#endif + + return data; +} + +/* + * Return next data byte from the VDM keyboard + */ +BYTE proctec_vdm_kbd_in(void) +{ + BYTE data; + +#ifdef WANT_SDL + if (keyn) { + SDL_LockMutex(keybuf_mutex); + keyn--; + data = (BYTE) keybuf[keyout++]; + if (keyout == KEYBUF_LEN) + keyout = 0; + SDL_UnlockMutex(keybuf_mutex); + } else + data = 0; +#else + if (kbd_status == 0) { + /* take over data and reset status */ + data = (BYTE) kbd_data; + kbd_status = 1; + } else + data = 0; +#endif + + return data; +} diff --git a/iodevices/proctec-vdm.h b/iodevices/proctec-vdm.h index 5ff7a03e..0cae5622 100644 --- a/iodevices/proctec-vdm.h +++ b/iodevices/proctec-vdm.h @@ -28,10 +28,9 @@ extern int slf; /* VDM scanlines factor */ extern uint8_t bg_color[3]; /* VDM background color */ extern uint8_t fg_color[3]; /* VDM foreground color */ -extern int proctec_kbd_status; -extern int proctec_kbd_data; - extern void proctec_vdm_off(void); -extern void proctec_vdm_out(BYTE data); +extern void proctec_vdm_ctl_out(BYTE data); +extern BYTE proctec_vdm_kbd_status_in(void); +extern BYTE proctec_vdm_kbd_in(void); #endif /* !PROTEC_VDM_INC */ From 6b8b1395432c64590758bc5705c9d339f0190e2b Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Tue, 7 Jan 2025 03:41:44 +0100 Subject: [PATCH 05/15] fix #ifdef jungle for X11 --- iodevices/cromemco-dazzler.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iodevices/cromemco-dazzler.c b/iodevices/cromemco-dazzler.c index 86097e61..da4f7f33 100644 --- a/iodevices/cromemco-dazzler.c +++ b/iodevices/cromemco-dazzler.c @@ -820,14 +820,13 @@ void cromemco_dazzler_ctl_out(BYTE data) if (display == NULL) open_display(); #endif - state = 1; #ifdef HAS_NETSERVER } else { if (state == 0) ws_clear(); - state = 1; } #endif + state = 1; #if defined(WANT_SDL) && defined(HAS_NETSERVER) if (n_flag) { #endif @@ -849,13 +848,13 @@ void cromemco_dazzler_ctl_out(BYTE data) sleep_for_ms(50); #ifdef HAS_NETSERVER if (!n_flag) { +#endif #ifndef WANT_SDL XLockDisplay(display); XClearWindow(display, window); XSync(display, True); XUnlockDisplay(display); #endif -#endif #ifdef HAS_NETSERVER } else ws_clear(); From 2975d3c184e61c2fa8450d0d1fd87789786c4784 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Tue, 7 Jan 2025 05:53:18 +0100 Subject: [PATCH 06/15] optimize VDM and VIO: use texture and set pixels directly SDL_RenderDrawPoint was slow, now the FPS stays at 60, previously it dropped into the 30's. --- iodevices/cromemco-dazzler.c | 2 +- iodevices/imsai-vio.c | 33 ++++++++++++++++++++++++--------- iodevices/proctec-vdm.c | 33 ++++++++++++++++++++++++--------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/iodevices/cromemco-dazzler.c b/iodevices/cromemco-dazzler.c index da4f7f33..d304b472 100644 --- a/iodevices/cromemco-dazzler.c +++ b/iodevices/cromemco-dazzler.c @@ -69,9 +69,9 @@ static const char *TAG = "DAZZLER"; #define WSIZE 512 static int size = WSIZE; #ifdef WANT_SDL +static int dazzler_win_id = -1; static SDL_Window *window; static SDL_Renderer *renderer; -static int dazzler_win_id = -1; static uint8_t colors[16][3] = { { 0x00, 0x00, 0x00 }, { 0x80, 0x00, 0x00 }, diff --git a/iodevices/imsai-vio.c b/iodevices/imsai-vio.c index 48209213..ca517242 100644 --- a/iodevices/imsai-vio.c +++ b/iodevices/imsai-vio.c @@ -71,9 +71,13 @@ static int xsize, ysize; /* window size */ static int xscale, yscale; static int sx, sy; #ifdef WANT_SDL +static int vio_win_id = -1; static SDL_Window *window; static SDL_Renderer *renderer; -static int vio_win_id = -1; +static SDL_Texture *texture; +static void *pixels; +static int pitch; +static uint8_t color[3]; static char keybuf[KEYBUF_LEN]; /* typeahead buffer */ static int keyn, keyin, keyout; static SDL_mutex *keybuf_mutex; @@ -117,6 +121,8 @@ static void open_display(void) xsize, ysize, 0); renderer = SDL_CreateRenderer(window, -1, (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STREAMING, xsize, ysize); keybuf_mutex = SDL_CreateMutex(); SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); @@ -171,9 +177,10 @@ static void open_display(void) static void close_display(void) { #ifdef WANT_SDL + SDL_DestroyMutex(keybuf_mutex); + SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); - SDL_DestroyMutex(keybuf_mutex); #else XLockDisplay(display); XFreePixmap(display, pixmap); @@ -223,21 +230,26 @@ void imsai_vio_off(void) static inline void set_fg_color(void) { - SDL_SetRenderDrawColor(renderer, - fg_color[0], fg_color[1], fg_color[2], - SDL_ALPHA_OPAQUE); + color[0] = fg_color[0]; + color[1] = fg_color[1]; + color[2] = fg_color[2]; } static inline void set_bg_color(void) { - SDL_SetRenderDrawColor(renderer, - bg_color[0], bg_color[1], bg_color[2], - SDL_ALPHA_OPAQUE); + color[0] = bg_color[0]; + color[1] = bg_color[1]; + color[2] = bg_color[2]; } static inline void draw_point(int x, int y) { - SDL_RenderDrawPoint(renderer, x, y); + uint8_t *p = (uint8_t *) pixels + y * pitch + x * 4; + + p[3] = color[0]; + p[2] = color[1]; + p[1] = color[2]; + p[0] = SDL_ALPHA_OPAQUE; } #else /* !WANT_SDL */ @@ -658,7 +670,10 @@ static void update_display(bool tick) UNUSED(tick); /* update display window */ + SDL_LockTexture(texture, NULL, &pixels, &pitch); refresh(); + SDL_UnlockTexture(texture); + SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); } diff --git a/iodevices/proctec-vdm.c b/iodevices/proctec-vdm.c index fed80e9b..dd5157d8 100644 --- a/iodevices/proctec-vdm.c +++ b/iodevices/proctec-vdm.c @@ -61,9 +61,13 @@ uint8_t fg_color[3] = {255, 255, 255}; /* default foreground color */ static int xsize, ysize; /* window size */ static int sx, sy; #ifdef WANT_SDL +static int proctec_win_id = -1; static SDL_Window *window; static SDL_Renderer *renderer; -static int proctec_win_id = -1; +static SDL_Texture *texture; +static void *pixels; +static int pitch; +static uint8_t color[3]; static char keybuf[KEYBUF_LEN]; /* typeahead buffer */ static int keyn, keyin, keyout; static SDL_mutex *keybuf_mutex; @@ -110,6 +114,8 @@ static void open_display(void) xsize, ysize, 0); renderer = SDL_CreateRenderer(window, -1, (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STREAMING, xsize, ysize); keybuf_mutex = SDL_CreateMutex(); SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); @@ -166,9 +172,10 @@ static void open_display(void) static void close_display(void) { #ifdef WANT_SDL + SDL_DestroyMutex(keybuf_mutex); + SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); - SDL_DestroyMutex(keybuf_mutex); #else XLockDisplay(display); XFreePixmap(display, pixmap); @@ -262,21 +269,26 @@ static void process_event(SDL_Event *event) static inline void set_fg_color(void) { - SDL_SetRenderDrawColor(renderer, - fg_color[0], fg_color[1], fg_color[2], - SDL_ALPHA_OPAQUE); + color[0] = fg_color[0]; + color[1] = fg_color[1]; + color[2] = fg_color[2]; } static inline void set_bg_color(void) { - SDL_SetRenderDrawColor(renderer, - bg_color[0], bg_color[1], bg_color[2], - SDL_ALPHA_OPAQUE); + color[0] = bg_color[0]; + color[1] = bg_color[1]; + color[2] = bg_color[2]; } static inline void draw_point(int x, int y) { - SDL_RenderDrawPoint(renderer, x, y); + uint8_t *p = (uint8_t *) pixels + y * pitch + x * 4; + + p[3] = color[0]; + p[2] = color[1]; + p[1] = color[2]; + p[0] = SDL_ALPHA_OPAQUE; } #else /* !WANT_SDL */ @@ -384,7 +396,10 @@ static void update_display(bool tick) if (state) { /* update display window */ + SDL_LockTexture(texture, NULL, &pixels, &pitch); refresh(); + SDL_UnlockTexture(texture); + SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); } } From d98ed6ccf67d4a5fc996a52e6853fda6542b08e9 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Tue, 7 Jan 2025 06:25:08 +0100 Subject: [PATCH 07/15] frontpanel text display clean-up Make fps display work in 3-D mode. Don't cut of descenders of font. Don't overlap fps and cursor position display. --- frontpanel/lp_font.c | 2 +- frontpanel/lp_window.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/frontpanel/lp_font.c b/frontpanel/lp_font.c index 4b190599..d2f4a570 100644 --- a/frontpanel/lp_font.c +++ b/frontpanel/lp_font.c @@ -116,7 +116,7 @@ void makeRasterFont(void) fontOffset = glGenLists(128); for (i = 32; i < 127; i++) { glNewList(i + fontOffset, GL_COMPILE); - glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, rasters[i - 32]); + glBitmap(8, 13, 0.0, 0.0, 10.0, 0.0, rasters[i - 32]); glEndList(); } } diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c index 5c82c506..c721f8da 100644 --- a/frontpanel/lp_window.c +++ b/frontpanel/lp_window.c @@ -1185,17 +1185,19 @@ void Lpanel_initGraphics(Lpanel_t *p) void Lpanel_draw_stats(Lpanel_t *p) { + glColor3f(1., 1., 0.); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0., p->window_xsize, 0., p->window_ysize, .1, 1000.); - glMatrixMode(GL_MODELVIEW); glPushMatrix(); + glLoadIdentity(); glTranslatef(0., 0., -10.); - glDisable(GL_DEPTH_TEST); - glColor3f(1., 1., 0.); snprintf(p->perf_txt, sizeof(p->perf_txt), "fps:%d sps:%d", p->frames_per_second, p->samples_per_second); printStringAt(p->perf_txt, p->bbox.xyz_min[0] + .2, p->bbox.xyz_min[1] + .2); @@ -1204,6 +1206,7 @@ void Lpanel_draw_stats(Lpanel_t *p) glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); + glEnable(GL_DEPTH_TEST); } @@ -1230,7 +1233,7 @@ void Lpanel_draw_cursor(Lpanel_t *p) glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - glTranslatef(0., 0., -10.); + glTranslatef(200., 0., -10.); printStringAt(p->cursor_txt, p->cursor_textpos[0], p->cursor_textpos[1]); From 8f8d853cf46314a69c7df8bdb14a208530e3bb8e Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Tue, 7 Jan 2025 06:47:55 +0100 Subject: [PATCH 08/15] fix copyrights --- frontpanel/COPYING | 2 +- frontpanel/frontpanel.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontpanel/COPYING b/frontpanel/COPYING index a7ce5287..7f1cf991 100644 --- a/frontpanel/COPYING +++ b/frontpanel/COPYING @@ -1,7 +1,7 @@ /* Copyright (c) 2007-2008, John Kichury - C and SDL2 conversion is Copyright (c) 2024-2025, Thomas Eberhardt + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt This software is freely distributable free of charge and without license fees with the following conditions: diff --git a/frontpanel/frontpanel.h b/frontpanel/frontpanel.h index c35a7f8a..fc098034 100644 --- a/frontpanel/frontpanel.h +++ b/frontpanel/frontpanel.h @@ -1,7 +1,7 @@ // frontpanel.h frontpanel api include file /* Copyright (c) 2007-2008, John Kichury - C and SDL2 conversion is Copyright (c) 2024-2025, Thomas Eberhardt + C conversion and SDL2 support is Copyright (c) 2024-2025, Thomas Eberhardt This software is freely distributable free of charge and without license fees with the following conditions: From 2ffb5aa689b2e4c22b768b13090ae39984d5327d Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Tue, 7 Jan 2025 22:13:26 +0100 Subject: [PATCH 09/15] fix X11 compilation on macOS; don't just crash when frontpanel openWindow fails --- altairsim/srcsim/Makefile | 2 +- cromemcosim/srcsim/Makefile | 2 +- frontpanel/Makefile | 7 +++++++ frontpanel/lp_gfx.c | 15 ++++++--------- frontpanel/lp_main.c | 11 +++++++++-- imsaisim/srcsim/Makefile | 2 +- intelmdssim/srcsim/Makefile | 2 +- 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/altairsim/srcsim/Makefile b/altairsim/srcsim/Makefile index bad492a7..c36305a8 100644 --- a/altairsim/srcsim/Makefile +++ b/altairsim/srcsim/Makefile @@ -72,7 +72,7 @@ PLAT_LDLIBS = -lX11 else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib -PLAT_LDLIBS = -LX11 +PLAT_LDLIBS = -lX11 endif endif ### diff --git a/cromemcosim/srcsim/Makefile b/cromemcosim/srcsim/Makefile index 182777a6..52701720 100644 --- a/cromemcosim/srcsim/Makefile +++ b/cromemcosim/srcsim/Makefile @@ -79,7 +79,7 @@ PLAT_LDLIBS = -lX11 else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib -PLAT_LDLIBS = -LX11 +PLAT_LDLIBS = -lX11 endif endif ### diff --git a/frontpanel/Makefile b/frontpanel/Makefile index 405cd3be..aadc1c8c 100644 --- a/frontpanel/Makefile +++ b/frontpanel/Makefile @@ -23,6 +23,13 @@ else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers \ -I/Library/Frameworks/SDL2_image.framework/Headers endif +else +ifeq ($(TARGET_OS),BSD) +PLAT_INCS = -I/usr/local/include +else ifeq ($(TARGET_OS),LINUX) +else ifeq ($(TARGET_OS),OSX) +PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include +endif endif ### ### END SDL2 VARIABLES diff --git a/frontpanel/lp_gfx.c b/frontpanel/lp_gfx.c index b7c203a6..6d882475 100644 --- a/frontpanel/lp_gfx.c +++ b/frontpanel/lp_gfx.c @@ -661,7 +661,6 @@ int lpTextures_addTexture(lpTextures_t *p, char *fname) texture_t *tp; #ifdef WANT_SDL SDL_Surface *surface, *temp_surface; - SDL_PixelFormat *format; #else unsigned char *pixels; #endif @@ -676,11 +675,9 @@ int lpTextures_addTexture(lpTextures_t *p, char *fname) temp_surface = IMG_Load(fname); if (!temp_surface) return 0; - /* convert loaded image to RGB pixels */ - format = SDL_AllocFormat(SDL_PIXELFORMAT_RGB24); - surface = SDL_ConvertSurface(temp_surface, format, 0); + /* convert loaded image to RGBA32 pixels */ + surface = SDL_ConvertSurfaceFormat(temp_surface, SDL_PIXELFORMAT_RGBA32, 0); SDL_FreeSurface(temp_surface); - SDL_FreeFormat(format); if (!surface) return 0; tp->imgXsize = surface->w; @@ -835,10 +832,10 @@ int lpTextures_downloadTextures(lpTextures_t *p) glGenTextures(1, (GLuint *) &tp->bind_id); glBindTexture(GL_TEXTURE_2D, tp->bind_id); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, tp->imgZsize, tp->texSsize, tp->texTsize, 0, tp->format, GL_UNSIGNED_BYTE, tp->texels); diff --git a/frontpanel/lp_main.c b/frontpanel/lp_main.c index 1b2988ed..4d39f85d 100644 --- a/frontpanel/lp_main.c +++ b/frontpanel/lp_main.c @@ -21,6 +21,7 @@ #include #include +#include #ifdef WANT_SDL #include #include @@ -65,7 +66,10 @@ static void *lp_mainloop_thread(void *n) // printf("mainloop thread starting\n"); thread_info.running = 1; - Lpanel_openWindow(panel, "FrontPanel"); + if (!Lpanel_openWindow(panel, "FrontPanel")) { + fprintf(stderr, "Can't open FrontPanel window\n"); + exit(EXIT_FAILURE); + } t1 = frate_gettime(); framerate_start_frame(); @@ -288,7 +292,10 @@ void fp_openWindow(void) { data_sample_lock = SDL_CreateMutex(); - Lpanel_openWindow(panel, "FrontPanel"); + if (!Lpanel_openWindow(panel, "FrontPanel")) { + fprintf(stderr, "Can't open FrontPanel window\n"); + exit(EXIT_FAILURE); + } Lpanel_initGraphics(panel); } diff --git a/imsaisim/srcsim/Makefile b/imsaisim/srcsim/Makefile index 8579d951..48ba0731 100644 --- a/imsaisim/srcsim/Makefile +++ b/imsaisim/srcsim/Makefile @@ -80,7 +80,7 @@ PLAT_LDLIBS = -lX11 else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib -PLAT_LDLIBS = -LX11 +PLAT_LDLIBS = -lX11 endif endif ### diff --git a/intelmdssim/srcsim/Makefile b/intelmdssim/srcsim/Makefile index 7b0eb493..10d005cf 100644 --- a/intelmdssim/srcsim/Makefile +++ b/intelmdssim/srcsim/Makefile @@ -71,7 +71,7 @@ PLAT_LDLIBS = -lX11 else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -I/opt/X11/include -I/opt/local/include -I/usr/local/include PLAT_LDFLAGS = -L/opt/X11/lib -L/usr/local/lib -PLAT_LDLIBS = -LX11 +PLAT_LDLIBS = -lX11 endif endif ### From 6228b895092811e0220c2f4da695d23470415944 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Wed, 8 Jan 2025 04:29:28 +0100 Subject: [PATCH 10/15] 32-bit depth buffer needed for macOS native OpenGL, clean-up frontpanel --- frontpanel/lp_gfx.c | 76 ++++++++++++++++++++-------------- frontpanel/lp_main.c | 1 - frontpanel/lp_window.c | 93 ++++++++++++++++++------------------------ frontpanel/lpanel.c | 72 ++++++++++++++------------------ 4 files changed, 116 insertions(+), 126 deletions(-) diff --git a/frontpanel/lp_gfx.c b/frontpanel/lp_gfx.c index 6d882475..528261f0 100644 --- a/frontpanel/lp_gfx.c +++ b/frontpanel/lp_gfx.c @@ -239,25 +239,23 @@ void lpObject_draw(lpObject_t *p) // glDisable(GL_DEPTH_TEST); - if (p->have_normals) { - glEnable(GL_LIGHTING); - if (p->material) - lp_bind_material(p->material); - } else { - glDisable(GL_LIGHTING); - glColor3fv(p->color); - } - if (p->texture_num) { glEnable(GL_TEXTURE_2D); + lpTextures_bindTexture(p->textures, p->texture_num); + if (p->envmapped) { glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); } - } else { - glDisable(GL_TEXTURE_2D); } + if (p->have_normals) { + glEnable(GL_LIGHTING); + if (p->material) + lp_bind_material(p->material); + } else + glColor3fv(p->color); + glPushMatrix(); glRotatef(p->rotate[2], 1., 0., 0.); @@ -267,30 +265,37 @@ void lpObject_draw(lpObject_t *p) for (i = 0; i < p->num_elements; i++) lpElement_draw(p->elements[i]); + if (p->have_normals) + glDisable(GL_LIGHTING); + obj = p->instance_object; while (obj) { if (!obj->referenced) { + glEnable(GL_LIGHTING); + if (obj->have_normals) { - glEnable(GL_LIGHTING); if (obj->material) lp_bind_material(obj->material); - } else { - glEnable(GL_LIGHTING); + } else glColor3fv(obj->color); - } for (i = 0; i < obj->num_elements; i++) lpElement_draw(obj->elements[i]); + + glDisable(GL_LIGHTING); } obj = obj->instance_object; } glPopMatrix(); - if (p->envmapped) { - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); + if (p->texture_num) { + if (p->envmapped) { + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + } + glDisable(GL_TEXTURE_2D); } } @@ -307,8 +312,6 @@ void lpObject_draw_refoverride(lpObject_t *p, int refoverride) glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); } - } else { - glDisable(GL_TEXTURE_2D); } if (p->have_normals) { @@ -316,18 +319,15 @@ void lpObject_draw_refoverride(lpObject_t *p, int refoverride) if (p->material) lp_bind_material(p->material); } else { - glDisable(GL_LIGHTING); if (refoverride != 2) glColor3fv(p->color); } glPushMatrix(); -#if 1 glRotatef(p->rotate[2], 1., 0., 0.); glRotatef(p->rotate[0], 1., 0., 0.); glRotatef(p->rotate[1], 1., 0., 0.); -#endif for (i = 0; i < p->num_elements; i++) lpElement_draw(p->elements[i]); @@ -335,22 +335,31 @@ void lpObject_draw_refoverride(lpObject_t *p, int refoverride) obj = p->instance_object; while (obj) { + glEnable(GL_LIGHTING); + if (obj->have_normals) { - glEnable(GL_LIGHTING); if (p->material) lp_bind_material(p->material); - } else { - glEnable(GL_LIGHTING); + } else glColor3fv(obj->color); - } for (i = 0; i < obj->num_elements; i++) lpElement_draw(obj->elements[i]); + glDisable(GL_LIGHTING); + obj = obj->instance_object; } glPopMatrix(); + + if (p->texture_num) { + if (p->envmapped) { + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + } + glDisable(GL_TEXTURE_2D); + } } void lpObject_genGraphicsData(lpObject_t *p) @@ -499,8 +508,6 @@ void lpElement_draw(lpElement_t *p) #if 0 if (p->have_tcoords) glEnable(GL_TEXTURE_2D); - else - glDisable(GL_TEXTURE_2D); #endif switch (p->type) { @@ -543,6 +550,11 @@ void lpElement_draw(lpElement_t *p) } } glEnd(); + +#if 0 + if (p->have_tcoords) + glDisable(GL_TEXTURE_2D); +#endif } void lpElement_genGraphicsData(lpElement_t *p) @@ -898,8 +910,10 @@ lpBBox_t *lpBBox_new(void) void lpBBox_delete(lpBBox_t *p) { - lpBBox_fini(p); - free(p); + if (p) { + lpBBox_fini(p); + free(p); + } } void lpBBox_init(lpBBox_t *p) diff --git a/frontpanel/lp_main.c b/frontpanel/lp_main.c index 4d39f85d..f9ed607c 100644 --- a/frontpanel/lp_main.c +++ b/frontpanel/lp_main.c @@ -296,7 +296,6 @@ void fp_openWindow(void) fprintf(stderr, "Can't open FrontPanel window\n"); exit(EXIT_FAILURE); } - Lpanel_initGraphics(panel); } void fp_procEvent(SDL_Event *event) diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c index c721f8da..f500525a 100644 --- a/frontpanel/lp_window.c +++ b/frontpanel/lp_window.c @@ -112,7 +112,6 @@ void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) if (event->button.windowID != SDL_GetWindowID(p->window)) break; - SDL_GL_MakeCurrent(p->window, p->cx); if (!Lpanel_pick(p, event->button.button - 1, 1, event->button.x, event->button.y)) { if (event->button.button == SDL_BUTTON_LEFT) { // left mousebutton ? @@ -127,7 +126,6 @@ void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) if (event->button.windowID != SDL_GetWindowID(p->window)) break; - SDL_GL_MakeCurrent(p->window, p->cx); if (!Lpanel_pick(p, event->button.button - 1, 0, event->button.x, event->button.y)) { if (event->button.button == SDL_BUTTON_LEFT) @@ -495,8 +493,8 @@ LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT msg, WPARAM wParam, LPARAM lPa glViewport(0, 0, p->window_xsize, p->window_ysize); glGetIntegerv(GL_VIEWPORT, p->viewport); - setProjection(false); - setModelview(false); + Lpanel_setProjection(p, false); + Lpanel_setModelview(p, false); return 0; @@ -799,7 +797,8 @@ int Lpanel_openWindow(Lpanel_t *p, const char *title) SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); if ((p->cx = SDL_GL_CreateContext(p->window)) == NULL) { fprintf(stderr, "Can't create context: %s\n", SDL_GetError()); return 0; @@ -972,6 +971,18 @@ int Lpanel_openWindow(Lpanel_t *p, const char *title) makeRasterFont(); Lpanel_make_cursor_text(p); +#ifdef WANT_SDL + SDL_GL_SwapWindow(p->window); +#else +#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) + SwapBuffers(p->hDC); + // UpdateWindow(p->hWnd); + // Sleep(100); +#else + glXSwapBuffers(p->dpy, p->window); +#endif +#endif + return 1; } @@ -1015,8 +1026,7 @@ void Lpanel_setModelview(Lpanel_t *p, bool dopick) float x, y; if (!dopick) - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + glLoadIdentity(); switch (p->view.projection) { case LP_ORTHO: @@ -1040,27 +1050,19 @@ void Lpanel_setModelview(Lpanel_t *p, bool dopick) void Lpanel_setProjection(Lpanel_t *p, bool dopick) { + if (!dopick) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + } + switch (p->view.projection) { case LP_ORTHO: - if (!dopick) { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - } - glOrtho(p->bbox.xyz_min[0], p->bbox.xyz_max[0], p->bbox.xyz_min[1], p->bbox.xyz_max[1], .1, 1000.); - - if (!dopick) - glMatrixMode(GL_MODELVIEW); break; - case LP_PERSPECTIVE: - if (!dopick) { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - } - + case LP_PERSPECTIVE: { // gluPerspective(p->view.fovy, p->view.aspect, p->view.znear, p->view.zfar); double deltaz = p->view.zfar - p->view.znear; double cotangent = 1 / tan(p->view.fovy / 2 * M_PI / 180); @@ -1071,11 +1073,12 @@ void Lpanel_setProjection(Lpanel_t *p, bool dopick) 0, 0, -2 * p->view.znear *p->view.zfar / deltaz, 0 }; glMultMatrixd(m); - - if (!dopick) - glMatrixMode(GL_MODELVIEW); + } break; } + + if (!dopick) + glMatrixMode(GL_MODELVIEW); } #if !defined(__MINGW32__) && !defined(_WIN32) && !defined(_WIN32_) && !defined(__WIN32__) @@ -1111,12 +1114,12 @@ void Lpanel_doPickProjection(Lpanel_t *p) // glOrtho(p->bbox.xyz_min[0], p->bbox.xyz_max[0], // p->bbox.xyz_min[1], p->bbox.xyz_max[1], // .1, 1000.); - Lpanel_setProjection(p, 1); + Lpanel_setProjection(p, true); } void Lpanel_doPickModelview(Lpanel_t *p) { - Lpanel_setModelview(p, 1); + Lpanel_setModelview(p, true); // glTranslatef(0., 0., -10.); // so objects at z=0 don't get clipped } @@ -1128,6 +1131,7 @@ void Lpanel_initGraphics(Lpanel_t *p) // define lights in case we use them + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLightfv(GL_LIGHT0, GL_POSITION, light_pos0); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); @@ -1140,11 +1144,9 @@ void Lpanel_initGraphics(Lpanel_t *p) glEnable(GL_LIGHT0); if (p->view.do_depthtest) glEnable(GL_DEPTH_TEST); - glPolygonOffset(0., -10.); // glEnable(GL_LIGHT1); glDisable(GL_LIGHTING); - // glEnable(GL_LIGHTING); glClearColor(0., 0., 0., 1.); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mtl_amb); @@ -1156,18 +1158,6 @@ void Lpanel_initGraphics(Lpanel_t *p) glEnable(GL_NORMALIZE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#ifdef WANT_SDL - SDL_GL_SwapWindow(p->window); -#else -#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) - SwapBuffers(p->hDC); - // UpdateWindow(p->hWnd); - // Sleep(100); -#else - glXSwapBuffers(p->dpy, p->window); -#endif -#endif - // download any textures that may have been read in lpTextures_downloadTextures(&p->textures); @@ -1176,18 +1166,12 @@ void Lpanel_initGraphics(Lpanel_t *p) glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); } - - p->cursor[0] = (p->bbox.xyz_max[0] + p->bbox.xyz_min[0]) * .5; - p->cursor[1] = (p->bbox.xyz_max[1] + p->bbox.xyz_min[1]) * .5; - makeRasterFont(); - Lpanel_make_cursor_text(p); } void Lpanel_draw_stats(Lpanel_t *p) { - glColor3f(1., 1., 0.); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); + if (p->view.do_depthtest) + glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -1198,6 +1182,7 @@ void Lpanel_draw_stats(Lpanel_t *p) glLoadIdentity(); glTranslatef(0., 0., -10.); + glColor3f(1., 1., 0.); snprintf(p->perf_txt, sizeof(p->perf_txt), "fps:%d sps:%d", p->frames_per_second, p->samples_per_second); printStringAt(p->perf_txt, p->bbox.xyz_min[0] + .2, p->bbox.xyz_min[1] + .2); @@ -1207,23 +1192,24 @@ void Lpanel_draw_stats(Lpanel_t *p) glMatrixMode(GL_MODELVIEW); glPopMatrix(); - glEnable(GL_DEPTH_TEST); + if (p->view.do_depthtest) + glEnable(GL_DEPTH_TEST); } void Lpanel_draw_cursor(Lpanel_t *p) { float size = 0.1; + if (p->view.do_depthtest) + glDisable(GL_DEPTH_TEST); + glColor3f(1., 1., 0.); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); glBegin(GL_LINES); glVertex3f(p->cursor[0] - size, p->cursor[1] - size, p->cursor[2]); glVertex3f(p->cursor[0] + size, p->cursor[1] + size, p->cursor[2]); glVertex3f(p->cursor[0] - size, p->cursor[1] + size, p->cursor[2]); glVertex3f(p->cursor[0] + size, p->cursor[1] - size, p->cursor[2]); - glEnd(); glMatrixMode(GL_PROJECTION); @@ -1242,7 +1228,8 @@ void Lpanel_draw_cursor(Lpanel_t *p) glMatrixMode(GL_MODELVIEW); glPopMatrix(); - glEnable(GL_DEPTH_TEST); + if (p->view.do_depthtest) + glEnable(GL_DEPTH_TEST); } void Lpanel_inc_cursor(Lpanel_t *p, float x, float y) diff --git a/frontpanel/lpanel.c b/frontpanel/lpanel.c index bd2dd4e3..c875b6d5 100644 --- a/frontpanel/lpanel.c +++ b/frontpanel/lpanel.c @@ -977,32 +977,20 @@ void Lpanel_draw(Lpanel_t *p) #endif if (p->view.redo_projections) { - Lpanel_setProjection(p, 0); - Lpanel_setModelview(p, 0); + Lpanel_setProjection(p, false); + Lpanel_setModelview(p, false); p->view.redo_projections = false; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw graphics objects - // glEnable(GL_LIGHTING); - - for (i = 0; i < p->num_objects; i++) { - if (p->objects[i]->is_alpha) - continue; - - if (p->objects[i]->texture_num) { - lpTextures_bindTexture(&p->textures, p->objects[i]->texture_num); - } - if (p->objects[i]->have_normals) - glEnable(GL_LIGHTING); - lpObject_draw(p->objects[i]); - } + for (i = 0; i < p->num_objects; i++) + if (!p->objects[i]->is_alpha) + lpObject_draw(p->objects[i]); // draw lights - glDisable(GL_TEXTURE_2D); - glDisable(GL_LIGHTING); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(0., -10.); @@ -1015,32 +1003,24 @@ void Lpanel_draw(Lpanel_t *p) p->switches[i]->drawFunc(p->switches[i]); if (p->alpha_objects) { - // glDisable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - for (i = 0; i < p->num_alpha_objects; i++) { - if (p->alpha_objects[i]->texture_num) { - lpTextures_bindTexture(&p->textures, - p->alpha_objects[i]->texture_num); - } - if (p->alpha_objects[i]->have_normals) - glEnable(GL_LIGHTING); + for (i = 0; i < p->num_alpha_objects; i++) lpObject_draw(p->alpha_objects[i]); - } - // glEnable(GL_DEPTH_TEST); + + glDisable(GL_BLEND); } - glDisable(GL_TEXTURE_2D); glDisable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); - if (p->do_cursor) { - glEnable(GL_POLYGON_OFFSET_LINE); + if (p->do_cursor) Lpanel_draw_cursor(p); - glDisable(GL_POLYGON_OFFSET_LINE); - } if (p->do_stats) Lpanel_draw_stats(p); + glDisable(GL_POLYGON_OFFSET_LINE); + #ifdef WANT_SDL SDL_GL_SwapWindow(p->window); #else @@ -1089,24 +1069,29 @@ int Lpanel_pick(Lpanel_t *p, int button, int state, int x, int y) return num_picked; } +#ifdef WANT_SDL + SDL_GL_MakeCurrent(p->window, p->cx); +#endif + namebuf[0] = 0; glSelectBuffer(500, &namebuf[0]); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); + glGetIntegerv(GL_VIEWPORT, p->viewport); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - // gluPickMatrix ((GLdouble) x, (GLdouble) (window_ysize - y), 1.0, 1.0, viewport); glTranslatef(p->viewport[2] - 2 * (x - p->viewport[0]), p->viewport[3] - 2 * (p->window_ysize - y - p->viewport[1]), 0); glScalef(p->viewport[2], p->viewport[3], 1.0); - Lpanel_doPickProjection(p); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); + glLoadIdentity(); Lpanel_doPickModelview(p); // draw switches @@ -1114,6 +1099,7 @@ int Lpanel_pick(Lpanel_t *p, int button, int state, int x, int y) for (i = 0; i < p->num_switches; i++) lpSwitch_drawForPick(p->switches[i]); + glPopName(); num_picked = glRenderMode(GL_RENDER); if (num_picked) { @@ -1133,7 +1119,7 @@ int Lpanel_pick(Lpanel_t *p, int button, int state, int x, int y) glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + glRenderMode(GL_RENDER); return num_picked; @@ -1367,12 +1353,16 @@ bool Lpanel_readConfig(Lpanel_t *p, const char *_fname) p->curr_object->have_normals = true; } } else if (!strcmp(token, "object")) { - p->curr_object = Lpanel_addObject(p); - lpObject_setTextureManager(p->curr_object, &p->textures); - if (gtoken(buffer, token, TOKENSIZE, &pos)) - lpObject_setName(p->curr_object, token); - p->curr_element = NULL; - p->curr_vertex = NULL; + if (!(p->curr_object = Lpanel_addObject(p))) { + printf("could not allocate memory for object.\n"); + bailout = true; + } else { + lpObject_setTextureManager(p->curr_object, &p->textures); + if (gtoken(buffer, token, TOKENSIZE, &pos)) + lpObject_setName(p->curr_object, token); + p->curr_element = NULL; + p->curr_vertex = NULL; + } } else if (!strcmp(token, "perspective")) { p->view.projection = LP_PERSPECTIVE; } else if (!strcmp(token, "polygon")) { From a88743453bf4e1268740e80a9a0897dbd9eb228e Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Wed, 8 Jan 2025 04:56:57 +0100 Subject: [PATCH 11/15] reset GL context attributes; don't install SDL signal handlers The GL context attributes also apply to the other accelerated windows (Dazzler, VDM, VIO), so reset them after creating the frontpanel context. Don't install SDL signal handlers, we have our own. --- frontpanel/lp_window.c | 1 + z80core/simsdl.c | 1 + 2 files changed, 2 insertions(+) diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c index f500525a..e81bd977 100644 --- a/frontpanel/lp_window.c +++ b/frontpanel/lp_window.c @@ -803,6 +803,7 @@ int Lpanel_openWindow(Lpanel_t *p, const char *title) fprintf(stderr, "Can't create context: %s\n", SDL_GetError()); return 0; } + SDL_GL_ResetAttributes(); if (SDL_GL_MakeCurrent(p->window, p->cx) < 0) { fprintf(stderr, "Can't make window current to context: %s\n", SDL_GetError()); return 0; diff --git a/z80core/simsdl.c b/z80core/simsdl.c index e8022282..76e2a021 100644 --- a/z80core/simsdl.c +++ b/z80core/simsdl.c @@ -46,6 +46,7 @@ int main(int argc, char *argv[]) int i, status; args_t args = {argc, argv}; + SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { fprintf(stderr, "Can't initialize SDL: %s\n", SDL_GetError()); return EXIT_FAILURE; From d4d8f75a4a3ca6d6e082877665aaa8d91ae5dc81 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Wed, 8 Jan 2025 05:31:33 +0100 Subject: [PATCH 12/15] add mouse wheel support for zooming in/out of the 3D view --- frontpanel/lp_window.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c index e81bd977..3b9b4bf6 100644 --- a/frontpanel/lp_window.c +++ b/frontpanel/lp_window.c @@ -290,6 +290,14 @@ void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) } break; + case SDL_MOUSEWHEEL: + if (event->wheel.direction == SDL_MOUSEWHEEL_NORMAL) + p->view.pan[2] += event->wheel.preciseY / 5.0; + else + p->view.pan[2] -= event->wheel.preciseY / 5.0; + p->view.redo_projections = true; + break; + default: break; } From 793815a50f22bfe648e84bbc6dde7f3e24c0f3d4 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Wed, 8 Jan 2025 11:33:10 +0100 Subject: [PATCH 13/15] add mouse wheel support for X11; use 24-bit depth buffer; version 2.1C --- frontpanel/lp_main.c | 7 +++--- frontpanel/lp_window.c | 53 ++++++++++++++++++++++++++---------------- frontpanel/lpanel.c | 6 ++--- frontpanel/lpanel.h | 5 ++-- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/frontpanel/lp_main.c b/frontpanel/lp_main.c index f9ed607c..e43502a2 100644 --- a/frontpanel/lp_main.c +++ b/frontpanel/lp_main.c @@ -253,12 +253,13 @@ int fp_init(const char *cfg_fname) int fp_init2(const char *cfg_root_path, const char *cfg_fname, int size) { - printf("FrontPanel Simulator v2.1 Copyright (C) 2007-2015 by John Kichury\n"); + printf("FrontPanel Simulator v2.1C Copyright (C) 2007-2015 by John Kichury\n"); +#ifdef WANT_SDL + printf("SDL2 version Copyright (C) 2024-2025 by Thomas Eberhardt\n"); +#else #if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) printf("Windows version Copyright (C) 2014 by Stefano Bodrato\n"); #endif -#ifdef WANT_SDL - printf("SDL2 version Copyright (C) 2024-2025 by Thomas Eberhardt\n"); #endif // allocate & initialize panel and parser instance diff --git a/frontpanel/lp_window.c b/frontpanel/lp_window.c index 3b9b4bf6..81267a26 100644 --- a/frontpanel/lp_window.c +++ b/frontpanel/lp_window.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -47,7 +48,7 @@ #ifndef WANT_SDL #if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) -const char FPClassName[] = "FrontPanel 2.1"; +const char FPClassName[] = "FrontPanel 2.1C"; #else static int RGBA_DB_attributes[] = { GLX_RGBA, @@ -74,7 +75,8 @@ static GLfloat mtl_spec[] = { 0.0, 0.0, 0.0, 1.0 }; static GLfloat mtl_shine[] = { 0.0 }; static GLfloat mtl_emission[] = { 0.0, 0.0, 0.0, 1.0 }; -static int mousex, mousey, omx, omy, lmouse; +static int mousex, mousey, omx, omy; +static bool lmouse; #ifdef WANT_SDL @@ -112,10 +114,10 @@ void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) if (event->button.windowID != SDL_GetWindowID(p->window)) break; - if (!Lpanel_pick(p, event->button.button - 1, 1, + if (!Lpanel_pick(p, event->button.button - 1, true, event->button.x, event->button.y)) { if (event->button.button == SDL_BUTTON_LEFT) { // left mousebutton ? - lmouse = 1; + lmouse = true; mousex = event->button.x; mousey = event->button.y; } @@ -126,10 +128,10 @@ void Lpanel_procEvent(Lpanel_t *p, SDL_Event *event) if (event->button.windowID != SDL_GetWindowID(p->window)) break; - if (!Lpanel_pick(p, event->button.button - 1, 0, + if (!Lpanel_pick(p, event->button.button - 1, false, event->button.x, event->button.y)) { if (event->button.button == SDL_BUTTON_LEFT) - lmouse = 0; + lmouse = false; } break; @@ -463,7 +465,7 @@ LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT msg, WPARAM wParam, LPARAM lPa return 0; case WM_LBUTTONDOWN: - if (!Lpanel_pick(p, 0, 1, LOWORD(lParam), HIWORD(lParam))) { + if (!Lpanel_pick(p, 0, true, LOWORD(lParam), HIWORD(lParam))) { mousex = LOWORD(lParam); mousey = HIWORD(lParam); lmouse = true; @@ -471,7 +473,7 @@ LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT msg, WPARAM wParam, LPARAM lPa return 0; case WM_LBUTTONUP: - if (!Lpanel_pick(p, 0, 0, LOWORD(lParam), HIWORD(lParam))) + if (!Lpanel_pick(p, 0, false, LOWORD(lParam), HIWORD(lParam))) lmouse = false; return 0; @@ -579,21 +581,31 @@ void Lpanel_procEvents(Lpanel_t *p) break; case ButtonPress: - if (!Lpanel_pick(p, event.xbutton.button - 1, 1, - event.xbutton.x, event.xbutton.y)) { - if (event.xbutton.button == 1) { // left mousebutton ? - lmouse = 1; - mousex = event.xbutton.x; - mousey = event.xbutton.y; + if (event.xbutton.button == 4) { + p->view.pan[2] += 0.2; + p->view.redo_projections = true; + } else if (event.xbutton.button == 5) { + p->view.pan[2] -= 0.2; + p->view.redo_projections = true; + } else { + if (!Lpanel_pick(p, event.xbutton.button - 1, true, + event.xbutton.x, event.xbutton.y)) { + if (event.xbutton.button == 1) { // left mousebutton? + lmouse = true; + mousex = event.xbutton.x; + mousey = event.xbutton.y; + } } } break; case ButtonRelease: - if (!Lpanel_pick(p, event.xbutton.button - 1, 0, - event.xbutton.x, event.xbutton.y)) { - if (event.xbutton.button == 1) - lmouse = 0; + if (event.xbutton.button < 4) { + if (!Lpanel_pick(p, event.xbutton.button - 1, false, + event.xbutton.x, event.xbutton.y)) { + if (event.xbutton.button == 1) + lmouse = false; + } } break; @@ -805,7 +817,7 @@ int Lpanel_openWindow(Lpanel_t *p, const char *title) SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); if ((p->cx = SDL_GL_CreateContext(p->window)) == NULL) { fprintf(stderr, "Can't create context: %s\n", SDL_GetError()); @@ -1090,7 +1102,8 @@ void Lpanel_setProjection(Lpanel_t *p, bool dopick) glMatrixMode(GL_MODELVIEW); } -#if !defined(__MINGW32__) && !defined(_WIN32) && !defined(_WIN32_) && !defined(__WIN32__) +#if !(defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__)) || \ + defined(WANT_SDL) void Lpanel_resizeWindow(Lpanel_t *p) { #ifdef WANT_SDL diff --git a/frontpanel/lpanel.c b/frontpanel/lpanel.c index c875b6d5..61749704 100644 --- a/frontpanel/lpanel.c +++ b/frontpanel/lpanel.c @@ -295,7 +295,7 @@ void Lpanel_init(Lpanel_t *p) // initializer p->window = NULL; p->cx = NULL; #else -#if !defined(__MINGW32__) && !defined(_WIN32) && !defined(_WIN32_) && !defined(__WIN32__) +#if !(defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__)) p->window = 0; p->vi = NULL; p->cx = 0; @@ -1053,7 +1053,7 @@ void Lpanel_growSwitches(Lpanel_t *p) p->switches = new_switches; } -int Lpanel_pick(Lpanel_t *p, int button, int state, int x, int y) +int Lpanel_pick(Lpanel_t *p, int button, bool state, int x, int y) { GLuint namebuf[500], *ptr; int i, @@ -1063,7 +1063,7 @@ int Lpanel_pick(Lpanel_t *p, int button, int state, int x, int y) UNUSED(button); - if (state == 0) { + if (!state) { if (p->mom_switch_pressed) lpSwitch_action(p->mom_switch_pressed, 2); return num_picked; diff --git a/frontpanel/lpanel.h b/frontpanel/lpanel.h index 9674e519..f13670bf 100644 --- a/frontpanel/lpanel.h +++ b/frontpanel/lpanel.h @@ -203,7 +203,7 @@ extern void Lpanel_growAlphaObjects(Lpanel_t *p); extern void Lpanel_growSwitches(Lpanel_t *p); extern lpObject_t *Lpanel_addObject(Lpanel_t *p); extern void Lpanel_addAlphaObject(Lpanel_t *p, lpObject_t *obj); -extern int Lpanel_pick(Lpanel_t *p, int button, int state, // mouse pick function +extern int Lpanel_pick(Lpanel_t *p, int button, bool state, // mouse pick function int x, int y); extern void Lpanel_setProjection(Lpanel_t *p, bool dopick); extern void Lpanel_setModelview(Lpanel_t *p, bool dopick); @@ -274,7 +274,8 @@ extern void Lpanel_destroyWindow(Lpanel_t *p); extern void Lpanel_doPickProjection(Lpanel_t *p); extern void Lpanel_doPickModelview(Lpanel_t *p); -#if defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__) +#if (defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__)) && \ + !defined(WANT_SDL) extern LRESULT CALLBACK Lpanel_WndProc(Lpanel_t *p, UINT Msg, WPARAM wParam, LPARAM lParam); #else extern void Lpanel_resizeWindow(Lpanel_t *p); From 57e4c251ca980be3725a1359cfa2baf0eeb148f0 Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Wed, 8 Jan 2025 22:11:08 +0100 Subject: [PATCH 14/15] add linker option -rpath for macOS --- altairsim/srcsim/Makefile | 1 + cromemcosim/srcsim/Makefile | 1 + imsaisim/srcsim/Makefile | 1 + intelmdssim/srcsim/Makefile | 1 + 4 files changed, 4 insertions(+) diff --git a/altairsim/srcsim/Makefile b/altairsim/srcsim/Makefile index c36305a8..de1c0f54 100644 --- a/altairsim/srcsim/Makefile +++ b/altairsim/srcsim/Makefile @@ -60,6 +60,7 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else diff --git a/cromemcosim/srcsim/Makefile b/cromemcosim/srcsim/Makefile index 52701720..82b2f9a8 100644 --- a/cromemcosim/srcsim/Makefile +++ b/cromemcosim/srcsim/Makefile @@ -67,6 +67,7 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else diff --git a/imsaisim/srcsim/Makefile b/imsaisim/srcsim/Makefile index 48ba0731..d98f4126 100644 --- a/imsaisim/srcsim/Makefile +++ b/imsaisim/srcsim/Makefile @@ -68,6 +68,7 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else diff --git a/intelmdssim/srcsim/Makefile b/intelmdssim/srcsim/Makefile index 10d005cf..01f5b826 100644 --- a/intelmdssim/srcsim/Makefile +++ b/intelmdssim/srcsim/Makefile @@ -59,6 +59,7 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers +PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else From a073ef2bd6c887b934f2a61b95c1a1f5820f4c1a Mon Sep 17 00:00:00 2001 From: Thomas Eberhardt Date: Wed, 8 Jan 2025 22:33:28 +0100 Subject: [PATCH 15/15] add more linker options for macOS These are what cmake uses when generating for macOS. --- altairsim/srcsim/Makefile | 3 ++- cromemcosim/srcsim/Makefile | 3 ++- imsaisim/srcsim/Makefile | 3 ++- intelmdssim/srcsim/Makefile | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/altairsim/srcsim/Makefile b/altairsim/srcsim/Makefile index de1c0f54..b4e9850a 100644 --- a/altairsim/srcsim/Makefile +++ b/altairsim/srcsim/Makefile @@ -60,7 +60,8 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers -PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks +PLAT_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else diff --git a/cromemcosim/srcsim/Makefile b/cromemcosim/srcsim/Makefile index 82b2f9a8..d797200a 100644 --- a/cromemcosim/srcsim/Makefile +++ b/cromemcosim/srcsim/Makefile @@ -67,7 +67,8 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers -PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks +PLAT_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else diff --git a/imsaisim/srcsim/Makefile b/imsaisim/srcsim/Makefile index d98f4126..220552ff 100644 --- a/imsaisim/srcsim/Makefile +++ b/imsaisim/srcsim/Makefile @@ -68,7 +68,8 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers -PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks +PLAT_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else diff --git a/intelmdssim/srcsim/Makefile b/intelmdssim/srcsim/Makefile index 01f5b826..c84de4b3 100644 --- a/intelmdssim/srcsim/Makefile +++ b/intelmdssim/srcsim/Makefile @@ -59,7 +59,8 @@ PLAT_INCS = -I/usr/include/SDL2 PLAT_LDLIBS = -lSDL2 -lSDL2main else ifeq ($(TARGET_OS),OSX) PLAT_INCS = -F/Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers -PLAT_LDFLAGS = -Wl,-rpath,/Library/Frameworks +PLAT_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks PLAT_LDLIBS = -framework SDL2 endif else