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..b4e9850a 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,88 @@ 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_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks +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 +133,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/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/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..d797200a 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,90 @@ 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_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks +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 +142,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..7f1cf991 100644 --- a/frontpanel/COPYING +++ b/frontpanel/COPYING @@ -1,6 +1,7 @@ /* 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: diff --git a/frontpanel/Makefile b/frontpanel/Makefile index bae30b02..aadc1c8c 100644 --- a/frontpanel/Makefile +++ b/frontpanel/Makefile @@ -1,45 +1,62 @@ +# 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 +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),LINUX) +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 -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 +64,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..fc098034 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 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,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..d2f4a570 --- /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, 0.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..528261f0 --- /dev/null +++ b/frontpanel/lp_gfx.c @@ -0,0 +1,930 @@ +// 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->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); + } + } + + 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.); + 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]); + + if (p->have_normals) + glDisable(GL_LIGHTING); + + obj = p->instance_object; + + while (obj) { + if (!obj->referenced) { + glEnable(GL_LIGHTING); + + if (obj->have_normals) { + if (obj->material) + lp_bind_material(obj->material); + } 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_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); + } + } + + if (p->have_normals) { + glEnable(GL_LIGHTING); + if (p->material) + lp_bind_material(p->material); + } else { + if (refoverride != 2) + glColor3fv(p->color); + } + + 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) { + glEnable(GL_LIGHTING); + + if (obj->have_normals) { + if (p->material) + lp_bind_material(p->material); + } 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) +{ + 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); +#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(); + +#if 0 + if (p->have_tcoords) + glDisable(GL_TEXTURE_2D); +#endif +} + +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; +#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 RGBA32 pixels */ + surface = SDL_ConvertSurfaceFormat(temp_surface, SDL_PIXELFORMAT_RGBA32, 0); + SDL_FreeSurface(temp_surface); + 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); + 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); + + 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) +{ + if (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..e00dc669 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,179 @@ */ - #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(); - - float xyz_min[3], - xyz_max[3], - center[3]; - -}; - -class lpObject -{ - - private: - - - void growElements(void); +struct lpElement; +struct lpTextures; - public: +typedef struct lpBBox { + float xyz_min[3], + xyz_max[3], + center[3]; +} lpBBox_t; - lpObject(); - ~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); +typedef struct lpObject { int num_elements, max_elements; - lpElement **elements; + struct lpElement **elements; - char *name; - void setName(char *s); + char *name; - char *instance_name; - void setInstanceName(char *s); - lpObject *instance_object; - - 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(); +typedef struct lpElement { + int type, // LP_POLYGON, LP_LINE + num_verts, + max_verts; + bool have_tcoords, + have_normals; - int type, // LP_POLYGON, LP_LINE - num_verts, - max_verts, - have_tcoords, - have_normals; + lpObject_t *parent; + vertex_t **verts; - lpObject *parent; - vertex_t **verts; + struct lpTextures *textures; - vertex_t *addVertex(void); - void draw(void); - void genGraphicsData(void); - void genTextureCoords(lpObject *obj, lpBBox *bbox); + lpBBox_t bbox; // element bounding box +} lpElement_t; - lpTextures *textures; - void setTextureManager(lpTextures *p) { textures = p; }; +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); - lpBBox bbox; // element bounding box -}; +// private functions +extern void lpElement_growVerts(lpElement_t *p); -#endif +// public functions +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); // texture class for managing graphics textures -typedef struct -{ - - // image specific attributes +typedef struct texture { + // image specific attributes - int imgXsize, - imgYsize, - imgZsize; + int imgXsize, + imgYsize, + imgZsize; +#ifdef WANT_SDL + SDL_Surface *surface; +#else + unsigned char *pixels; +#endif - unsigned char *pixels; - - // texture specific attributes - - 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; +typedef struct lpTextures { + int num_textures, + max_textures, + last_accessed; + texture_t **tex; +} lpTextures_t; -class lpTextures -{ - private: +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); - void growTextures(void); +// private functions - public: - lpTextures(); - ~lpTextures(); +extern void lpTextures_growTextures(lpTextures_t *p); - int num_textures, - max_textures, - last_accessed; - texture_t **tex; +// 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..e43502a2 --- /dev/null +++ b/frontpanel/lp_main.c @@ -0,0 +1,429 @@ +// 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 +#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; + if (!Lpanel_openWindow(panel, "FrontPanel")) { + fprintf(stderr, "Can't open FrontPanel window\n"); + exit(EXIT_FAILURE); + } + + 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.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 +#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(); + + if (!Lpanel_openWindow(panel, "FrontPanel")) { + fprintf(stderr, "Can't open FrontPanel window\n"); + exit(EXIT_FAILURE); + } +} + +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..3841d267 --- /dev/null +++ b/frontpanel/lp_switch.c @@ -0,0 +1,932 @@ +// 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..a963b659 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,105 @@ #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 -{ - - private: - - - public: +typedef struct lpSwitch { + char *name; - lpSwitch(void); - ~lpSwitch(void); + 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 - char *name; + 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; - 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 + char **object_ref_names; + lpObject_t *object_refs[3]; // object references for gfx_mode=object - 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; + lp_obj_parm_t *parms; + struct Lpanel *panel; - char **object_ref_names; - lpObject *object_refs[3]; // object references for gfx_mode=object + // rotation values for 3 switch states (for 3D models) - lp_obj_parm_t *parms; - Lpanel *panel; + float rotate[3][4]; // ang, 3D unit vector for 3 switch states - // rotation values for 3 switch states (for 3D models) + GLuint select_up_name, + select_dn_name; - float rotate[3][4]; // ang, 3D unit vector for 3 switch states + float up_target[4][3], // mouse pick targets for activation + down_target[4][3]; - GLuint select_up_name, - select_dn_name; + lp_switch_df_t drawFunc; +} lpSwitch_t; - float up_target[4][3], // mouse pick targets for activation - down_target[4][3]; +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); - 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); +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); - void setName(const char *_name); - void setupData(int sw_num); // resolve graphics references etc. - -}; - -#endif +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..b8d94a29 --- /dev/null +++ b/frontpanel/lp_utils.c @@ -0,0 +1,841 @@ +// 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..8abc25c2 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,91 @@ */ +#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..81267a26 --- /dev/null +++ b/frontpanel/lp_window.c @@ -0,0 +1,1274 @@ +// 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 +#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.1C"; +#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; +static bool 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; + + 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: + // 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; + + 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 = true; + mousex = event->button.x; + mousey = event->button.y; + } + } + break; + + case SDL_MOUSEBUTTONUP: + if (event->button.windowID != SDL_GetWindowID(p->window)) + break; + + if (!Lpanel_pick(p, event->button.button - 1, false, + event->button.x, event->button.y)) { + if (event->button.button == SDL_BUTTON_LEFT) + lmouse = false; + } + 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; + + 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; + } +} // 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, true, LOWORD(lParam), HIWORD(lParam))) { + mousex = LOWORD(lParam); + mousey = HIWORD(lParam); + lmouse = true; + } + return 0; + + case WM_LBUTTONUP: + if (!Lpanel_pick(p, 0, false, 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); + Lpanel_setProjection(p, false); + Lpanel_setModelview(p, 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 (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 (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; + + 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, 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()); + 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; + } + /* 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); + +#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; +} + +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) + 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) +{ + if (!dopick) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + } + + switch (p->view.projection) { + case LP_ORTHO: + glOrtho(p->bbox.xyz_min[0], p->bbox.xyz_max[0], + p->bbox.xyz_min[1], p->bbox.xyz_max[1], + .1, 1000.); + break; + + 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); + 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); + } + break; + } + + if (!dopick) + glMatrixMode(GL_MODELVIEW); +} + +#if !(defined(__MINGW32__) || defined(_WIN32) || defined(_WIN32_) || defined(__WIN32__)) || \ + defined(WANT_SDL) +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, true); +} + +void Lpanel_doPickModelview(Lpanel_t *p) +{ + Lpanel_setModelview(p, true); + // 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 + + glMatrixMode(GL_MODELVIEW); + 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); + // glEnable(GL_LIGHT1); + + glDisable(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); + + // 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); + } +} + +void Lpanel_draw_stats(Lpanel_t *p) +{ + if (p->view.do_depthtest) + glDisable(GL_DEPTH_TEST); + + 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.); + + 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(); + + 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.); + 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(200., 0., -10.); + + printStringAt(p->cursor_txt, p->cursor_textpos[0], p->cursor_textpos[1]); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + if (p->view.do_depthtest) + 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..61749704 --- /dev/null +++ b/frontpanel/lpanel.c @@ -0,0 +1,2055 @@ +// 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, false); + Lpanel_setModelview(p, false); + p->view.redo_projections = false; + } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // draw graphics objects + + for (i = 0; i < p->num_objects; i++) + if (!p->objects[i]->is_alpha) + lpObject_draw(p->objects[i]); + + // draw lights + + 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) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + for (i = 0; i < p->num_alpha_objects; i++) + lpObject_draw(p->alpha_objects[i]); + + glDisable(GL_BLEND); + } + + glDisable(GL_POLYGON_OFFSET_FILL); + + glEnable(GL_POLYGON_OFFSET_LINE); + if (p->do_cursor) + Lpanel_draw_cursor(p); + if (p->do_stats) + Lpanel_draw_stats(p); + glDisable(GL_POLYGON_OFFSET_LINE); + +#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, bool state, int x, int y) +{ + GLuint namebuf[500], *ptr; + int i, + num_picked = 0, + switch_dir; + uint32_t switch_num; + + UNUSED(button); + + if (!state) { + if (p->mom_switch_pressed) + lpSwitch_action(p->mom_switch_pressed, 2); + 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 + + for (i = 0; i < p->num_switches; i++) + lpSwitch_drawForPick(p->switches[i]); + + glPopName(); + 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); + + 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")) { + 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")) { + 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..f13670bf 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,31 +17,33 @@ */ -#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 }; enum obj_subtypes { LP_SUBTYPE_NULL, LP_LED_3D, LP_LED_2D }; @@ -49,328 +51,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, 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); + +// 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__)) && \ + !defined(WANT_SDL) +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); - - void draw_stats(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); -}; // end Lpanel +// dev functions +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: - - - public: - - lpLight(void); - ~lpLight(void); +typedef struct lpLight { + Lpanel_t *panel; - Lpanel *panel; + int bindtype; // bound to bit or array of floats - int bindtype; // bound to bit or array of floats + int smoothing; // 0= no intensity transition smoothing + // >0 = number of frames to transition. - int smoothing; // 0= no intensity transition smoothing, >0 = number of frames to transition. + uint64_t *simclock; + int *clock_warp; - uint64_t *simclock; - int *clock_warp; + uint8_t default_runflag, + *runflag; - uint8_t default_runflag, - *runflag; - //void bindRunFlag(const uint8_t *addr); - void bindRunFlag(uint8_t *addr); + char *name; + void *dataptr; // pointer to data to sample + int datatype; // datatype dataptr points to + int bitnum; // bit in data controlling this light - char *name; - void *dataptr; // pointer to data to sample - int datatype; // datatype dataptr points to - int bitnum; // bit in data controlling this light + char *obj_refname; // name of object if this light references one. + lpObject_t *obj_ref; // pointer to object if this light references one. - 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; + uint64_t t1, t2, + on_time; + uint64_t start_clock, + old_clock; - uint64_t start_clock, - old_clock; + 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[] - 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[] + float color[3]; // adjusted color + unsigned char state, + old_state; + bool dirty; - float color[3]; // adjusted color - unsigned char state, - old_state, - dirty; + lp_obj_parm_t *parms; - lp_obj_parm_t *parms; + lp_light_df_t drawFunc; + lp_light_sdf_t sampleDataFunc; +} lpLight_t; - void bindData8(uint8_t *ptr); - void bindData8invert(uint8_t *ptr); +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); - void bindData16(uint16_t *ptr); - void bindDatafv(float *ptr); +extern void lpLight_bindRunFlag(lpLight_t *p, uint8_t *addr); - 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_bindData8(lpLight_t *p, uint8_t *ptr); +extern void lpLight_bindData8invert(lpLight_t *p, uint8_t *ptr); - void bindSimclock(uint64_t *addr, int *clockwarp); +extern void lpLight_bindData16(lpLight_t *p, uint16_t *ptr); +extern void lpLight_bindDatafv(lpLight_t *p, float *ptr); - void calcIntensity(void); - void draw(void); - void (*drawFunc)(lpLight *lp); - void print(void); +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 setupData(void); - void (*sampleDataFunc)(lpLight *p); - void sampleData(void); +extern void lpLight_bindSimclock(lpLight_t *p, uint64_t *addr, int *clockwarp); - void setName(const char *name); - void setBitNumber(int _bitnum) { bitnum = _bitnum; }; -}; +extern void lpLight_calcIntensity(lpLight_t *p); +extern void lpLight_draw(lpLight_t *p); +extern void lpLight_print(lpLight_t *p); +extern void lpLight_setupData(lpLight_t *p); +extern void lpLight_sampleData(lpLight_t *p); +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..220552ff 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,90 @@ 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_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks +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 +143,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..c84de4b3 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,88 @@ 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_LDFLAGS = -Wl,-search_paths_first -Wl,-headerpad_max_install_names \ + -Wl,-rpath,/Library/Frameworks +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 +132,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..d304b472 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 int dazzler_win_id = -1; +static SDL_Window *window; +static SDL_Renderer *renderer; +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 process_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, + process_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,24 +813,35 @@ 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 #ifdef HAS_NETSERVER } else { if (state == 0) ws_clear(); - state = 1; } #endif - if (thread == 0) { - if (pthread_create(&thread, NULL, update_display, - (void *) NULL)) { - LOGE(TAG, "can't create thread"); - exit(EXIT_FAILURE); + state = 1; +#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; @@ -818,10 +849,12 @@ void cromemco_dazzler_ctl_out(BYTE data) #ifdef HAS_NETSERVER if (!n_flag) { #endif +#ifndef WANT_SDL XLockDisplay(display); XClearWindow(display, window); XSync(display, True); XUnlockDisplay(display); +#endif #ifdef HAS_NETSERVER } else ws_clear(); @@ -832,10 +865,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-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 d78889fe..ca517242 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,68 @@ * 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" +#ifdef WANT_SDL +#include "simsdl.h" +#endif #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 */ +#define XOFF 10 /* use some offset inside the window */ +#define YOFF 15 /* for the drawing area */ +#ifdef WANT_SDL +#define KEYBUF_LEN 20 +#endif -/* X11 stuff */ - int slf = 1; /* scanlines factor, default no lines */ +/* SDL2/X11 stuff */ +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; +#ifdef WANT_SDL +static int vio_win_id = -1; +static SDL_Window *window; +static SDL_Renderer *renderer; +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; +#else /* !WANT_SDL */ static Display *display; static Window window; static int screen; @@ -61,31 +91,48 @@ 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 */ /* 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 -/* 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)); + 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); + 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 +160,117 @@ 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_DestroyMutex(keybuf_mutex); + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); +#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) +{ + color[0] = fg_color[0]; + color[1] = fg_color[1]; + color[2] = fg_color[2]; +} + +static inline void set_bg_color(void) +{ + color[0] = bg_color[0]; + color[1] = bg_color[1]; + color[2] = bg_color[2]; } +static inline void draw_point(int x, int 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 */ + +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 +281,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 +314,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 +346,103 @@ 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 + +/* + * 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 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: + 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)) + for (p = event->text.text; *p; p++) + enqueue_key(*p); + break; + case SDL_KEYDOWN: + 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))) + 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) { + kbd_data = res; + 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 @@ -263,7 +452,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 */ @@ -271,21 +460,23 @@ 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 } +#endif /* !WANT_SDL */ + /* refresh the display buffer dependent on video mode */ static void refresh(void) { @@ -323,15 +514,24 @@ 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 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; +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) event_handler(); +#endif for (x = 0; x < cols; x++) { c = getmem(0xf000 + (y * cols) + x); dc1(c); @@ -344,7 +544,9 @@ static void refresh(void) case 2: /* Video mode 2: display character codes 00-7F */ for (y = 0; y < rows; y++) { sx = XOFF; +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) event_handler(); +#endif for (x = 0; x < cols; x++) { c = getmem(0xf000 + (y * cols) + x); dc2(c); @@ -357,7 +559,9 @@ static void refresh(void) case 3: /* Video mode 3: display character codes 00-FF */ for (y = 0; y < rows; y++) { sx = XOFF; +#if !defined(WANT_SDL) || defined(HAS_NETSERVER) event_handler(); +#endif for (x = 0; x < cols; x++) { c = getmem(0xf000 + (y * cols) + x); dc3(c); @@ -457,10 +661,33 @@ 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 */ + SDL_LockTexture(texture, NULL, &pixels, &pitch); + refresh(); + SDL_UnlockTexture(texture); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); +} + +static win_funcs_t vio_funcs = { + open_display, + close_display, + process_event, + 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 +700,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 +714,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 +731,78 @@ 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 +} + +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 eb12eda0..9e92558d 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,17 +20,20 @@ * 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 -extern int slf; /* VIO scanlines factor */ -extern char bg_color[]; /* VIO background color */ -extern char fg_color[]; /* VIO foreground color */ +#include -extern int imsai_kbd_status, imsai_kbd_data; +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 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 c86f07ae..dd5157d8 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,64 @@ * 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" +#ifdef WANT_SDL +#include "simsdl.h" +#endif #include "proctec-vdm-charset.h" #include "proctec-vdm.h" +#ifndef WANT_SDL #include "log.h" static const char *TAG = "VDM"; - -#define XOFF 10 /* use some offset inside the window */ -#define YOFF 15 /* for the drawing area */ - -/* X11 stuff */ - int slf = 1; /* scanlines factor, default no lines */ +#endif + +#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 */ +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 int proctec_win_id = -1; +static SDL_Window *window; +static SDL_Renderer *renderer; +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; +#else static Display *display; static Window window; static int screen; @@ -52,32 +81,51 @@ 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 /* 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 */ +#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)); + 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); + 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 +153,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 +165,134 @@ static void open_display(void) XFillRectangle(display, pixmap, gc, 0, 0, xsize, ysize); XSync(display, True); XUnlockDisplay(display); +#endif /* !WANT_SDL */ +} + +/* close the SDL window for VDM display */ +static void close_display(void) +{ +#ifdef WANT_SDL + SDL_DestroyMutex(keybuf_mutex); + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); +#else + XLockDisplay(display); + XFreePixmap(display, pixmap); + XFreeGC(display, gc); + XUnlockDisplay(display); + XCloseDisplay(display); +#endif } -/* shutdown VDM thread and window */ +/* 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 + +/* + * 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 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: + 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)) + for (p = event->text.text; *p; p++) + enqueue_key(*p); + break; + case SDL_KEYDOWN: + 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))) + enqueue_key(event->key.keysym.sym & 0x1f); + break; + default: + break; + } +} + +static inline void set_fg_color(void) +{ + color[0] = fg_color[0]; + color[1] = fg_color[1]; + color[2] = fg_color[2]; +} + +static inline void set_bg_color(void) +{ + color[0] = bg_color[0]; + color[1] = bg_color[1]; + color[2] = bg_color[2]; +} + +static inline void draw_point(int x, int 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 */ + /* * 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 @@ -147,7 +302,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 */ @@ -155,12 +310,29 @@ 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; } } } +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 +343,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 +369,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 +387,32 @@ 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 */ + SDL_LockTexture(texture, NULL, &pixels, &pitch); + refresh(); + SDL_UnlockTexture(texture); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + } +} + +static win_funcs_t proctec_funcs = { + open_display, + close_display, + process_event, + update_display +}; + +#else /* !WANT_SDL */ + /* thread for updating the display */ static void *update_display(void *arg) { @@ -251,27 +451,73 @@ static void *update_display(void *arg) pthread_exit(NULL); } -/* create the X11 window and start display refresh thread */ -static void vdm_init(void) +#endif /* !WANT_SDL */ + +/* I/O port for the VDM */ +void proctec_vdm_ctl_out(BYTE data) { - open_display(); + mode = data; + first = (data & 0xf0) >> 4; + beg = data & 0x0f; state = 1; - if (pthread_create(&thread, NULL, update_display, (void *) NULL)) { - LOGE(TAG, "can't create thread"); - exit(EXIT_FAILURE); +#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 } -/* I/O port for the VDM */ -void proctec_vdm_out(BYTE data) +/* + * Return status of the VDM keyboard + */ +BYTE proctec_vdm_kbd_status_in(void) { - mode = data; - first = (data & 0xf0) >> 4; - beg = data & 0x0f; + BYTE data; - if (display == 0) - vdm_init(); +#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 69d73334..0cae5622 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,22 +13,24 @@ * 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 int proctec_kbd_status; -extern int proctec_kbd_data; +extern uint8_t bg_color[3]; /* VDM background color */ +extern uint8_t fg_color[3]; /* VDM foreground color */ 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 */ 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..76e2a021 --- /dev/null +++ b/z80core/simsdl.c @@ -0,0 +1,155 @@ +/* + * 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}; + + 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; + } + + 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)