Merge branch 'master' of https://github.com/finalburnneo/FBNeo into finalburnneo-master

This commit is contained in:
barbudreadmon committed 2026-10-29 11:20:27 +01:00
commit d4d81688d0
80 files changed
+7584 -1421

No files matched your search

+1
View File
@@ -24,6 +24,7 @@ nvram
*.nvr
config/*
fbneo.dat
fbneo_headless.dylib
# libretro
/.github
+3
View File
@@ -120,6 +120,9 @@ sdl: FORCE
sdl2: FORCE
@$(MAKE) -s -f makefile.sdl2
headless: FORCE
@$(MAKE) -s -f makefile.headless
vc: FORCE
@$(MAKE) -s -f makefile.vc
+1 -1
View File
@@ -14,7 +14,7 @@ drvsrc = d_akkaarrh.o d_arcadecl.o d_atarig1.o d_atarisy1.o d_atarisy2.o d_badl
\
d_cps1.o d_mitchell.o \
\
d_cps2.o \
d_cps2.o d_cps2_custom.o \
\
d_cps3.o \
\
+1 -1
View File
@@ -27,7 +27,7 @@ depobj += about.o bzip.o choose_monitor.o cona.o d3d11shaderparams.o debugger.o
\
2xpm.o 2xsai.o crt.o ddt3x.o epx.o hq2xs.o hq2xs_16.o hq3xs.o hq_shared32.o xbr.o xbr32.o \
\
aud_dsound3.o aud_xaudio2.o cd_img.o ddraw_core.o dinput_core.o directx9_core.o dsound_core.o \
aud_dsound3.o aud_xaudio2.o aud_wasapi.o cd_img.o ddraw_core.o dinput_core.o directx9_core.o dsound_core.o \
inp_dinput.o inp_xinput.o prf_performance_counter.o vid_d3d.o vid_d3d11.o vid_d3d11_shader.o vid_ddraw.o vid_ddrawfx.o vid_effect.o vid_directx9.o vid_directx_support.o
ifdef INCLUDE_7Z_SUPPORT
+639
View File
@@ -0,0 +1,639 @@
# Makefile for FBNeo, headless core (derived from makefile.sdl2)
#
# The first pass makes sure all intermediary targets are present. The second pass updates
# any targets, if necessary. (Intermediary) targets which have their own unique rules
# are generated as required.
unexport
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
DARWIN=1
endif
ifdef DARWIN
PLATFLAGS += -arch arm64 -mmacosx-version-min=11.0 -Wno-deprecated-declarations
endif
ifeq ($(OS),Windows_NT)
WINDOWS=1
endif
#
# Flags. Uncomment any of these declarations to enable their function.
#
# Check for changes in header files
ifndef SKIPDEPEND
DEPEND = 1
endif
# SANITIZE = 1
#
# Declare variables
#
# Specify the name of the executable file, without ".exe"
NAME = fbneo
PERL = 1
LSB_FIRST = 1
INCLUDE_7Z_SUPPORT = 1
BUILD_X86_ASM=
INCLUDE_AVI_RECORDING=
BUILD_A68K=
UNICODE=
#
# Specify paths/files
#
objdir = obj/
srcdir = src/
include makefile.burn_rules
# Platform stuff
alldir += burner burner/headless burner/sdl dep/libs/libspng dep/libs/lib7z dep/libs/zlib intf intf/video \
intf/video/scalers intf/video/headless intf/audio intf/audio/headless intf/input intf/input/headless intf/cd \
dep/generated
depobj += cdlist.o \
\
conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o sshot.o state.o statec.o unzip.o zipfn.o \
\
adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o gzwrite.o infback.o inffast.o inflate.o inftrees.o \
trees.o uncompr.o zutil.o \
\
spng.o \
\
aud_dsp.o aud_interface.o cd_interface.o cd_chd.o inp_interface.o interface.o lowpass2.o vid_interface.o \
vid_support.o \
\
inp_headless.o aud_headless.o vid_headless.o support_paths.o ips_manager.o scrn.o localise_gamelist.o romdata.o \
cd_img.o stringset.o bzip.o media.o \
inpdipsw.o inputbuf.o replay.o stated.o headless_main.o headless_drv.o headless_misc.o headless_input.o headless_memory.o
ifdef FORCE_PULSE_AUDIO
alldir += intf/audio/linux
depobj += aud_pulse_simple.o
endif
ifdef INCLUDE_7Z_SUPPORT
depobj += un7z.o \
\
7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o 7zFile.o 7zStream.o Alloc.o Bcj2.o Bra.o Bra86.o BraIA64.o CpuArch.o \
Delta.o LzFindOpt.o LzmaDec.o Lzma2Dec.o MtDec.o Ppmd7.o Ppmd7Dec.o Ppmd7aDec.o Sha256.o Sha1Opt.o Sha256Opt.o Threads.o Xxh64.o Xz.o XzCrc64.o XzCrc64Opt.o XzDec.o ZstdDec.o
endif
autobj += $(depobj)
ifdef BUILD_X86_ASM
autobj += eagle_fm.o 2xsaimmx.o hq2x32.o hq3x32.o hq4x32.o superscale.o
endif
# End, platform stuff
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated
lib = -lstdc++ -lm -lpthread
ifdef FORCE_PULSE_AUDIO
lib += -lpulse-simple
endif
ifdef INCLUDE_SWITCHRES
incdir += `pkg-config --cflags switchres`
lib += `pkg-config --libs switchres`
endif
autdep = $(depobj:.o=.d)
drvdep = $(drvsrc:.o=.d)
ifdef BUILD_A68K
a68k.o = $(objdir)cpu/a68k/a68k.o
endif
driverlist.h = $(srcdir)dep/generated/driverlist.h
ctv.h = $(srcdir)dep/generated/ctv.h
toa_gp9001_func.h = $(srcdir)dep/generated/toa_gp9001_func.h
neo_sprite_func.h = $(srcdir)dep/generated/neo_sprite_func.h
cave_tile_func.h = $(srcdir)dep/generated/cave_tile_func.h
cave_sprite_func.h = $(srcdir)dep/generated/cave_sprite_func.h
psikyo_tile_func.h = $(srcdir)dep/generated/psikyo_tile_func.h
pgm_sprite.h = $(srcdir)dep/generated/pgm_sprite.h
build_details.h = $(srcdir)dep/generated/build_details.h
allobj = $(objdir)cpu/m68k/m68kcpu.o $(objdir)cpu/m68k/m68kops.o \
$(foreach file,$(autobj:.o=.c), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .c,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.cpp), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .cpp,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.asm), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .asm,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.rc), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .rc,.o,$(wildcard $(srcdir)$(dir)/$(file)))))))
ifdef BUILD_A68K
allobj += $(a68k.o)
endif
alldep = $(foreach file,$(autobj:.o=.c), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .c,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.cpp), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .cpp,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.rc), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .rc,.d,$(wildcard $(srcdir)$(dir)/$(file)))))))
autdrv := $(drvsrc:.cpp=.o)
#
#
# Specify compiler/linker/assembler
#
#
ifdef DARWIN
CC = gcc
else
CC = gcc
endif
CXX = $(CC)
LD = $(CC)
AS = nasm
# While cross-compiling, tools need to be compiled for host so that they can be executed by host.
# if HOST_CC is not set, then we aren't cross-compiling, so we'll use target compiler as host compiler
ifeq ($(HOST_CC),)
HOST_CC := $(CC)
HOST_CXX := $(CXX)
HOST_CFLAGS := $(CFLAGS)
HOST_CXXFLAGS := $(CXXFLAGS)
HOST_LDFLAGS := $(LDFLAGS)
endif
#LDFLAGS = -static
CFLAGS = -O2 -fomit-frame-pointer -Wno-write-strings \
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
-Wno-conversion -Wno-attributes \
-Wno-unused-parameter -Wno-unused-value -std=c99 \
$(PLATFLAGS) $(DEF) $(incdir)
CXXFLAGS = -O2 -fomit-frame-pointer -Wno-write-strings \
-Wall -W -Wno-long-long -Wno-sign-compare \
-Wunknown-pragmas -Wundef -Wconversion -Wno-missing-braces \
-Wuninitialized -Wpointer-arith -Winline -Wno-multichar \
-Wno-conversion -Wno-attributes \
-Wno-unused-parameter -Wno-unused-value -Wno-narrowing \
$(PLATFLAGS) $(DEF) $(incdir)
ASFLAGS = -O1 -f coff -w-orphan-labels
# D3DUtils & D3DMath need these
# DEF = -Dsinf=\(float\)sin -Dcosf=\(float\)cos -Dasinf=\(float\)asin -Dacosf=\(float\)acos -Dsqrtf=\(float\)sqrt
# FIXME
DEF := -DBUILD_HEADLESS -DINCLUDE_FLACMP3_SUPPORT -DUSE_SPEEDHACKS -DFILENAME=$(NAME) -DUSE_FILE32API -DHAVE_UNISTD_H
ifdef FORCE_PULSE_AUDIO
DEF := $(DEF) -DFORCE_PULSE_AUDIO
endif
ifdef WINDOWS
DEF := $(DEF) -DSDL_WINDOWS
endif
ifdef UNICODE
DEF := $(DEF) -D_UNICODE
endif
ifdef SPECIALBUILD
DEF := $(DEF) -DSPECIALBUILD=$(SPECIALBUILD)
endif
ifdef FASTCALL
DEF := $(DEF) -DFASTCALL
endif
ifdef DEBUG
DEF := $(DEF) -DFBNEO_DEBUG
endif
ifdef ROM_VERIFY
DEF := $(DEF) -DROM_VERIFY
endif
ifdef INCLUDE_7Z_SUPPORT
DEF := $(DEF) -DINCLUDE_7Z_SUPPORT
endif
ifdef INCLUDE_AVI_RECORDING
DEF := $(DEF) -DINCLUDE_AVI_RECORDING
endif
ifdef LSB_FIRST
DEF := $(DEF) -DLSB_FIRST
endif
ifdef INCLUDE_LIB_PNGH
DEF := $(DEF) -DINCLUDE_LIB_PNGH
endif
ifdef BUILD_A68K
DEF := $(DEF) -DBUILD_A68K
endif
ifdef BUILD_X86_ASM
DEF := $(DEF) -DBUILD_X86_ASM
endif
ifdef BUILD_X64_EXE
DEF := $(DEF) -DBUILD_X64_EXE
endif
ifdef INCLUDE_SWITCHRES
DEF := $(DEF) -DINCLUDE_SWITCHRES
endif
ifdef SANITIZE
ifndef SYMBOL
SYMBOL =1
endif
CFLAGS += -fsanitize=address -fsanitize=undefined -fsanitize=bounds-strict
CXXFLAGS += -fsanitize=address -fsanitize=undefined -fsanitize=bounds-strict
endif
ifdef SYMBOL
CFLAGS += -ggdb3 -fno-omit-frame-pointer
CXXFLAGS += -ggdb3 -fno-omit-frame-pointer
ASFLAGS += -g
DEF := $(DEF) -D_DEBUG
else
LDFLAGS += -s
endif
ifdef PROFILE
CFLAGS += -pg
CXXFLAGS += -pg
endif
ifdef BUILD_NATIVE
CFLAGS += -march=native -mtune=native
CXXFLAGS += -march=native -mtune=native
endif
# For zlib
DEF := $(DEF) -DNO_VIZ -D_LARGEFILE64_SOURCE=0 -D_FILE_OFFSET_BITS=64
# For libchdr
DEF := $(DEF) -DCHDR_SYSTEM_ZLIB
# For lib7z
ifdef INCLUDE_7Z_SUPPORT
DEF := $(DEF) -D_7ZIP_PPMD_SUPPPORT -D_7ZIP_ST
endif
#
#
# Specify paths
#
#
vpath %.asm $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.cpp $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.c $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.h $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.rc $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.o $(foreach dir,$(alldir),$(objdir)$(dir)/ )
vpath %.d $(foreach dir,$(alldir),$(objdir)$(dir)/ )
#
#
# Rules
#
#
.PHONY: all init cleandep touch clean
ifeq ($(MAKELEVEL),1)
ifdef DEPEND
all: init $(drvdep) $(autdep) $(autobj) $(autdrv)
@$(MAKE) -f makefile.headless -s
else
all: init $(autobj) $(autdrv)
@$(MAKE) -f makefile.headless -s
endif
else
all: fbneo_headless.dylib
endif
#
#
# Rule for linking the executable
#
#
ifeq ($(MAKELEVEL),2)
$(objdir)drivers.o: $(autdrv)
@echo Linking drivers...
@$(LD) -r -nostdlib -o $@ $^
ifdef WINDOWS
$(NAME): $(allobj) $(objdir)drivers.o
@echo
@echo Linking executable... $(NAME)
@$(LD) -Wl,--image-base -Wl,0x10000000 -mconsole $(CFLAGS) $(LDFLAGS) -o $@ $^ $(lib)
else
fbneo_headless.dylib: $(allobj) $(objdir)drivers.o
@echo
@echo Linking dylib... $@
@$(LD) -dynamiclib -install_name @rpath/fbneo_headless.dylib $(CFLAGS) $(LDFLAGS) -o $@ $^ $(lib)
endif
ifdef DEBUG
# Don't compress when making a debug build
else
ifdef COMPRESS
@upx --best $@
endif
endif
endif
ifeq ($(MAKELEVEL),1)
ifdef FORCE_UPDATE
$(build_details.h): FORCE
endif
endif
#
# Generate the gamelist
#
burn.o burn.d: $(driverlist.h)
$(driverlist.h): $(drvsrc) $(srcdir)dep/scripts/gamelist.pl
ifdef PERL
@$(srcdir)dep/scripts/gamelist.pl -o $@ -l gamelist.txt \
$(filter %.cpp,$(foreach file,$(drvsrc:.o=.cpp),$(foreach dir,$(alldir), \
$(firstword $(wildcard $(srcdir)$(dir)/$(file))))))
else
ifeq ($(MAKELEVEL),2)
@echo
@echo Warning: Perl is not available on this system.
@echo $@ cannot be updated or created!
@echo
endif
endif
#
# Verify if driverlist.h needs to be updated
#
#ifeq ($(MAKELEVEL),1)
#ifdef FORCE_UPDATE
#$(driverlist.h): FORCE
#endif
#endif
#
# Compile 68000 cores
#
# A68K
ifdef BUILD_A68K
$(a68k.o): fba_make68k.c
@echo Compiling A68K MC68000 core...
@$(CC) -mconsole $(CFLAGS) $(LDFLAGS) -DWIN32 -Wno-unused -Wno-conversion -Wno-missing-prototypes \
-s $< -o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe)
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) $(@:.o=.asm) \
$(@D)/a68k_tab.asm 00 $(ppro)
@echo Assembling A68K MC68000 core...
@$(AS) $(ASFLAGS) $(@:.o=.asm) -o $@
endif
# Musashi
$(objdir)cpu/m68k/m68kcpu.o: $(srcdir)cpu/m68k/m68kcpu.c $(objdir)dep/generated/m68kops.h $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo Compiling Musashi MC680x0 core \(m68kcpu.c\)...
@$(CC) $(CFLAGS) -c $(srcdir)cpu/m68k/m68kcpu.c -o $(objdir)cpu/m68k/m68kcpu.o
$(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kops.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo Compiling Musashi MC680x0 core \(m68kops.c\)...
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kops.c -o $(objdir)cpu/m68k/m68kops.o
$(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kops.c: $(objdir)cpu/m68k/m68kmake $(srcdir)cpu/m68k/m68k_in.c
$(objdir)cpu/m68k/m68kmake $(objdir)dep/generated/ $(srcdir)cpu/m68k/m68k_in.c
$(objdir)cpu/m68k/m68kmake: $(srcdir)cpu/m68k/m68kmake.c
@echo Compiling Musashi MC680x0 core \(m68kmake.c\)...
@$(HOST_CC) $(HOST_CFLAGS) $(srcdir)cpu/m68k/m68kmake.c -o $(objdir)cpu/m68k/m68kmake -Dmain=main
#
# Extra rules for generated header file ctv.h, needed by ctv.cpp
#
ctv.d ctv.o: $(ctv.h)
$(ctv.h): ctv_make.cpp
@echo Generating $(srcdir)dep/generated/$(@F)...
@$(HOST_CC) $(HOST_CXXFLAGS) $(HOST_LDFLAGS) $< \
-o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) -Dmain=main
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
#
# Extra rules for generated header file toa_gp9001_func.h, needed by toa_gp9001.cpp
#
toa_bcu2.d toa_bcu2.o toa_gp9001.d toa_gp9001.o: $(toa_gp9001_func.h)
$(toa_gp9001_func.h): $(srcdir)dep/scripts/toa_gp9001_func.pl
@$(srcdir)dep/scripts/toa_gp9001_func.pl -o $(toa_gp9001_func.h)
#
# Extra rules for generated header file neo_sprite_func.h, needed by neo_sprite.cpp
#
neo_sprite.d neo_sprite.o: $(neo_sprite_func.h)
$(neo_sprite_func.h): $(srcdir)dep/scripts/neo_sprite_func.pl
@$(srcdir)dep/scripts/neo_sprite_func.pl -o $(neo_sprite_func.h)
#
# Extra rules for generated header file cave_tile_func.h, needed by cave_tile.cpp
#
cave_tile.d cave_tile.o: $(cave_tile_func.h)
$(cave_tile_func.h): $(srcdir)dep/scripts/cave_tile_func.pl
@$(srcdir)dep/scripts/cave_tile_func.pl -o $(cave_tile_func.h)
#
# Extra rules for generated header file cave_sprite_func.h, needed by cave_sprite.cpp
#
cave_sprite.d cave_sprite.o: $(cave_sprite_func.h)
$(cave_sprite_func.h): $(srcdir)dep/scripts/cave_sprite_func.pl
@$(srcdir)dep/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
#
# Extra rules for generated header file psikyo_tile_func.h / psikyo_sprite_func.h, needed by psikyo_tile.cpp / psikyo_sprite.cpp
#
psikyo_tile.d psikyo_tile.o psikyosprite.d psikyo_sprite.o: $(psikyo_tile_func.h)
$(psikyo_tile_func.h): $(srcdir)dep/scripts/psikyo_tile_func.pl
$(srcdir)dep/scripts/psikyo_tile_func.pl -o $(psikyo_tile_func.h)
#
# Extra rules for generated header file pgm_sprite.h, needed by pgm_draw.cpp
#
pgm_draw.d pgm_draw.o: $(pgm_sprite.h)
$(pgm_sprite.h): pgm_sprite_create.cpp
@echo Generating $(srcdir)dep/generated/$(@F)...
@$(HOST_CC) $(HOST_CXXFLAGS) $(HOST_LDFLAGS) $< \
-o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) -Dmain=main
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
ifeq ($(MAKELEVEL),2)
ifdef DEPEND
include $(alldep)
endif
endif
#
# Generic rules for C/C++ files
#
# Note: require init to complete before assembling anything (see "| init" below)
# to avoid parallization issues on fresh builds.
#
ifeq ($(MAKELEVEL),1)
%.o: %.cpp
@echo Compiling $<...
@$(CC) $(CXXFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.o: %.c
@echo Compiling $<...
@$(CC) $(CFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.o: %.asm | init
@echo Assembling $<...
@$(AS) $(ASFLAGS) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
else
%.o: %.c
@echo Compiling $<...
@$(CC) $(CFLAGS) -c $< -o $@
%.o: %.asm | init
@echo Assembling $<...
@$(AS) $(ASFLAGS) $< -o $@
%.o:
@echo Compiling $<...
@$(CC) $(CXXFLAGS) -c $< -o $@
endif
#
# Generate dependencies for C/C++ files
#
ifdef DEPEND
%.d: %.c
@echo Generating depend file for $<...
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.d: %.cpp
@echo Generating depend file for $<...
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.d: %.rc
@echo Generating depend file for $<...
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
endif
#
# Phony targets
#
init:
ifdef DEBUG
@echo Making debug build...
else
@echo Making normal build...
endif
@echo
@mkdir -p $(foreach dir, $(alldir),$(objdir)$(dir))
@mkdir -p $(srcdir)dep/generated
cleandep:
@echo Removing depend files from $(objdir)...
-@for dir in $(alldir); do rm -f $(objdir)$$dir/*.d; done
touch:
@echo Marking all targets for $(NAME) as uptodate...
-@touch $(NAME).exe
-@touch -c -r $(NAME).exe $(srcdir)/dep/generated/*
-@for dir in $(alldir); do touch -c -r $(NAME).exe $(objdir)$$dir/*; done
clean:
@echo Removing build files...
-@rm -fr $(objdir) $(ctv.h) $(dep)generated gamelist.txt $(NAME)
ifdef PERL
@echo Removing all files generated with perl scripts...
-@rm -f -r $(app_gnuc.rc) $(driverlist)
endif
#
# Rule to force recompilation of any target that depends on it
#
FORCE:
+1
View File
@@ -317,6 +317,7 @@ $$DRV_CAPCOM {
../../src/burn/drv/capcom/ctv.cpp \
../../src/burn/drv/capcom/d_cps1.cpp \
../../src/burn/drv/capcom/d_cps2.cpp \
../../src/burn/drv/capcom/d_cps2_custom.cpp \
../../src/burn/drv/capcom/fcrash_snd.cpp \
../../src/burn/drv/capcom/kabuki.cpp \
../../src/burn/drv/capcom/ps_m.cpp \
@@ -363,6 +363,9 @@
<File
RelativePath="..\..\src\burn\drv\capcom\d_cps2.cpp">
</File>
<File
RelativePath="..\..\src\burn\drv\capcom\d_cps2_custom.cpp">
</File>
<File
RelativePath="..\..\src\burn\drv\capcom\fcrash_snd.cpp">
</File>
@@ -71,6 +71,7 @@
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps1.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\kabuki.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\ps.cpp" />
@@ -206,6 +206,9 @@
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp">
<Filter>Source Files\burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp">
<Filter>Source Files\burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\kabuki.cpp">
<Filter>Source Files\burn\drv\capcom</Filter>
</ClCompile>
@@ -529,6 +529,7 @@ rm %(Filename).exe</Command>
</CustomBuild>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps1.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\kabuki.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\ps.cpp" />
@@ -1227,6 +1227,9 @@
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp">
<Filter>Burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp">
<Filter>Burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp">
<Filter>Burn\drv\capcom</Filter>
</ClCompile>
@@ -477,6 +477,7 @@ del %(Filename).exe</Command>
</CustomBuild>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps1.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\kabuki.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\ps.cpp" />
@@ -247,6 +247,9 @@
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
@@ -477,6 +477,7 @@ del %(Filename).exe</Command>
</CustomBuild>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps1.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\kabuki.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\ps.cpp" />
@@ -247,6 +247,9 @@
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
@@ -477,6 +477,7 @@ del %(Filename).exe</Command>
</CustomBuild>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps1.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\kabuki.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\ps.cpp" />
@@ -247,6 +247,9 @@
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
@@ -161,6 +161,7 @@
<ClCompile Include="..\..\src\burn\drv\capcom\ctv.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps1.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\d_mitchell.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\fcrash_snd.cpp" />
<ClCompile Include="..\..\src\burn\drv\capcom\kabuki.cpp" />
@@ -391,6 +391,9 @@
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_cps2_custom.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\capcom\d_mitchell.cpp">
<Filter>burn\drv\capcom</Filter>
</ClCompile>
@@ -614,6 +614,7 @@
FE1B262B23561A770065200C /* d_psikyo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1B208823561A6C0065200C /* d_psikyo.cpp */; };
FE1B262C23561A770065200C /* cpsrd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1B208A23561A6C0065200C /* cpsrd.cpp */; };
FE1B262D23561A770065200C /* d_cps2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1B208B23561A6C0065200C /* d_cps2.cpp */; };
A427B0010000000000000001 /* d_cps2_custom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A427B0010000000000000002 /* d_cps2_custom.cpp */; };
FE1B262E23561A770065200C /* cpst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1B208C23561A6C0065200C /* cpst.cpp */; };
FE1B262F23561A770065200C /* qs_z.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1B208D23561A6C0065200C /* qs_z.cpp */; };
FE1B263023561A770065200C /* d_cps1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1B208E23561A6C0065200C /* d_cps1.cpp */; };
@@ -2156,6 +2157,7 @@
FE1B208823561A6C0065200C /* d_psikyo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = d_psikyo.cpp; sourceTree = "<group>"; };
FE1B208A23561A6C0065200C /* cpsrd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpsrd.cpp; sourceTree = "<group>"; };
FE1B208B23561A6C0065200C /* d_cps2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = d_cps2.cpp; sourceTree = "<group>"; };
A427B0010000000000000002 /* d_cps2_custom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = d_cps2_custom.cpp; sourceTree = "<group>"; };
FE1B208C23561A6C0065200C /* cpst.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpst.cpp; sourceTree = "<group>"; };
FE1B208D23561A6C0065200C /* qs_z.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = qs_z.cpp; sourceTree = "<group>"; };
FE1B208E23561A6C0065200C /* d_cps1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = d_cps1.cpp; sourceTree = "<group>"; };
@@ -4587,6 +4589,7 @@
children = (
FE1B208A23561A6C0065200C /* cpsrd.cpp */,
FE1B208B23561A6C0065200C /* d_cps2.cpp */,
A427B0010000000000000002 /* d_cps2_custom.cpp */,
FE1B208C23561A6C0065200C /* cpst.cpp */,
FE1B208D23561A6C0065200C /* qs_z.cpp */,
FE1B208E23561A6C0065200C /* d_cps1.cpp */,
@@ -5845,6 +5848,7 @@
FE1B252523561A760065200C /* d_pkscram.cpp in Sources */,
FE1B276423561A790065200C /* tilemap_generic.cpp in Sources */,
FE1B262D23561A770065200C /* d_cps2.cpp in Sources */,
A427B0010000000000000001 /* d_cps2_custom.cpp in Sources */,
FE1B26E923561A780065200C /* d_alpha68k1.cpp in Sources */,
FE1B244E23561A750065200C /* 7zBuf.c in Sources */,
FE1B23DC23561A750065200C /* m6809_intf.cpp in Sources */,
+70 -53
View File
@@ -90,8 +90,51 @@ bool bSaveCRoms = 0;
UINT32 *pBurnDrvPalette;
static char** pszShortName = NULL, ** pszFullNameA = NULL;
static wchar_t** pszFullNameW = NULL;
// Writable driver names, created only for drivers whose name is changed
// (RomData, custom/sub-driver names, localisation). Copying all of them at
// startup cost about 1.4 KiB per driver: about 39 MiB for 28,000 drivers.
struct BurnNameCopy {
UINT32 nDrv;
char* szOrigShortName;
char* szOrigFullNameA;
wchar_t* szOrigFullNameW;
char szShortName[100];
char szFullNameA[MAX_PATH];
#if defined (_UNICODE)
wchar_t szFullNameW[MAX_PATH];
#endif
BurnNameCopy* pNext;
};
static BurnNameCopy* pBurnNameCopies = NULL;
static BurnNameCopy* BurnNameCopyGet(UINT32 i)
{
if (i >= nBurnDrvCount) return NULL;
for (BurnNameCopy* p = pBurnNameCopies; p; p = p->pNext) {
if (p->nDrv == i) return p;
}
BurnNameCopy* p = (BurnNameCopy*)calloc(1, sizeof(BurnNameCopy));
if (NULL == p) return NULL;
p->nDrv = i;
p->szOrigShortName = pDriver[i]->szShortName;
p->szOrigFullNameA = pDriver[i]->szFullNameA;
p->szOrigFullNameW = pDriver[i]->szFullNameW;
if (pDriver[i]->szShortName) strncpy(p->szShortName, pDriver[i]->szShortName, sizeof(p->szShortName) - 1);
if (pDriver[i]->szFullNameA) strncpy(p->szFullNameA, pDriver[i]->szFullNameA, MAX_PATH - 1);
pDriver[i]->szShortName = p->szShortName;
pDriver[i]->szFullNameA = p->szFullNameA;
#if defined (_UNICODE)
if (pDriver[i]->szFullNameW) wcsncpy(p->szFullNameW, pDriver[i]->szFullNameW, MAX_PATH - 1);
pDriver[i]->szFullNameW = p->szFullNameW;
#endif
p->pNext = pBurnNameCopies;
pBurnNameCopies = p;
return p;
}
bool BurnCheckMMXSupport()
{
@@ -107,53 +150,20 @@ bool BurnCheckMMXSupport()
}
static void BurnGameListInit()
{ // Avoid broken references, RomData requires separate string storage
if (0 == nBurnDrvCount) return;
pszShortName = (char** )malloc(nBurnDrvCount * sizeof(char*));
pszFullNameA = (char** )malloc(nBurnDrvCount * sizeof(char*));
pszFullNameW = (wchar_t**)malloc(nBurnDrvCount * sizeof(wchar_t*));
if ((NULL != pszShortName) && (NULL != pszFullNameA) && (NULL != pszFullNameW)) {
for (UINT32 i = 0; i < nBurnDrvCount; i++) {
pszShortName[i] = (char* )malloc(100 * sizeof(char));
pszFullNameA[i] = (char* )malloc(MAX_PATH * sizeof(char));
pszFullNameW[i] = (wchar_t*)malloc(MAX_PATH * sizeof(wchar_t));
memset(pszShortName[i], '\0', 100 * sizeof(char));
memset(pszFullNameA[i], '\0', MAX_PATH * sizeof(char));
memset(pszFullNameW[i], '\0', MAX_PATH * sizeof(wchar_t));
if (NULL != pszShortName[i]) {
strcpy(pszShortName[i], pDriver[i]->szShortName);
pDriver[i]->szShortName = pszShortName[i];
}
if (NULL != pszFullNameA[i]) {
strcpy(pszFullNameA[i], pDriver[i]->szFullNameA);
pDriver[i]->szFullNameA = pszFullNameA[i];
}
#if defined (_UNICODE)
if (NULL != pDriver[i]->szFullNameW) {
wmemcpy(pszFullNameW[i], pDriver[i]->szFullNameW, MAX_PATH); // Include '\0'
}
pDriver[i]->szFullNameW = pszFullNameW[i];
#endif
}
}
{ // Names are copied on first change, see BurnNameCopyGet().
}
static void BurnGameListExit()
{
// Release of storage space
for (UINT32 i = 0; i < nBurnDrvCount; i++) {
if ((NULL != pszShortName) && (NULL != pszShortName[i])) free(pszShortName[i]);
if ((NULL != pszFullNameA) && (NULL != pszFullNameA[i])) free(pszFullNameA[i]);
if ((NULL != pszFullNameW) && (NULL != pszFullNameW[i])) free(pszFullNameW[i]);
// Point the drivers back at their built-in names, then release the copies.
while (pBurnNameCopies) {
BurnNameCopy* p = pBurnNameCopies;
pDriver[p->nDrv]->szShortName = p->szOrigShortName;
pDriver[p->nDrv]->szFullNameA = p->szOrigFullNameA;
pDriver[p->nDrv]->szFullNameW = p->szOrigFullNameW;
pBurnNameCopies = p->pNext;
free(p);
}
if (NULL != pszShortName) free(pszShortName);
if (NULL != pszFullNameA) free(pszFullNameA);
if (NULL != pszFullNameW) free(pszFullNameW);
}
extern "C" INT32 BurnLibInit()
@@ -519,9 +529,10 @@ static INT32 BurnDrvSetFullNameA(char* szName, UINT32 i = nBurnDrvActive)
{
// Preventing the emergence of ~0U
// If not NULL, then FullNameA is customized
if ((i >= 0) && (NULL != szName)) {
memset(pszFullNameA[i], '\0', MAX_PATH * sizeof(char));
strcpy(pszFullNameA[i], szName);
BurnNameCopy* p = (NULL != szName) ? BurnNameCopyGet(i) : NULL;
if (NULL != p) {
memset(p->szFullNameA, '\0', MAX_PATH * sizeof(char));
strncpy(p->szFullNameA, szName, MAX_PATH - 1);
return 0;
}
@@ -534,8 +545,10 @@ INT32 BurnDrvSetFullNameW(TCHAR* szName, INT32 i = nBurnDrvActive)
if ((-1 == i) || (NULL == szName)) return -1;
#if defined (_UNICODE)
memset(pszFullNameW[i], '\0', MAX_PATH * sizeof(wchar_t));
wcscpy(pszFullNameW[i], szName);
BurnNameCopy* p = BurnNameCopyGet(i);
if (NULL == p) return -1;
memset(p->szFullNameW, '\0', MAX_PATH * sizeof(wchar_t));
wcsncpy(p->szFullNameW, szName, MAX_PATH - 1);
#endif
return 0;
@@ -548,8 +561,10 @@ void BurnLocalisationSetName(char* szName, TCHAR* szLongName)
nBurnDrvActive = i;
if (!strcmp(szName, pDriver[i]->szShortName)) {
// pDriver[i]->szFullNameW = szLongName;
memset(pszFullNameW[i], '\0', MAX_PATH * sizeof(wchar_t));
_tcscpy(pszFullNameW[i], szLongName);
BurnNameCopy* p = BurnNameCopyGet(i);
if (NULL == p) continue;
memset(p->szFullNameW, '\0', MAX_PATH * sizeof(wchar_t));
wcsncpy(p->szFullNameW, szLongName, MAX_PATH - 1);
}
}
}
@@ -618,7 +633,9 @@ extern "C" INT32 BurnDrvSetZipName(char* szName, INT32 i)
{
if ((NULL == szName) || (-1 == i)) return -1;
strcpy(pszShortName[i], szName);
BurnNameCopy* p = BurnNameCopyGet((UINT32)i);
if (NULL == p) return -1;
strncpy(p->szShortName, szName, sizeof(p->szShortName) - 1);
return 0;
}
@@ -1735,7 +1752,7 @@ struct MovieExtInfo
UINT32 hour, minute, second;
};
#if !defined(BUILD_SDL) && !defined(BUILD_SDL2) && !defined(BUILD_MACOS) && !defined(__LIBRETRO__)
#if !defined(BUILD_SDL) && !defined(BUILD_SDL2) && !defined(BUILD_MACOS) && !defined(BUILD_HEADLESS) && !defined(__LIBRETRO__)
extern struct MovieExtInfo MovieInfo; // from replay.cpp
#else
struct MovieExtInfo MovieInfo = { 0, 0, 0, 0, 0, 0, 0 };
+57
View File
@@ -845,3 +845,60 @@ bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsi
return value;
}
#ifdef BUILD_HEADLESS
// Added for OpenEmu-Silicon headless: fast helpers for cheat search / achievements.
// Author: Leonardo Kasperavičius
// Size (in bytes) of the main CPU (cpu 0) address space, 0 if no driver is loaded.
unsigned int GetMainMemorySize()
{
if (!bDrvOkay)
return 0;
// cpu 0 still holds dummy_config (nMemorySize = ~0UL) when no CPU registered with
// the cheat engine; report 0 so the host never tries to allocate a 4GB buffer.
unsigned int size = (unsigned int)cpus[0].cpuconfig->nMemorySize;
return (size == ~0U) ? 0 : size;
}
// Bulk-read a contiguous range from the main CPU (cpu 0) address space, opening
// the cpu once. Returns the number of bytes actually read (clamped to memory size).
unsigned int ReadMemoryRange(HWAddressType address, unsigned char *buffer, unsigned int length)
{
if (!bDrvOkay || buffer == NULL)
return 0;
cheat_ptr = &cpus[0];
cpu_core_config *cfg = cheat_ptr->cpuconfig;
unsigned int memSize = (unsigned int)cfg->nMemorySize;
INT32 nActiveCPU = cfg->active();
if (nActiveCPU >= 0) cfg->close();
cfg->open(cheat_ptr->nCPU);
unsigned int i;
for (i = 0; i < length; i++) {
if (address + i >= memSize) break;
buffer[i] = cfg->read(address + i);
}
cfg->close();
if (nActiveCPU >= 0) cfg->open(nActiveCPU);
return i;
}
// Multi-byte order hint for the host's cheat search and cheat writes. This is
// deliberately NOT derived from nAddressFlags: RetroAchievements sets and
// libretro .cht cheats (the formats the host matches) are authored
// little-endian for the 68K arcade boards -- every FBNeo libretro .cht is
// big_endian="false" -- and the CPUs that set MB_CHEAT_ENDI_SWAP (TMS34010,
// V60) are natively little-endian; the flag only exists because FBNeo's own
// cheat engine stores values big-endian. Reporting 1 for those made the host
// write "0000A260:00A1" in Mortal Kombat as bytes 00 A1, so the game read
// P1 health as 0xA100. Every board is therefore reported little-endian.
int GetMainMemoryBigEndian()
{
return 0;
}
#endif
+7
View File
@@ -81,3 +81,10 @@ bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsi
bool WriteValueAtHardwareAddress_audio(HWAddressType address, unsigned int value, unsigned int size, int isLittleEndian);
bool IsHardwareAddressValid(HWAddressType address);
#ifdef BUILD_HEADLESS
// OpenEmu-Silicon headless helpers (see cheat.cpp).
unsigned int GetMainMemorySize();
unsigned int ReadMemoryRange(HWAddressType address, unsigned char *buffer, unsigned int length);
int GetMainMemoryBigEndian(); // multibyte order for host cheats; always 0 (little-endian), see cheat.cpp
#endif
+26 -49
View File
@@ -15,6 +15,8 @@ UINT8 *CpsRom =NULL; UINT32 nCpsRomLen =0; // Program Rom (as in rom)
UINT8 *CpsCode=NULL; UINT32 nCpsCodeLen=0; // Program Rom (decrypted)
UINT8 *CpsZRom=NULL; UINT32 nCpsZRomLen=0; // Z80 Roms
INT8 *CpsQSam=NULL; UINT32 nCpsQSamLen=0; // QSound Sample Roms
UINT32 nCpsQSamMask = 0;
UINT32 nCpsRomMapLen = 0;
UINT8 *CpsAd =NULL; UINT32 nCpsAdLen =0; // ADPCM Data
UINT8 *CpsStar=NULL;
UINT8 *CpsKey=NULL; UINT32 nCpsKeyLen = 0;
@@ -1778,23 +1780,7 @@ INT32 Cps2LoadTiles(UINT8* Tile, INT32 nStart)
return 0;
}
#if 0
"usual cps2":
rom0 12
rom1 34
rom2 56
rom3 78
"interleaved (zero800/cps2turbo)"
rom 12345678
12 12 12 12
34 34 34 34
56 56 56 56
78 78 78 78
(visualization helper)
#endif
// Four interleaved ROM lanes in one source image.
#define BLOCK_MOD 4
inline static void Cps2LoadBlockInterleaved(UINT8* Tile, UINT8* Sect, INT32 nShift)
@@ -1856,19 +1842,6 @@ INT32 Cps2LoadTilesInterleaved(UINT8 *Tile, UINT8 *pSrc, UINT32 nSize)
#undef BLOCK_MOD
INT32 Cps2LoadTilesTurbo(UINT8* Tile, INT32 nSize) // cps2turbo
{
UINT8 *Rom = (UINT8*)BurnMalloc(nSize);
memcpy(Rom, Tile, nSize);
memset(Tile, 0, nSize);
Cps2LoadTilesInterleaved(Tile, Rom, nSize);
BurnFree(Rom);
return 0;
}
INT32 Cps2LoadTilesSplit4(UINT8* Tile, INT32 nStart)
{
// left side of 16x16 tiles
@@ -1986,7 +1959,7 @@ INT32 Cps2LoadTilesGigaman2(UINT8 *Tile, UINT8 *pSrc)
static UINT32 nGfxMaxSize;
static INT32 CpsGetROMs(bool bLoad)
static INT32 CpsGetROMs(bool bLoad, INT32 bLinear)
{
struct BurnRomInfo ri;
@@ -2023,7 +1996,7 @@ static INT32 CpsGetROMs(bool bLoad)
if ((ri.nType & 0x0f) == CPS2_PRG_68K) {
if (bLoad) {
if (BurnLoadRom(CpsRomLoad, i, 1)) return 1;
if (Cps2Turbo) BurnByteswap(CpsRomLoad, ri.nLen);
if (bLinear) BurnByteswap(CpsRomLoad, ri.nLen);
CpsRomLoad += ri.nLen;
} else {
nCpsRomLen += ri.nLen;
@@ -2052,7 +2025,7 @@ static INT32 CpsGetROMs(bool bLoad)
if ((ri.nType & 0x0f) == CPS2_GFX) {
if (bLoad) {
if (Cps2Turbo) {
if (bLinear) {
BurnLoadRom(CpsGfxLoad, i, 1);
CpsGfxLoad += ri.nLen;
@@ -2142,7 +2115,7 @@ static INT32 CpsGetROMs(bool bLoad)
if ((ri.nType & 0x0f) == CPS2_QSND) {
if (bLoad) {
BurnLoadRom(CpsQSamLoad, i, 1);
if (Cps2Turbo == 0) {
if (!bLinear) {
BurnByteswap(CpsQSamLoad, ri.nLen);
}
CpsQSamLoad += ri.nLen;
@@ -2189,11 +2162,8 @@ static INT32 CpsGetROMs(bool bLoad)
((UINT32*)CpsCode)[i] ^= ((UINT32*)CpsRom)[i];
}
#endif
if (Cps2Turbo) {
Cps2LoadTilesTurbo(CpsGfx, nCpsGfxLen);
}
cps2_decrypt_game_data();
if (nCpsCodeLen && CpsCode == NULL) return 1;
// if (!nCpsCodeLen) return 1;
} else {
@@ -2252,9 +2222,6 @@ INT32 CpsInit()
nCPS68KClockspeed = 10000000;
}
}
if (Cps2Turbo) {
nCPS68KClockspeed = 32000000;
}
nCPS68KClockspeed = (INT64)nCPS68KClockspeed * 100 / nBurnFPS;
nMemLen = nCpsGfxLen + nCpsRomLen + nCpsCodeLen + nCpsZRomLen + nCpsQSamLen + nCpsAdLen + nCpsKeyLen;
@@ -2318,15 +2285,24 @@ INT32 CpsInit()
INT32 Cps2Init()
{
Cps = 2;
return Cps2Init(0, 0, 0);
}
if (CpsGetROMs(false)) {
INT32 Cps2Init(INT32 nMapLen, UINT32 nGfxSize, INT32 bLinear)
{
Cps = 2;
nCpsRomMapLen = nMapLen;
if (CpsGetROMs(false, bLinear)) {
return 1;
}
CpsInit();
if (nGfxSize) nCpsGfxLen = nGfxSize;
if (CpsInit()) return 1;
if (CpsGetROMs(true)) {
if (CpsGetROMs(true, bLinear)) {
// Before decryption, CpsCode aliases the shared ROM allocation.
if (!nCpsCodeLen) CpsCode = NULL;
return 1;
}
@@ -2351,6 +2327,7 @@ INT32 CpsExit()
nCpsCodeLen = nCpsRomLen = nCpsGfxLen = nCpsZRomLen = nCpsQSamLen = nCpsAdLen = nCpsKeyLen = 0;
CpsRom = CpsZRom = CpsAd = CpsStar = NULL;
CpsQSam = NULL;
nCpsQSamMask = 0;
CpsKey = NULL;
// All Memory is allocated to this (this is the only one we can free)
@@ -2369,10 +2346,10 @@ INT32 CpsExit()
nCpsGlobalXOffset = 0;
nCpsGlobalYOffset = 0;
if (Cps2Turbo) {
BurnSampleExit();
Cps2Turbo = 0;
}
nCpsRomMapLen = 0;
CpsDrawPaletteCallbackFunction = NULL;
Cps2ScrollCallbackFunction = NULL;
Cps2Scroll1CallbackFunction = NULL;
return 0;
}
+53 -20
View File
@@ -28,9 +28,11 @@ extern INT32 nCpsCycles; // Cycles per frame
extern INT32 nCpsZ80Cycles;
extern UINT8 *CpsGfx; extern UINT32 nCpsGfxLen; // All the graphics
extern UINT8 *CpsRom; extern UINT32 nCpsRomLen; // Program Rom (as in rom)
extern UINT32 nCpsRomMapLen; // Optional program mapping size; 0 uses the ROM size
extern UINT8 *CpsCode; extern UINT32 nCpsCodeLen; // Program Rom (decrypted)
extern UINT8 *CpsZRom; extern UINT32 nCpsZRomLen; // Z80 Roms
extern INT8 *CpsQSam; extern UINT32 nCpsQSamLen; // QSound Sample Roms
extern UINT32 nCpsQSamMask; // Optional sample decoder mask; 0 uses the ROM size
extern UINT8 *CpsAd; extern UINT32 nCpsAdLen; // ADPCM Data
extern UINT8 *CpsKey; extern UINT32 nCpsKeyLen;
extern UINT32 nCpsGfxScroll[4]; // Offset to Scroll tiles
@@ -38,6 +40,7 @@ extern UINT32 nCpsGfxMask; // Address mask
extern UINT8* CpsStar;
INT32 CpsInit();
INT32 Cps2Init();
INT32 Cps2Init(INT32 nMapLen, UINT32 nGfxSize, INT32 bLinear);
INT32 CpsExit();
INT32 CpsLoadTiles(UINT8 *Tile,INT32 nStart);
INT32 CpsLoadTilesByte(UINT8 *Tile,INT32 nStart);
@@ -82,6 +85,7 @@ INT32 CpsLoadStarsByte(UINT8 *pStar, INT32 nStart);
INT32 CpsLoadStarsForgottnAlt(UINT8 *pStar, INT32 nStart);
INT32 Cps2LoadTiles(UINT8 *Tile,INT32 nStart);
INT32 Cps2LoadTilesSIM(UINT8 *Tile,INT32 nStart);
INT32 Cps2LoadTilesInterleaved(UINT8 *Tile, UINT8 *pSrc, UINT32 nSize);
INT32 Cps2LoadTilesGigaman2(UINT8 *Tile, UINT8 *pSrc);
// cps_config.h
@@ -177,6 +181,8 @@ INT32 Cps2LoadTilesGigaman2(UINT8 *Tile, UINT8 *pSrc);
#define mapper_pang3b4 48
#define mapper_TKSGZB 49
#define mapper_varthb2 50
#define mapper_STRIDEREX 51
#define mapper_FFIGHTEX 52
extern void SetGfxMapper(INT32 MapperId);
extern INT32 GfxRomBankMapper(INT32 Type, INT32 Code);
extern void SetCpsBId(INT32 CpsBId, INT32 bStars);
@@ -188,6 +194,9 @@ extern INT32 bCpsUpdatePalEveryFrame;
INT32 CpsPalInit();
INT32 CpsPalExit();
INT32 CpsPalUpdate(UINT8 *pNewPal);
typedef void (*CpsPalUpdateCallback)(INT32 nPage, const UINT16* pPalette);
extern CpsPalUpdateCallback CpsPalUpdateCallbackFunction;
void CpsPalRecalc(const UINT16* pRaw);
// cps_mem.cpp
extern UINT8 *CpsRam90;
@@ -204,6 +213,13 @@ INT32 CpsAreaScan(INT32 nAction,INT32 *pnMin);
typedef INT32 (*CpsMemScanCallback)(INT32, INT32*);
extern CpsMemScanCallback CpsMemScanCallbackFunction;
// Additional device state precedes sound state in the scan order.
extern CpsMemScanCallback CpsMemScanExtraCallbackFunction;
// Optional replacement for the QSound state scan.
typedef void (*CpsSoundScanCallback)(INT32, INT32*);
extern CpsSoundScanCallback CpsSoundScanCallbackFunction;
extern INT32 bCpsObjectBankHandlers;
// cps_run.cpp
extern UINT8 CpsReset;
@@ -287,7 +303,6 @@ extern INT32 Ssf2tb;
extern INT32 Dinohunt;
extern INT32 Port6SoundWrite;
extern INT32 CpsBootlegEEPROM;
extern INT32 Cps2Turbo;
extern INT32 Jurassic99;
extern INT32 Dinoh;
extern INT32 Wofhfh;
@@ -312,8 +327,14 @@ void __fastcall CpsWriteWord(UINT32 a, UINT16 d);
typedef void (*CpsRWSoundCommandCallback)(UINT16);
extern CpsRWSoundCommandCallback CpsRWSoundCommandCallbackFunction;
// Prepare inputs before port compilation; return the number of stock-port players.
typedef INT32 (*CpsRwGetInpCallback)();
extern CpsRwGetInpCallback CpsRwGetInpCallbackFunction;
// cps_draw.cpp
typedef INT32 (*CpsDrawPaletteCallback)();
// Return nonzero when the palette is already current for this draw.
extern CpsDrawPaletteCallback CpsDrawPaletteCallbackFunction;
extern UINT8 CpsRecalcPal; // Flag - If it is 1, recalc the whole palette
extern INT32 nCpsLcReg; // Address of layer controller register
extern INT32 CpsLayEn[6]; // bits for layer enable
@@ -349,9 +370,15 @@ void QsndReset();
void QsndNewFrame();
void QsndEndFrame();
void QsndSyncZ80();
INT32 QsndScan(INT32 nAction);
INT32 QsndScan(INT32 nAction, INT32 bScanHistory = 0);
// qs_z.cpp
extern INT32 nQsndZ80Clock, nQsndZBankOffset;
void QsndZReset();
void QsndZSetBank(INT32 nBank);
INT32 QsndZGetBank();
UINT8 __fastcall QsndZRead(UINT16 a);
void __fastcall QsndZWrite(UINT16 a, UINT8 d);
INT32 QsndZInit();
INT32 QsndZExit();
INT32 QsndZScan(INT32 nAction);
@@ -361,7 +388,7 @@ INT32 QscInit(INT32 nRate);
void QscSetRoute(INT32 nIndex, double nVolume, INT32 nRouteDir);
void QscReset();
void QscExit();
INT32 QscScan(INT32 nAction);
INT32 QscScan(INT32 nAction, INT32 bScanHistory = 0);
void QscNewFrame();
void QscWrite(INT32 a, INT32 d);
UINT8 QscRead();
@@ -411,6 +438,7 @@ INT32 CtvReady();
// cps_obj.cpp
extern INT32 nCpsObjectBank;
extern INT32 nCpsObjExtraLen; // Optional extra data bytes per buffered sprite frame
extern UINT8 *CpsBootlegSpriteRam;
extern INT32 Cps1LockSpriteList910000;
extern INT32 Cps1DetectEndSpriteList8000;
@@ -419,7 +447,17 @@ typedef INT32 (*Cps1ObjGetCallback)();
extern Cps1ObjGetCallback Cps1ObjGetCallbackFunction;
typedef INT32 (*Cps1ObjDrawCallback)(INT32, INT32);
extern Cps1ObjDrawCallback Cps1ObjDrawCallbackFunction;
extern INT32 bCpsUseParentBlend;
typedef void (*Cps2ObjGetCallback)(UINT8* pExtra, INT32 nEntry, INT32 nSource);
extern Cps2ObjGetCallback Cps2ObjGetCallbackFunction;
typedef INT32 (*Cps2ObjTileCallback)(UINT16* pObject, INT32 nTile, const UINT8* pExtra, INT32 nEntry);
extern Cps2ObjTileCallback Cps2ObjTileCallbackFunction;
// Negative skips the object, zero uses its palette, positive supplies 16 colors.
typedef INT32 (*Cps2ObjPaletteCallback)(INT32, UINT16, UINT16, INT32, UINT32*);
extern Cps2ObjPaletteCallback Cps2ObjPaletteCallbackFunction;
void CpsObjReset();
INT32 CpsObjScan(INT32 nAction, char* szName);
INT32 CpsObjInit();
INT32 CpsObjExit();
INT32 CpsObjGet();
@@ -449,6 +487,18 @@ INT32 Cps1Scr3Draw(UINT8 *Base,INT32 sx,INT32 sy);
INT32 Cps2Scr1Draw(UINT8 *Base,INT32 sx,INT32 sy);
INT32 Cps2Scr3Draw(UINT8 *Base,INT32 sx,INT32 sy);
typedef INT32 (*Cps2ScrollCallback)(INT32, INT32, INT32);
extern Cps2ScrollCallback Cps2ScrollCallbackFunction;
typedef const UINT8* (*Cps2Scroll1Callback)();
extern Cps2Scroll1Callback Cps2Scroll1CallbackFunction;
// Resolve a scroll tile address, including its layer's graphics offset.
inline static INT32 Cps2ScrollAddress(INT32 nAddress, INT32 nAttributes, INT32 nLayer)
{
if (Cps2ScrollCallbackFunction) return Cps2ScrollCallbackFunction(nAddress, nAttributes, nLayer);
return nAddress + nCpsGfxScroll[nLayer];
}
// cpsr.cpp
extern UINT8 *CpsrBase; // Tile data base
extern INT32 nCpsrScrX,nCpsrScrY; // Basic scroll info
@@ -560,21 +610,4 @@ extern UINT16 Cps2VolumeStates[40];
extern INT32 Cps2DisableDigitalVolume;
extern UINT8 Cps2VolUp;
extern UINT8 Cps2VolDwn;
extern UINT8 AspectDIP;
// cps_rw.cpp: X-Men Vs. Street Fighter 3v3 + DHC board additions (xmvsf3v3.h)
extern UINT8 CpsXmvSixButtons[6][13];
extern INT32 CpsXmvSixEnabled;
extern INT32 CpsXmvWide;
INT32 CpsXmvSixInit(INT32 bWide);
void CpsXmvSixExit();
INT32 CpsXmvSixReset();
INT32 CpsXmvSixScan(INT32 nAction, INT32* pnMin);
const UINT8* CpsXmvScroll1Extension();
// ... and its exact save states (run-ahead, netplay): the display state other games rebuild after a load
INT32 CpsXmvVisualScan(INT32 nAction); // cps_mem.cpp
INT32 CpsObjVisualScan(INT32 nAction); // cps_obj.cpp
INT32 CpsPalVisualScan(INT32 nAction); // cps_pal.cpp
INT32 CpsPalConsumeRestoredCache();
#endif
+3 -1
View File
@@ -643,8 +643,10 @@ static void cps2_decrypt(const UINT32 *master_key, UINT32 lower_limit, UINT32 up
UINT16 *rom = (UINT16 *)CpsRom;
UINT32 length = (upper_limit > 0) ? (upper_limit * 2) : nCpsRomLen;
if (length > nCpsRomLen) length = nCpsRomLen;
CpsCode = (UINT8*)BurnMalloc(length);
if (nCpsRomMapLen && length > nCpsRomMapLen) length = nCpsRomMapLen;
nCpsCodeLen = length;
CpsCode = (UINT8*)BurnMalloc(length);
if (CpsCode == NULL) return;
UINT16 *dec = (UINT16*)CpsCode;
INT32 i;
+42
View File
@@ -72,6 +72,19 @@ static const struct GfxRange mapper_ST24M1_table[] =
{ 0 , 0, 0, 0 }
};
// Strider EX: original ST24M1 ranges plus the native backport graphics bank.
static const struct GfxRange mapper_STRIDEREX_table[] = {
{ GFXTYPE_STARS, 0x00000, 0x003ff, 0 },
{ GFXTYPE_SPRITES, 0x00000, 0x04fff, 0 },
{ GFXTYPE_SCROLL2, 0x04000, 0x07fff, 0 },
{ GFXTYPE_SCROLL3, 0x00000, 0x07fff, 1 },
{ GFXTYPE_SCROLL1, 0x07000, 0x07fff, 1 },
{ GFXTYPE_SPRITES | GFXTYPE_SCROLL2, 0x10000, 0x17fff, 2 },
{ GFXTYPE_SCROLL1, 0x08000, 0x0bfff, 2 },
{ GFXTYPE_SCROLL3, 0x1c000, 0x1ffff, 2 },
{ 0, 0, 0, 0 }
};
static const struct GfxRange mapper_ST22B_table[] = {
{ GFXTYPE_STARS, 0x00000, 0x1ffff, 0 },
{ GFXTYPE_SPRITES, 0x00000, 0x03fff, 0 },
@@ -107,6 +120,17 @@ static const struct GfxRange mapper_WL24B_table[] = {
{ 0 , 0, 0, 0 }
};
// Final Fight EX: published 6 MiB (4+2) graphics mapper.
static const struct GfxRange mapper_FFIGHTEX_table[] = {
{ GFXTYPE_SPRITES, 0x00000, 0x043ff, 0 },
{ GFXTYPE_SCROLL1, 0x04400, 0x04bff, 0 },
{ GFXTYPE_SCROLL3, 0x04c00, 0x05fff, 0 },
{ GFXTYPE_SCROLL2, 0x06000, 0x07fff, 0 },
{ GFXTYPE_SPRITES | GFXTYPE_SCROLL1 | GFXTYPE_SCROLL2 | GFXTYPE_SCROLL3, 0x08000, 0x0ffff, 0 },
{ GFXTYPE_SPRITES | GFXTYPE_SCROLL1 | GFXTYPE_SCROLL2 | GFXTYPE_SCROLL3, 0x10000, 0x17fff, 1 },
{ 0, 0, 0, 0 }
};
static const struct GfxRange mapper_S224B_table[] = {
{ GFXTYPE_SPRITES, 0x0000, 0x43ff, 0 },
{ GFXTYPE_SCROLL1, 0x4400, 0x4bff, 0 },
@@ -542,6 +566,24 @@ void SetGfxMapper(INT32 MapperId)
return;
}
case mapper_FFIGHTEX: {
GfxBankSizes[0] = 0x10000;
GfxBankSizes[1] = 0x08000;
GfxBankSizes[2] = 0x00000;
GfxBankSizes[3] = 0x00000;
GfxBankMapper = mapper_FFIGHTEX_table;
return;
}
case mapper_STRIDEREX: {
GfxBankSizes[0] = 0x08000;
GfxBankSizes[1] = 0x08000;
GfxBankSizes[2] = 0x10000;
GfxBankSizes[3] = 0x00000;
GfxBankMapper = mapper_STRIDEREX_table;
return;
}
case mapper_ST24M1: {
GfxBankSizes[0] = 0x8000;
GfxBankSizes[1] = 0x8000;
+3 -2
View File
@@ -1,6 +1,8 @@
#include "cps.h"
// CPS - Draw
CpsDrawPaletteCallback CpsDrawPaletteCallbackFunction = NULL;
UINT8 CpsRecalcPal = 0; // Flag - If it is 1, recalc the whole palette
static INT32 LayerCont;
@@ -499,8 +501,7 @@ static void DoDraw(INT32 Recalc)
{
CtvReady(); // Point to correct tile drawing functions
// xmvsf3v3: a state load restores the effective palette itself; rereading palette RAM would lose it
if (!CpsPalConsumeRestoredCache()) {
if (!CpsDrawPaletteCallbackFunction || !CpsDrawPaletteCallbackFunction()) {
if (CpsRecalcPal || bCpsUpdatePalEveryFrame) GetPalette(0, 6);
if (Recalc || bCpsUpdatePalEveryFrame) CpsPalUpdate(CpsSavePal); // recalc whole palette if needed
}
+17 -137
View File
@@ -16,6 +16,9 @@ UINT8 *CpsRam660=NULL,*CpsRam708=NULL,*CpsReg=NULL,*CpsFrg=NULL;
UINT8 *CpsRamFF=NULL;
CpsMemScanCallback CpsMemScanCallbackFunction = NULL;
CpsMemScanCallback CpsMemScanExtraCallbackFunction = NULL;
CpsSoundScanCallback CpsSoundScanCallbackFunction = NULL;
INT32 bCpsObjectBankHandlers = 0;
// This routine is called first to determine how much memory is needed
// and then to set up all the pointers.
@@ -87,6 +90,8 @@ void CpsDoMapObjectBanks(INT32 nBank)
{
nCpsObjectBank = nBank;
if (bCpsObjectBankHandlers) return;
if (nCpsObjectBank) {
SekMapMemory(CpsRam708 + 0x8000, 0x708000, 0x709FFF, MAP_RAM);
SekMapMemory(CpsRam708 + 0x8000, 0x70A000, 0x70BFFF, MAP_RAM);
@@ -117,106 +122,6 @@ INT32 __fastcall CPSResetCallback()
return 0;
}
// samples:
// empty + 0x3f L, channel 0, sample + 0x00
// empty + 0x3f R, channel 1, sample + 0x40
static void samples_l_start(int channel, int sample, int loop)
{
BurnSampleChannelPlay(channel + 0x00, sample + 0x00, loop);
}
static int samples_l_playing()
{
return BurnSampleGetChannelStatus(0x00) == SAMPLE_PLAYING;
}
static int samples_r_playing()
{
return BurnSampleGetChannelStatus(0x01) == SAMPLE_PLAYING;
}
static void samples_r_start(int channel, int sample, int loop)
{
BurnSampleChannelPlay(channel + 0x01, sample + 0x40, loop);
}
// ----------------------------------------------------------------------------
static void qsound_cps2turbo_write(UINT32 offset, UINT8 data) //Zero800 allows you to write and signal when a new song is played
{
UINT8 *m_qsound_sharedram1 = CpsZRamC0;
UINT8 *m_qsound_sharedram2 = CpsZRamF0;
if (offset == 0x0001 && (data & 0xff) == 0x00 && m_qsound_sharedram1[0x00] == 0xff) //stop samples sound
{
samples_l_start(0, 0, 0);
samples_r_start(0, 0, 0);
bprintf(0, _T("Stop: %02x to %x\n"), offset, offset);
}
if (offset == 0xffe)
{
if (m_qsound_sharedram1[0x80] == 0x77) //stop music condition in audiocpu = C080 (z80 hacked)
{
samples_l_start(0, 0, 0); //init L samples
samples_r_start(0, 0, 0); //init R samples
m_qsound_sharedram2[0x27] = 0xc9; //Enable Qsound Volume
m_qsound_sharedram1[0x80] = 0xff; //Reset music id flag
m_qsound_sharedram1[0x81] = 0xff; //Reset music id flag
bprintf(0, _T("Clear: %02x to %x\n"), data, offset);
}
else
if (m_qsound_sharedram1[0x81] > 0x00 && m_qsound_sharedram1[0x81] < 0x40) //play music condition in audiocpu = C081 (z80 hacked)
{
int data_byte = m_qsound_sharedram1[0x81];
m_qsound_sharedram1[0x80] = 0xff; //Reset music id flag
m_qsound_sharedram1[0x81] = 0xff; //Reset music id flag
bprintf(0, _T("Music: %02x to %x\n"), data_byte, offset);
samples_l_start(0, data_byte, 1);
if (samples_l_playing() == 1)
{
m_qsound_sharedram2[0x27] = 0x00; //Qsound music volume = 0
}
else
samples_l_start(0, 0, 0); //init L samples
samples_r_start(0, data_byte, 1);
if (samples_r_playing() == 1)
{
m_qsound_sharedram2[0x27] = 0x00; //Qsound music volume = 0
}
else
samples_r_start(0, 0, 0); //init R samples
}
else
if (m_qsound_sharedram2[0x27] == 0x00 && samples_l_playing() != 1) //if loadstate and qsound volume = 0 && samples stopped
{
samples_l_start(0, 0, 0); //init L samples
samples_r_start(0, 0, 0); //init R samples
m_qsound_sharedram2[0x27] = 0xc9; //Enable Qsound Volume
m_qsound_sharedram1[0x80] = 0xff; //Reset music id flag
m_qsound_sharedram1[0x81] = 0xff; //Reset music id flag
bprintf(0, _T("Volume0: %02x to %x\n"), data, offset);
}
else
if (m_qsound_sharedram2[0x27] != 0x00 && samples_l_playing() == 1) //if loadstate and qsound volume != 0 && samples playing
{
samples_l_start(0, 0, 0); //init L samples
samples_r_start(0, 0, 0); //init R samples
m_qsound_sharedram2[0x27] = 0xc9; //Enable Qsound Volume
m_qsound_sharedram1[0x80] = 0xff; //Reset music id flag
m_qsound_sharedram1[0x81] = 0xff; //Reset music id flag
bprintf(0, _T("Volume0: %02x to %x\n"), data, offset);
}
else
if ((data & 0xff) == 0x55) //init samples in rom start
{
samples_l_start(0, 0, 0);
samples_r_start(0, 0, 0);
}
}
m_qsound_sharedram1[offset] = data; //Play data Qsound
}
UINT8 __fastcall CPSQSoundC0ReadByte(UINT32 sekAddress)
{
// bprintf(PRINT_NORMAL, _T(" QS %06X read\n"), sekAddress);
@@ -241,10 +146,6 @@ void __fastcall CPSQSoundC0WriteByte(UINT32 sekAddress, UINT8 byteValue)
sekAddress &= 0x1FFF;
if (Cps2Turbo) {
qsound_cps2turbo_write(sekAddress >> 1, byteValue);
}
#if 1 && defined USE_SPEEDHACKS
// Sync only when the last byte of the sound command is written
if (sekAddress == 0x001F) {
@@ -361,25 +262,19 @@ INT32 CpsMemInit()
SekSetResetCallback(CPSResetCallback);
if (Cps2Turbo) {
// hmmmmmm
bprintf(0, _T("limit 68k to 0x400000\n"));
nCpsRomLen = 0x400000;
nCpsCodeLen = 0x400000;
}
// Map in memory:
// 68000 Rom (as seen as is, through read)
SekMapMemory(CpsRom, 0, nCpsRomLen - 1, MAP_READ);
UINT32 nRomMapLen = nCpsRomMapLen ? nCpsRomMapLen : nCpsRomLen;
SekMapMemory(CpsRom, 0, nRomMapLen - 1, MAP_READ);
// 68000 Rom (as seen decrypted, through fetch)
if (nCpsCodeLen > 0) {
// Decoded part (up to nCpsCodeLen)
SekMapMemory(CpsCode, 0, nCpsCodeLen - 1, MAP_FETCH);
}
if (nCpsRomLen > nCpsCodeLen) {
// The rest (up to nCpsRomLen)
SekMapMemory(CpsRom + nCpsCodeLen, nCpsCodeLen, nCpsRomLen - 1, MAP_FETCH);
if (nRomMapLen > nCpsCodeLen) {
// The remaining program data is fetched without decryption.
SekMapMemory(CpsRom + nCpsCodeLen, nCpsCodeLen, nRomMapLen - 1, MAP_FETCH);
}
if (Cps == 2) {
@@ -456,6 +351,9 @@ INT32 CpsMemExit()
BurnFree(CpsMem);
CpsMemScanCallbackFunction = NULL;
CpsMemScanExtraCallbackFunction = NULL;
CpsSoundScanCallbackFunction = NULL;
bCpsObjectBankHandlers = 0;
return 0;
}
@@ -541,11 +439,9 @@ INT32 CpsAreaScan(INT32 nAction, INT32 *pnMin)
SCAN_VAR(nCps1LayerOffs);
}
CpsRwScan(); // scan cps_rw.cpp stuff
if (CpsMemScanExtraCallbackFunction && CpsMemScanExtraCallbackFunction(nAction, pnMin)) return 1;
if (Cps2Turbo) {
BurnSampleScan(nAction, pnMin);
}
CpsRwScan(); // scan cps_rw.cpp stuff
if (nAction & ACB_WRITE) { // Palette could have changed
CpsRecalcPal = 1;
@@ -559,7 +455,8 @@ INT32 CpsAreaScan(INT32 nAction, INT32 *pnMin)
}
if (((Cps == 2) && !Cps2DisableQSnd) || Cps1Qs == 1) { // Scan QSound chips
QsndScan(nAction);
if (CpsSoundScanCallbackFunction) CpsSoundScanCallbackFunction(nAction, pnMin);
else QsndScan(nAction);
} else { // Scan PSound chips
if ((Cps & 1) && !Cps1DisablePSnd) PsndScan(nAction, pnMin);
}
@@ -570,20 +467,3 @@ INT32 CpsAreaScan(INT32 nAction, INT32 *pnMin)
return 0;
}
// xmvsf3v3: the display state other games rebuild after a load (latched palette, registers and
// 'four' registers, sprite lag buffers), so its states restore exactly, a paused redraw included
INT32 CpsXmvVisualScan(INT32 nAction)
{
if (!CpsXmvSixEnabled || !(nAction & ACB_DRIVER_DATA)) return 0;
struct BurnArea ba;
memset(&ba, 0, sizeof(ba));
ba.Data = CpsSavePal; ba.nLen = 0x2000; ba.szName = "XMvsSF 3v3 latched palette"; BurnAcb(&ba);
ba.Data = CpsSaveRegData; ba.nLen = 0x100 * (MAX_RASTER + 1); ba.szName = "XMvsSF 3v3 latched registers"; BurnAcb(&ba);
ba.Data = CpsSaveFrgData; ba.nLen = 0x20; ba.szName = "XMvsSF 3v3 latched frg"; BurnAcb(&ba);
if (CpsObjVisualScan(nAction)) return 1;
return CpsPalVisualScan(nAction);
}
+63 -45
View File
@@ -1,8 +1,8 @@
#include "cps.h"
#include "xmvsf3v3.h"
// CPS Objs (sprites)
INT32 nCpsObjectBank;
INT32 nCpsObjExtraLen = 0;
INT32 Sfa2ObjHack = 0;
UINT8 *CpsBootlegSpriteRam = NULL;
@@ -12,9 +12,14 @@ INT32 Cps1DetectEndSpriteList8000 = 0;
Cps1ObjGetCallback Cps1ObjGetCallbackFunction = NULL;
Cps1ObjDrawCallback Cps1ObjDrawCallbackFunction = NULL;
Cps2ObjGetCallback Cps2ObjGetCallbackFunction = NULL;
Cps2ObjTileCallback Cps2ObjTileCallbackFunction = NULL;
Cps2ObjPaletteCallback Cps2ObjPaletteCallbackFunction = NULL;
INT32 bCpsUseParentBlend = 1;
// Our copy of the sprite table
static UINT8 *ObjMem = NULL;
static INT32 nObjMemLen;
static INT32 nMax = 0;
static INT32 nGetNext = 0;
@@ -28,6 +33,7 @@ static INT32 nZOffset;
struct ObjFrame {
INT32 nShiftX, nShiftY;
UINT8* Obj;
UINT8* Extra;
INT32 nCount;
};
@@ -35,10 +41,12 @@ static INT32 nFrameCount = 0;
static struct ObjFrame of[3];
static UINT8 *blendtable;
static UINT32 nBlendCount;
static void CpsBlendInit()
{
blendtable = NULL;
nBlendCount = 0;
TCHAR filename[MAX_PATH];
@@ -46,12 +54,8 @@ static void CpsBlendInit()
FILE *fa = _tfopen(filename, _T("rt"));
INT32 is_sfz3mix = strstr("sfz3mix", BurnDrvGetTextA(DRV_NAME)) != NULL;
if (fa == NULL) {
if (is_sfz3mix) {
// for sfz3mix, don't use parent's blend table. sfz3mix uses different
// sprite indexing
if (!bCpsUseParentBlend) {
return;
}
@@ -66,8 +70,15 @@ static void CpsBlendInit()
bprintf (PRINT_IMPORTANT, _T("Using sprite blending (.bld) table!\n"));
blendtable = (UINT8*)BurnMalloc(0x40000); // maximum number of sprites
memset (blendtable, 0, 0x40000); // no blend
// One entry per 16x16 tile; retain the native range for mirrored tile addresses.
nBlendCount = (nCpsGfxMask + 1) >> 7;
if (nBlendCount < 0x40000) nBlendCount = 0x40000;
blendtable = (UINT8*)BurnMalloc(nBlendCount);
if (blendtable == NULL) {
fclose(fa);
return;
}
memset(blendtable, 0, nBlendCount);
char szLine[64];
@@ -97,7 +108,7 @@ static void CpsBlendInit()
}
for (k = min; k <= max; k++) {
if (k < 0x40000)
if (k < nBlendCount)
blendtable[k] = table[type&3];
}
}
@@ -118,19 +129,17 @@ INT32 CpsObjInit()
nFrameCount = 2; // CPS2 sprites lagged by 1 frame and double buffered
// CPS1 sprites lagged by 1 frame
ObjMem = (UINT8*)BurnMalloc((nMax << 3) * nFrameCount);
nObjMemLen = ((nMax << 3) + nCpsObjExtraLen) * nFrameCount;
ObjMem = (UINT8*)BurnMalloc(nObjMemLen);
if (ObjMem == NULL) {
return 1;
}
// xmvsf3v3: every buffer its states hold starts the same way
if (CpsXmvSixEnabled) memset(ObjMem, 0, (nMax << 3) * nFrameCount);
// Set up the frame buffers
for (INT32 i = 0; i < nFrameCount; i++) {
of[i].Obj = ObjMem + (nMax << 3) * i;
of[i].Extra = nCpsObjExtraLen ? ObjMem + (nMax << 3) * nFrameCount + nCpsObjExtraLen * i : NULL;
of[i].nCount = 0;
if (CpsXmvSixEnabled) of[i].nShiftX = of[i].nShiftY = 0;
}
nGetNext=0;
@@ -146,11 +155,18 @@ INT32 CpsObjInit()
INT32 CpsObjExit()
{
Cps2ObjGetCallbackFunction = NULL;
Cps2ObjTileCallbackFunction = NULL;
Cps2ObjPaletteCallbackFunction = NULL;
bCpsUseParentBlend = 1;
nCpsObjExtraLen = 0;
if (blendtable)
BurnFree(blendtable);
for (INT32 i = 0; i < nFrameCount; i++) {
of[i].Obj = NULL;
of[i].Extra = NULL;
of[i].nCount = 0;
}
@@ -167,6 +183,17 @@ INT32 CpsObjExit()
return 0;
}
void CpsObjReset()
{
if (ObjMem == NULL) return;
memset(ObjMem, 0, nObjMemLen);
for (INT32 i = 0; i < nFrameCount; i++) {
of[i].nCount = 0;
of[i].nShiftX = of[i].nShiftY = 0;
}
nGetNext = 0;
}
// Get CPS sprites into Obj
INT32 CpsObjGet()
{
@@ -236,6 +263,7 @@ INT32 CpsObjGet()
// Okay - this sprite is active:
memcpy(po, pg, 8); // copy it over
if (Cps2ObjGetCallbackFunction) Cps2ObjGetCallbackFunction(pof->Extra, pof->nCount, i);
pof->nCount++;
po += 8;
@@ -431,30 +459,17 @@ INT32 Cps2ObjDraw(INT32 nLevelFrom, INT32 nLevelTo)
// y -= CpsSaveFrg[0][0xB];
#endif
if (Cps2Turbo) {
if (BURN_ENDIAN_SWAP_INT16(ps[1]) & 0x1000) ps[1] |= BURN_ENDIAN_SWAP_INT16(0x8000);
n |= (BURN_ENDIAN_SWAP_INT16(ps[1]) & 0xe000) << 3; // high bits of address
} else {
n |= (BURN_ENDIAN_SWAP_INT16(ps[1]) & 0x6000) << 3; // high bits of address
}
n |= (BURN_ENDIAN_SWAP_INT16(ps[1]) & 0x6000) << 3;
// Find the palette for the tiles on this sprite
CpstPal = CpsPal + ((a & 0x1F) << 4);
// xmvsf3v3: the HUD's mini portraits in each fighter's colour, decoded from the program ROM
UINT32* pStockPal = CpstPal;
UINT32 nPortraitPal[16];
UINT32 nPortraitColor = 0;
if (CpsXmvSixEnabled && XmvPortraitObject(n, BURN_ENDIAN_SWAP_INT16(ps[0]), BURN_ENDIAN_SWAP_INT16(ps[1]), a, CpsXmvWide != 0, &nPortraitColor)) {
UINT16 nColors[16];
if (!XmvPortraitColors(CpsRom, nCpsRomLen, n, nPortraitColor, nColors)) {
continue; // the marker isn't a palette, so don't draw it with one
}
for (INT32 pen = 0; pen < 16; pen++) {
UINT32 c = nColors[pen];
nPortraitPal[pen] = BurnHighCol(((c >> 8) & 15) * 17, ((c >> 4) & 15) * 17, (c & 15) * 17, 0);
}
CpstPal = nPortraitPal;
UINT32 nObjectPal[16];
if (Cps2ObjPaletteCallbackFunction) {
INT32 nResult = Cps2ObjPaletteCallbackFunction(n, BURN_ENDIAN_SWAP_INT16(ps[0]), BURN_ENDIAN_SWAP_INT16(ps[1]), a, nObjectPal);
if (nResult < 0) continue;
if (nResult) CpstPal = nObjectPal;
}
nFlip = (a >> 5) & 3;
@@ -494,7 +509,11 @@ INT32 Cps2ObjDraw(INT32 nLevelFrom, INT32 nLevelTo)
nCpstY = y + (ey << 4);
// nCpstTile = n + (dy << 4) + dx; // normal version
nCpstTile = (n & ~0x0F) + (dy << 4) + ((n + dx) & 0x0F); // pgear fix
nCpstTile = (n & ~0x0F) + (dy << 4) + ((n + dx) & 0x0F); // pgear fix
if (Cps2ObjTileCallbackFunction) {
INT32 nEntry = ((UINT8*)ps - pof->Obj) >> 3;
nCpstTile = Cps2ObjTileCallbackFunction(ps, nCpstTile, pof->Extra, nEntry);
}
if (Sfa2ObjHack) {
// hack to not render blue squares on high score screen after name entry - they should be hidden by priority from what I can see
@@ -503,7 +522,7 @@ INT32 Cps2ObjDraw(INT32 nLevelFrom, INT32 nLevelTo)
//if (ps[2] == 0xa410) bprintf(PRINT_NORMAL, _T("%x, %x, %x, %x, %x, %x, %x\n"), nCpstTile, a & 0x1f, nCpstX, nCpstY, v, nLevelFrom, nLevelTo);
}
nCpsBlend = (blendtable) ? blendtable[nCpstTile] : 0;
nCpsBlend = (blendtable && nCpstTile < nBlendCount) ? blendtable[nCpstTile] : 0;
nCpstTile <<= 7; // Find real tile address
pCpstOne();
@@ -511,7 +530,7 @@ INT32 Cps2ObjDraw(INT32 nLevelFrom, INT32 nLevelTo)
}
}
CpstPal = pStockPal; // never leave it pointing at nPortraitPal
CpstPal = pStockPal; // never leave it pointing at nObjectPal
}
return 0;
@@ -907,19 +926,18 @@ INT32 FcrashObjDraw(INT32 nLevelFrom,INT32 nLevelTo)
return 0;
}
// xmvsf3v3: the sprite lag buffers (the Obj pointers are rebuilt by CpsObjInit, never saved).
// The Z buffer and its counters aren't saved: only drawing changes them, so they'd make a state
// depend on which frames were drawn (netplay replays and run-ahead's hidden frames aren't), and
// each frame's Z values start above what's already in the buffer
INT32 CpsObjVisualScan(INT32 nAction)
// Save the sprite lag buffers, but rebuild their pointers on initialization.
// The Z buffer and counters are drawing scratch: saving them would make states
// depend on which frames were drawn. Each frame starts above the old Z values.
INT32 CpsObjScan(INT32 nAction, char* szName)
{
if (!CpsXmvSixEnabled || !(nAction & ACB_DRIVER_DATA)) return 0;
if (!(nAction & ACB_DRIVER_DATA)) return 0;
struct BurnArea ba;
memset(&ba, 0, sizeof(ba));
ba.Data = ObjMem;
ba.nLen = (nMax << 3) * nFrameCount;
ba.szName = "XMvsSF 3v3 sprite lag buffers";
ba.nLen = nObjMemLen;
ba.szName = szName;
BurnAcb(&ba);
SCAN_VAR(nGetNext);
+19 -39
View File
@@ -3,8 +3,8 @@
// CPS (palette)
static bool CpsXmvPaletteRestored = false; // xmvsf3v3: CpsPalVisualScan() restored CpsPal
static UINT8* CpsPalSrc = NULL; // Copy of current input palette
CpsPalUpdateCallback CpsPalUpdateCallbackFunction = NULL;
UINT32* CpsPal = NULL; // Hicolor version of palette
INT32 nCpsPalCtrlReg;
INT32 bCpsUpdatePalEveryFrame = 0; // Some of the hacks need this as they don't write to CpsReg 0x0a
@@ -25,8 +25,6 @@ INT32 CpsPalInit()
if (CpsPal == NULL) {
return 1;
}
if (CpsXmvSixEnabled) memset(CpsPal, 0, nLen);
CpsXmvPaletteRestored = false;
return 0;
}
@@ -35,10 +33,21 @@ INT32 CpsPalExit()
{
BurnFree(CpsPal);
BurnFree(CpsPalSrc);
CpsPalUpdateCallbackFunction = NULL;
return 0;
}
// Update CpsPal with the new palette at pNewPal (length 0xc00 bytes)
static inline UINT32 CpsPalColor(UINT16 nRaw)
{
INT32 Palette = BURN_ENDIAN_SWAP_INT16(nRaw);
INT32 Bright = 0x0f + ((Palette >> 12) << 1);
INT32 r = ((Palette >> 8) & 0x0f) * 0x11 * Bright / 0x2d;
INT32 g = ((Palette >> 4) & 0x0f) * 0x11 * Bright / 0x2d;
INT32 b = ((Palette >> 0) & 0x0f) * 0x11 * Bright / 0x2d;
return BurnHighCol(r, g, b, 0);
}
// Update CpsPal with the new palette at pNewPal (length 0xc00 words)
INT32 CpsPalUpdate(UINT8* pNewPal)
{
UINT16 *ps, *pn;
@@ -47,23 +56,15 @@ INT32 CpsPalUpdate(UINT8* pNewPal)
pn = (UINT16*)pNewPal;
memcpy(ps, pn, 0xc00 * sizeof(UINT16));
INT32 nCtrl = CpsReg[nCpsPalCtrlReg];
UINT16 *PaletteRAM = (UINT16*)CpsPalSrc;
for (INT32 nPage = 0; nPage < 6; nPage++) {
if (BIT(nCtrl, nPage)) {
if (CpsPalUpdateCallbackFunction) CpsPalUpdateCallbackFunction(nPage, PaletteRAM);
for (INT32 Offset = 0; Offset < 0x200; ++Offset) {
INT32 Palette = BURN_ENDIAN_SWAP_INT16(*(PaletteRAM++));
INT32 r, g, b, Bright;
Bright = 0x0f + ((Palette >> 12) << 1);
r = ((Palette >> 8) & 0x0f) * 0x11 * Bright / 0x2d;
g = ((Palette >> 4) & 0x0f) * 0x11 * Bright / 0x2d;
b = ((Palette >> 0) & 0x0f) * 0x11 * Bright / 0x2d;
CpsPal[(0x200 * nPage) + (Offset ^ 15)] = BurnHighCol(r, g, b, 0);
CpsPal[(0x200 * nPage) + (Offset ^ 15)] = CpsPalColor(*PaletteRAM++);
}
} else {
if (PaletteRAM != (UINT16*)CpsPalSrc) {
@@ -75,28 +76,7 @@ INT32 CpsPalUpdate(UINT8* pNewPal)
return 0;
}
// xmvsf3v3: the effective colours: a palette DMA converts only the pages enabled at the time, and
// palette RAM may already hold the next DMA's colours, so rereading it after a load can't rebuild
// them; the pixel format must not change in between. CpsPalSrc isn't saved: CpsPalUpdate()
// overwrites it before reading it
INT32 CpsPalVisualScan(INT32 nAction)
void CpsPalRecalc(const UINT16* pRaw)
{
if (!CpsXmvSixEnabled || !(nAction & ACB_DRIVER_DATA)) return 0;
struct BurnArea ba;
memset(&ba, 0, sizeof(ba));
ba.Data = CpsPal; ba.nLen = 0xc00 * sizeof(UINT32); ba.szName = "XMvsSF 3v3 effective palette"; BurnAcb(&ba);
if (nAction & ACB_WRITE) CpsXmvPaletteRestored = true;
return 0;
}
INT32 CpsPalConsumeRestoredCache()
{
if (!CpsXmvSixEnabled || !CpsXmvPaletteRestored) return 0;
CpsXmvPaletteRestored = false;
return 1;
for (INT32 i = 0; i < 0xc00; i++) CpsPal[i ^ 15] = CpsPalColor(pRaw[i]);
}
-29
View File
@@ -6,7 +6,6 @@ INT32 Cps2Volume = 39;
INT32 Cps2DisableDigitalVolume = 0;
UINT8 Cps2VolUp;
UINT8 Cps2VolDwn;
UINT8 AspectDIP; // only for Cps2Turbo == 1
UINT16 Cps2VolumeStates[40] = {
0xf010, 0xf008, 0xf004, 0xf002, 0xf001, 0xe810, 0xe808, 0xe804, 0xe802, 0xe801,
@@ -36,8 +35,6 @@ INT32 Cps1VBlankIRQLine = 2;
INT32 Cps1DrawAtVblank = 0;
static UINT8 AspectDIPLast = 0;
CpsRunInitCallback CpsRunInitCallbackFunction = NULL;
CpsRunInitCallback CpsRunExitCallbackFunction = NULL;
CpsRunResetCallback CpsRunResetCallbackFunction = NULL;
@@ -59,23 +56,6 @@ static void CpsQSoundCheatSearchCallback()
}
}
static void check_aspect()
{
if (Cps2Turbo && (AspectDIP & 0x03) != AspectDIPLast) {
INT32 aspects[3][2] = { { 16, 9 }, { 4, 3 }, { 112, 81 } };
AspectDIPLast = AspectDIP & 0x03;
INT32 nAspectX, nAspectY;
BurnDrvGetAspect(&nAspectX, &nAspectY);
if (nAspectX != aspects[AspectDIPLast][0] || nAspectY != aspects[AspectDIPLast][1]) {
bprintf(0, _T("* CPS-2: Changing to %d:%d aspect\n"), aspects[AspectDIPLast][0], aspects[AspectDIPLast][1]);
BurnDrvSetAspect(aspects[AspectDIPLast][0], aspects[AspectDIPLast][1]);
Reinitialise();
}
}
}
static INT32 DrvReset()
{
// Reset machine
@@ -115,11 +95,6 @@ static INT32 DrvReset()
CpsRunResetCallbackFunction();
}
if (Cps2Turbo) {
AspectDIPLast = 0xff;
check_aspect();
}
HiscoreReset();
return 0;
@@ -433,10 +408,6 @@ INT32 Cps2Frame()
DrvReset();
}
if (Cps2Turbo) {
check_aspect();
}
// extern INT32 prevline;
// prevline = -1;
+11 -166
View File
@@ -1,7 +1,8 @@
#include "cps.h"
#include "xmvsf3v3.h"
// CPS - Read/Write
CpsRwGetInpCallback CpsRwGetInpCallbackFunction = NULL;
// Input bits
#define INP(nnn) UINT8 CpsInp##nnn[8];
CPSINPSET
@@ -48,7 +49,6 @@ INT32 Ssf2tb = 0;
INT32 Dinohunt = 0;
INT32 Port6SoundWrite = 0;
INT32 CpsBootlegEEPROM = 0;
INT32 Cps2Turbo = 0;
INT32 Jurassic99 = 0;
INT32 Dinoh = 0;
INT32 Wofhfh = 0;
@@ -466,130 +466,8 @@ void CpsWritePort(const UINT32 ia, UINT8 d)
// bprintf(PRINT_NORMAL, _T("Write Port %x, %x\n"), ia, d);
}
// X-Men Vs. Street Fighter 3v3 + DHC board additions (see xmvsf3v3.h), enabled by its drivers only
UINT8 CpsXmvSixButtons[XMV6_PLAYERS][13];
INT32 CpsXmvSixEnabled = 0;
INT32 CpsXmvWide = 0;
static UINT16 CpsXmvSixCapabilities = 0;
static XmvSixInputState CpsXmvSixState;
static UINT8 *CpsXmvSixWorkRam = NULL;
INT32 CpsXmvSixInit(INT32 bWide)
{
CpsXmvSixWorkRam = (UINT8*)BurnMalloc(XMV6_WORK_RAM_BYTES);
if (CpsXmvSixWorkRam == NULL) {
return 1;
}
CpsXmvWide = bWide ? 1 : 0;
CpsXmvSixCapabilities = XMV6_CAP_WORK_RAM | XMV6_CAP_PORTRAITS | XMV6_CAP_PORTRAITS_6 | XMV6_CAP_PORTRAITS_12 | XMV6_CAP_PORTRAITS_18;
if (bWide) {
CpsXmvSixCapabilities |= XMV6_CAP_WIDE | XMV6_CAP_WIDE_SCROLL1;
}
CpsXmvSixEnabled = 1;
memset(CpsXmvSixButtons, 0, sizeof(CpsXmvSixButtons));
CpsXmvSixReset();
return 0;
}
void CpsXmvSixExit()
{
CpsXmvSixEnabled = 0;
CpsXmvWide = 0;
BurnFree(CpsXmvSixWorkRam);
}
INT32 CpsXmvSixReset()
{
if (!CpsXmvSixEnabled) return 0;
XmvSixReset(&CpsXmvSixState);
memset(CpsXmvSixWorkRam, 0, XMV6_WORK_RAM_BYTES);
return 0;
}
INT32 CpsXmvSixScan(INT32 nAction, INT32* /*pnMin*/)
{
if (!CpsXmvSixEnabled) return 0;
if (nAction & ACB_MEMORY_RAM) {
struct BurnArea ba;
memset(&ba, 0, sizeof(ba));
ba.Data = CpsXmvSixWorkRam;
ba.nLen = XMV6_WORK_RAM_BYTES;
ba.nAddress = XMV6_WORK_RAM_BASE;
ba.szName = "XMvsSF 3v3 work RAM";
BurnAcb(&ba);
}
if (nAction & ACB_DRIVER_DATA) {
SCAN_VAR(CpsXmvSixState);
if (nAction & ACB_WRITE) {
if (CpsXmvSixState.abi != XMV6_VERSION || CpsXmvSixState.count > XMV6_DEPTH) {
// not a state of this board
CpsXmvSixReset();
return 1;
}
}
}
return CpsXmvVisualScan(nAction);
}
// Wide screen: while the ROM keeps 'XS1X' at 0x813ff8, scroll1 columns 64-127 come from 0x814000
const UINT8* CpsXmvScroll1Extension()
{
if (!CpsXmvSixEnabled || !CpsXmvWide) return NULL;
const UINT8* tag = CpsXmvSixWorkRam + 0x3ff8;
if (tag[0] != 'X' || tag[1] != 'S' || tag[2] != '1' || tag[3] != 'X') return NULL;
return CpsXmvSixWorkRam + 0x4000;
}
// Once a frame, before the input ports are compiled
static void CpsXmvSixSample()
{
UINT16 raw[XMV6_PLAYERS];
for (INT32 p = 0; p < XMV6_PLAYERS; p++) {
raw[p] = 0;
for (INT32 bit = 0; bit < 13; bit++) {
raw[p] |= (CpsXmvSixButtons[p][bit] & 1) << bit;
}
}
XmvSixSample(&CpsXmvSixState, raw);
// P1 and P2 also reach the stock input ports, for the game's own menus
for (INT32 bit = 0; bit < 7; bit++) {
CpsInp001[bit] = (CpsXmvSixState.held[0] >> bit) & 1;
CpsInp000[bit] = (CpsXmvSixState.held[1] >> bit) & 1;
}
for (INT32 p = 0; p < 2; p++) {
UINT16 value = CpsXmvSixState.held[p];
CpsInp011[p * 4 + 0] = (value >> 8) & 1; // weak kick
CpsInp011[p * 4 + 1] = (value >> 9) & 1; // medium kick
CpsInp020[p + 0] = (value >> 11) & 1; // start
CpsInp020[p + 4] = (value >> 12) & 1; // coin
}
CpsInp011[2] = (CpsXmvSixState.held[0] >> 10) & 1; // P1 strong kick
CpsInp020[6] = (CpsXmvSixState.held[1] >> 10) & 1; // P2 strong kick
}
UINT8 __fastcall CpsReadByte(UINT32 a)
{
if (CpsXmvSixEnabled) {
if (a >= XMV6_BASE && a < XMV6_BASE + XMV6_WINDOW_BYTES) {
return XmvSixReadByte(&CpsXmvSixState, CpsXmvSixCapabilities, a - XMV6_BASE);
}
if (a >= XMV6_WORK_RAM_BASE && a < XMV6_WORK_RAM_BASE + XMV6_WORK_RAM_BYTES) {
return CpsXmvSixWorkRam[a - XMV6_WORK_RAM_BASE];
}
}
// Input ports mirrored between 0x800000 and 0x807fff
if ((a & 0xFF8000) == 0x800000) {
return CpsReadPort(a & 0x1FF);
@@ -618,11 +496,6 @@ UINT8 __fastcall CpsReadByte(UINT32 a)
void __fastcall CpsWriteByte(UINT32 a,UINT8 d)
{
if (CpsXmvSixEnabled && a >= XMV6_WORK_RAM_BASE && a < XMV6_WORK_RAM_BASE + XMV6_WORK_RAM_BYTES) {
CpsXmvSixWorkRam[a - XMV6_WORK_RAM_BASE] = d;
return;
}
// Output ports mirrored between 0x800000 and 0x807fff
if ((a & 0xFF8000) == 0x800000) {
CpsWritePort(a & 0x1FF, d);
@@ -631,20 +504,9 @@ void __fastcall CpsWriteByte(UINT32 a,UINT8 d)
if (Cps == 2) {
// 0x400000 registers
if (Cps2Turbo) {
if ((a & 0xFFFFF0) == 0x665000) {
CpsFrg[a & 0x0F] = d;
return;
}
if ((a & 0xFFFFF0) == 0xfffff0) {
CpsFrg[a & 0x0F] = d;
return;
}
} else {
if ((a & 0xFFFFF0) == 0x400000) {
CpsFrg[a & 0x0F] = d;
return;
}
if ((a & 0xFFFFF0) == 0x400000) {
CpsFrg[a & 0x0F] = d;
return;
}
if ((a & 0xFF8000) == 0x660000) {
if (a == 0x664001) {
@@ -671,15 +533,6 @@ void __fastcall CpsWriteByte(UINT32 a,UINT8 d)
UINT16 __fastcall CpsReadWord(UINT32 a)
{
if (CpsXmvSixEnabled) {
if (a >= XMV6_BASE && a < XMV6_BASE + XMV6_WINDOW_BYTES) {
return XmvSixReadWord(&CpsXmvSixState, CpsXmvSixCapabilities, a - XMV6_BASE);
}
if (a >= XMV6_WORK_RAM_BASE && a < XMV6_WORK_RAM_BASE + XMV6_WORK_RAM_BYTES) {
return XmvSixRamReadWord(CpsXmvSixWorkRam, a - XMV6_WORK_RAM_BASE);
}
}
if ((a & 0xFF8FFF) == 0x800100 + CpsMProt[3]) {
return (UINT16)((nCalc[0] * nCalc[1]) >> 16);
}
@@ -695,11 +548,6 @@ UINT16 __fastcall CpsReadWord(UINT32 a)
void __fastcall CpsWriteWord(UINT32 a, UINT16 d)
{
if (CpsXmvSixEnabled && a >= XMV6_WORK_RAM_BASE && a < XMV6_WORK_RAM_BASE + XMV6_WORK_RAM_BYTES) {
XmvSixRamWriteWord(CpsXmvSixWorkRam, a - XMV6_WORK_RAM_BASE, d);
return;
}
// ports mirrored between 0x800000 and 0x807fff
if ((a & 0xFF8FFF) == 0x800100 + CpsMProt[0])
nCalc[0] = d;
@@ -742,6 +590,7 @@ INT32 CpsRwInit()
INT32 CpsRwExit()
{
CpsRwGetInpCallbackFunction = NULL;
InpBlank();
CpsRWSoundCommandCallbackFunction = NULL;
return 0;
@@ -749,9 +598,7 @@ INT32 CpsRwExit()
INT32 CpsRwGetInp()
{
if (CpsXmvSixEnabled) {
CpsXmvSixSample();
}
INT32 nPortPlayers = CpsRwGetInpCallbackFunction ? CpsRwGetInpCallbackFunction() : nMaxPlayers;
// Compile separate buttons into Inpxxx
#define INP(nnn) \
@@ -862,22 +709,20 @@ INT32 CpsRwGetInp()
}
}
// xmvsf3v3: players 3-6 never reach the stock ports (Inp011 is P1/P2's kicks there), and
// CpsXmvSixSample() has already cleaned every player's opposite directions
if (nMaxPlayers > 2 && !CpsXmvSixEnabled) {
if (nPortPlayers > 2) {
if (Cps == 2) {
clear_opposite.check(2, Inp011, 0x08, 0x04, 0x02, 0x01, nSocd[2]);
if (nMaxPlayers == 4) {
if (nPortPlayers == 4) {
clear_opposite.check(3, Inp010, 0x08, 0x04, 0x02, 0x01, nSocd[3]);
}
} else {
clear_opposite.check(2, Inp177, 0x08, 0x04, 0x02, 0x01, nSocd[2]);
if (nMaxPlayers == 4) {
if (nPortPlayers == 4) {
clear_opposite.check(3, Inp179, 0x08, 0x04, 0x02, 0x01, nSocd[3]);
}
if (Cps1Qs) {
clear_opposite.check(2, Inpc001, 0x08, 0x04, 0x02, 0x01, nSocd[2]);
if (nMaxPlayers == 4) {
if (nPortPlayers == 4) {
clear_opposite.check(3, Inpc003, 0x08, 0x04, 0x02, 0x01, nSocd[3]);
}
}
+9 -7
View File
@@ -1,5 +1,8 @@
#include "cps.h"
Cps2ScrollCallback Cps2ScrollCallbackFunction = NULL;
Cps2Scroll1Callback Cps2Scroll1CallbackFunction = NULL;
// CPS Scroll (Background Layers)
// Base = 0x4000 long tile map
@@ -82,8 +85,8 @@ INT32 Cps2Scr1Draw(UINT8 *Base, INT32 sx, INT32 sy)
INT32 nKnowBlank = -1; // The tile we know is blank
INT32 nXTile = nCpsScreenWidth>>3; // 8x8 tiles
// xmvsf3v3 wide screen: scroll1 columns 64-127 can come from the board's extra work RAM
const UINT8* pExt = CpsXmvScroll1Extension();
// A board may supply the upper half of the scroll1 tilemap.
const UINT8* pExt = Cps2Scroll1CallbackFunction ? Cps2Scroll1CallbackFunction() : NULL;
ix = (sx >> 3) + 1;
sx &= 7;
@@ -115,10 +118,10 @@ INT32 Cps2Scr1Draw(UINT8 *Base, INT32 sx, INT32 sy)
t = pe ? ((pe[0] << 8) | pe[1]) : BURN_ENDIAN_SWAP_INT16(pst[0]);
t <<= 6; // Get real tile address
t += nCpsGfxScroll[1]; // add on offset to scroll tiles
a = pe ? ((pe[2] << 8) | pe[3]) : BURN_ENDIAN_SWAP_INT16(pst[1]);
t = Cps2ScrollAddress(t, a, 1);
if (t != nKnowBlank) { // Draw tile
a = pe ? ((pe[2] << 8) | pe[3]) : BURN_ENDIAN_SWAP_INT16(pst[1]);
CpstSetPal(0x20 | (a & 0x1F));
@@ -242,11 +245,10 @@ INT32 Cps2Scr3Draw(UINT8 *Base, INT32 sx, INT32 sy)
if(Xmcota && t>=0x5800) t-=0x4000;
else if(Ssf2t && t<0x5600) t+=0x4000;
t <<= 9; // Get real tile address
if (Cps2Turbo) t &= ~nCpsGfxScroll[3]; // buggy hack
t += nCpsGfxScroll[3]; // add on offset to scroll tiles
a = BURN_ENDIAN_SWAP_INT16(pst[1]);
t = Cps2ScrollAddress(t, a, 3);
if (t != nKnowBlank) { // Draw tile
a = BURN_ENDIAN_SWAP_INT16(pst[1]);
CpstSetPal(0x60 | (a & 0x1F));
+4 -4
View File
@@ -76,9 +76,9 @@ static void Cps2TileLine(INT32 y,INT32 sx)
pst=FindTile(ix+x,iy+y);
t = BURN_ENDIAN_SWAP_INT16(pst[0]);
t<<=7; // Get real tile address
t+=nCpsGfxScroll[2]; // add on offset to scroll tiles
a = BURN_ENDIAN_SWAP_INT16(pst[1]);
t = Cps2ScrollAddress(t, a, 2);
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a = BURN_ENDIAN_SWAP_INT16(pst[1]);
CpstSetPal(0x40 | (a&0x1f));
nCpstX=sx+(x<<4); nCpstTile=t; nCpstFlip=(a>>5)&3;
@@ -185,10 +185,10 @@ static void Cps2TileLineRows(INT32 y,struct CpsrLineInfo *pli)
pst=FindTile(tx,iy+y);
t = BURN_ENDIAN_SWAP_INT16(pst[0]);
t<<=7; // Get real tile address
t+=nCpsGfxScroll[2]; // add on offset to scroll tiles
a = BURN_ENDIAN_SWAP_INT16(pst[1]);
t = Cps2ScrollAddress(t, a, 2);
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a = BURN_ENDIAN_SWAP_INT16(pst[1]);
CpstSetPal(0x40 | (a&0x1f));
+174
View File
@@ -7348,6 +7348,62 @@ static struct BurnRomInfo DynwarjrRomDesc[] = {
STD_ROM_PICK(Dynwarjr)
STD_ROM_FN(Dynwarjr)
// https://arcadepatches.com/projects/final-fight-ex/ (RC4)
static struct BurnRomInfo Ffightus01RomDesc[] = {
{ "c07.p1", 0x020000, 0x1bbe6639, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07.p2", 0x020000, 0x9a9fe4f3, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07.p3", 0x020000, 0xd3c9e580, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07u.p4", 0x020000, 0x55a29283, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07.p5", 0x080000, 0x1c9b1b36, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_NO_BYTESWAP },
{ "c07us01.p7", 0x100000, 0xe6e4df5f, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_NO_BYTESWAP },
{ "c07.c01", 0x080000, 0x7b4aad16, BRF_GRA | CPS1_TILES },
{ "c07.c03", 0x080000, 0x28192faf, BRF_GRA | CPS1_TILES },
{ "c07.c05", 0x080000, 0xdeff8c10, BRF_GRA | CPS1_TILES },
{ "c07.c07", 0x080000, 0x4b532b36, BRF_GRA | CPS1_TILES },
{ "c07us01.c09", 0x080000, 0x3365bae7, BRF_GRA | CPS1_TILES },
{ "c07us01.c11", 0x080000, 0x9f53c8e0, BRF_GRA | CPS1_TILES },
{ "c07us01.c13", 0x080000, 0xcf35f998, BRF_GRA | CPS1_TILES },
{ "c07us01.c15", 0x080000, 0xd65f25ed, BRF_GRA | CPS1_TILES },
{ "c07us01.c17", 0x080000, 0xc9dbe31e, BRF_GRA | CPS1_TILES },
{ "c07us01.c19", 0x080000, 0x30c802e6, BRF_GRA | CPS1_TILES },
{ "c07us01.c21", 0x080000, 0x936c49c4, BRF_GRA | CPS1_TILES },
{ "c07us01.c23", 0x080000, 0xce2427a3, BRF_GRA | CPS1_TILES },
{ "c07.m1", 0x010000, 0x87eca9ec, BRF_PRG | CPS1_Z80_PROGRAM },
{ "c07.v1", 0x020000, 0x375c66e7, BRF_SND | CPS1_OKIM6295_SAMPLES },
{ "c07.v2", 0x020000, 0x1ef137f9, BRF_SND | CPS1_OKIM6295_SAMPLES },
};
STD_ROM_PICK(Ffightus01)
STD_ROM_FN(Ffightus01)
// https://arcadepatches.com/projects/final-fight-ex/ (RC4)
static struct BurnRomInfo Ffightjs01RomDesc[] = {
{ "c07.p1", 0x020000, 0x4dcd780e, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07.p2", 0x020000, 0xfd0623ca, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07.p3", 0x020000, 0x4d30793c, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07j.p4", 0x020000, 0xdabe8850, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "c07.p5", 0x080000, 0xf9e7b052, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_NO_BYTESWAP },
{ "c07js01.p7", 0x100000, 0x8bdfd316, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_NO_BYTESWAP },
{ "c07.c01", 0x080000, 0x976bcfbb, BRF_GRA | CPS1_TILES },
{ "c07.c03", 0x080000, 0xcfeb60c6, BRF_GRA | CPS1_TILES },
{ "c07.c05", 0x080000, 0x32deeebd, BRF_GRA | CPS1_TILES },
{ "c07.c07", 0x080000, 0xaca1645f, BRF_GRA | CPS1_TILES },
{ "c07js01.c09", 0x080000, 0x923bfeba, BRF_GRA | CPS1_TILES },
{ "c07js01.c11", 0x080000, 0x2699067e, BRF_GRA | CPS1_TILES },
{ "c07js01.c13", 0x080000, 0xed5833cb, BRF_GRA | CPS1_TILES },
{ "c07js01.c15", 0x080000, 0xbed965c8, BRF_GRA | CPS1_TILES },
{ "c07js01.c17", 0x080000, 0x7d0a63fa, BRF_GRA | CPS1_TILES },
{ "c07js01.c19", 0x080000, 0xb61bca08, BRF_GRA | CPS1_TILES },
{ "c07js01.c21", 0x080000, 0x8e33931b, BRF_GRA | CPS1_TILES },
{ "c07js01.c23", 0x080000, 0xd60af261, BRF_GRA | CPS1_TILES },
{ "c07.m1", 0x010000, 0x57a4cf41, BRF_PRG | CPS1_Z80_PROGRAM },
{ "c07.v1", 0x020000, 0x375c66e7, BRF_SND | CPS1_OKIM6295_SAMPLES },
{ "c07.v2", 0x020000, 0x1ef137f9, BRF_SND | CPS1_OKIM6295_SAMPLES },
};
STD_ROM_PICK(Ffightjs01)
STD_ROM_FN(Ffightjs01)
static struct BurnRomInfo FfightRomDesc[] = {
{ "ff_36.11f", 0x020000, 0xf9a5ce83, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "ff_42.11h", 0x020000, 0x65f11215, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
@@ -16387,6 +16443,57 @@ static struct BurnRomInfo StriderfixRomDesc[] = {
STD_ROM_PICK(Striderfix)
STD_ROM_FN(Striderfix)
static struct BurnRomInfo Striderus01RomDesc[] = {
{ "c03us01.p1", 0x020000, 0x457395b9, CPS1_68K_PROGRAM_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03us01.p2", 0x020000, 0x118f8690, CPS1_68K_PROGRAM_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03us01.p3", 0x020000, 0x3306fd0f, CPS1_68K_PROGRAM_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03us01.p4", 0x020000, 0x1ac8cad9, CPS1_68K_PROGRAM_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03us01.p5", 0x080000, 0x06edfbaf, CPS1_68K_PROGRAM_NO_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03us01.p6", 0x100000, 0x075dfc39, CPS1_68K_PROGRAM_NO_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03us01.c01", 0x080000, 0xf92cc010, CPS1_TILES | BRF_GRA },
{ "c03us01.c03", 0x080000, 0x9abd7b1e, CPS1_TILES | BRF_GRA },
{ "c03us01.c05", 0x080000, 0x085ec243, CPS1_TILES | BRF_GRA },
{ "c03us01.c07", 0x080000, 0x2443df27, CPS1_TILES | BRF_GRA },
{ "c03.c17", 0x080000, 0x005f000b, CPS1_TILES | BRF_GRA },
{ "c03.c19", 0x080000, 0xb9441519, CPS1_TILES | BRF_GRA },
{ "c03.c21", 0x080000, 0xb7d04e8b, CPS1_TILES | BRF_GRA },
{ "c03.c23", 0x080000, 0x6b4713b4, CPS1_TILES | BRF_GRA },
{ "c03us01.c25", 0x100000, 0xe8507e5b, CPS1_TILES | BRF_GRA },
{ "c03us01.c27", 0x100000, 0x1120f48d, CPS1_TILES | BRF_GRA },
{ "c03us01.c29", 0x100000, 0xf7a36cd4, CPS1_TILES | BRF_GRA },
{ "c03us01.c31", 0x100000, 0xb0ef929a, CPS1_TILES | BRF_GRA },
{ "c03us01.m1", 0x010000, 0xa08e24b9, CPS1_Z80_PROGRAM | BRF_ESS | BRF_PRG },
{ "c03us01.v1", 0x020000, 0x897269dd, CPS1_OKIM6295_SAMPLES | BRF_SND },
{ "c03us01.v2", 0x020000, 0x3f56c8cc, CPS1_OKIM6295_SAMPLES | BRF_SND },
};
STD_ROM_PICK(Striderus01)
STD_ROM_FN(Striderus01)
static struct BurnRomInfo Striderjs01RomDesc[] = {
{ "c03js01.p1", 0x080000, 0x39260f46, CPS1_68K_PROGRAM_NO_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03js01.p5", 0x080000, 0xabc6d8ff, CPS1_68K_PROGRAM_NO_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03js01.p6", 0x100000, 0x150e1549, CPS1_68K_PROGRAM_NO_BYTESWAP | BRF_ESS | BRF_PRG },
{ "c03js01.c01", 0x080000, 0xf92cc010, CPS1_TILES | BRF_GRA },
{ "c03js01.c03", 0x080000, 0x9abd7b1e, CPS1_TILES | BRF_GRA },
{ "c03js01.c05", 0x080000, 0x085ec243, CPS1_TILES | BRF_GRA },
{ "c03js01.c07", 0x080000, 0x2443df27, CPS1_TILES | BRF_GRA },
{ "c03.c17", 0x080000, 0x005f000b, CPS1_TILES | BRF_GRA },
{ "c03.c19", 0x080000, 0xb9441519, CPS1_TILES | BRF_GRA },
{ "c03.c21", 0x080000, 0xb7d04e8b, CPS1_TILES | BRF_GRA },
{ "c03.c23", 0x080000, 0x6b4713b4, CPS1_TILES | BRF_GRA },
{ "c03js01.c25", 0x100000, 0xe8507e5b, CPS1_TILES | BRF_GRA },
{ "c03js01.c27", 0x100000, 0x1120f48d, CPS1_TILES | BRF_GRA },
{ "c03js01.c29", 0x100000, 0xf7a36cd4, CPS1_TILES | BRF_GRA },
{ "c03js01.c31", 0x100000, 0xb0ef929a, CPS1_TILES | BRF_GRA },
{ "c03js01.m1", 0x010000, 0xa08e24b9, CPS1_Z80_PROGRAM | BRF_ESS | BRF_PRG },
{ "c03js01.v1", 0x020000, 0x897269dd, CPS1_OKIM6295_SAMPLES | BRF_SND },
{ "c03js01.v2", 0x020000, 0x3f56c8cc, CPS1_OKIM6295_SAMPLES | BRF_SND },
};
STD_ROM_PICK(Striderjs01)
STD_ROM_FN(Striderjs01)
static struct BurnRomInfo UnsquadRomDesc[] = {
{ "aru_30.11f", 0x020000, 0x24d8f88d, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
{ "aru_35.11h", 0x020000, 0x8b954b59, BRF_ESS | BRF_PRG | CPS1_68K_PROGRAM_BYTESWAP },
@@ -17647,6 +17754,8 @@ static const struct GameConfig ConfigTable[] =
{ "ffightae" , CPS_B_21_DEF, mapper_S224B , 0, NULL },
{ "ffightaemgc" , CPS_B_21_DEF, mapper_S224B , 0, NULL },
{ "ffighta" , CPS_B_04 , mapper_S224B , 0, NULL },
{ "ffightus01" , CPS_B_04 , mapper_FFIGHTEX, 0, NULL },
{ "ffightjs01" , CPS_B_04 , mapper_FFIGHTEX, 0, NULL },
{ "ffightu" , CPS_B_04 , mapper_S224B , 0, NULL },
{ "ffightu1" , CPS_B_04 , mapper_S224B , 0, NULL },
{ "ffightu2" , CPS_B_04 , mapper_S224B , 0, NULL },
@@ -17908,6 +18017,8 @@ static const struct GameConfig ConfigTable[] =
{ "slampic" , CPS_B_21_QS4, mapper_MB63B , 0, slammast_patch },
{ "slampic2" , CPS_B_21_QS4, mapper_MB63B , 0, NULL },
{ "strider" , CPS_B_01 , mapper_ST24M1, 1, NULL },
{ "striderus01" , CPS_B_01 , mapper_STRIDEREX, 1, NULL },
{ "striderjs01" , CPS_B_21_DEF, mapper_STRIDEREX, 1, NULL },
{ "striderua" , CPS_B_01 , mapper_ST24M1, 1, NULL },
{ "strideruc" , CPS_B_17 , mapper_ST24M1, 1, NULL },
{ "striderjr" , CPS_B_21_DEF, mapper_ST24M1, 1, NULL },
@@ -22087,6 +22198,29 @@ static INT32 StriderjrInit()
return nRet;
}
// EX adds a program ROM before the graphics; derive the star ROM index
// from the loaded program inventory rather than the stock parent's index.
static INT32 StriderusexInit()
{
INT32 nRet = Cps1RasterInit();
if (!nRet) {
CpsStar = CpsGfx + nCpsGfxLen - 0x2000;
CpsLoadStars(CpsStar, nCps68KByteswapRomNum + nCps68KNoByteswapRomNum);
}
return nRet;
}
static INT32 StriderjexInit()
{
INT32 nRet = TwelveMhzInit();
if (!nRet) {
CpsStar = CpsGfx + nCpsGfxLen - 0x2000;
CpsLoadStars(CpsStar, nCps68KByteswapRomNum + nCps68KNoByteswapRomNum);
Cps1DrawAtVblank = 1;
}
return nRet;
}
static INT32 StriderjInit()
{
INT32 nRet = 0;
@@ -23716,6 +23850,26 @@ struct BurnDriver BurnDrvCpsDynwarjr = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsFfightus01 = {
"ffightus01", "ffight", NULL, NULL, "2026",
"Final Fight EX (USA, Backport RC4)\0", NULL, "Strygo", "CPS1",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS1, GBF_SCRFIGHT, 0,
NULL, Ffightus01RomInfo, Ffightus01RomName, NULL, NULL, NULL, NULL, FfightInputInfo, FfightDIPInfo,
DrvInit, DrvExit, Cps1Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsFfightjs01 = {
"ffightjs01", "ffight", NULL, NULL, "2026",
"Final Fight EX (Japan, Backport RC4)\0", NULL, "Strygo", "CPS1",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS1, GBF_SCRFIGHT, 0,
NULL, Ffightjs01RomInfo, Ffightjs01RomName, NULL, NULL, NULL, NULL, FfightInputInfo, FfightDIPInfo,
DrvInit, DrvExit, Cps1Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsFfight = {
"ffight", NULL, NULL, NULL, "1989",
"Final Fight (World, set 1)\0", NULL, "Capcom", "CPS1",
@@ -26336,6 +26490,26 @@ struct BurnDriver BurnDrvCpsStriderjr = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsStriderus01 = {
"striderus01", "strider", NULL, NULL, "2026",
"Strider EX (USA, Backport RC1)\0", NULL, "Strygo", "CPS1",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS1, GBF_PLATFORM | GBF_SCRFIGHT, 0,
NULL, Striderus01RomInfo, Striderus01RomName, NULL, NULL, NULL, NULL, StriderInputInfo, StrideruaDIPInfo,
StriderusexInit, DrvExit, Cps1Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsStriderjs01 = {
"striderjs01", "strider", NULL, NULL, "2026",
"Strider Hiryu EX (Japan, Backport RC1)\0", NULL, "Strygo", "CPS1",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS1, GBF_PLATFORM | GBF_SCRFIGHT, 0,
NULL, Striderjs01RomInfo, Striderjs01RomName, NULL, NULL, NULL, NULL, StriderInputInfo, StriderDIPInfo,
StriderjexInit, DrvExit, Cps1Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsStriderj = {
"striderj", "strider", NULL, NULL, "1989",
"Strider Hiryu (Japan)\0", NULL, "Capcom", "CPS1",
+191 -642
View File
@@ -40,57 +40,6 @@ static struct BurnInputInfo Cps2FightingInputList[] = {
STDINPUTINFO(Cps2Fighting)
static struct BurnInputInfo Sfz3mixInputList[] = {
{"P1 Coin" , BIT_DIGITAL , CpsInp020+4, "p1 coin" },
{"P1 Start" , BIT_DIGITAL , CpsInp020+0, "p1 start" },
{"P1 Up" , BIT_DIGITAL , CpsInp001+3, "p1 up" },
{"P1 Down" , BIT_DIGITAL , CpsInp001+2, "p1 down" },
{"P1 Left" , BIT_DIGITAL , CpsInp001+1, "p1 left" },
{"P1 Right" , BIT_DIGITAL , CpsInp001+0, "p1 right" },
{"P1 Weak Punch" , BIT_DIGITAL , CpsInp001+4, "p1 fire 1" },
{"P1 Medium Punch" , BIT_DIGITAL , CpsInp001+5, "p1 fire 2" },
{"P1 Strong Punch" , BIT_DIGITAL , CpsInp001+6, "p1 fire 3" },
{"P1 Weak Kick" , BIT_DIGITAL , CpsInp011+0, "p1 fire 4" },
{"P1 Medium Kick" , BIT_DIGITAL , CpsInp011+1, "p1 fire 5" },
{"P1 Strong Kick" , BIT_DIGITAL , CpsInp011+2, "p1 fire 6" },
{"P2 Coin" , BIT_DIGITAL , CpsInp020+5, "p2 coin" },
{"P2 Start" , BIT_DIGITAL , CpsInp020+1, "p2 start" },
{"P2 Up" , BIT_DIGITAL , CpsInp000+3, "p2 up" },
{"P2 Down" , BIT_DIGITAL , CpsInp000+2, "p2 down" },
{"P2 Left" , BIT_DIGITAL , CpsInp000+1, "p2 left" },
{"P2 Right" , BIT_DIGITAL , CpsInp000+0, "p2 right" },
{"P2 Weak Punch" , BIT_DIGITAL , CpsInp000+4, "p2 fire 1" },
{"P2 Medium Punch" , BIT_DIGITAL , CpsInp000+5, "p2 fire 2" },
{"P2 Strong Punch" , BIT_DIGITAL , CpsInp000+6, "p2 fire 3" },
{"P2 Weak Kick" , BIT_DIGITAL , CpsInp011+4, "p2 fire 4" },
{"P2 Medium Kick" , BIT_DIGITAL , CpsInp011+5, "p2 fire 5" },
{"P2 Strong Kick" , BIT_DIGITAL , CpsInp020+6, "p2 fire 6" },
{"Reset" , BIT_DIGITAL , &CpsReset , "reset" },
{"Diagnostic" , BIT_DIGITAL , CpsInp021+1, "diag" },
{"Service" , BIT_DIGITAL , CpsInp021+2, "service" },
{"Volume Up" , BIT_DIGITAL , &Cps2VolUp , "volumeup" },
{"Volume Down" , BIT_DIGITAL , &Cps2VolDwn, "volumedown"},
{"Dip A" , BIT_DIPSWITCH, &AspectDIP , "dip" },
};
STDINPUTINFO(Sfz3mix)
// sfz3mix 0.20+ only!
static struct BurnDIPInfo Sfz3mixDIPList[] =
{
DIP_OFFSET(0x1d)
{0x00, 0xff, 0xff, 0x00, NULL },
{0 , 0xfe, 0 , 3, "Aspect Ratio" },
{0x00, 0x01, 0x03, 0x00, "16:9" },
{0x00, 0x01, 0x03, 0x01, "4:3" },
{0x00, 0x01, 0x03, 0x02, "112:81" },
};
STDDIPINFO(Sfz3mix)
static struct BurnInputInfo NineXXInputList[] = {
{"P1 Coin" , BIT_DIGITAL , CpsInp020+4, "p1 coin" },
{"P1 Start" , BIT_DIGITAL , CpsInp020+0, "p1 start" },
@@ -9997,7 +9946,6 @@ static INT32 DrvExit()
Ssf2tb = 0;
Xmcota = 0;
Ecofght = 0;
CpsXmvSixExit();
Cps2Volume = 39;
Cps2DisableDigitalVolume = 0;
@@ -14146,160 +14094,6 @@ static struct BurnRomInfo Sfz3jr2dRomDesc[] = {
STD_ROM_PICK(Sfz3jr2d)
STD_ROM_FN(Sfz3jr2d)
// Street Fighter Zero 3 Mix v0.32 (hacked by Zero800)
// https://sfz3mix.github.io/
static struct BurnSampleInfo Sfz3mixSampleDesc[] = {
{ "empty", SAMPLE_NOLOOP },
{ "L01", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L02", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L03", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L04", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L05", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L06", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L07", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L08", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L09", SAMPLE_NOLOOP },
{ "L0A", SAMPLE_NOLOOP },
{ "L0B", SAMPLE_NOLOOP },
{ "L0C", SAMPLE_NOLOOP },
{ "L0D", SAMPLE_NOLOOP },
{ "L0E", SAMPLE_NOLOOP },
{ "L0F", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L10", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L11", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L12", SAMPLE_NOLOOP },
{ "L13", SAMPLE_NOLOOP },
{ "L14", SAMPLE_NOLOOP },
{ "L15", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L16", SAMPLE_NOLOOP },
{ "L17", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L18", SAMPLE_NOLOOP },
{ "L19", SAMPLE_NOLOOP },
{ "L1A", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L1B", SAMPLE_NOLOOP },
{ "L1C", SAMPLE_NOLOOP },
{ "L1D", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L1E", SAMPLE_NOLOOP },
{ "L1F", SAMPLE_NOLOOP },
{ "L20", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L21", SAMPLE_NOLOOP },
{ "L22", SAMPLE_NOLOOP },
{ "L23", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L24", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L25", SAMPLE_NOLOOP },
{ "L26", SAMPLE_NOLOOP },
{ "L27", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L28", SAMPLE_NOLOOP },
{ "L29", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L2A", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L2B", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L2C", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L2D", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L2E", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L2F", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L30", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L31", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L32", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L33", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L34", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L35", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L36", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L37", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L38", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L39", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L3A", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L3B", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L3C", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L3D", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L3E", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "L3F", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "empty", SAMPLE_NOLOOP },
{ "R01", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R02", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R03", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R04", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R05", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R06", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R07", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R08", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R09", SAMPLE_NOLOOP },
{ "R0A", SAMPLE_NOLOOP },
{ "R0B", SAMPLE_NOLOOP },
{ "R0C", SAMPLE_NOLOOP },
{ "R0D", SAMPLE_NOLOOP },
{ "R0E", SAMPLE_NOLOOP },
{ "R0F", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R10", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R11", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R12", SAMPLE_NOLOOP },
{ "R13", SAMPLE_NOLOOP },
{ "R14", SAMPLE_NOLOOP },
{ "R15", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R16", SAMPLE_NOLOOP },
{ "R17", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R18", SAMPLE_NOLOOP },
{ "R19", SAMPLE_NOLOOP },
{ "R1A", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R1B", SAMPLE_NOLOOP },
{ "R1C", SAMPLE_NOLOOP },
{ "R1D", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R1E", SAMPLE_NOLOOP },
{ "R1F", SAMPLE_NOLOOP },
{ "R20", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R21", SAMPLE_NOLOOP },
{ "R22", SAMPLE_NOLOOP },
{ "R23", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R24", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R25", SAMPLE_NOLOOP },
{ "R26", SAMPLE_NOLOOP },
{ "R27", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R28", SAMPLE_NOLOOP },
{ "R29", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R2A", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R2B", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R2C", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R2D", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R2E", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R2F", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R30", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R31", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R32", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R33", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R34", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R35", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R36", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R37", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R38", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R39", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R3A", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R3B", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R3C", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R3D", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R3E", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "R3F", SAMPLE_NOLOOP | SAMPLE_NODUMP },
{ "", 0 }
};
STD_SAMPLE_PICK(Sfz3mix)
STD_SAMPLE_FN(Sfz3mix)
static struct BurnRomInfo Sfz3mixRomDesc[] = {
{ "sz3mx.03", 0x0600000, 0x7a968da6, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3mx.13m", 0x2000000, 0x5389b651, CPS2_GFX | BRF_GRA },
{ "sz3mx.21m", 0x2000000, 0x914c7031, CPS2_GFX | BRF_GRA },
{ "sz3mx.01", 0x0080000, 0x52f98a5c, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sz3mx.11m", 0x1000000, 0x395edce2, CPS2_QSND | BRF_SND },
{ "phoenix.key", 0x0000014, 0x2cf772b0, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Sfz3mix)
STD_ROM_FN(Sfz3mix)
// Street Fighter Zero 3 Mix v0.13 (hacked by Zero800)
// https://sfz3mix.github.io/
@@ -15303,37 +15097,6 @@ struct BurnDriver BurnDrvCpsSfz3jr2d = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
static INT32 Cps2TurboInit()
{
Cps2Turbo = 1;
INT32 rc = PhoenixInit();
if (!rc) {
BurnSampleInit(1);
for (int i = 0; i < 0x40; i++) {
// Left side
BurnSampleSetRoute(i + 0x00, BURN_SND_SAMPLE_ROUTE_1, 0.10, BURN_SND_ROUTE_LEFT);
BurnSampleSetRoute(i + 0x00, BURN_SND_SAMPLE_ROUTE_2, 0.10, BURN_SND_ROUTE_NONE);
// Right side
BurnSampleSetRoute(i + 0x40, BURN_SND_SAMPLE_ROUTE_1, 0.10, BURN_SND_ROUTE_RIGHT);
BurnSampleSetRoute(i + 0x40, BURN_SND_SAMPLE_ROUTE_2, 0.10, BURN_SND_ROUTE_NONE);
}
}
return rc;
}
struct BurnDriver BurnDrvCpsSfz3mix = {
"sfz3mix", "sfa3", NULL, "sfz3mix", "2026",
"Street Fighter Zero 3 Mix v0.32\0", NULL, "hack (zero800)", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK | BDF_HISCORE_SUPPORTED, 2, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, Sfz3mixRomInfo, Sfz3mixRomName, NULL, NULL, Sfz3mixSampleInfo, Sfz3mixSampleName, Sfz3mixInputInfo, Sfz3mixDIPInfo,
Cps2TurboInit, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 416, 234, 16, 9
};
struct BurnDriver BurnDrvCpsSfz3mix13 = {
"sfz3mix13", "sfa3", NULL, NULL, "2022",
"Street Fighter Zero 3 Mix v0.13\0", NULL, "hack", "CPS2",
@@ -16618,325 +16381,6 @@ struct BurnDriver BurnDrvCpsXmvsfcph = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// X-Men Vs. Street Fighter 3v3 + DHC (Hack, v1.1.0)
// Modified by Morphus56K
// 2026-10-11
// https://www.morphus56k.com/blog/xmvsf-three-on-three
// Three characters a team, Delayed Hyper Combos, snapbacks and eighteen colours per character.
// The 6 player sets put P1-P3 against P4-P6; the wide sets show a 512 pixel wide arena.
// All four need the board additions in xmvsf3v3.h (inputs for six players, extra work RAM,
// HUD portraits in the chosen colour).
static struct BurnInputInfo Xmvsf3v3InputList[] = {
{"P1 Coin" , BIT_DIGITAL , CpsXmvSixButtons[0] + 12, "p1 coin" },
{"P1 Start" , BIT_DIGITAL , CpsXmvSixButtons[0] + 11, "p1 start" },
{"P1 Up" , BIT_DIGITAL , CpsXmvSixButtons[0] + 3 , "p1 up" },
{"P1 Down" , BIT_DIGITAL , CpsXmvSixButtons[0] + 2 , "p1 down" },
{"P1 Left" , BIT_DIGITAL , CpsXmvSixButtons[0] + 1 , "p1 left" },
{"P1 Right" , BIT_DIGITAL , CpsXmvSixButtons[0] + 0 , "p1 right" },
{"P1 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[0] + 4 , "p1 fire 1" },
{"P1 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[0] + 5 , "p1 fire 2" },
{"P1 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[0] + 6 , "p1 fire 3" },
{"P1 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[0] + 8 , "p1 fire 4" },
{"P1 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[0] + 9 , "p1 fire 5" },
{"P1 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[0] + 10, "p1 fire 6" },
{"P2 Coin" , BIT_DIGITAL , CpsXmvSixButtons[1] + 12, "p2 coin" },
{"P2 Start" , BIT_DIGITAL , CpsXmvSixButtons[1] + 11, "p2 start" },
{"P2 Up" , BIT_DIGITAL , CpsXmvSixButtons[1] + 3 , "p2 up" },
{"P2 Down" , BIT_DIGITAL , CpsXmvSixButtons[1] + 2 , "p2 down" },
{"P2 Left" , BIT_DIGITAL , CpsXmvSixButtons[1] + 1 , "p2 left" },
{"P2 Right" , BIT_DIGITAL , CpsXmvSixButtons[1] + 0 , "p2 right" },
{"P2 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[1] + 4 , "p2 fire 1" },
{"P2 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[1] + 5 , "p2 fire 2" },
{"P2 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[1] + 6 , "p2 fire 3" },
{"P2 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[1] + 8 , "p2 fire 4" },
{"P2 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[1] + 9 , "p2 fire 5" },
{"P2 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[1] + 10, "p2 fire 6" },
{"Reset" , BIT_DIGITAL , &CpsReset , "reset" },
{"Diagnostic" , BIT_DIGITAL , CpsInp021+1 , "diag" },
{"Service" , BIT_DIGITAL , CpsInp021+2 , "service" },
{"Volume Up" , BIT_DIGITAL , &Cps2VolUp , "volumeup" },
{"Volume Down" , BIT_DIGITAL , &Cps2VolDwn , "volumedown"},
};
STDINPUTINFO(Xmvsf3v3)
static struct BurnInputInfo Xmvsf6pInputList[] = {
{"P1 Coin" , BIT_DIGITAL , CpsXmvSixButtons[0] + 12, "p1 coin" },
{"P1 Start" , BIT_DIGITAL , CpsXmvSixButtons[0] + 11, "p1 start" },
{"P1 Up" , BIT_DIGITAL , CpsXmvSixButtons[0] + 3 , "p1 up" },
{"P1 Down" , BIT_DIGITAL , CpsXmvSixButtons[0] + 2 , "p1 down" },
{"P1 Left" , BIT_DIGITAL , CpsXmvSixButtons[0] + 1 , "p1 left" },
{"P1 Right" , BIT_DIGITAL , CpsXmvSixButtons[0] + 0 , "p1 right" },
{"P1 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[0] + 4 , "p1 fire 1" },
{"P1 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[0] + 5 , "p1 fire 2" },
{"P1 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[0] + 6 , "p1 fire 3" },
{"P1 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[0] + 8 , "p1 fire 4" },
{"P1 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[0] + 9 , "p1 fire 5" },
{"P1 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[0] + 10, "p1 fire 6" },
{"P2 Coin" , BIT_DIGITAL , CpsXmvSixButtons[1] + 12, "p2 coin" },
{"P2 Start" , BIT_DIGITAL , CpsXmvSixButtons[1] + 11, "p2 start" },
{"P2 Up" , BIT_DIGITAL , CpsXmvSixButtons[1] + 3 , "p2 up" },
{"P2 Down" , BIT_DIGITAL , CpsXmvSixButtons[1] + 2 , "p2 down" },
{"P2 Left" , BIT_DIGITAL , CpsXmvSixButtons[1] + 1 , "p2 left" },
{"P2 Right" , BIT_DIGITAL , CpsXmvSixButtons[1] + 0 , "p2 right" },
{"P2 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[1] + 4 , "p2 fire 1" },
{"P2 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[1] + 5 , "p2 fire 2" },
{"P2 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[1] + 6 , "p2 fire 3" },
{"P2 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[1] + 8 , "p2 fire 4" },
{"P2 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[1] + 9 , "p2 fire 5" },
{"P2 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[1] + 10, "p2 fire 6" },
{"P3 Coin" , BIT_DIGITAL , CpsXmvSixButtons[2] + 12, "p3 coin" },
{"P3 Start" , BIT_DIGITAL , CpsXmvSixButtons[2] + 11, "p3 start" },
{"P3 Up" , BIT_DIGITAL , CpsXmvSixButtons[2] + 3 , "p3 up" },
{"P3 Down" , BIT_DIGITAL , CpsXmvSixButtons[2] + 2 , "p3 down" },
{"P3 Left" , BIT_DIGITAL , CpsXmvSixButtons[2] + 1 , "p3 left" },
{"P3 Right" , BIT_DIGITAL , CpsXmvSixButtons[2] + 0 , "p3 right" },
{"P3 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[2] + 4 , "p3 fire 1" },
{"P3 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[2] + 5 , "p3 fire 2" },
{"P3 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[2] + 6 , "p3 fire 3" },
{"P3 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[2] + 8 , "p3 fire 4" },
{"P3 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[2] + 9 , "p3 fire 5" },
{"P3 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[2] + 10, "p3 fire 6" },
{"P4 Coin" , BIT_DIGITAL , CpsXmvSixButtons[3] + 12, "p4 coin" },
{"P4 Start" , BIT_DIGITAL , CpsXmvSixButtons[3] + 11, "p4 start" },
{"P4 Up" , BIT_DIGITAL , CpsXmvSixButtons[3] + 3 , "p4 up" },
{"P4 Down" , BIT_DIGITAL , CpsXmvSixButtons[3] + 2 , "p4 down" },
{"P4 Left" , BIT_DIGITAL , CpsXmvSixButtons[3] + 1 , "p4 left" },
{"P4 Right" , BIT_DIGITAL , CpsXmvSixButtons[3] + 0 , "p4 right" },
{"P4 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[3] + 4 , "p4 fire 1" },
{"P4 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[3] + 5 , "p4 fire 2" },
{"P4 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[3] + 6 , "p4 fire 3" },
{"P4 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[3] + 8 , "p4 fire 4" },
{"P4 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[3] + 9 , "p4 fire 5" },
{"P4 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[3] + 10, "p4 fire 6" },
{"P5 Coin" , BIT_DIGITAL , CpsXmvSixButtons[4] + 12, "p5 coin" },
{"P5 Start" , BIT_DIGITAL , CpsXmvSixButtons[4] + 11, "p5 start" },
{"P5 Up" , BIT_DIGITAL , CpsXmvSixButtons[4] + 3 , "p5 up" },
{"P5 Down" , BIT_DIGITAL , CpsXmvSixButtons[4] + 2 , "p5 down" },
{"P5 Left" , BIT_DIGITAL , CpsXmvSixButtons[4] + 1 , "p5 left" },
{"P5 Right" , BIT_DIGITAL , CpsXmvSixButtons[4] + 0 , "p5 right" },
{"P5 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[4] + 4 , "p5 fire 1" },
{"P5 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[4] + 5 , "p5 fire 2" },
{"P5 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[4] + 6 , "p5 fire 3" },
{"P5 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[4] + 8 , "p5 fire 4" },
{"P5 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[4] + 9 , "p5 fire 5" },
{"P5 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[4] + 10, "p5 fire 6" },
{"P6 Coin" , BIT_DIGITAL , CpsXmvSixButtons[5] + 12, "p6 coin" },
{"P6 Start" , BIT_DIGITAL , CpsXmvSixButtons[5] + 11, "p6 start" },
{"P6 Up" , BIT_DIGITAL , CpsXmvSixButtons[5] + 3 , "p6 up" },
{"P6 Down" , BIT_DIGITAL , CpsXmvSixButtons[5] + 2 , "p6 down" },
{"P6 Left" , BIT_DIGITAL , CpsXmvSixButtons[5] + 1 , "p6 left" },
{"P6 Right" , BIT_DIGITAL , CpsXmvSixButtons[5] + 0 , "p6 right" },
{"P6 Weak Punch" , BIT_DIGITAL , CpsXmvSixButtons[5] + 4 , "p6 fire 1" },
{"P6 Medium Punch" , BIT_DIGITAL , CpsXmvSixButtons[5] + 5 , "p6 fire 2" },
{"P6 Strong Punch" , BIT_DIGITAL , CpsXmvSixButtons[5] + 6 , "p6 fire 3" },
{"P6 Weak Kick" , BIT_DIGITAL , CpsXmvSixButtons[5] + 8 , "p6 fire 4" },
{"P6 Medium Kick" , BIT_DIGITAL , CpsXmvSixButtons[5] + 9 , "p6 fire 5" },
{"P6 Strong Kick" , BIT_DIGITAL , CpsXmvSixButtons[5] + 10, "p6 fire 6" },
{"Reset" , BIT_DIGITAL , &CpsReset , "reset" },
{"Diagnostic" , BIT_DIGITAL , CpsInp021+1 , "diag" },
{"Service" , BIT_DIGITAL , CpsInp021+2 , "service" },
{"Volume Up" , BIT_DIGITAL , &Cps2VolUp , "volumeup" },
{"Volume Down" , BIT_DIGITAL , &Cps2VolDwn , "volumedown"},
};
STDINPUTINFO(Xmvsf6p)
static INT32 Xmvsf3v3CommonInit(INT32 bWide)
{
if (CpsXmvSixInit(bWide)) return 1;
INT32 nRet = Cps2Init();
if (nRet) {
CpsXmvSixExit();
return nRet;
}
CpsRunResetCallbackFunction = CpsXmvSixReset;
CpsMemScanCallbackFunction = CpsXmvSixScan;
return 0;
}
static INT32 Xmvsf3v3Init()
{
return Xmvsf3v3CommonInit(0);
}
static INT32 Xmvsf3v3WideInit()
{
return Xmvsf3v3CommonInit(1);
}
static struct BurnRomInfo Xmvsf3v3RomDesc[] = {
{ "xvs3v3.03f", 0x080000, 0x7b151acd, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvse.04f", 0x080000, 0xef015aef, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.05a", 0x080000, 0x7db6025d, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.06a", 0x080000, 0xe8e2c75c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.07", 0x080000, 0x08f0abed, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3.08", 0x080000, 0x477a3f86, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3.09", 0x080000, 0x98e06515, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3.13m", 0x400000, 0xc8b777f6, CPS2_GFX | BRF_GRA },
{ "xvs3v3.15m", 0x400000, 0x8143c2b0, CPS2_GFX | BRF_GRA },
{ "xvs3v3.17m", 0x400000, 0x10cceec9, CPS2_GFX | BRF_GRA },
{ "xvs3v3.19m", 0x400000, 0xf458a1f8, CPS2_GFX | BRF_GRA },
{ "xvs.14m", 0x400000, 0xbcac2e41, CPS2_GFX | BRF_GRA },
{ "xvs.16m", 0x400000, 0xea04a272, CPS2_GFX | BRF_GRA },
{ "xvs.18m", 0x400000, 0xb0def86a, CPS2_GFX | BRF_GRA },
{ "xvs.20m", 0x400000, 0x4b40ff9f, CPS2_GFX | BRF_GRA },
{ "xvs.01", 0x020000, 0x3999e93a, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.02", 0x020000, 0x101bdee9, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.11m", 0x200000, 0x9cadcdbc, CPS2_QSND | BRF_SND },
{ "xvs.12m", 0x200000, 0x7b11e460, CPS2_QSND | BRF_SND },
{ "xmvsf.key", 0x000014, 0xd5c07311, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Xmvsf3v3)
STD_ROM_FN(Xmvsf3v3)
static struct BurnRomInfo Xmvsf3v3wRomDesc[] = {
{ "xvs3v3w.03f", 0x080000, 0x54ed459e, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvse.04f", 0x080000, 0xef015aef, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.05a", 0x080000, 0x7db6025d, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.06a", 0x080000, 0xe8e2c75c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.07", 0x080000, 0x08f0abed, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3.08", 0x080000, 0x477a3f86, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3w.09", 0x080000, 0x145e92b6, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3.13m", 0x400000, 0xc8b777f6, CPS2_GFX | BRF_GRA },
{ "xvs3v3.15m", 0x400000, 0x8143c2b0, CPS2_GFX | BRF_GRA },
{ "xvs3v3.17m", 0x400000, 0x10cceec9, CPS2_GFX | BRF_GRA },
{ "xvs3v3.19m", 0x400000, 0xf458a1f8, CPS2_GFX | BRF_GRA },
{ "xvs.14m", 0x400000, 0xbcac2e41, CPS2_GFX | BRF_GRA },
{ "xvs.16m", 0x400000, 0xea04a272, CPS2_GFX | BRF_GRA },
{ "xvs.18m", 0x400000, 0xb0def86a, CPS2_GFX | BRF_GRA },
{ "xvs.20m", 0x400000, 0x4b40ff9f, CPS2_GFX | BRF_GRA },
{ "xvs.01", 0x020000, 0x3999e93a, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.02", 0x020000, 0x101bdee9, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.11m", 0x200000, 0x9cadcdbc, CPS2_QSND | BRF_SND },
{ "xvs.12m", 0x200000, 0x7b11e460, CPS2_QSND | BRF_SND },
{ "xmvsf.key", 0x000014, 0xd5c07311, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Xmvsf3v3w)
STD_ROM_FN(Xmvsf3v3w)
static struct BurnRomInfo Xmvsf6pRomDesc[] = {
{ "xvs6p.03f", 0x080000, 0x8940699a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvse.04f", 0x080000, 0xef015aef, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.05a", 0x080000, 0x7db6025d, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.06a", 0x080000, 0xe8e2c75c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.07", 0x080000, 0x08f0abed, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs6p.08", 0x080000, 0x14b6a689, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs6p.09", 0x080000, 0x6ea8fdea, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3.13m", 0x400000, 0xc8b777f6, CPS2_GFX | BRF_GRA },
{ "xvs3v3.15m", 0x400000, 0x8143c2b0, CPS2_GFX | BRF_GRA },
{ "xvs3v3.17m", 0x400000, 0x10cceec9, CPS2_GFX | BRF_GRA },
{ "xvs3v3.19m", 0x400000, 0xf458a1f8, CPS2_GFX | BRF_GRA },
{ "xvs.14m", 0x400000, 0xbcac2e41, CPS2_GFX | BRF_GRA },
{ "xvs.16m", 0x400000, 0xea04a272, CPS2_GFX | BRF_GRA },
{ "xvs.18m", 0x400000, 0xb0def86a, CPS2_GFX | BRF_GRA },
{ "xvs.20m", 0x400000, 0x4b40ff9f, CPS2_GFX | BRF_GRA },
{ "xvs.01", 0x020000, 0x3999e93a, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.02", 0x020000, 0x101bdee9, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.11m", 0x200000, 0x9cadcdbc, CPS2_QSND | BRF_SND },
{ "xvs.12m", 0x200000, 0x7b11e460, CPS2_QSND | BRF_SND },
{ "xmvsf.key", 0x000014, 0xd5c07311, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Xmvsf6p)
STD_ROM_FN(Xmvsf6p)
static struct BurnRomInfo Xmvsf6pwRomDesc[] = {
{ "xvs6pw.03f", 0x080000, 0xa6b836c9, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvse.04f", 0x080000, 0xef015aef, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.05a", 0x080000, 0x7db6025d, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.06a", 0x080000, 0xe8e2c75c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs.07", 0x080000, 0x08f0abed, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs6p.08", 0x080000, 0x14b6a689, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs6pw.09", 0x080000, 0xe2160a49, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "xvs3v3.13m", 0x400000, 0xc8b777f6, CPS2_GFX | BRF_GRA },
{ "xvs3v3.15m", 0x400000, 0x8143c2b0, CPS2_GFX | BRF_GRA },
{ "xvs3v3.17m", 0x400000, 0x10cceec9, CPS2_GFX | BRF_GRA },
{ "xvs3v3.19m", 0x400000, 0xf458a1f8, CPS2_GFX | BRF_GRA },
{ "xvs.14m", 0x400000, 0xbcac2e41, CPS2_GFX | BRF_GRA },
{ "xvs.16m", 0x400000, 0xea04a272, CPS2_GFX | BRF_GRA },
{ "xvs.18m", 0x400000, 0xb0def86a, CPS2_GFX | BRF_GRA },
{ "xvs.20m", 0x400000, 0x4b40ff9f, CPS2_GFX | BRF_GRA },
{ "xvs.01", 0x020000, 0x3999e93a, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.02", 0x020000, 0x101bdee9, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "xvs.11m", 0x200000, 0x9cadcdbc, CPS2_QSND | BRF_SND },
{ "xvs.12m", 0x200000, 0x7b11e460, CPS2_QSND | BRF_SND },
{ "xmvsf.key", 0x000014, 0xd5c07311, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Xmvsf6pw)
STD_ROM_FN(Xmvsf6pw)
struct BurnDriver BurnDrvCpsXmvsf3v3 = {
"xmvsf3v3", "xmvsf", NULL, NULL, "2026",
"X-Men Vs. Street Fighter 3v3 + DHC (Hack, v1.1.0)\0", NULL, "hack (Morphus56K)", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, Xmvsf3v3RomInfo, Xmvsf3v3RomName, NULL, NULL, NULL, NULL, Xmvsf3v3InputInfo, NULL,
Xmvsf3v3Init, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsXmvsf3v3w = {
"xmvsf3v3w", "xmvsf", NULL, NULL, "2026",
"X-Men Vs. Street Fighter 3v3 + DHC (Hack, v1.1.0, wide)\0", NULL, "hack (Morphus56K)", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, Xmvsf3v3wRomInfo, Xmvsf3v3wRomName, NULL, NULL, NULL, NULL, Xmvsf3v3InputInfo, NULL,
Xmvsf3v3WideInit, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 512, 224, 16, 9
};
struct BurnDriver BurnDrvCpsXmvsf6p = {
"xmvsf6p", "xmvsf", NULL, NULL, "2026",
"X-Men Vs. Street Fighter 3v3 + DHC (Hack, v1.1.0, 6 players)\0", NULL, "hack (Morphus56K)", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 6, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, Xmvsf6pRomInfo, Xmvsf6pRomName, NULL, NULL, NULL, NULL, Xmvsf6pInputInfo, NULL,
Xmvsf3v3Init, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
struct BurnDriver BurnDrvCpsXmvsf6pw = {
"xmvsf6pw", "xmvsf", NULL, NULL, "2026",
"X-Men Vs. Street Fighter 3v3 + DHC (Hack, v1.1.0, 6 players, wide)\0", NULL, "hack (Morphus56K)", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 6, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, Xmvsf6pwRomInfo, Xmvsf6pwRomName, NULL, NULL, NULL, NULL, Xmvsf6pInputInfo, NULL,
Xmvsf3v3WideInit, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 512, 224, 16, 9
};
// Mars Matrix: Hyper Solid Shooting (Hack, Improvement v1.0.0)
// 20251204
@@ -17114,34 +16558,34 @@ struct BurnDriver BurnDrvCpsSsf2xdced = {
// https://strygo.github.io/arcade-patches/
// -----------------------------------------------------------------------------
// Final Fight EX (Hack, CPS2 hardware, USA RC1)
// Final Fight EX (Hack, CPS2 hardware, USA RC2)
// 2026-10-25
static struct BurnRomInfo Ffex2uRomDesc[] = {
{ "sz3ud.03c", 0x080000, 0xe022fd18, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3ud.04c", 0x080000, 0x9c228c18, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.05c", 0x080000, 0x787bb7f2, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.06c", 0x080000, 0x5652684a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.07c", 0x080000, 0x6e430b5c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.08c", 0x080000, 0x0b37c61a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.09c", 0x080000, 0xc0a36b4d, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.10b", 0x080000, 0x85f1c748, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexd.03c", 0x080000, 0x4f9873c4, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexd.04c", 0x080000, 0x4957978c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.05c", 0x080000, 0x787bb7f2, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.06c", 0x080000, 0x5652684a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.07c", 0x080000, 0x6e430b5c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.08c", 0x080000, 0x0b37c61a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.09c", 0x080000, 0xc0a36b4d, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.10b", 0x080000, 0x85f1c748, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.13m", 0x400000, 0x48cbc129, CPS2_GFX | BRF_GRA },
{ "sz3.15m", 0x400000, 0xfd20f3aa, CPS2_GFX | BRF_GRA },
{ "sz3.17m", 0x400000, 0x5ea87831, CPS2_GFX | BRF_GRA },
{ "sz3.19m", 0x400000, 0xda6a3e7e, CPS2_GFX | BRF_GRA },
{ "sz3.14m", 0x400000, 0xeca6de34, CPS2_GFX | BRF_GRA },
{ "sz3.16m", 0x400000, 0x17069cbd, CPS2_GFX | BRF_GRA },
{ "sz3.18m", 0x400000, 0x0f560d8c, CPS2_GFX | BRF_GRA },
{ "sz3.20m", 0x400000, 0xe96d3923, CPS2_GFX | BRF_GRA },
{ "ffex.13m", 0x400000, 0x48cbc129, CPS2_GFX | BRF_GRA },
{ "ffex.15m", 0x400000, 0xfd20f3aa, CPS2_GFX | BRF_GRA },
{ "ffex.17m", 0x400000, 0x5ea87831, CPS2_GFX | BRF_GRA },
{ "ffex.19m", 0x400000, 0xda6a3e7e, CPS2_GFX | BRF_GRA },
{ "ffex.14m", 0x400000, 0xeca6de34, CPS2_GFX | BRF_GRA },
{ "ffex.16m", 0x400000, 0x17069cbd, CPS2_GFX | BRF_GRA },
{ "ffex.18m", 0x400000, 0x0f560d8c, CPS2_GFX | BRF_GRA },
{ "ffex.20m", 0x400000, 0xe96d3923, CPS2_GFX | BRF_GRA },
{ "sz3.01", 0x020000, 0x03d74a70, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sz3.02", 0x020000, 0x7ee8cdcd, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "ffex.01", 0x020000, 0x03d74a70, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "ffex.02", 0x020000, 0x7ee8cdcd, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sz3.11m", 0x400000, 0xbea96b44, CPS2_QSND | BRF_SND },
{ "sz3.12m", 0x400000, 0xdf5e34c3, CPS2_QSND | BRF_SND },
{ "ffex.11m", 0x400000, 0xbea96b44, CPS2_QSND | BRF_SND },
{ "ffex.12m", 0x400000, 0xdf5e34c3, CPS2_QSND | BRF_SND },
{ "phoenix.key", 0x000014, 0x2cf772b0, CPS2_ENCRYPTION_KEY },
{ "phoenix.key", 0x000014, 0x2cf772b0, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Ffex2u)
@@ -17149,7 +16593,7 @@ STD_ROM_FN(Ffex2u)
struct BurnDriver BurnDrvCpsFfex2u = {
"ffex2u", NULL, NULL, NULL, "2026",
"Final Fight EX (Hack, CPS2 hardware, USA RC1)\0", NULL, "Strygo", "CPS2",
"Final Fight EX (Hack, CPS2 hardware, USA RC2)\0", NULL, "Strygo", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HACK, 2, HARDWARE_CAPCOM_CPS2, GBF_SCRFIGHT, 0,
NULL, Ffex2uRomInfo, Ffex2uRomName, NULL, NULL, NULL, NULL, Ffex2InputInfo, NULL,
@@ -17157,34 +16601,34 @@ struct BurnDriver BurnDrvCpsFfex2u = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// Final Fight EX (Hack, CPS2 hardware, Japan RC1)
// Final Fight EX (Hack, CPS2 hardware, Japan RC2)
// 2026-10-25
static struct BurnRomInfo Ffex2jRomDesc[] = {
{ "sz3ud.03c", 0x080000, 0x9eb92f51, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3ud.04c", 0x080000, 0x3a2393c0, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.05c", 0x080000, 0x787bb7f2, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.06c", 0x080000, 0xa8d2d10b, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.07c", 0x080000, 0xbcf7297e, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.08c", 0x080000, 0x7afbcbad, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.09c", 0x080000, 0x0642626b, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.10b", 0x080000, 0xb4208a79, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexjd.03c", 0x080000, 0x789ff036, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexjd.04c", 0x080000, 0x613c6ecc, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.05c", 0x080000, 0x787bb7f2, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexj.06c", 0x080000, 0xa8d2d10b, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexj.07c", 0x080000, 0xbcf7297e, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexj.08c", 0x080000, 0x7afbcbad, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexj.09c", 0x080000, 0x0642626b, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexj.10b", 0x080000, 0xb4208a79, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.13m", 0x400000, 0xd24130e3, CPS2_GFX | BRF_GRA },
{ "sz3.15m", 0x400000, 0xcef0a6b3, CPS2_GFX | BRF_GRA },
{ "sz3.17m", 0x400000, 0x00464598, CPS2_GFX | BRF_GRA },
{ "sz3.19m", 0x400000, 0x6f5379cc, CPS2_GFX | BRF_GRA },
{ "sz3.14m", 0x400000, 0xae054c04, CPS2_GFX | BRF_GRA },
{ "sz3.16m", 0x400000, 0x0e09c2ba, CPS2_GFX | BRF_GRA },
{ "sz3.18m", 0x400000, 0x0f560d8c, CPS2_GFX | BRF_GRA },
{ "sz3.20m", 0x400000, 0xe96d3923, CPS2_GFX | BRF_GRA },
{ "ffexj.13m", 0x400000, 0xd24130e3, CPS2_GFX | BRF_GRA },
{ "ffexj.15m", 0x400000, 0xcef0a6b3, CPS2_GFX | BRF_GRA },
{ "ffexj.17m", 0x400000, 0x00464598, CPS2_GFX | BRF_GRA },
{ "ffexj.19m", 0x400000, 0x6f5379cc, CPS2_GFX | BRF_GRA },
{ "ffexj.14m", 0x400000, 0xae054c04, CPS2_GFX | BRF_GRA },
{ "ffexj.16m", 0x400000, 0x0e09c2ba, CPS2_GFX | BRF_GRA },
{ "ffex.18m", 0x400000, 0x0f560d8c, CPS2_GFX | BRF_GRA },
{ "ffex.20m", 0x400000, 0xe96d3923, CPS2_GFX | BRF_GRA },
{ "sz3.01", 0x020000, 0x36ef522c, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sz3.02", 0x020000, 0x7ee8cdcd, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "ffexj.01", 0x020000, 0x36ef522c, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "ffex.02", 0x020000, 0x7ee8cdcd, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sz3.11m", 0x400000, 0xbea96b44, CPS2_QSND | BRF_SND },
{ "sz3.12m", 0x400000, 0xdf5e34c3, CPS2_QSND | BRF_SND },
{ "ffex.11m", 0x400000, 0xbea96b44, CPS2_QSND | BRF_SND },
{ "ffex.12m", 0x400000, 0xdf5e34c3, CPS2_QSND | BRF_SND },
{ "phoenix.key", 0x000014, 0x2cf772b0, CPS2_ENCRYPTION_KEY },
{ "phoenix.key", 0x000014, 0x2cf772b0, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Ffex2j)
@@ -17192,7 +16636,7 @@ STD_ROM_FN(Ffex2j)
struct BurnDriver BurnDrvCpsFfex2j = {
"ffex2j", "ffex2u", NULL, NULL, "2026",
"Final Fight EX (Hack, CPS2 hardware, Japan RC1)\0", NULL, "Strygo", "CPS2",
"Final Fight EX (Hack, CPS2 hardware, Japan RC2)\0", NULL, "Strygo", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS2, GBF_SCRFIGHT, 0,
NULL, Ffex2jRomInfo, Ffex2jRomName, NULL, NULL, NULL, NULL, Ffex2InputInfo, NULL,
@@ -17200,34 +16644,34 @@ struct BurnDriver BurnDrvCpsFfex2j = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// Final Fight EX (Hack, CPS2 hardware, English Restoration RC1)
// Final Fight EX (Hack, CPS2 hardware, English Restoration RC2)
// 2026-10-25
static struct BurnRomInfo Ffex2rRomDesc[] = {
{ "sz3ud.03c", 0x080000, 0xd1129b95, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3ud.04c", 0x080000, 0x5d10506d, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.05c", 0x080000, 0x787bb7f2, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.06c", 0x080000, 0x5652684a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.07c", 0x080000, 0x6e430b5c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.08c", 0x080000, 0x64f42ba9, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.09c", 0x080000, 0xbd69566a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.10b", 0x080000, 0x9539a4aa, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexrd.03c", 0x080000, 0xbce36dc0, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexrd.04c", 0x080000, 0x273ae5d9, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.05c", 0x080000, 0x787bb7f2, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.06c", 0x080000, 0x5652684a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffex.07c", 0x080000, 0x6e430b5c, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexr.08c", 0x080000, 0x64f42ba9, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexr.09c", 0x080000, 0xbd69566a, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "ffexr.10b", 0x080000, 0x9539a4aa, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sz3.13m", 0x400000, 0x231f811f, CPS2_GFX | BRF_GRA },
{ "sz3.15m", 0x400000, 0x26cea23a, CPS2_GFX | BRF_GRA },
{ "sz3.17m", 0x400000, 0xf118f464, CPS2_GFX | BRF_GRA },
{ "sz3.19m", 0x400000, 0x876d7d45, CPS2_GFX | BRF_GRA },
{ "sz3.14m", 0x400000, 0xeca6de34, CPS2_GFX | BRF_GRA },
{ "sz3.16m", 0x400000, 0x17069cbd, CPS2_GFX | BRF_GRA },
{ "sz3.18m", 0x400000, 0x0f560d8c, CPS2_GFX | BRF_GRA },
{ "sz3.20m", 0x400000, 0xe96d3923, CPS2_GFX | BRF_GRA },
{ "ffexr.13m", 0x400000, 0x231f811f, CPS2_GFX | BRF_GRA },
{ "ffexr.15m", 0x400000, 0x26cea23a, CPS2_GFX | BRF_GRA },
{ "ffexr.17m", 0x400000, 0xf118f464, CPS2_GFX | BRF_GRA },
{ "ffexr.19m", 0x400000, 0x876d7d45, CPS2_GFX | BRF_GRA },
{ "ffex.14m", 0x400000, 0xeca6de34, CPS2_GFX | BRF_GRA },
{ "ffex.16m", 0x400000, 0x17069cbd, CPS2_GFX | BRF_GRA },
{ "ffex.18m", 0x400000, 0x0f560d8c, CPS2_GFX | BRF_GRA },
{ "ffex.20m", 0x400000, 0xe96d3923, CPS2_GFX | BRF_GRA },
{ "sz3.01", 0x020000, 0x3c1c4965, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sz3.02", 0x020000, 0x7ee8cdcd, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "ffexr.01", 0x020000, 0x3c1c4965, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "ffex.02", 0x020000, 0x7ee8cdcd, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sz3.11m", 0x400000, 0xbea96b44, CPS2_QSND | BRF_SND },
{ "sz3.12m", 0x400000, 0xdf5e34c3, CPS2_QSND | BRF_SND },
{ "ffex.11m", 0x400000, 0xbea96b44, CPS2_QSND | BRF_SND },
{ "ffex.12m", 0x400000, 0xdf5e34c3, CPS2_QSND | BRF_SND },
{ "phoenix.key", 0x000014, 0x2cf772b0, CPS2_ENCRYPTION_KEY },
{ "phoenix.key", 0x000014, 0x2cf772b0, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Ffex2r)
@@ -17235,7 +16679,7 @@ STD_ROM_FN(Ffex2r)
struct BurnDriver BurnDrvCpsFfex2r = {
"ffex2r", "ffex2u", NULL, NULL, "2026",
"Final Fight EX (Hack, CPS2 hardware, English Restoration RC1)\0", NULL, "Strygo", "CPS2",
"Final Fight EX (Hack, CPS2 hardware, English Restoration RC2)\0", NULL, "Strygo", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_CAPCOM_CPS2, GBF_SCRFIGHT, 0,
NULL, Ffex2rRomInfo, Ffex2rRomName, NULL, NULL, NULL, NULL, Ffex2InputInfo, NULL,
@@ -17606,6 +17050,111 @@ struct BurnDriver BurnDrvCpsSfzrej = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// Street Fighter Alpha EX: Warriors' Dreams (Hack, USA RC1)
// 2026-10-26
static struct BurnRomInfo SfaexRomDesc[] = {
{ "sfzex.03c", 0x080000, 0xa0c070cb, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzre.04b", 0x080000, 0x8d9b2480, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzre.05a", 0x080000, 0x8cf0a98f, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzex.06", 0x080000, 0x9b5fc006, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzex.14m", 0x200000, 0x5e90868c, CPS2_GFX | BRF_GRA },
{ "sfzex.16m", 0x200000, 0x97ac2170, CPS2_GFX | BRF_GRA },
{ "sfzex.18m", 0x200000, 0x5e414b4f, CPS2_GFX | BRF_GRA },
{ "sfzex.20m", 0x200000, 0xf29757b8, CPS2_GFX | BRF_GRA },
{ "sfzex.01", 0x020000, 0xe52887c9, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sfz.02", 0x020000, 0x45f46a08, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sfz.11m", 0x200000, 0xc4b093cd, CPS2_QSND | BRF_SND },
{ "sfz.12m", 0x200000, 0x8bdbc4b4, CPS2_QSND | BRF_SND },
{ "sfzj.key", 0x000014, 0x355d85b8, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Sfaex)
STD_ROM_FN(Sfaex)
struct BurnDriver BurnDrvCpsSfaex = {
"sfaex", "sfa", NULL, NULL, "2026",
"Street Fighter Alpha EX: Warriors' Dreams (Hack, USA RC1)\0", NULL, "Strygo", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK | BDF_HISCORE_SUPPORTED, 2, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, SfaexRomInfo, SfaexRomName, NULL, NULL, NULL, NULL, Cps2FightingInputInfo, NULL,
Cps2Init, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// Street Fighter Zero EX (Hack, Asia RC1)
// 2026-10-26
static struct BurnRomInfo SfzexaRomDesc[] = {
{ "sfzexa.03c", 0x080000, 0x14c3e640, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzre.04b", 0x080000, 0x8d9b2480, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzre.05a", 0x080000, 0x8cf0a98f, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzexa.06", 0x080000, 0x4185da04, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzexa.14m", 0x200000, 0x31318783, CPS2_GFX | BRF_GRA },
{ "sfzexa.16m", 0x200000, 0xb905c57d, CPS2_GFX | BRF_GRA },
{ "sfzexa.18m", 0x200000, 0x0ed47cd2, CPS2_GFX | BRF_GRA },
{ "sfzexa.20m", 0x200000, 0x688f9434, CPS2_GFX | BRF_GRA },
{ "sfzex.01", 0x020000, 0xe52887c9, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sfz.02", 0x020000, 0x45f46a08, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sfz.11m", 0x200000, 0xc4b093cd, CPS2_QSND | BRF_SND },
{ "sfz.12m", 0x200000, 0x8bdbc4b4, CPS2_QSND | BRF_SND },
{ "sfzj.key", 0x000014, 0x355d85b8, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Sfzexa)
STD_ROM_FN(Sfzexa)
struct BurnDriver BurnDrvCpsSfzexa = {
"sfzexa", "sfa", NULL, NULL, "2026",
"Street Fighter Zero EX (Hack, Asia RC1)\0", NULL, "Strygo", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK | BDF_HISCORE_SUPPORTED, 2, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, SfzexaRomInfo, SfzexaRomName, NULL, NULL, NULL, NULL, Cps2FightingInputInfo, NULL,
Cps2Init, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// Street Fighter Zero EX (Hack, Japan RC1)
// 2026-10-26
static struct BurnRomInfo SfzexjRomDesc[] = {
{ "sfzexj.03c", 0x080000, 0x7eb7adce, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzex.04b", 0x080000, 0x8d9b2480, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzrej.05a", 0x080000, 0xfa9ceda6, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzexj.06", 0x080000, 0x995752fb, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfzexj.14m", 0x200000, 0x0a7de3b8, CPS2_GFX | BRF_GRA },
{ "sfzexj.16m", 0x200000, 0xc1b36217, CPS2_GFX | BRF_GRA },
{ "sfzexj.18m", 0x200000, 0x8f468f11, CPS2_GFX | BRF_GRA },
{ "sfzexj.20m", 0x200000, 0x37c3c380, CPS2_GFX | BRF_GRA },
{ "sfzex.01", 0x020000, 0xe52887c9, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sfz.02", 0x020000, 0x45f46a08, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sfz.11m", 0x200000, 0xc4b093cd, CPS2_QSND | BRF_SND },
{ "sfz.12m", 0x200000, 0x8bdbc4b4, CPS2_QSND | BRF_SND },
{ "sfzj.key", 0x000014, 0x355d85b8, CPS2_ENCRYPTION_KEY },
};
STD_ROM_PICK(Sfzexj)
STD_ROM_FN(Sfzexj)
struct BurnDriver BurnDrvCpsSfzexj = {
"sfzexj", "sfa", NULL, NULL, "2026",
"Street Fighter Zero EX (Hack, Japan RC1)\0", NULL, "Strygo", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK | BDF_HISCORE_SUPPORTED, 2, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, SfzexjRomInfo, SfzexjRomName, NULL, NULL, NULL, NULL, Cps2FightingInputInfo, NULL,
Cps2Init, DrvExit, Cps2Frame, CpsRedraw, CpsAreaScan,
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// Street Fighter Alpha 2 Restoration (Hack, USA RC2)
// 2026-10-13
static struct BurnRomInfo Sfa2reRomDesc[] = {
@@ -18102,29 +17651,29 @@ struct BurnDriver BurnDrvCpsSfz3rej = {
&CpsRecalcPal, 0x1000, 384, 224, 4, 3
};
// Super Street Fighter II Turbo: Grand Master Challenge (Hack, English Restoration RC3)
// 2026-10-21
// Super Street Fighter II Turbo: Grand Master Challenge (Hack, English Restoration RC4)
// 2026-10-25
static struct BurnRomInfo Ssf2tgmcRomDesc[] = {
{ "sfxgmc.03d", 0x080000, 0xee8e9e9b, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxgmc.03d", 0x080000, 0xcfc87616, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxgmc.04a", 0x080000, 0xc9df66cd, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxj.05", 0x080000, 0xf4ff18f5, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxj.06b", 0x080000, 0x413477c2, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxj.07a", 0x080000, 0xa18b3d83, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxgmc.08", 0x080000, 0xea0d1d90, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxgmc.09", 0x080000, 0x95718f1e, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxgmc.08", 0x080000, 0xf7587a54, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxgmc.09", 0x080000, 0x9a6ae34e, CPS2_PRG_68K | BRF_ESS | BRF_PRG },
{ "sfxgmc.13m", 0x200000, 0x75dac0eb, CPS2_GFX | BRF_GRA },
{ "sfxgmc.15m", 0x200000, 0x84dcc039, CPS2_GFX | BRF_GRA },
{ "sfxgmc.17m", 0x200000, 0xbfcaf206, CPS2_GFX | BRF_GRA },
{ "sfxgmc.19m", 0x200000, 0x13a55fd3, CPS2_GFX | BRF_GRA },
{ "sfxgmc.14m", 0x100000, 0x1f8dd3ca, CPS2_GFX | BRF_GRA },
{ "sfxgmc.16m", 0x100000, 0x8033c95d, CPS2_GFX | BRF_GRA },
{ "sfxgmc.18m", 0x100000, 0xdd6cdee2, CPS2_GFX | BRF_GRA },
{ "sfxgmc.20m", 0x100000, 0x4dacc976, CPS2_GFX | BRF_GRA },
{ "sfxgmc.21m", 0x100000, 0x34f361da, CPS2_GFX | BRF_GRA },
{ "sfxgmc.23m", 0x100000, 0x279f2671, CPS2_GFX | BRF_GRA },
{ "sfxgmc.25m", 0x100000, 0x1fbd5b9e, CPS2_GFX | BRF_GRA },
{ "sfxgmc.27m", 0x100000, 0x11725784, CPS2_GFX | BRF_GRA },
{ "sfxgmc.14m", 0x100000, 0xa821a895, CPS2_GFX | BRF_GRA },
{ "sfxgmc.16m", 0x100000, 0xf4dd5566, CPS2_GFX | BRF_GRA },
{ "sfxgmc.18m", 0x100000, 0x6ac0a5bd, CPS2_GFX | BRF_GRA },
{ "sfxgmc.20m", 0x100000, 0x3942554d, CPS2_GFX | BRF_GRA },
{ "sfxgmc.21m", 0x100000, 0xc507ee10, CPS2_GFX | BRF_GRA },
{ "sfxgmc.23m", 0x100000, 0xd0bd63db, CPS2_GFX | BRF_GRA },
{ "sfxgmc.25m", 0x100000, 0x2a8193c4, CPS2_GFX | BRF_GRA },
{ "sfxgmc.27m", 0x100000, 0x3c6e0a1a, CPS2_GFX | BRF_GRA },
{ "sfx.01", 0x020000, 0xb47b8835, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
{ "sfx.02", 0x020000, 0x0022633f, CPS2_PRG_Z80 | BRF_ESS | BRF_PRG },
@@ -18140,7 +17689,7 @@ STD_ROM_FN(Ssf2tgmc)
struct BurnDriver BurnDrvCpsSsf2tgmc = {
"ssf2tgmc", "ssf2t", NULL, NULL, "2026",
"Super Street Fighter II Turbo: Grand Master Challenge (Hack, English Restoration RC3)\0", NULL, "Strygo", "CPS2",
"Super Street Fighter II Turbo: Grand Master Challenge (Hack, English Restoration RC4)\0", NULL, "Strygo", "CPS2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK | BDF_HISCORE_SUPPORTED, 2, HARDWARE_CAPCOM_CPS2, GBF_VSFIGHT, FBF_SF,
NULL, Ssf2tgmcRomInfo, Ssf2tgmcRomName, NULL, NULL, NULL, NULL, Cps2FightingInputInfo, NULL,
File diff suppressed because it is too large. Load diff
+1
View File
@@ -33,5 +33,6 @@ group_srcs = [
drivers = {
'd_cps1.cpp': ['ay8910', 'eeprom', 'm68000', 'msm5205', 'msm6295', 'samples', 'timekpr', 'ym2151', 'ym2203', 'z80'],
'd_cps2.cpp': ['ay8910', 'eeprom', 'm68000', 'msm5205', 'msm6295', 'samples', 'ym2151', 'ym2203', 'z80'],
'd_cps2_custom.cpp': ['ay8910', 'eeprom', 'm68000', 'msm5205', 'msm6295', 'samples', 'ym2151', 'ym2203', 'z80'],
'd_mitchell.cpp': ['ay8910', 'eeprom', 'm68000', 'msm5205', 'msm6295', 'samples', 'ym2151', 'ym2203', 'ym2413', 'z80'],
}
+5 -17
View File
@@ -21,18 +21,9 @@ INT32 QsndInit()
}
BurnTimerInit(qsndTimerOver, NULL);
if (Cps1Qs == 1) {
nCpsZ80Cycles = 8000000 * 100 / nBurnFPS;
BurnTimerAttachZet(8000000);
} else {
if (Cps2Turbo) {
nCpsZ80Cycles = 16000000 * 100 / nBurnFPS;
BurnTimerAttachZet(16000000);
} else {
nCpsZ80Cycles = 8000000 * 100 / nBurnFPS;
BurnTimerAttachZet(8000000);
}
}
INT32 nClock = (Cps1Qs == 1) ? 8000000 : nQsndZ80Clock;
nCpsZ80Cycles = nClock * 100 / nBurnFPS;
BurnTimerAttachZet(nClock);
if (nBurnSoundRate >= 0) {
nRate = nBurnSoundRate;
@@ -66,11 +57,11 @@ void QsndExit()
QsndZExit();
}
INT32 QsndScan(INT32 nAction)
INT32 QsndScan(INT32 nAction, INT32 bScanHistory)
{
if (nAction & ACB_DRIVER_DATA) {
QsndZScan(nAction); // Scan Z80
QscScan(nAction); // Scan QSound Chip
QscScan(nAction, bScanHistory); // Scan QSound Chip
BurnTimerScan(nAction, NULL);
SCAN_VAR(nQsndCyclesExtra);
@@ -93,9 +84,6 @@ void QsndEndFrame()
{
BurnTimerEndFrame(nCpsZ80Cycles);
if (pBurnSoundOut) QscUpdate(nBurnSoundLen);
if (Cps2Turbo && pBurnSoundOut) {
BurnSampleRender(pBurnSoundOut, nBurnSoundLen);
}
nQsndCyclesExtra = ZetTotalCycles() - nCpsZ80Cycles;
ZetClose();
+4 -4
View File
@@ -310,7 +310,7 @@ inline INT16 get_sample(UINT16 bank, UINT16 address)
UINT8 sample_data;
if(nCpsQSamLen)
rom_mask = nCpsQSamLen - 1;
rom_mask = nCpsQSamMask ? nCpsQSamMask : nCpsQSamLen - 1;
if (! rom_mask)
return 0; // no ROM loaded
@@ -765,7 +765,7 @@ void QscSetRoute(INT32 nIndex, double nVolume, INT32 nRouteDir)
QsndOutputDir[nIndex] = nRouteDir;
}
INT32 QscScan(INT32 nAction)
INT32 QscScan(INT32 nAction, INT32 bScanHistory)
{
struct BurnArea ba;
char szName[16];
@@ -778,8 +778,8 @@ INT32 QscScan(INT32 nAction)
ba.szName = szName;
BurnAcb(&ba);
if (CpsXmvSixEnabled) {
// xmvsf3v3: the resampler too, so its states replay exactly (other games' states keep their size)
if (bScanHistory) {
// Preserve resampler history when replaying a saved frame.
SCAN_VAR(nDelta);
SCAN_VAR(nPos);
SCAN_VAR(interpolate_buffer);
+27 -5
View File
@@ -1,6 +1,9 @@
#include "cps.h"
// QSound - Z80
INT32 nQsndZ80Clock = 8000000;
INT32 nQsndZBankOffset = 0x8000;
static INT32 nQsndZBank = 0;
static UINT8 QscCmd[2] = {0, 0};
@@ -10,7 +13,7 @@ static INT32 QsndZBankMap()
UINT32 nOff;
UINT8* Bank;
nOff = nQsndZBank << 14;
nOff += (Cps2Turbo) ? 0x10000 : 0x8000; // sfz3mix .22 z80 rom stored in mame memmap format (banks start at 0x10000, instead of 0x8000 like fbneo)
nOff += nQsndZBankOffset;
if (Cps1Qs == 0) {
if (nOff + 0x4000 > nCpsZRomLen) { // End of bank is out of range
@@ -52,10 +55,7 @@ void __fastcall QsndZWrite(UINT16 a, UINT8 d)
}
if (a == 0xd003) {
INT32 nNewBank = d & 0x0f;
if (nQsndZBank != nNewBank) {
nQsndZBank = nNewBank;
QsndZBankMap();
}
QsndZSetBank(nNewBank);
}
}
@@ -119,8 +119,30 @@ INT32 QsndZInit()
return 0;
}
void QsndZSetBank(INT32 nBank)
{
if (nQsndZBank != nBank) {
nQsndZBank = nBank;
QsndZBankMap();
}
}
INT32 QsndZGetBank()
{
return nQsndZBank;
}
void QsndZReset()
{
nQsndZBank = 0;
QsndZBankMap();
QscCmd[0] = QscCmd[1] = 0;
}
INT32 QsndZExit()
{
nQsndZ80Clock = 8000000;
nQsndZBankOffset = 0x8000;
ZetExit();
return 0;
}
+1 -1
View File
@@ -7,7 +7,7 @@
// 0x810000-0x81ffff 64KB of extra work RAM, each 68000 word stored high byte first
// The ROMs also mark the mini portraits on the HUD so that this board can draw them in the
// fighter's chosen colour (one of eighteen), decoded from the colour table in the program ROM.
// Nothing here is used by any other game: cps_rw.cpp only enables it for the 3v3 drivers.
// Enabled by the 3v3 drivers in d_cps2_custom.cpp.
#ifndef XMVSF3V3_H
#define XMVSF3V3_H
+25
View File
@@ -512,6 +512,21 @@ static struct BurnRomInfo sfiii2hRomDesc[] = {
STD_ROM_PICK(sfiii2h)
STD_ROM_FN(sfiii2h)
// ---------------------------------------------------------
// Street Fighter III 2nd Impact: Giant Attack (Asia 970930)
// ---------------------------------------------------------
static struct BurnRomInfo sfiii2aRomDesc[] = {
{ "sfiii2_asia.29f400.u2", 0x080000, 0x4518d589, BRF_ESS | BRF_BIOS }, // SH-2 Bios
#if !defined ROM_VERIFY
SFIII2_970930_FLASH
#endif
};
STD_ROM_PICK(sfiii2a)
STD_ROM_FN(sfiii2a)
// ----------------------------------------------------------------
// Street Fighter III 2nd Impact: Giant Attack (Asia 970930, NO CD)
// ----------------------------------------------------------------
@@ -1718,6 +1733,16 @@ struct BurnDriver BurnDrvSfiii2h = {
384, 224, 4, 3
};
struct BurnDriver BurnDrvSfiii2a = {
"sfiii2a", "sfiii2", NULL, NULL, "1997",
"Street Fighter III 2nd Impact: Giant Attack (Asia 970930)\0", NULL, "Capcom", "CPS-3",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY | BDF_CLONE | BDF_HISCORE_SUPPORTED, 2, HARDWARE_CAPCOM_CPS3, GBF_VSFIGHT, FBF_SF,
NULL, sfiii2aRomInfo, sfiii2aRomName, NULL, NULL, NULL, NULL, cps3InputInfo, sfiiiwideasiaDIPInfo,
sfiii2Init, cps3Exit, cps3Frame, DrvCps3Draw, cps3Scan, &cps3_palette_change, 0x40000,
384, 224, 4, 3
};
struct BurnDriver BurnDrvSfiii2n = {
"sfiii2n", "sfiii2", NULL, NULL, "1997",
"Street Fighter III 2nd Impact: Giant Attack (Asia 970930, NO CD)\0", NULL, "Capcom", "CPS-3",
+78 -16
View File
@@ -36,6 +36,7 @@ static UINT8 *DrvSprBuf1;
static UINT8 *DrvZ80RAM;
static UINT32 *DrvPalette;
static UINT16 *DrvTmpDraw[3]; // mutantf alpha temp. mixing
static UINT8 DrvRecalc;
static UINT8 *soundlatch;
@@ -1057,6 +1058,10 @@ static INT32 MemIndex()
DrvPalette = (UINT32*)Next; Next += 0x0800 * sizeof(UINT32);
for (INT32 i = 0; i < 3; i++) {
DrvTmpDraw[i] = (UINT16*)Next; Next += 512 * 256 * sizeof(UINT16);
}
AllRam = Next;
Drv68KRAM = Next; Next += 0x008000;
@@ -1915,7 +1920,7 @@ static void cninjabl_draw_sprites()
}
}
static void mutantf_draw_sprites(UINT8 *ram, UINT8 *gfx, INT32 colbank, INT32 gfxbank)
static void mutantf_draw_sprites(UINT8 *ram, UINT8 *gfx, INT32 colbank, INT32 gfxbank, UINT16 *dest)
{
UINT16 *spriteptr = (UINT16*)ram;
@@ -1937,7 +1942,6 @@ static void mutantf_draw_sprites(UINT8 *ram, UINT8 *gfx, INT32 colbank, INT32 gf
while (offs != end)
{
INT32 x, y, sprite, colour, fx, fy, w, h, sx, sy, x_mult, y_mult;
INT32 alpha = 0xff;
sprite = BURN_ENDIAN_SWAP_INT16(spriteptr[offs + 3]);
if (!sprite)
@@ -1962,7 +1966,6 @@ static void mutantf_draw_sprites(UINT8 *ram, UINT8 *gfx, INT32 colbank, INT32 gf
if (gfxbank == 4)
{
alpha = 0x80;
colour &= 0xf;
}
@@ -2000,8 +2003,7 @@ static void mutantf_draw_sprites(UINT8 *ram, UINT8 *gfx, INT32 colbank, INT32 gf
{
for (y = 0; y < h; y++)
{
// needs alpha blending...
deco16_draw_prio_sprite(pTransDraw, gfx, sprite + y + h * x, (colour << 4) + colbank, sx + x_mult * (w-x), sy + y_mult * (h-y), fx, fy, 0);
deco16_draw_prio_sprite(dest, gfx, sprite + y + h * x, (colour << 4) + colbank, sx + x_mult * (w-x), sy + y_mult * (h-y), fx, fy, 0);
}
}
offs += inc;
@@ -2179,6 +2181,36 @@ static INT32 Robocop2Draw()
}
static inline UINT32 mutantf_alpha_blend(UINT32 d, UINT32 s, UINT32 p)
{
INT32 a = 256 - p;
return (((((s & 0xff00ff) * p) + ((d & 0xff00ff) * a)) & 0xff00ff00) +
((((s & 0x00ff00) * p) + ((d & 0x00ff00) * a)) & 0x00ff0000)) / 256;
}
// mix a 16-bit (palette index) layer onto the 32bpp output, 0 = transparent
static void mutantf_mix_layer(UINT16 *src, INT32 alpha)
{
UINT8 *dst = pBurnDraw;
for (INT32 y = 0; y < nScreenHeight; y++, src += nScreenWidth, dst += nBurnPitch)
{
UINT32 *d = (UINT32*)dst;
for (INT32 x = 0; x < nScreenWidth; x++)
{
if (src[x] == 0) continue;
if (alpha == 0xff) {
d[x] = DrvPalette[src[x]];
} else {
d[x] = mutantf_alpha_blend(d[x], DrvPalette[src[x]], alpha);
}
}
}
}
static INT32 MutantfDraw()
{
// if (DrvRecalc) {
@@ -2195,24 +2227,54 @@ static INT32 MutantfDraw()
if (nSpriteEnable & 2) deco16_draw_layer(1, pTransDraw, 0);
if (nSpriteEnable & 4) deco16_draw_layer(2, pTransDraw, 0);
if (nBurnBpp != 4)
{
// no alpha @ < 32bpp
if (deco16_priority & 1)
{
deco16_clear_prio_map();
if (nBurnLayer & 1) mutantf_draw_sprites(DrvSprBuf, DrvGfxROM3, 0x100, 3, pTransDraw);
deco16_clear_prio_map();
if (nBurnLayer & 2) mutantf_draw_sprites(DrvSprBuf1, DrvGfxROM4, 0x700, 4, pTransDraw);
}
else
{
deco16_clear_prio_map();
if (nBurnLayer & 2) mutantf_draw_sprites(DrvSprBuf1, DrvGfxROM4, 0x700, 4, pTransDraw);
deco16_clear_prio_map();
if (nBurnLayer & 1) mutantf_draw_sprites(DrvSprBuf, DrvGfxROM3, 0x100, 3, pTransDraw);
}
if (nSpriteEnable & 8) deco16_draw_layer(0, pTransDraw, 0);
BurnTransferCopy(DrvPalette);
return 0;
}
for (INT32 i = 0; i < 3; i++) memset(DrvTmpDraw[i], 0, nScreenWidth * nScreenHeight * sizeof(UINT16));
deco16_clear_prio_map();
if (nBurnLayer & 1) mutantf_draw_sprites(DrvSprBuf, DrvGfxROM3, 0x100, 3, DrvTmpDraw[0]);
deco16_clear_prio_map();
if (nBurnLayer & 2) mutantf_draw_sprites(DrvSprBuf1, DrvGfxROM4, 0x700, 4, DrvTmpDraw[1]);
if (nSpriteEnable & 8) deco16_draw_layer(0, DrvTmpDraw[2], 0);
BurnTransferCopy(DrvPalette);
if (deco16_priority & 1)
{
deco16_clear_prio_map();
mutantf_draw_sprites(DrvSprBuf, DrvGfxROM3, 0x100, 3);
deco16_clear_prio_map();
mutantf_draw_sprites(DrvSprBuf1, DrvGfxROM4, 0x700, 4);
mutantf_mix_layer(DrvTmpDraw[0], 0xff);
mutantf_mix_layer(DrvTmpDraw[1], 0x80);
}
else
{
deco16_clear_prio_map();
mutantf_draw_sprites(DrvSprBuf1, DrvGfxROM4, 0x700, 4);
deco16_clear_prio_map();
mutantf_draw_sprites(DrvSprBuf, DrvGfxROM3, 0x100, 3);
mutantf_mix_layer(DrvTmpDraw[1], 0x80);
mutantf_mix_layer(DrvTmpDraw[0], 0xff);
}
if (nSpriteEnable & 8) deco16_draw_layer(0, pTransDraw, 0);
BurnTransferCopy(DrvPalette);
mutantf_mix_layer(DrvTmpDraw[2], 0xff);
return 0;
}
+5 -2
View File
@@ -4590,7 +4590,10 @@ static void TmntDecodeTitleSample()
val = (val >> 3) & (0x3ff);
val -= 0x200;
val <<= (expo-3);
// expo-3 can be negative; a negative left-shift is undefined behaviour
// (produced garbage spikes on arm64). Shift right for the negative case.
INT32 sh = expo - 3;
if (sh >= 0) val <<= sh; else val >>= (-sh);
DrvTitleSample[i] = val;
}
@@ -5892,7 +5895,7 @@ static void RenderTitleSample(INT16 *pSoundBuf, INT32 nLength)
{
double Addr = TitleSamplePos;
double Step = (double)20000 / nBurnSoundRate;
for (INT32 i = 0; i < nLength; i += 2) {
if (Addr > 0x3ffff) break;
INT16 Sample = DrvTitleSample[(INT32)Addr];
+15 -15
View File
@@ -38677,10 +38677,10 @@ struct BurnDriver BurnDrvmd_bioblade = {
&bMegadriveRecalcPalette, 0x100, 320, 224, 4, 3
};
// Black Tiger (HB, v1.9.1)
// Black Tiger (HB, v1.9.3)
// https://rester159.itch.io/black-tiger-md
static struct BurnRomInfo md_blacktigerRomDesc[] = {
{ "Black Tiger v1.9.1 (2026)(rester159).bin", 4194304, 0xa1b19794, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
{ "Black Tiger v1.9.3 (2026)(rester159).bin", 4194304, 0xe5debe42, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
};
STD_ROM_PICK(md_blacktiger)
@@ -38688,7 +38688,7 @@ STD_ROM_FN(md_blacktiger)
struct BurnDriver BurnDrvmd_blacktiger = {
"md_blacktiger", NULL, NULL, NULL, "2026",
"Black Tiger (HB, v1.9.1)\0", NULL, "rester159", "Genesis / Mega Drive",
"Black Tiger (HB, v1.9.3)\0", NULL, "rester159", "Genesis / Mega Drive",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY | BDF_HOMEBREW, 1, HARDWARE_SEGA_MEGADRIVE, GBF_PLATFORM | GBF_RUNGUN, 0,
MegadriveGetZipName, md_blacktigerRomInfo, md_blacktigerRomName, NULL, NULL, NULL, NULL, MegadriveInputInfo, MegadriveDIPInfo,
@@ -42625,10 +42625,10 @@ struct BurnDriver BurnDrvmd_pandajump = {
&bMegadriveRecalcPalette, 0x100, 320, 224, 4, 3
};
// Pang (DavidGames) (HB, Beta v1.03)
// Pang (DavidGames) (HB, v1.00)
// https://davidsgame.itch.io/pang-md
static struct BurnRomInfo md_pangRomDesc[] = {
{ "Pang Beta v1.03 (2026)(DavidGames).bin", 1310720, 0xbdd4517a, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
{ "Pang v1.00 (2026)(DavidGames).bin", 1310720, 0x2d816dcb, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
};
STD_ROM_PICK(md_pang)
@@ -42636,7 +42636,7 @@ STD_ROM_FN(md_pang)
struct BurnDriver BurnDrvmd_pang = {
"md_pang", NULL, NULL, NULL, "2026",
"Pang (DavidGames) (HB, Beta v1.03)\0", NULL, "DavidGames", "Genesis / Mega Drive",
"Pang (DavidGames) (HB, v1.00)\0", NULL, "DavidGames", "Genesis / Mega Drive",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY | BDF_HOMEBREW, 2, HARDWARE_SEGA_MEGADRIVE, GBF_ACTION, 0,
MegadriveGetZipName, md_pangRomInfo, md_pangRomName, NULL, NULL, NULL, NULL, MegadriveInputInfo, MegadriveDIPInfo,
@@ -42644,10 +42644,10 @@ struct BurnDriver BurnDrvmd_pang = {
&bMegadriveRecalcPalette, 0x100, 320, 224, 4, 3
};
// Pang (Oldschool Is Beautiful) (HB, Beta 3)
// Pang (Oldschool Is Beautiful) (HB, v1.00)
// https://mlouvet.itch.io/pang-megadrive
static struct BurnRomInfo md_pangoibRomDesc[] = {
{ "Pang Beta 3 (2026)(Oldschool Is Beautiful).bin", 3877096, 0xa789941b, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
{ "Pang v1.00 (2026)(Oldschool Is Beautiful).bin", 3909708, 0x2022a547, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
};
STD_ROM_PICK(md_pangoib)
@@ -42655,7 +42655,7 @@ STD_ROM_FN(md_pangoib)
struct BurnDriver BurnDrvmd_pangoib = {
"md_pangoib", NULL, NULL, NULL, "2026",
"Pang (Oldschool Is Beautiful) (HB, Beta 3)\0", NULL, "Oldschool Is Beautiful", "Genesis / Mega Drive",
"Pang (Oldschool Is Beautiful) (HB, v1.00)\0", NULL, "Oldschool Is Beautiful", "Genesis / Mega Drive",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY | BDF_HOMEBREW, 2, HARDWARE_SEGA_MEGADRIVE, GBF_ACTION, 0,
MegadriveGetZipName, md_pangoibRomInfo, md_pangoibRomName, NULL, NULL, NULL, NULL, MegadriveInputInfo, MegadriveDIPInfo,
@@ -42952,10 +42952,10 @@ struct BurnDriver BurnDrvmd_papriumunlck = {
&bMegadriveRecalcPalette, 0x100, 320, 224, 4, 3
};
// Parasol Stars (HB, v1.0 RC3)
// Parasol Stars (HB, v1.0.2)
// https://mlouvet.itch.io/parasol-stars-megadrive-genesis
static struct BurnRomInfo md_parasolRomDesc[] = {
{ "Parasol Stars v1.0 RC3 (2026)(Oldschool Is Beautiful).bin", 4194304, 0x181b816a, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
{ "Parasol Stars v1.0.2 (2026)(Oldschool Is Beautiful).bin", 4194304, 0x72fc1b17, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
};
STD_ROM_PICK(md_parasol)
@@ -42963,7 +42963,7 @@ STD_ROM_FN(md_parasol)
struct BurnDriver BurnDrvmd_parasol = {
"md_parasol", NULL, NULL, NULL, "2026",
"Parasol Stars (HB, v1.0 RC3)\0", NULL, "Oldschool Is Beautiful", "Genesis / Mega Drive",
"Parasol Stars (HB, v1.0.2)\0", NULL, "Oldschool Is Beautiful", "Genesis / Mega Drive",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY | BDF_HOMEBREW, 2, HARDWARE_SEGA_MEGADRIVE, GBF_PLATFORM, 0,
MegadriveGetZipName, md_parasolRomInfo, md_parasolRomName, NULL, NULL, NULL, NULL, MegadriveInputInfo, MegadriveDIPInfo,
@@ -44619,10 +44619,10 @@ struct BurnDriver BurnDrvmd_threestooges = {
&bMegadriveRecalcPalette, 0x100, 320, 224, 4, 3
};
// Tiger Road (hombreimaginario) (HB, 2026-10-23)
// Tiger Road (hombreimaginario) (HB, 2026-10-26)
// https://hombreimaginario.itch.io/tiger-road-md
static struct BurnRomInfo md_tigeroadRomDesc[] = {
{ "Tiger Road 2026-10-23 (2026)(hombreimaginario).bin", 2490368, 0x8db153ab, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
{ "Tiger Road 2026-10-26 (2026)(hombreimaginario).bin", 2490368, 0x98decaf0, BRF_PRG | SEGA_MD_ROM_LOAD16_WORD_SWAP | SEGA_MD_ROM_OFFS_000000 },
};
STD_ROM_PICK(md_tigeroad)
@@ -44630,7 +44630,7 @@ STD_ROM_FN(md_tigeroad)
struct BurnDriver BurnDrvmd_tigeroad = {
"md_tigeroad", NULL, NULL, NULL, "2026",
"Tiger Road (hombreimaginario) (HB, 2026-10-23)\0", NULL, "hombreimaginario", "Genesis / Mega Drive",
"Tiger Road (hombreimaginario) (HB, 2026-10-26)\0", NULL, "hombreimaginario", "Genesis / Mega Drive",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY | BDF_HOMEBREW, 1, HARDWARE_SEGA_MEGADRIVE, GBF_PLATFORM | GBF_SCRFIGHT, 0,
MegadriveGetZipName, md_tigeroadRomInfo, md_tigeroadRomName, NULL, NULL, NULL, NULL, MegadriveInputInfo, MegadriveDIPInfo,
+6 -6
View File
@@ -12562,7 +12562,7 @@ struct BurnDriver BurnDrvPulstar = {
};
// Pulstar Aegis (Hack)
// Pulstar Aegis (Hack, v1.0.0)
// https://github.com/Boomchil/neo-geo-romhacks/tree/main/public/patches/pulstar
static struct BurnRomInfo pulstaraeRomDesc[] = {
{ "089-p1ae.p1", 0x100000, 0xdcb02236, 1 | BRF_ESS | BRF_PRG }, // 0 68K code / mask rom TC538200
@@ -12590,7 +12590,7 @@ STD_ROM_FN(pulstarae)
struct BurnDriver BurnDrvPulstarae = {
"pulstarae", "pulstar", "neogeo", NULL, "2026",
"Pulstar Aegis (Hack)\0", NULL, "Boomchil", "Neo Geo MVS",
"Pulstar Aegis (Hack, v1.0.0)\0", NULL, "Boomchil", "Neo Geo MVS",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK | BDF_HISCORE_SUPPORTED, 2, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_SNK_NEOGEO, GBF_HORSHOOT, 0,
NULL, pulstaraeRomInfo, pulstaraeRomName, NULL, NULL, NULL, NULL, neogeoInputInfo, neogeoDIPInfo,
@@ -12745,7 +12745,7 @@ struct BurnDriver BurnDrvWjammers = {
};
// Windjammers / Flying Power Disc (Endless Breeze, Hack, v1.2.0)
// Windjammers / Flying Power Disc - Endless Breeze (Hack, v1.2.0)
// https://github.com/Boomchil/neo-geo-romhacks/tree/main/public/patches/wjammers
static struct BurnRomInfo wjammebRomDesc[] = {
@@ -12771,7 +12771,7 @@ STD_ROM_FN(wjammeb)
struct BurnDriver BurnDrvWjammeb = {
"wjammeb", "wjammers", "neogeo", NULL, "2025-26",
"Windjammers / Flying Power Disc (Endless Breeze, Hack, v1.2.0)\0", NULL, "Boomchil", "Neo Geo MVS",
"Windjammers / Flying Power Disc - Endless Breeze (Hack, v1.2.0)\0", NULL, "Boomchil", "Neo Geo MVS",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_SNK_NEOGEO, GBF_SPORTSMISC, 0,
NULL, wjammebRomInfo, wjammebRomName, NULL, NULL, NULL, NULL, neogeoInputInfo, neogeoDIPInfo,
@@ -28294,7 +28294,7 @@ struct BurnDriver BurnDrvRobocopi = {
BDF_GAME_WORKING | BDF_DEMO, 1, HARDWARE_SNK_NEOGEO, GBF_MISC, 0,
NULL, robocopiRomInfo, robocopiRomName, NULL, NULL, NULL, NULL, neogeoInputInfo, neogeouniDIPInfo,
NeoInit, NeoExit, NeoFrame, NeoRender, NeoScan, &NeoRecalcPalette,
0x1000, 304, 224, 4, 3
0x1000, 320, 224, 4, 3
};
@@ -30444,7 +30444,7 @@ struct BurnDriver BurnDrvKarnovng = {
// Maiya: Super Nature Girl (HB, v4)
static struct BurnRomInfo maiyaRomDesc[] = {
{ "maiya-p1.p1", 0x080000, 0x5fe28a51, 1 | BRF_ESS | BRF_PRG }, // 0 68K code
{ "maiya-p1.p1", 0x080000, 0xecef6baa, 1 | BRF_ESS | BRF_PRG }, // 0 68K code
{ "maiya-s1.s1", 0x020000, 0x5c7951e1, 2 | BRF_GRA }, // 1 Text layer tiles
+43 -4
View File
@@ -14699,7 +14699,27 @@ struct BurnDriver BurnDrvnes_aliensmash = {
SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT
};
// All Hell Unleashed - Ultimate Edition (HB)
// https://8bitslasher.itch.io/ahu
static struct BurnRomInfo nes_allhellunlueRomDesc[] = {
{ "All Hell Unleashed - Ultimate Edition (2025-26)(Fista Productions).nes", 524304, 0x205da9ad, BRF_ESS | BRF_PRG },
};
STD_ROM_PICK(nes_allhellunlue)
STD_ROM_FN(nes_allhellunlue)
struct BurnDriver BurnDrvnes_allhellunlue = {
"nes_allhellunlue", NULL, NULL, NULL, "2025-26",
"All Hell Unleashed - Ultimate Edition (HB)\0", NULL, "Fista Productions", "NES / Famicom",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_NES, GBF_SCRFIGHT | GBF_VSFIGHT, 0,
NESGetZipName, nes_allhellunlueRomInfo, nes_allhellunlueRomName, NULL, NULL, NULL, NULL, NESInputInfo, NESDIPInfo,
NESInit, NESExit, NESFrame, NESDraw, NESScan, &NESRecalc, 0x40,
SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT
};
// All Hell Unleashed (HB, v6.66)
// https://8bitslasher.itch.io/ahu
static struct BurnRomInfo nes_allhellunl666RomDesc[] = {
{ "All Hell Unleashed v6.66 (2025)(Fista Productions).nes", 524304, 0x4203e09a, BRF_ESS | BRF_PRG },
};
@@ -14708,16 +14728,17 @@ STD_ROM_PICK(nes_allhellunl666)
STD_ROM_FN(nes_allhellunl666)
struct BurnDriver BurnDrvnes_allhellunl666 = {
"nes_allhellunl666", NULL, NULL, NULL, "2025",
"nes_allhellunl666", "nes_allhellunlue", NULL, NULL, "2025",
"All Hell Unleashed (HB, v6.66)\0", NULL, "Fista Productions", "NES / Famicom",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_NES, GBF_SCRFIGHT | GBF_VSFIGHT, 0,
BDF_GAME_WORKING | BDF_CLONE | BDF_HOMEBREW, 1, HARDWARE_NES, GBF_SCRFIGHT | GBF_VSFIGHT, 0,
NESGetZipName, nes_allhellunl666RomInfo, nes_allhellunl666RomName, NULL, NULL, NULL, NULL, NESInputInfo, NESDIPInfo,
NESInit, NESExit, NESFrame, NESDraw, NESScan, &NESRecalc, 0x40,
SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT
};
// All Hell Unleashed (HB)
// https://8bitslasher.itch.io/ahu
static struct BurnRomInfo nes_allhellunlRomDesc[] = {
{ "All Hell Unleashed (2025)(Fista Productions).nes", 524304, 0x2f78164f, BRF_ESS | BRF_PRG },
};
@@ -14726,7 +14747,7 @@ STD_ROM_PICK(nes_allhellunl)
STD_ROM_FN(nes_allhellunl)
struct BurnDriver BurnDrvnes_allhellunl = {
"nes_allhellunl", "nes_allhellunl666", NULL, NULL, "2025",
"nes_allhellunl", "nes_allhellunlue", NULL, NULL, "2025",
"All Hell Unleashed (HB)\0", NULL, "Fista Productions", "NES / Famicom",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HOMEBREW, 1, HARDWARE_NES, GBF_SCRFIGHT | GBF_VSFIGHT, 0,
@@ -14898,6 +14919,24 @@ struct BurnDriver BurnDrvnes_ambersa = {
SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT
};
// Angry Video Game Nerd 8-bit, The (HB)
static struct BurnRomInfo nes_angrynerdRomDesc[] = {
{ "Angry Video Game Nerd 8-bit, The (2025)(Retroware - Mega Cat Studios).nes", 786448, 0xfd8ddfb7, BRF_ESS | BRF_PRG },
};
STD_ROM_PICK(nes_angrynerd)
STD_ROM_FN(nes_angrynerd)
struct BurnDriver BurnDrvnes_angrynerd = {
"nes_angrynerd", NULL, NULL, NULL, "2025",
"Angry Video Game Nerd 8-bit, The (HB)\0", NULL, "Retroware - Mega Cat Studios", "NES / Famicom",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_NES, GBF_PLATFORM | GBF_RUNGUN, 0,
NESGetZipName, nes_angrynerdRomInfo, nes_angrynerdRomName, NULL, NULL, NULL, NULL, NESInputInfo, NESDIPInfo,
NESInit, NESExit, NESFrame, NESDraw, NESScan, &NESRecalc, 0x40,
SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT
};
// Anguna: Scourge of the Goblin King (HB)
static struct BurnRomInfo nes_angunaRomDesc[] = {
{ "Anguna - Scourge of the Goblin King (2021)(The 6502 Collective).nes", 524304, 0x1119efff, BRF_ESS | BRF_PRG },
@@ -21542,7 +21581,7 @@ struct BurnDriver BurnDrvnes_machinecave = {
// Mad Mix Game R (HB)
// https://enriqueggalvez.itch.io/mad-mix-game-r
static struct BurnRomInfo nes_madmixgrRomDesc[] = {
{ "Mad Mix Game R (2026)(Magic Games).nes", 2097168, 0x58702f7d, BRF_ESS | BRF_PRG },
{ "Mad Mix Game R (2026)(Magic Games).nes", 2097168, 0xbb5d8cc7, BRF_ESS | BRF_PRG },
};
STD_ROM_PICK(nes_madmixgr)
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -221,7 +221,7 @@ static struct BurnInputInfo GrainbowInputList[] = {
{"P2 Button 2", BIT_DIGITAL, DrvJoy1 + 13, "p2 fire 2" },
{"P2 Button 3", BIT_DIGITAL, DrvJoy1 + 14, "p2 fire 3" },
{"P3 Start", BIT_DIGITAL, DrvJoy1 + 8, "p3 start" },
{"P3 Start", BIT_DIGITAL, DrvJoy3 + 8, "p3 start" },
{"P3 Up", BIT_DIGITAL, DrvJoy2 + 0, "p3 up" },
{"P3 Down", BIT_DIGITAL, DrvJoy2 + 1, "p3 down" },
{"P3 Left", BIT_DIGITAL, DrvJoy2 + 2, "p3 left" },
@@ -230,7 +230,7 @@ static struct BurnInputInfo GrainbowInputList[] = {
{"P3 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p3 fire 2" },
{"P3 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p3 fire 3" },
{"P4 Start", BIT_DIGITAL, DrvJoy1 + 9, "p4 start" },
{"P4 Start", BIT_DIGITAL, DrvJoy3 + 9, "p4 start" },
{"P4 Up", BIT_DIGITAL, DrvJoy2 + 8, "p4 up" },
{"P4 Down", BIT_DIGITAL, DrvJoy2 + 9, "p4 down" },
{"P4 Left", BIT_DIGITAL, DrvJoy2 + 10, "p4 left" },
+63
View File
@@ -4848,6 +4848,69 @@ struct BurnDriver BurnDrvValkyrie = {
};
// Valkyrie no Densetsu (Hack, English Translation from Namco Museum Vol. 5)
// https://github.com/SpiralBrad/valkyrie-no-densetsu-english
static struct BurnRomInfo valkyrienmv5RomDesc[] = {
{ "wd1mpr0.bin", 0x20000, 0xf6e93a8c, 0x01 | BRF_PRG | BRF_ESS }, // 0 Main 68K Code
{ "wd1mpr1.bin", 0x20000, 0x0f496013, 0x01 | BRF_PRG | BRF_ESS }, // 1
{ "wd1spr0.bin", 0x10000, 0xb2398321, 0x02 | BRF_PRG | BRF_ESS }, // 2 Sub 68K Code
{ "wd1spr1.bin", 0x10000, 0x38dba897, 0x02 | BRF_PRG | BRF_ESS }, // 3
{ "wd1snd0.bin", 0x20000, 0xd0fbf58b, 0x03 | BRF_PRG | BRF_ESS }, // 4 M6809 Code
#if !defined ROM_VERIFY
{ "sys2mcpu.bin", 0x02000, 0xa342a97e, 0x04 | BRF_PRG | BRF_ESS }, // 5 HD68705 Code
#endif
{ "sys2c65c.bin", 0x08000, 0xa5b2a4ff, 0x04 | BRF_PRG | BRF_ESS }, // 6
{ "wdobj0.bin", 0x40000, 0xe8089451, 0x05 | BRF_GRA }, // 7 Sprites
{ "wdobj1.bin", 0x40000, 0x7ca65666, 0x05 | BRF_GRA }, // 8
{ "wdobj2.bin", 0x40000, 0x7c159407, 0x05 | BRF_GRA }, // 9
{ "wdobj3.bin", 0x40000, 0x649f8760, 0x05 | BRF_GRA }, // 10
{ "wdobj4.bin", 0x40000, 0x7ca39ae7, 0x05 | BRF_GRA }, // 11
{ "wdobj5.bin", 0x40000, 0x9ead2444, 0x05 | BRF_GRA }, // 12
{ "wdobj6.bin", 0x40000, 0x9fa2ea21, 0x05 | BRF_GRA }, // 13
{ "wdobj7.bin", 0x40000, 0x66e07a36, 0x05 | BRF_GRA }, // 14
{ "wdchr0.bin", 0x20000, 0xdebb0116, 0x06 | BRF_GRA }, // 15 Layer Tiles
{ "wdchr1.bin", 0x20000, 0x8a1431e8, 0x06 | BRF_GRA }, // 16
{ "wdchr2.bin", 0x20000, 0x62f75f69, 0x06 | BRF_GRA }, // 17
{ "wdchr3.bin", 0x20000, 0xcc43bbe7, 0x06 | BRF_GRA }, // 18
{ "wdchr4.bin", 0x20000, 0x2f73d05e, 0x06 | BRF_GRA }, // 19
{ "wdchr5.bin", 0x20000, 0xb632b2ec, 0x06 | BRF_GRA }, // 20
{ "wdroz0.bin", 0x20000, 0xf776bf66, 0x07 | BRF_GRA }, // 21 Roz Layer Tiles
{ "wdroz1.bin", 0x20000, 0xc1a345c3, 0x07 | BRF_GRA }, // 22
{ "wdroz2.bin", 0x20000, 0x28ffb44a, 0x07 | BRF_GRA }, // 23
{ "wdroz3.bin", 0x20000, 0x7e77b46d, 0x07 | BRF_GRA }, // 24
{ "wdshape.bin", 0x20000, 0x3b5e0249, 0x08 | BRF_GRA }, // 25 Layer Tiles Mask Data
{ "wd1dat0.13s", 0x20000, 0xea209f48, 0x09 | BRF_PRG | BRF_ESS }, // 26 Shared 68K Data
{ "wd1dat1.13p", 0x20000, 0x04b48ada, 0x09 | BRF_PRG | BRF_ESS }, // 27
{ "wd1voi1.bin", 0x40000, 0xf1ace193, 0x0a | BRF_SND }, // 28 C140 Samples Samples
{ "wd1voi2.bin", 0x20000, 0xe95c5cf3, 0x0a | BRF_SND }, // 29
{ "valkyrie.nv", 0x02000, 0xd5ce4069, 0x0b | BRF_PRG | BRF_ESS}, // 30 nvram
};
STD_ROM_PICK(valkyrienmv5)
STD_ROM_FN(valkyrienmv5)
struct BurnDriver BurnDrvValkyrienmv5 = {
"valkyrienmv5", "valkyrie", NULL, NULL, "2026",
"Valkyrie no Densetsu (Hack, English Translation from Namco Museum Vol. 5)\0", NULL, "hack (SpiralBrad)", "System 2",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK | BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED | BDF_HISCORE_SUPPORTED, 2, HARDWARE_MISC_PRE90S, GBF_SCRFIGHT, 0,
NULL, valkyrienmv5RomInfo, valkyrienmv5RomName, NULL, NULL, NULL, NULL, DefaultInputInfo, DefaultDIPInfo,
ValkyrieInit, Namcos2Exit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x4000,
224, 288, 3, 4
};
// Rolling Thunder 2
static struct BurnRomInfo rthun2RomDesc[] = {
+63 -9
View File
@@ -3635,6 +3635,24 @@ struct BurnDriver BurnDrvngpc_cavitm = {
160, 152, 4, 3
};
// Civilisation (HB)
static struct BurnRomInfo ngpc_civilisationRomDesc[] = {
{ "Civilisation (2026)(Chris Ahchay).ngp", 2097152, 0x9392c0d0, 1 | BRF_PRG | BRF_ESS }, // Cartridge
};
STDROMPICKEXT(ngpc_civilisation, ngpc_civilisation, ngpc_ngp)
STD_ROM_FN(ngpc_civilisation)
struct BurnDriver BurnDrvngpc_civilisation = {
"ngp_civilisation", NULL, "ngp_ngp", NULL, "2026",
"Civilisation (HB)\0", NULL, "Chris Ahchay", "NeoGeo Pocket Color",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SNK_NGPC, GBF_STRATEGY, 0,
NgpGetZipName, ngpc_civilisationRomInfo, ngpc_civilisationRomName, NULL, NULL, NULL, NULL, NgpInputInfo, NgpDIPInfo,
DrvInit, DrvExit, DrvFrame, k1geDraw, DrvScan, &BurnRecalc, 0x1000,
160, 152, 4, 3
};
// Columns (HB)
static struct BurnRomInfo ngpc_columnsRomDesc[] = {
{ "Columns (2007)(Thor).ngp", 196608, 0x7b628e3b, 1 | BRF_PRG | BRF_ESS }, // Cartridge
@@ -3815,9 +3833,9 @@ struct BurnDriver BurnDrvngpc_furry = {
160, 152, 4, 3
};
// Gardenia (HB, v1.4)
// Gardenia (HB, v1.5)
static struct BurnRomInfo ngpc_gardeniaRomDesc[] = {
{ "Gardenia v1.4 (2026)(Chris Ahchay).ngp", 2097152, 0x6bf8b0aa, 1 | BRF_PRG | BRF_ESS }, // Cartridge
{ "Gardenia v1.5 (2026)(Chris Ahchay).ngp", 2097152, 0x1e8081c2, 1 | BRF_PRG | BRF_ESS }, // Cartridge
};
STDROMPICKEXT(ngpc_gardenia, ngpc_gardenia, ngpc_ngp)
@@ -3825,7 +3843,7 @@ STD_ROM_FN(ngpc_gardenia)
struct BurnDriver BurnDrvngpc_gardenia = {
"ngp_gardenia", NULL, "ngp_ngp", NULL, "2026",
"Gardenia (HB, v1.4)\0", NULL, "Chris Ahchay", "NeoGeo Pocket Color",
"Gardenia (HB, v1.5)\0", NULL, "Chris Ahchay", "NeoGeo Pocket Color",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SNK_NGPC, GBF_VERSHOOT, 0,
NgpGetZipName, ngpc_gardeniaRomInfo, ngpc_gardeniaRomName, NULL, NULL, NULL, NULL, NgpInputInfo, NgpDIPInfo,
@@ -4175,9 +4193,9 @@ struct BurnDriver BurnDrvngpc_neurasm = {
160, 152, 4, 3
};
// Neo Bowling (HB, v0.9)
// Neo Bowling (HB, v1.0)
static struct BurnRomInfo ngpc_neobowlingRomDesc[] = {
{ "Neo Bowling v0.9 (2026)(Hardhat Warrior).ngp", 2097152, 0x90e9e1cb, 1 | BRF_PRG | BRF_ESS }, // Cartridge
{ "Neo Bowling v1.0 (2026)(Hardhat Warrior).ngp", 2097152, 0xc2eb225c, 1 | BRF_PRG | BRF_ESS }, // Cartridge
};
STDROMPICKEXT(ngpc_neobowling, ngpc_neobowling, ngpc_ngp)
@@ -4185,7 +4203,7 @@ STD_ROM_FN(ngpc_neobowling)
struct BurnDriver BurnDrvngpc_neobowling = {
"ngp_neobowling", NULL, "ngp_ngp", NULL, "2026",
"Neo Bowling (HB, v0.9)\0", NULL, "Hardhat Warrior", "NeoGeo Pocket Color",
"Neo Bowling (HB, v1.0)\0", NULL, "Hardhat Warrior", "NeoGeo Pocket Color",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 2, HARDWARE_SNK_NGPC, GBF_SPORTSMISC, 0,
NgpGetZipName, ngpc_neobowlingRomInfo, ngpc_neobowlingRomName, NULL, NULL, NULL, NULL, NgpInputInfo, NgpDIPInfo,
@@ -4247,9 +4265,9 @@ struct BurnDriver BurnDrvngpc_neotris = {
160, 152, 4, 3
};
// Over Rev (HB, v2.0)
// Over Rev (HB, v3.0)
static struct BurnRomInfo ngpc_overrevRomDesc[] = {
{ "Over Rev v2.0 (2026)(Tixul).ngp", 2097152, 0xbd6dcde5, 1 | BRF_PRG | BRF_ESS }, // Cartridge
{ "Over Rev v3.0 (2026)(Tixul).ngp", 2097152, 0x8539834d, 1 | BRF_PRG | BRF_ESS }, // Cartridge
};
STDROMPICKEXT(ngpc_overrev, ngpc_overrev, ngpc_ngp)
@@ -4257,7 +4275,7 @@ STD_ROM_FN(ngpc_overrev)
struct BurnDriver BurnDrvngpc_overrev = {
"ngp_overrev", NULL, "ngp_ngp", NULL, "2026",
"Over Rev (HB, v2.0)\0", NULL, "Tixul", "NeoGeo Pocket Color",
"Over Rev (HB, v3.0)\0", NULL, "Tixul", "NeoGeo Pocket Color",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 2, HARDWARE_SNK_NGPC, GBF_RACING, 0,
NgpGetZipName, ngpc_overrevRomInfo, ngpc_overrevRomName, NULL, NULL, NULL, NULL, NgpInputInfo, NgpDIPInfo,
@@ -4355,6 +4373,24 @@ struct BurnDriver BurnDrvngpc_robotron = {
160, 152, 4, 3
};
// Rogue Aces (HB)
static struct BurnRomInfo ngpc_rogueacesRomDesc[] = {
{ "Rogue Aces (2026)(Chris Ahchay).ngp", 2097152, 0x6ea9eb85, 1 | BRF_PRG | BRF_ESS }, // Cartridge
};
STDROMPICKEXT(ngpc_rogueaces, ngpc_rogueaces, ngpc_ngp)
STD_ROM_FN(ngpc_rogueaces)
struct BurnDriver BurnDrvngpc_rogueaces = {
"ngp_rogueaces", NULL, "ngp_ngp", NULL, "2026",
"Rogue Aces (HB)\0", NULL, "Chris Ahchay", "NeoGeo Pocket Color",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SNK_NGPC, GBF_MULTISHOOT, 0,
NgpGetZipName, ngpc_rogueacesRomInfo, ngpc_rogueacesRomName, NULL, NULL, NULL, NULL, NgpInputInfo, NgpDIPInfo,
DrvInit, DrvExit, DrvFrame, k1geDraw, DrvScan, &BurnRecalc, 0x1000,
160, 152, 4, 3
};
// Ruptus Mini (HB)
static struct BurnRomInfo ngpc_ruptusmRomDesc[] = {
{ "Ruptus Mini (2025)(Inufuto).ngp", 524288, 0x09f1b098, 1 | BRF_PRG | BRF_ESS }, // Cartridge
@@ -4391,6 +4427,24 @@ struct BurnDriver BurnDrvngpc_samegame = {
160, 152, 4, 3
};
// Shut the Box (HB, v0.1)
static struct BurnRomInfo ngpc_shutboxRomDesc[] = {
{ "Shut the Box v0.1 (2026)(Hardhat Warrior).ngp", 2097152, 0xe89d2a9c, 1 | BRF_PRG | BRF_ESS }, // Cartridge
};
STDROMPICKEXT(ngpc_shutbox, ngpc_shutbox, ngpc_ngp)
STD_ROM_FN(ngpc_shutbox)
struct BurnDriver BurnDrvngpc_shutbox = {
"ngp_shutbox", NULL, "ngp_ngp", NULL, "2026",
"Shut the Box (HB, v0.1)\0", NULL, "Hardhat Warrior", "NeoGeo Pocket Color",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 2, HARDWARE_SNK_NGPC, GBF_BOARD, 0,
NgpGetZipName, ngpc_shutboxRomInfo, ngpc_shutboxRomName, NULL, NULL, NULL, NULL, NgpInputInfo, NgpDIPInfo,
DrvInit, DrvExit, DrvFrame, k1geDraw, DrvScan, &BurnRecalc, 0x1000,
160, 152, 4, 3
};
// Snake (HB, v1.2)
static struct BurnRomInfo ngpc_snakeRomDesc[] = {
{ "Snake v1.2 (2000)(Ivan Mackintosh).ngp", 524288, 0x82510aa9, 1 | BRF_PRG | BRF_ESS }, // Cartridge
+261 -33
View File
@@ -3502,7 +3502,7 @@ struct BurnDriver BurnSpecbarbarn2 = {
// Barmy Burgers (48K)
static struct BurnRomInfo SpecBarmyburgRomDesc[] = {
{ "Barmy Burgers 48K (1983)(Blaby Computer Games).z80", 28248, 0x138faacd, BRF_ESS | BRF_PRG },
{ "Barmy Burgers 48K (1983)(Blaby Computer Games).tzx", 31126, 0x70455c9d, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecBarmyburg, SpecBarmyburg, Spectrum)
@@ -6121,6 +6121,25 @@ struct BurnDriver BurnSpecCasanova = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Casey Jones (48K)
static struct BurnRomInfo SpecCaseyjonesRomDesc[] = {
{ "Casey Jones 48K (1984)(Blaby Computer Games).tzx", 36421, 0xde4b4598, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecCaseyjones, SpecCaseyjones, Spectrum)
STD_ROM_FN(SpecCaseyjones)
struct BurnDriver BurnSpecCaseyjones = {
"spec_caseyjones", NULL, "spec_spectrum", NULL, "1984",
"Casey Jones (48K)\0", NULL, "Blaby Computer Games", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_SPECTRUM, GBF_ACTION | GBF_HORSHOOT, 0,
SpectrumGetZipName, SpecCaseyjonesRomInfo, SpecCaseyjonesRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Cashdash (48K)
static struct BurnRomInfo SpeccashdashRomDesc[] = {
@@ -19594,6 +19613,25 @@ struct BurnDriver BurnSpecMindtrap = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Mine Alert (48K)
static struct BurnRomInfo SpecMinealertRomDesc[] = {
{ "Mine Alert 48K (1987)(Ramon Gallastegui).tzx", 31444, 0x8d6e6afa, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecMinealert, SpecMinealert, Spectrum)
STD_ROM_FN(SpecMinealert)
struct BurnDriver BurnSpecMinealert = {
"spec_minealert", NULL, "spec_spectrum", NULL, "1987",
"Mine Alert (48K)\0", NULL, "Ramon Gallastegui", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_SPECTRUM, GBF_MAZE, 0,
SpectrumGetZipName, SpecMinealertRomInfo, SpecMinealertRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecQAOPSpaceDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Mined Out (48K)
static struct BurnRomInfo SpecMinedoutRomDesc[] = {
@@ -19911,7 +19949,7 @@ struct BurnDriver BurnSpecMoonpatrol = {
"spec_moonpatrol", NULL, "spec_spectrum", NULL, "1984",
"Moon Patrol (48K)\0", NULL, "Atarisoft", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 2, HARDWARE_SPECTRUM, GBF_ACTION, 0,
BDF_GAME_WORKING, 2, HARDWARE_SPECTRUM, GBF_ACTION | GBF_HORSHOOT, 0,
SpectrumGetZipName, SpecMoonpatrolRomInfo, SpecMoonpatrolRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
@@ -21380,6 +21418,25 @@ struct BurnDriver BurnSpecNubowls = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Nuke Lear (48K)
static struct BurnRomInfo SpecNukelearRomDesc[] = {
{ "Nuke Lear 48K (1984)(CCS).tzx", 30334, 0xf3e65284, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecNukelear, SpecNukelear, Spectrum)
STD_ROM_FN(SpecNukelear)
struct BurnDriver BurnSpecNukelear = {
"spec_nukelear", NULL, "spec_spectrum", NULL, "1984",
"Nuke Lear (48K)\0", NULL, "CCS", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_SPECTRUM, GBF_ACTION, 0,
SpectrumGetZipName, SpecNukelearRomInfo, SpecNukelearRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Number Painter (48K)
static struct BurnRomInfo SpecNumbpaintRomDesc[] = {
@@ -32248,6 +32305,44 @@ struct BurnDriver BurnSpecViz = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Vulcan ~ The Tunisian Campaign (128K)
static struct BurnRomInfo SpecVulcan128RomDesc[] = {
{ "Vulcan 128K (1986)(CCS).tzx", 53740, 0xc1299a09, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecVulcan128, SpecVulcan128, Spec128)
STD_ROM_FN(SpecVulcan128)
struct BurnDriver BurnSpecVulcan128 = {
"spec_vulcan128", NULL, "spec_spec128", NULL, "1986",
"Vulcan ~ The Tunisian Campaign (128K)\0", NULL, "CCS", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 2, HARDWARE_SPECTRUM, GBF_STRATEGY, 0,
SpectrumGetZipName, SpecVulcan128RomInfo, SpecVulcan128RomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecCursorKeysDIPInfo,
Spec128KInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Vulcan ~ The Tunisian Campaign (48K)
static struct BurnRomInfo SpecVulcan48RomDesc[] = {
{ "Vulcan 48K (1986)(CCS).tzx", 49796, 0x378fc601, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecVulcan48, SpecVulcan48, Spectrum)
STD_ROM_FN(SpecVulcan48)
struct BurnDriver BurnSpecVulcan48 = {
"spec_vulcan48", "spec_vulcan128", "spec_spectrum", NULL, "1986",
"Vulcan ~ The Tunisian Campaign (48K)\0", NULL, "CCS", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SPECTRUM, GBF_STRATEGY, 0,
SpectrumGetZipName, SpecVulcan48RomInfo, SpecVulcan48RomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecCursorKeysDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Wacky Darts (48K-128K)
static struct BurnRomInfo SpecWackydartsRomDesc[] = {
@@ -32516,19 +32611,19 @@ struct BurnDriver BurnSpecWhiteheat = {
// Who Dares Wins II (48K)
static struct BurnRomInfo SpecWhodareswinsiiRomDesc[] = {
{ "Who Dares Wins II 48K (1986)(Alligata).tap", 48631, 0x02dc6931, BRF_ESS | BRF_PRG },
static struct BurnRomInfo SpecWdwiiRomDesc[] = {
{ "Who Dares Wins II 48K (1986)(Alligata).tzx", 48692, 0xbf14f1aa, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecWhodareswinsii, SpecWhodareswinsii, Spectrum)
STD_ROM_FN(SpecWhodareswinsii)
STDROMPICKEXT(SpecWdwii, SpecWdwii, Spectrum)
STD_ROM_FN(SpecWdwii)
struct BurnDriver BurnSpecWhodareswinsii = {
"spec_whodareswinsii", NULL, "spec_spectrum", NULL, "1986",
struct BurnDriver BurnSpecWdwii = {
"spec_wdwii", NULL, "spec_spectrum", NULL, "1986",
"Who Dares Wins II (48K)\0", NULL, "Alligata Software", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_SPECTRUM, GBF_RUNGUN, 0,
SpectrumGetZipName, SpecWhodareswinsiiRomInfo, SpecWhodareswinsiiRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpectrumGetZipName, SpecWdwiiRomInfo, SpecWdwiiRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
@@ -52910,6 +53005,25 @@ struct BurnDriver BurnSpecModrains = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Mine Alert 2 (128K) (HB)
static struct BurnRomInfo SpecMinealert2RomDesc[] = {
{ "Mine Alert 2 128K (2026)(namco-nexgen).tap", 85093, 0x2eca386a, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecMinealert2, SpecMinealert2, Spec128)
STD_ROM_FN(SpecMinealert2)
struct BurnDriver BurnSpecMinealert2 = {
"spec_minealert2", NULL, "spec_spec128", NULL, "2026",
"Mine Alert 2 (128K) (HB)\0", NULL, "namco/nexgen", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_MAZE | GBF_MULTISHOOT, 0,
SpectrumGetZipName, SpecMinealert2RomInfo, SpecMinealert2RomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
Spec128KInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Minesweeper (128K) (HB, v1.03)
static struct BurnRomInfo SpecMinesweeper128RomDesc[] = {
@@ -53481,10 +53595,10 @@ struct BurnDriver BurnSpecMoonpirates = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Moon Ranger (128K) (HB)
// Moon Ranger (48K-128K) (HB)
static struct BurnRomInfo SpecMoonrangerRomDesc[] = {
{ "Moon Ranger 128K (2020)(Gabriele Amore).tap", 29940, 0xd33c199a, BRF_ESS | BRF_PRG },
{ "Moon Ranger 48K-128K (2020)(Gabriele Amore).tap", 29940, 0xd33c199a, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecMoonranger, SpecMoonranger, Spec128)
@@ -53492,18 +53606,18 @@ STD_ROM_FN(SpecMoonranger)
struct BurnDriver BurnSpecMoonranger = {
"spec_moonranger", NULL, "spec_spec128", NULL, "2020",
"Moon Ranger (128K) (HB)\0", NULL, "Gabriele Amore", "ZX Spectrum",
"Moon Ranger (48K-128K) (HB)\0", NULL, "Gabriele Amore", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_ACTION, 0,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_ACTION | GBF_HORSHOOT, 0,
SpectrumGetZipName, SpecMoonrangerRomInfo, SpecMoonrangerRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecQAOPMDIPInfo,
Spec128KInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Moon Ranger (128K) (HB, v2)
// Moon Ranger (48K-128K) (HB, v2)
static struct BurnRomInfo SpecMoonrangerv2RomDesc[] = {
{ "Moon Ranger v2 128K (2021)(Gabriele Amore).tap", 45527, 0xebb5c2a1, BRF_ESS | BRF_PRG },
{ "Moon Ranger v2 48K-128K (2021)(Gabriele Amore).tap", 45527, 0xebb5c2a1, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecMoonrangerv2, SpecMoonrangerv2, Spec128)
@@ -53511,9 +53625,9 @@ STD_ROM_FN(SpecMoonrangerv2)
struct BurnDriver BurnSpecMoonrangerv2 = {
"spec_moonrangerv2", NULL, "spec_spec128", NULL, "2021",
"Moon Ranger (128K) (HB, v2)\0", NULL, "Gabriele Amore", "ZX Spectrum",
"Moon Ranger (48K-128K) (HB, v2)\0", NULL, "Gabriele Amore", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_ACTION, 0,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_ACTION | GBF_HORSHOOT, 0,
SpectrumGetZipName, SpecMoonrangerv2RomInfo, SpecMoonrangerv2RomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecQAOPMDIPInfo,
Spec128KInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
@@ -55571,6 +55685,25 @@ struct BurnDriver BurnSpecOure = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Outpost (48K) (HB)
static struct BurnRomInfo SpecOutpostRomDesc[] = {
{ "Outpost 48K (2026)(usebox.net).tap", 22114, 0x2ac59251, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecOutpost, SpecOutpost, Spectrum)
STD_ROM_FN(SpecOutpost)
struct BurnDriver BurnSpecOutpost = {
"spec_outpost", NULL, "spec_spectrum", NULL, "2026",
"Outpost (48K) (HB)\0", NULL, "usebox.net", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_PLATFORM, 0,
SpectrumGetZipName, SpecOutpostRomInfo, SpecOutpostRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// P-47 The Freedom Fighter (128K) (Hack)
static struct BurnRomInfo SpecP47freedomfRomDesc[] = {
@@ -58801,10 +58934,10 @@ struct BurnDriver BurnSpecRiverrad = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// River Raid+ (48K) (Hack, v0.2)
// River Raid+ (48K) (Hack, v0.7)
static struct BurnRomInfo SpecRiveraidplusRomDesc[] = {
{ "River Raid+ v0.2 48K (2026)(theALFEST).tap", 22554, 0x2e917c63, BRF_ESS | BRF_PRG },
{ "River Raid+ v0.7 48K-AY (2026)(theALFEST).tap", 26652, 0x53f67db2, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecRiveraidplus, SpecRiveraidplus, Spectrum)
@@ -58812,7 +58945,7 @@ STD_ROM_FN(SpecRiveraidplus)
struct BurnDriver BurnSpecRiveraidplus = {
"spec_riveraidplus", "spec_riveraid", "spec_spectrum", NULL, "2026",
"River Raid+ (48K) (Hack, v0.2)\0", NULL, "theALFEST", "ZX Spectrum",
"River Raid+ (48K) (Hack, v0.7)\0", "AY Sound supported", "theALFEST", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 1, HARDWARE_SPECTRUM, GBF_VERSHOOT, 0,
SpectrumGetZipName, SpecRiveraidplusRomInfo, SpecRiveraidplusRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
@@ -60568,10 +60701,10 @@ struct BurnDriver BurnSpecShadowfields = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Shadows of Belial (English) (128K) (HB, v1.0.4)
// Shadows of Belial (English) (128K) (HB, v1.0.5)
static struct BurnRomInfo SpecShabelialenRomDesc[] = {
{ "Shadows of Belial EN v1.0.4 128K (2016)(RetroWorks).tap", 138736, 0xcaf1f445, BRF_ESS | BRF_PRG },
{ "Shadows of Belial EN v1.0.5 128K (2026)(RetroWorks).tap", 138687, 0x4ac79734, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecShabelialen, SpecShabelialen, Spec128)
@@ -60579,7 +60712,7 @@ STD_ROM_FN(SpecShabelialen)
struct BurnDriver BurnSpecShabelialen = {
"spec_shabelialen", NULL, "spec_spec128", NULL, "RetroWorks",
"Shadows of Belial (English) (128K) (HB, v1.0.4)\0", NULL, "2026", "ZX Spectrum",
"Shadows of Belial (English) (128K) (HB, v1.0.5)\0", NULL, "2026", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_PLATFORM, 0,
SpectrumGetZipName, SpecShabelialenRomInfo, SpecShabelialenRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
@@ -60587,10 +60720,10 @@ struct BurnDriver BurnSpecShabelialen = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Shadows of Belial (Spanish) (128K) (HB, v1.0.4)
// Shadows of Belial (Spanish) (128K) (HB, v1.0.5)
static struct BurnRomInfo SpecShabelialesRomDesc[] = {
{ "Shadows of Belial ES v1.0.4 128K (2026)(RetroWorks).tap", 139295, 0x07167c28, BRF_ESS | BRF_PRG },
{ "Shadows of Belial ES v1.0.5 128K (2026)(RetroWorks).tap", 139297, 0x2faa2142, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecShabeliales, SpecShabeliales, Spec128)
@@ -60598,7 +60731,7 @@ STD_ROM_FN(SpecShabeliales)
struct BurnDriver BurnSpecShabeliales = {
"spec_shabeliales", "spec_shabelialen", "spec_spec128", NULL, "RetroWorks",
"Shadows of Belial (Spanish) (128K) (HB, v1.0.4)\0", NULL, "2026", "ZX Spectrum",
"Shadows of Belial (Spanish) (128K) (HB, v1.0.5)\0", NULL, "2026", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_PLATFORM, 0,
SpectrumGetZipName, SpecShabelialesRomInfo, SpecShabelialesRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
@@ -60606,6 +60739,44 @@ struct BurnDriver BurnSpecShabeliales = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Shadows of Belial (Portuguese) (128K) (HB, v1.0.5)
static struct BurnRomInfo SpecShabelialptRomDesc[] = {
{ "Shadows of Belial PT v1.0.5 128K (2026)(RetroWorks).tap", 139372, 0xb20c499b, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecShabelialpt, SpecShabelialpt, Spec128)
STD_ROM_FN(SpecShabelialpt)
struct BurnDriver BurnSpecShabelialpt = {
"spec_shabelialpt", "spec_shabelialen", "spec_spec128", NULL, "RetroWorks",
"Shadows of Belial (Portuguese) (128K) (HB, v1.0.5)\0", NULL, "2026", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_PLATFORM, 0,
SpectrumGetZipName, SpecShabelialptRomInfo, SpecShabelialptRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
Spec128KInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Shadows of Belial (Russian) (128K) (HB, v1.0.5)
static struct BurnRomInfo SpecShabelialruRomDesc[] = {
{ "Shadows of Belial RU v1.0.5 128K (2026)(RetroWorks).tap", 139086, 0x719f3964, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecShabelialru, SpecShabelialru, Spec128)
STD_ROM_FN(SpecShabelialru)
struct BurnDriver BurnSpecShabelialru = {
"spec_shabelialru", "spec_shabelialen", "spec_spec128", NULL, "RetroWorks",
"Shadows of Belial (Russian) (128K) (HB, v1.0.5)\0", NULL, "2026", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_PLATFORM, 0,
SpectrumGetZipName, SpecShabelialruRomInfo, SpecShabelialruRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
Spec128KInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Shape Shifter (48K) (HB)
static struct BurnRomInfo SpecShapeshiftRomDesc[] = {
@@ -66382,6 +66553,25 @@ struct BurnDriver BurnSpecWhitejaguarzx = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Who Dares Wins III (128K) (HB, v1.1)
static struct BurnRomInfo SpecWdwiiiRomDesc[] = {
{ "Who Dares Wins III v1.1 128K (2026)(namco-nexgen).tap", 73967, 0xb8f9cc8b, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecWdwiii, SpecWdwiii, Spec128)
STD_ROM_FN(SpecWdwiii)
struct BurnDriver BurnSpecWdwiii = {
"spec_wdwiii", NULL, "spec_spec128", NULL, "2026",
"Who Dares Wins III (128K) (HB, v1.1)\0", NULL, "namco/nexgen", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_RUNGUN, 0,
SpectrumGetZipName, SpecWdwiiiRomInfo, SpecWdwiiiRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
Spec128KInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Wiking - Improved Version (Polish) (128K) (Hack)
static struct BurnRomInfo SpecWiking128RomDesc[] = {
@@ -66858,6 +67048,25 @@ struct BurnDriver BurnSpecXenomaze = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// XPong48 (48K) (HB)
static struct BurnRomInfo SpecXpong48RomDesc[] = {
{ "XPong48 48K-AY (2026)(CodeBiters).tap", 32548, 0xc563401a, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecXpong48, SpecXpong48, Spectrum)
STD_ROM_FN(SpecXpong48)
struct BurnDriver BurnSpecXpong48 = {
"spec_xpong48", NULL, "spec_spectrum", NULL, "2026",
"XPong48 (48K) (HB)\0", "AY Sound supported", "CodeBiters", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 2, HARDWARE_SPECTRUM, GBF_BALLPADDLE, 0,
SpectrumGetZipName, SpecXpong48RomInfo, SpecXpong48RomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// X=Y=Z (48K) (HB)
static struct BurnRomInfo SpecXyzRomDesc[] = {
@@ -67428,21 +67637,40 @@ struct BurnDriver BurnSpecZlalox = {
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Zoinho (Spanish) (48K) (HB)
// Zoinho: No Jardim dos Tolos (Spanish) (48K) (HB)
static struct BurnRomInfo SpecZoinhoRomDesc[] = {
{ "Zoinho 48K (2021)(Bitnamic).tap", 29137, 0xa64d5e5a, BRF_ESS | BRF_PRG },
{ "Zoinho - No Jardim dos Tolos 48K (2021)(Bitnamic).tap", 29137, 0xa64d5e5a, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecZoinho, SpecZoinho, Spectrum)
STD_ROM_FN(SpecZoinho)
struct BurnDriver BurnSpecZoinho = {
"spec_zoinho", NULL, "spec_spectrum", NULL, "2021",
"Zoinho (Spanish) (48K) (HB)\0", NULL, "Bitnamic", "ZX Spectrum",
"spec_zoinho", "spec_zoinho25", "spec_spectrum", NULL, "2021",
"Zoinho: No Jardim dos Tolos (Spanish) (48K) (HB)\0", NULL, "Bitnamic", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_ACTION | GBF_ADV, 0,
SpectrumGetZipName, SpecZoinhoRomInfo, SpecZoinhoRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecIntf2DIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
// Zoinho: In the Garden of the Fools (English) (48K) (HB)
static struct BurnRomInfo SpecZoinho25RomDesc[] = {
{ "Zoinho - In the Garden of the Fools 48K (2025)(R.C. Nunes).tap", 42058, 0x7ec6faaa, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(SpecZoinho25, SpecZoinho25, Spectrum)
STD_ROM_FN(SpecZoinho25)
struct BurnDriver BurnSpecZoinho25 = {
"spec_zoinho25", NULL, "spec_spectrum", NULL, "2025",
"Zoinho: In the Garden of the Fools (English) (48K) (HB)\0", "Set 'Cursor Keys' to use controller", "R.C. Nunes", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_ACTION | GBF_ADV, 0,
SpectrumGetZipName, SpecZoinhoRomInfo, SpecZoinhoRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecIntf2DIPInfo,
SpectrumGetZipName, SpecZoinho25RomInfo, SpecZoinho25RomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecCursorKeysDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
};
@@ -67450,7 +67678,7 @@ struct BurnDriver BurnSpecZoinho = {
// Zombie Calavera Prologue (48K) (HB)
static struct BurnRomInfo SpeczcalaveraRomDesc[] = {
{ "Zombie Calavera Prologue 48K (2010)(Mojon Twins).tap", 37966, 0x9eaf2b79, BRF_ESS | BRF_PRG },
{ "Zombie Calavera Prologue 48K (2010)(The Mojon Twins).tzx", 38000, 0xbb2c916b, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(Speczcalavera, Speczcalavera, Spectrum)
@@ -67460,7 +67688,7 @@ struct BurnDriver BurnSpeczcalavera = {
"spec_zcalavera", NULL, "spec_spectrum", NULL, "2010",
"Zombie Calavera Prologue (48K) (HB)\0", NULL, "The Mojon Twins", "ZX Spectrum",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_RUNGUN | GBF_PLATFORM, 0,
BDF_GAME_WORKING | BDF_HOMEBREW, 1, HARDWARE_SPECTRUM, GBF_PLATFORM | GBF_RUNGUN, 0,
SpectrumGetZipName, SpeczcalaveraRomInfo, SpeczcalaveraRomName, NULL, NULL, NULL, NULL, SpecInputInfo, SpecDIPInfo,
SpecInit, SpecExit, SpecFrame, SpecDraw, SpecScan,
&SpecRecalc, 0x10, 288, 224, 4, 3
+31
View File
@@ -466,9 +466,40 @@ void MultiPCMExit()
}
}
// The slot pointers (sample, LFO tables) are only valid in the process that set
// them, a state loaded in another one (netplay) would crash. They are kept out of
// the state and rebuilt from the slot registers, as WriteSlot sets them: reg 1
// selects the sample, regs 6 and 7 the LFO scales (an LFO is only stepped when
// its depth, reg & 7, is not zero).
static void ClearSlotPointers()
{
for (INT32 i = 0; i < 28; i++) {
SLOT *slot = &chip.Slots[i];
slot->Sample = NULL;
slot->PLFO.table = slot->PLFO.scale = NULL;
slot->ALFO.table = slot->ALFO.scale = NULL;
}
}
static void RebuildSlotPointers()
{
for (INT32 i = 0; i < 28; i++) {
SLOT *slot = &chip.Slots[i];
slot->Sample = chip.Samples + slot->Regs[1];
slot->PLFO.table = PLFO_TRI;
slot->PLFO.scale = PSCALES[slot->Regs[6] & 7];
slot->ALFO.table = ALFO_TRI;
slot->ALFO.scale = ASCALES[slot->Regs[7] & 7];
}
}
void MultiPCMScan(INT32 nAction, INT32 *pnMin)
{
ClearSlotPointers();
SCAN_VAR(chip);
RebuildSlotPointers();
}
void MultiPCMReset()
+2
View File
@@ -45,6 +45,8 @@ typedef struct tagIMAGE {
#include "burner_macos.h"
#elif defined (BUILD_SDL) || defined (BUILD_SDL2)
#include "burner_sdl.h"
#elif defined (BUILD_HEADLESS)
#include "burner_headless.h"
#elif defined (_XBOX) && !defined(__LIBRETRO__)
#include "burner_xbox.h"
#elif defined(__LIBRETRO__)
+140
View File
@@ -0,0 +1,140 @@
// Platform burner header for the headless FinalBurn Neo frontend.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// Declares the types, globals and frontend prototypes the shared burner code
// expects (the headless counterpart of burner_sdl.h / burner_macos.h), without
// any SDL or GUI dependencies. Subject to the FB Neo license (see src/license.txt).
#ifndef BURNER_HEADLESS_PLATFORM_H
#define BURNER_HEADLESS_PLATFORM_H
// Win32 type aliases the shared code relies on.
#ifndef _WIN32
typedef struct tagRECT
{
int left;
int top;
int right;
int bottom;
} RECT, * PRECT, * LPRECT;
typedef const RECT* LPCRECT;
typedef UINT32 DWORD;
typedef UINT8 BYTE;
#else
#include <windows.h>
#endif
#ifndef MAX_PATH
#define MAX_PATH 511
#endif
#ifndef __cdecl
#define __cdecl
#endif
// misc.cpp
int SetBurnHighCol(int nDepth);
extern int nAppVirtualFps;
extern bool bRunPause;
extern bool bAppDoFast;
extern char fpsstring[20];
extern bool bAppShowFPS;
extern bool bAlwaysProcessKeyboardInput;
extern TCHAR szAppBurnVer[16];
extern bool bAppFullscreen;
extern bool bIntegerScale;
extern int nWindowScale;
extern bool bAlwaysMenu;
extern int nGameSelect;
extern int nFilterSelect;
extern bool bShowAvailableOnly;
extern bool bShowClones;
extern int gameSelectedFromFilter;
extern TCHAR* GetIsoPath();
TCHAR* ANSIToTCHAR(const char* pszInString, TCHAR* pszOutString, int nOutSize);
char* TCHARToANSI(const TCHAR* pszInString, char* pszOutString, int nOutSize);
#define _TtoA(a) TCHARToANSI(a, NULL, 0)
#define _AtoT(a) ANSIToTCHAR(a, NULL, 0)
bool AppProcessKeyboardInput();
// config
int ConfigAppLoad();
int ConfigAppSave();
// drv.cpp (headless)
extern int bDrvOkay;
extern char szAppRomPaths[DIRS_MAX][MAX_PATH];
int DrvInit(int nDrvNum, bool bRestore);
int DrvInitCallback();
int DrvExit();
int ProgressUpdateBurner(double dProgress, const TCHAR* pszText, bool bAbs);
int AppError(TCHAR* szText, int bWarning);
// run
extern int RunMessageLoop();
extern int RunReset();
#define MESSAGE_MAX_FRAMES 180
#define MESSAGE_MAX_LENGTH 255
extern UINT32 messageFrames;
extern char lastMessage[MESSAGE_MAX_LENGTH];
void UpdateMessage(char* message);
int StatedAuto(int bSave);
// media.cpp
int MediaInit();
int MediaExit();
// inpdipsw.cpp
#define DIP_MAX_NAME 64
#define MAXDIPSWITCHES 32
#define MAXDIPOPTIONS 32
bool setDIPSwitchOption(int dipgroup, int dipoption);
int InpDIPSWCreate();
void InpDIPSWResetDIPs();
struct GroupOfDIPSwitches
{
BurnDIPInfo dipSwitch;
UINT16 DefaultDIPOption;
UINT16 SelectedDIPOption;
char OptionsNamesWithCheckBoxes[MAXDIPOPTIONS][DIP_MAX_NAME];
BurnDIPInfo dipSwitchesOptions[MAXDIPOPTIONS];
};
// inp_interface.cpp
int InputInit();
int InputExit();
int InputMake(bool bCopy);
// stated.cpp
int QuickState(int bSave);
extern int bDrvSaveAll;
// stringset.cpp
class StringSet {
public:
TCHAR* szText;
int nLen;
int __cdecl Add(TCHAR* szFormat, ...);
int Reset();
StringSet();
~StringSet();
};
// support_paths.cpp
extern TCHAR szAppListsPath[MAX_PATH];
extern TCHAR szAppDatListsPath[MAX_PATH];
extern TCHAR szAppArchivesPath[MAX_PATH];
#endif // BURNER_HEADLESS_PLATFORM_H
+101
View File
@@ -0,0 +1,101 @@
// Headless C API for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// Consumed by a thin host wrapper so the emulator-side glue stays in the fork.
// Subject to the FB Neo license (see src/license.txt).
#ifndef BURNER_HEADLESS_H
#define BURNER_HEADLESS_H
#ifdef __cplusplus
extern "C" {
#endif
// Lifecycle
int FBHeadlessInit(void);
void FBHeadlessExit(void);
void FBHeadlessSetRomPath(const char *path);
int FBHeadlessLoadDriver(const char *shortName); // e.g. "mslug"; returns 0 on success
void FBHeadlessRunFrame(int draw);
// Video (filled by intf/video/headless)
const unsigned char *FBHeadlessGetVideoBuffer(void);
int FBHeadlessGetVideoWidth(void);
int FBHeadlessGetVideoHeight(void);
int FBHeadlessGetVideoPitch(void);
int FBHeadlessGetVideoBPP(void);
// Audio (filled each frame by the frontend)
int FBHeadlessGetAudioSampleRate(void);
const short *FBHeadlessGetAudioBuffer(void);
int FBHeadlessGetAudioFrames(void); // stereo sample frames produced last RunFrame
// Input: value is non-zero when pressed. code is an FBNeo input switch code.
void FBHeadlessSetInputState(int code, int value);
// Frame timing / geometry (valid after a driver is loaded).
int FBHeadlessGetFrameRate(void); // frames per second * 100 (e.g. 6000 = 60fps)
int FBHeadlessGetAspectX(void);
int FBHeadlessGetAspectY(void);
// Reset the loaded driver.
void FBHeadlessReset(void);
// Save/load a full machine state to/from a file. Returns 0 on success.
int FBHeadlessSaveState(const char *path);
int FBHeadlessLoadState(const char *path);
// Memory access for cheats, cheat search, and achievements. Addresses are in the
// main CPU (cpu 0) hardware address space. size is 1..4 bytes; littleEndian
// controls byte order for multi-byte values. A value found via a memory-range
// snapshot can be written back at the same address with FBHeadlessWriteMemory.
unsigned int FBHeadlessGetMainMemorySize(void); // 0 until a driver is loaded
unsigned int FBHeadlessReadMemoryRange(unsigned int address, unsigned char *out, unsigned int length); // returns bytes read
unsigned int FBHeadlessReadMemory(unsigned int address, int size, int littleEndian);
int FBHeadlessWriteMemory(unsigned int address, unsigned int value, int size, int littleEndian); // 1 on success
int FBHeadlessIsAddressValid(unsigned int address);
// Achievements memory. RetroAchievements sets are authored against FBNeo's flat
// main-RAM exposure (per driver hardware type), not the CPU address space.
// FBHeadlessCheevosInit rebuilds the map (call after load/reset); the read is
// gated to the mapped regions. Returns bytes read (stops at the first unmapped byte).
void FBHeadlessCheevosInit(void);
unsigned int FBHeadlessReadAchievementMemory(unsigned int address, unsigned char *out, unsigned int length);
// Cheats: write into the achievement memory map (same flat RAM the search reads), and
// enumerate the mapped regions so the host can present cheat search. bigEndian follows
// the libretro/RetroAchievements convention the host matches: 0 (little-endian) for every
// board, including the 68K ones. See GetMainMemoryBigEndian.
int FBHeadlessWriteAchievementMemory(unsigned int address, unsigned int value, int size, int littleEndian);
int FBHeadlessGetMemoryRegionCount(void);
int FBHeadlessGetMemoryRegion(int index, unsigned int *start, unsigned int *length, int *bigEndian);
// High-level input. player is 0-based; button is an FBHeadlessButton value. The
// fork maps it to the active driver's inputs (parsed from its input names).
typedef enum {
FBHeadlessButtonUp = 0,
FBHeadlessButtonDown,
FBHeadlessButtonLeft,
FBHeadlessButtonRight,
FBHeadlessButton1,
FBHeadlessButton2,
FBHeadlessButton3,
FBHeadlessButton4,
FBHeadlessButton5,
FBHeadlessButton6,
FBHeadlessButtonStart,
FBHeadlessButtonCoin,
FBHeadlessButtonService, // test switch (settings menu); "service" when there is none
FBHeadlessButtonConfigure, // "service" input of drivers that also have a test switch
FBHeadlessButtonCount
} FBHeadlessButton;
void FBHeadlessSetInput(int player, int button, int value);
#ifdef __cplusplus
}
#endif
#endif // BURNER_HEADLESS_H
+134
View File
@@ -0,0 +1,134 @@
// Headless driver glue for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// The headless counterpart of the SDL burner's drv.cpp: wraps BurnDrvInit in the
// zip loader and provides the frontend callbacks the shared burner code calls.
// CD systems (NeoGeo CD / PCE CD) are not wired yet. Subject to the FB Neo
// license (see src/license.txt).
#include "burner.h"
int bDrvOkay = 0;
char szAppRomPaths[DIRS_MAX][MAX_PATH] = { { "roms/" }, };
static bool bSaveRAM = false;
// Battery-backed RAM (ACB_NVRAM: Mortal Kombat's settings, Robotron's high
// scores...) is not saved by the driver, unlike the EEPROM device. Like the
// Windows burner's StatedAuto, keep it in <szAppEEPROMPath><set>.fs: loaded
// after init and saved before exit. Drivers without NVRAM write no file.
static void DrvNvramAuto(int bSave)
{
TCHAR szName[MAX_PATH];
_stprintf(szName, _T("%s%s.fs"), szAppEEPROMPath, BurnDrvGetText(DRV_NAME));
if (bSave)
BurnStateSave(szName, 0);
else
BurnStateLoad(szName, 0, NULL);
}
static int DoLibInit() // Init the Burn library's driver
{
BzipOpen(false);
int nRet = BurnDrvInit();
BzipClose();
return nRet ? 1 : 0;
}
// Catch BurnLoadRom() calls once emulation has started: open the zip module,
// forward, then exit cleanly.
static int DrvLoadRom(unsigned char* Dest, int* pnWrote, int i)
{
BzipOpen(false);
int nRet = BurnExtLoadRom(Dest, pnWrote, i);
BzipClose();
BurnExtLoadRom = DrvLoadRom;
return nRet;
}
int DrvInit(int nDrvNum, bool bRestore)
{
DrvExit(); // Make sure exited
MediaExit();
nBurnDrvActive = nDrvNum;
{ // Init input and audio; defer blitter init.
bVidOkay = 1;
bAudOkay = 1;
MediaInit();
bVidOkay = 0;
bAudOkay = 0;
}
nMaxPlayers = BurnDrvGetMaxPlayers();
GameInpInit();
bSaveInputs = ConfigGameLoad(true);
if (bSaveInputs) ConfigGameLoadHardwareDefaults();
InputMake(true);
GameInpDefault();
if (DoLibInit()) {
BurnDrvExit();
return 1;
}
BurnExtLoadRom = DrvLoadRom;
bDrvOkay = 1;
bSaveRAM = false;
nBurnLayer = 0xFF;
ConfigCheatLoad();
RunReset();
if (bRestore) {
DrvNvramAuto(0);
bSaveRAM = true;
}
return 0;
}
int DrvInitCallback()
{
return DrvInit(nBurnDrvActive, false);
}
int DrvExit()
{
if (bDrvOkay) {
if (nBurnDrvActive < nBurnDrvCount) {
if (bSaveRAM) {
DrvNvramAuto(1);
bSaveRAM = false;
}
ConfigGameSave(bSaveInputs);
GameInpExit();
BurnDrvExit();
}
}
BurnExtLoadRom = NULL;
bDrvOkay = 0;
return 0;
}
int ProgressUpdateBurner(double /* dProgress */, const TCHAR* /* pszText */, bool /* bAbs */)
{
return 0;
}
int AppError(TCHAR* /* szText */, int /* bWarning */)
{
return 0;
}
// The host drives frame timing, so there is no throttle to reset.
int RunReset()
{
return 0;
}
+209
View File
@@ -0,0 +1,209 @@
// Headless input mapping for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// Maps a (player, FBHeadlessButton) pair to the active driver's GameInp. FBNeo
// exposes each input's canonical lowercase name via szInfo ("p1 up",
// "p1 fire 1", "p1 coin", "p1 start"); each matched digital input is rebound to
// a private switch code the headless input plugin reads from its state table.
// Subject to the FB Neo license (see src/license.txt).
#include "burner.h"
#include "fbheadless.h"
// Private switch-code space, chosen to avoid the driver's default key/joy codes.
// code = HL_CODE_BASE + player*16 + button; unmatched digital inputs get a dead
// code that is never set so they read as released.
#define HL_CODE_BASE 0x100
#define HL_CODE_DEAD 0x1FF
static int hl_code(int player, int button)
{
return HL_CODE_BASE + player * 16 + button;
}
// Parse an FBNeo szInfo name into (player, FBHeadlessButton). Returns 1 on match.
static int hl_classify(const char *szInfo, int *outPlayer, int *outButton)
{
if (szInfo == NULL)
return 0;
// "pN <control>" form (the common case).
if ((szInfo[0] == 'p' || szInfo[0] == 'P') &&
szInfo[1] >= '1' && szInfo[1] <= '4' && szInfo[2] == ' ') {
int player = szInfo[1] - '1';
const char *r = szInfo + 3;
int b = -1;
if (!strcmp(r, "up")) b = FBHeadlessButtonUp;
else if (!strcmp(r, "down")) b = FBHeadlessButtonDown;
else if (!strcmp(r, "left")) b = FBHeadlessButtonLeft;
else if (!strcmp(r, "right")) b = FBHeadlessButtonRight;
else if (!strcmp(r, "start")) b = FBHeadlessButtonStart;
else if (!strcmp(r, "coin")) b = FBHeadlessButtonCoin;
else if (!strcmp(r, "service")) b = FBHeadlessButtonService;
else if (!strcmp(r, "diagnostic")) b = FBHeadlessButtonService;
else if (!strncmp(r, "fire ", 5) && r[5] >= '1' && r[5] <= '6')
b = FBHeadlessButton1 + (r[5] - '1');
else if (!strncmp(r, "button ", 7) && r[7] >= '1' && r[7] <= '6')
b = FBHeadlessButton1 + (r[7] - '1');
if (b >= 0) {
*outPlayer = player;
*outButton = b;
return 1;
}
return 0;
}
// System "coin N" / "start N" form.
if (!strncmp(szInfo, "coin ", 5) && szInfo[5] >= '1' && szInfo[5] <= '4') {
*outPlayer = szInfo[5] - '1';
*outButton = FBHeadlessButtonCoin;
return 1;
}
if (!strncmp(szInfo, "start ", 6) && szInfo[6] >= '1' && szInfo[6] <= '4') {
*outPlayer = szInfo[6] - '1';
*outButton = FBHeadlessButtonStart;
return 1;
}
return 0;
}
// Cabinet-wide test switch ("diag" in most drivers), which opens the game's
// settings menu.
static int hl_is_test_switch(const char *szInfo)
{
return szInfo != NULL &&
(!strcmp(szInfo, "diag") || !strcmp(szInfo, "diagnostic") ||
!strcmp(szInfo, "diagnostics") || !strcmp(szInfo, "test"));
}
// Cabinet-wide "service" input. Drivers with a separate test switch use it as a
// service credit; older drivers without one use it as the test switch itself.
static int hl_is_service_switch(const char *szInfo)
{
return szInfo != NULL && !strcmp(szInfo, "service");
}
// Index of a direction word at the start of s (0 left, 1 up, 2 down, 3 right),
// or -1. *len receives its length.
static int hl_direction(const char *s, size_t *len)
{
static const char *const dirs[] = { "left", "up", "down", "right" };
for (int d = 0; d < 4; d++) {
size_t n = strlen(dirs[d]);
if (!strncasecmp(s, dirs[d], n)) {
*len = n;
return d;
}
}
return -1;
}
// Twin-stick games (Robotron, Smash TV, Angel Kids, Ikari Warriors...), mapped
// the way the MAME core does: the left stick on the player's d-pad, the right
// stick on buttons 1-4 (left, up, down, right), since OpenEmu's arcade
// controller has one stick. Drivers name the sticks inconsistently: the second
// stick may be "pN <dir> 2", or either stick may borrow another player's plain
// d-pad ("p2 up" for Robotron's "Fire Up", "p3 up" for Angel Kids' "P1 Left
// Stick Up"). The display name, when it names a stick, decides the stick and
// the player; otherwise "pN <dir> 2" is player N's right stick.
static int hl_twin_stick(const char *szName, const char *szInfo, int *outPlayer, int *outButton)
{
if (szName == NULL || szInfo == NULL)
return 0;
if (szInfo[0] != 'p' || szInfo[1] < '1' || szInfo[1] > '4' || szInfo[2] != ' ')
return 0;
size_t len = 0;
int dir = hl_direction(szInfo + 3, &len);
if (dir < 0)
return 0;
const char *rest = szInfo + 3 + len;
int secondStick = !strcmp(rest, " 2");
if (!secondStick && *rest != '\0')
return 0;
static const struct { const char *prefix; int right; } sticks[] = {
{ "Left Stick ", 0 }, { "Lft Stick ", 0 }, { "L Stick ", 0 }, { "Left ", 0 },
{ "Right Stick ", 1 }, { "Rght Stick ", 1 }, { "ight Stick ", 1 }, { "R Stick ", 1 },
{ "Right ", 1 }, { "Fire ", 1 }, { "Shoot ", 1 }, { "Aim ", 1 },
};
static const int dpad[] = { FBHeadlessButtonLeft, FBHeadlessButtonUp, FBHeadlessButtonDown, FBHeadlessButtonRight };
const char *n = szName;
int player = 0;
if ((n[0] == 'P' || n[0] == 'p') && n[1] >= '1' && n[1] <= '4' && n[2] == ' ') {
player = n[1] - '1';
n += 3;
}
for (size_t s = 0; s < sizeof(sticks) / sizeof(sticks[0]); s++) {
size_t sl = strlen(sticks[s].prefix);
size_t nameDirLen = 0;
if (strncasecmp(n, sticks[s].prefix, sl) != 0)
continue;
if (hl_direction(n + sl, &nameDirLen) != dir || n[sl + nameDirLen] != '\0')
break;
*outPlayer = player;
*outButton = sticks[s].right ? FBHeadlessButton1 + dir : dpad[dir];
return 1;
}
if (secondStick) {
*outPlayer = szInfo[1] - '1';
*outButton = FBHeadlessButton1 + dir;
return 1;
}
return 0;
}
// Rebind every digital input of the loaded driver to the headless code space.
// Called after DrvInit (which runs GameInpInit/GameInpDefault).
void headless_map_inputs(void)
{
struct BurnInputInfo bii;
// Service always opens the settings menu: it drives the test switch when the
// driver has one (and Configure drives "service"), otherwise "service".
int hasTestSwitch = 0;
for (UINT32 i = 0; i < nGameInpCount; i++) {
if (BurnDrvGetInputInfo(&bii, i) == 0 && bii.nType == BIT_DIGITAL && hl_is_test_switch(bii.szInfo)) {
hasTestSwitch = 1;
break;
}
}
for (UINT32 i = 0; i < nGameInpCount; i++) {
if (BurnDrvGetInputInfo(&bii, i))
continue;
if (bii.nType != BIT_DIGITAL)
continue;
GameInp[i].nInput = GIT_SWITCH;
int player = 0, button = 0;
if (hl_is_test_switch(bii.szInfo))
GameInp[i].Input.Switch.nCode = (UINT16)hl_code(0, FBHeadlessButtonService);
else if (hl_is_service_switch(bii.szInfo))
GameInp[i].Input.Switch.nCode = (UINT16)hl_code(0, hasTestSwitch ? FBHeadlessButtonConfigure : FBHeadlessButtonService);
else if (hl_twin_stick(bii.szName, bii.szInfo, &player, &button))
GameInp[i].Input.Switch.nCode = (UINT16)hl_code(player, button);
else if (hl_classify(bii.szInfo, &player, &button) && player >= 0 && player < 4)
GameInp[i].Input.Switch.nCode = (UINT16)hl_code(player, button);
else
GameInp[i].Input.Switch.nCode = HL_CODE_DEAD;
}
}
extern "C" void FBHeadlessSetInput(int player, int button, int value)
{
if (player < 0 || player >= 4)
return;
if (button < 0 || button >= FBHeadlessButtonCount)
return;
FBHeadlessSetInputState(hl_code(player, button), value);
}
+192
View File
@@ -0,0 +1,192 @@
// Headless frontend for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// Provides the burner-side globals the FBNeo library expects from a frontend and
// a small C API the host drives. Video/audio/input are routed through the
// intf/{video,audio,input}/headless plugins; driver init/exit lives in drv.cpp.
//
// Subject to the FB Neo license (see src/license.txt).
#include "burner.h"
#include "fbheadless.h"
// Implemented in headless_input.cpp.
void headless_map_inputs(void);
// Implemented in vid_headless.cpp (rotates the native frame to the display buffer).
void headless_video_present(void);
// --- Burner globals expected by the FBNeo library / shared burner code ---
int nAppVirtualFps = 6000; // app fps * 100
bool bRunPause = 0;
bool bAppDoFast = 0;
char fpsstring[20] = "";
bool bAppShowFPS = 0;
bool bAlwaysProcessKeyboardInput = 0;
bool bAppFullscreen = 0;
bool bIntegerScale = false;
int nWindowScale = 2;
bool bAlwaysMenu = false;
int nGameSelect = 0;
int nFilterSelect = 0;
bool bShowAvailableOnly = true;
bool bShowClones = true;
int gameSelectedFromFilter = -1;
UINT32 messageFrames = 0;
char lastMessage[MESSAGE_MAX_LENGTH] = "";
int bDrvSaveAll = 0;
TCHAR szAppBurnVer[16] = _T("");
// --- Frontend audio state ---
static short *audBuffer = NULL;
static int audFrames = 0; // stereo sample frames produced last frame
static int audSampleRate = 48000;
static int allocAudio()
{
free(audBuffer);
audBuffer = NULL;
if (nBurnSoundLen <= 0)
return 1;
audBuffer = (short *)malloc((nBurnSoundLen * 2 + 16) * sizeof(short));
if (audBuffer == NULL)
return 1;
memset(audBuffer, 0, (nBurnSoundLen * 2 + 16) * sizeof(short));
return 0;
}
// --- C API ---
int FBHeadlessInit(void)
{
BurnLibInit();
return 0;
}
void FBHeadlessExit(void)
{
DrvExit();
VidExit();
AudSoundExit();
InputExit();
free(audBuffer);
audBuffer = NULL;
BurnLibExit();
}
void FBHeadlessSetRomPath(const char *path)
{
// BzipOpen builds zip paths as szAppRomPaths[d] + "<name>.zip" with no
// separator, so the path must end with a slash.
size_t n = strlen(path);
if (n > 0 && path[n - 1] == '/')
snprintf(szAppRomPaths[0], MAX_PATH, "%s", path);
else
snprintf(szAppRomPaths[0], MAX_PATH, "%s/", path);
}
int FBHeadlessLoadDriver(const char *shortName)
{
UINT32 i;
for (i = 0; i < nBurnDrvCount; i++) {
nBurnDrvActive = i;
if (strcmp(BurnDrvGetTextA(DRV_NAME), shortName) == 0)
break;
}
if (i >= nBurnDrvCount)
return 1;
nAudSampleRate[0] = audSampleRate;
nBurnSoundRate = audSampleRate;
InputInit();
AudSoundInit();
if (DrvInit(i, true)) // true: restore battery-backed RAM
return 1;
VidInit(); // after DrvInit: the game's visible size is known
headless_map_inputs();
nAppVirtualFps = nBurnFPS;
if (nAppVirtualFps <= 0)
nAppVirtualFps = 6000;
nBurnSoundLen = (audSampleRate * 100 + (nAppVirtualFps >> 1)) / nAppVirtualFps;
allocAudio();
FBHeadlessCheevosInit(); // build the achievement memory map
return 0;
}
void FBHeadlessRunFrame(int draw)
{
if (!bDrvOkay)
return;
InputMake(true);
pBurnDraw = draw ? pVidImage : NULL;
pBurnSoundOut = audBuffer;
BurnDrvFrame();
if (draw)
headless_video_present();
audFrames = nBurnSoundLen;
}
// Audio accessors
int FBHeadlessGetAudioSampleRate(void) { return audSampleRate; }
const short *FBHeadlessGetAudioBuffer(void) { return audBuffer; }
int FBHeadlessGetAudioFrames(void) { return audFrames; }
// Frame timing / geometry
int FBHeadlessGetFrameRate(void) { return nBurnFPS; }
int FBHeadlessGetAspectX(void)
{
INT32 x = 0, y = 0;
if (bDrvOkay)
BurnDrvGetAspect(&x, &y);
return x;
}
int FBHeadlessGetAspectY(void)
{
INT32 x = 0, y = 0;
if (bDrvOkay)
BurnDrvGetAspect(&x, &y);
return y;
}
void FBHeadlessReset(void)
{
if (!bDrvOkay)
return;
DrvInit(nBurnDrvActive, true); // full re-init; DrvExit saves battery RAM, DrvInit restores it
VidInit(); // DrvInit defers blitter init + frees buffers; recreate them
headless_map_inputs();
FBHeadlessCheevosInit(); // RAM buffers were reallocated; refresh the map
}
int FBHeadlessSaveState(const char *path)
{
if (!bDrvOkay || path == NULL)
return 1;
TCHAR szName[1024];
ANSIToTCHAR(path, szName, 1024);
return BurnStateSave(szName, 1); // bAll=1: full state
}
int FBHeadlessLoadState(const char *path)
{
if (!bDrvOkay || path == NULL)
return 1;
TCHAR szName[1024];
ANSIToTCHAR(path, szName, 1024);
return BurnStateLoad(szName, 1, NULL); // game already loaded, so no reload callback
}
+217
View File
@@ -0,0 +1,217 @@
// Memory access for cheats, cheat search, and achievements (FinalBurn Neo headless).
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// Thin C wrappers over FBNeo's cheat-engine memory interface (src/burn/cheat.cpp).
// All addresses are in the main CPU (cpu 0) hardware address space — the same
// space FBNeo's own cheat and achievement support uses, so a value found by a
// memory search can be written back by address.
//
// Subject to the FB Neo license (see src/license.txt).
#include "burner.h"
#include "state.h" // BurnArea, BurnAreaScan, BurnAcb, ACB_FULLSCAN
#include "fbheadless.h"
unsigned int FBHeadlessGetMainMemorySize(void)
{
return GetMainMemorySize();
}
unsigned int FBHeadlessReadMemoryRange(unsigned int address, unsigned char *out, unsigned int length)
{
return ReadMemoryRange(address, out, length);
}
// Standard byte order: byte i lives at address+i. littleEndian controls which end
// is the least-significant byte. (FBNeo's own Read/WriteValueAtHardwareAddress use
// an MSB-first, address-decrementing convention — not exposed here to avoid surprises.)
unsigned int FBHeadlessReadMemory(unsigned int address, int size, int littleEndian)
{
if (!bDrvOkay || size < 1 || size > 4)
return 0;
unsigned char b[4] = { 0, 0, 0, 0 };
ReadMemoryRange(address, b, (unsigned int)size);
unsigned int value = 0;
for (int i = 0; i < size; i++) {
int shift = littleEndian ? (8 * i) : (8 * (size - 1 - i));
value |= (unsigned int)b[i] << shift;
}
return value;
}
int FBHeadlessWriteMemory(unsigned int address, unsigned int value, int size, int littleEndian)
{
if (!bDrvOkay || size < 1 || size > 4)
return 0;
for (int i = 0; i < size; i++) {
int shift = littleEndian ? (8 * i) : (8 * (size - 1 - i));
unsigned char byte = (value >> shift) & 0xFF;
WriteValueAtHardwareAddress(address + i, byte, 1, 1); // single byte, no endian ambiguity
}
return 1;
}
int FBHeadlessIsAddressValid(unsigned int address)
{
return IsHardwareAddressValid(address) ? 1 : 0;
}
// --- Achievements memory map ---
//
// RetroAchievements sets are authored against the flat main-RAM buffer FBNeo's
// libretro port exposes (see CheevosInit / StateGetMainRamAcb in retro_memory.cpp),
// NOT the CPU hardware address space. Find the same RAM area(s) by driver hardware
// type and expose them at the same RA base addresses the libretro port uses.
#define FBH_MAX_RA_REGIONS 10
typedef struct { unsigned int start; unsigned int len; unsigned char *ptr; } FBHRaRegion;
static FBHRaRegion s_raRegions[FBH_MAX_RA_REGIONS];
static int s_raRegionCount = 0;
static int s_raBigEndian = 0; // main CPU multibyte order (68K etc. = big-endian)
static void fbh_ra_add(unsigned int start, unsigned int len, void *ptr)
{
if (s_raRegionCount >= FBH_MAX_RA_REGIONS || ptr == NULL || len == 0)
return;
s_raRegions[s_raRegionCount].start = start;
s_raRegions[s_raRegionCount].len = len;
s_raRegions[s_raRegionCount].ptr = (unsigned char *)ptr;
s_raRegionCount++;
}
static INT32 __cdecl fbh_ra_acb(struct BurnArea *pba)
{
if (!pba->szName)
return 0;
switch (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) {
case HARDWARE_CAPCOM_CPS1:
case HARDWARE_CAPCOM_CPS1_QSOUND:
case HARDWARE_CAPCOM_CPS1_GENERIC:
case HARDWARE_CAPCOM_CPSCHANGER:
case HARDWARE_CAPCOM_CPS2:
if (strcmp(pba->szName, "CpsRamFF") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
case HARDWARE_CAPCOM_CPS3:
if (strcmp(pba->szName, "Main RAM") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
case HARDWARE_SNK_NEOCD:
if (strcmp(pba->szName, "68K program RAM") == 0) fbh_ra_add(0x00000000, pba->nLen, pba->Data);
if (strcmp(pba->szName, "Memory card") == 0) fbh_ra_add(0x00800000, pba->nLen, pba->Data);
return 0;
case HARDWARE_SNK_NEOGEO:
case HARDWARE_IGS_PGM:
if (strcmp(pba->szName, "68K RAM") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
case HARDWARE_PSIKYO:
if (strcmp(pba->szName, "All RAM") == 0 || strcmp(pba->szName, "68K RAM") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
case HARDWARE_CAVE_68K_Z80:
case HARDWARE_CAVE_68K_ONLY:
if (strcmp(pba->szName, "RAM") == 0 || strcmp(pba->szName, "68K RAM") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
case HARDWARE_SEGA_MEGADRIVE:
if (strcmp(pba->szName, "RAM") == 0) fbh_ra_add(0x00FF0000, pba->nLen, pba->Data);
if (strcmp(pba->szName, "NV RAM") == 0) fbh_ra_add(0x00000000, pba->nLen, pba->Data);
return 0;
case HARDWARE_SEGA_MASTER_SYSTEM:
case HARDWARE_SEGA_GAME_GEAR:
if (strcmp(pba->szName, "sms") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
case HARDWARE_NES:
case HARDWARE_FDS:
case HARDWARE_NVS:
if (strcmp(pba->szName, "CPU Ram") == 0) fbh_ra_add(0x00000000, pba->nLen, pba->Data);
if (strcmp(pba->szName, "Work Ram") == 0) fbh_ra_add(0x00006000, pba->nLen, pba->Data);
return 0;
case HARDWARE_SNK_NGP:
case HARDWARE_SNK_NGPC:
if (strcmp(pba->szName, "Main Ram") == 0) fbh_ra_add(0x00004000, pba->nLen, pba->Data);
if (strcmp(pba->szName, "Shared Ram") == 0) fbh_ra_add(0x00007000, pba->nLen, pba->Data);
return 0;
case HARDWARE_TOAPLAN_RAIZING:
if (strcmp(pba->szName, "All Ram") == 0 || strcmp(pba->szName, "All RAM") == 0 || strcmp(pba->szName, "RAM") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
default:
// Most other drivers expose main RAM as "All Ram" / "All RAM".
if (strcmp(pba->szName, "All Ram") == 0 || strcmp(pba->szName, "All RAM") == 0) fbh_ra_add(0, pba->nLen, pba->Data);
return 0;
}
}
// Rebuild the achievement memory map. Call after a driver loads or resets, since
// DrvInit reallocates the RAM buffers (the cached pointers would otherwise dangle).
void FBHeadlessCheevosInit(void)
{
INT32 nMin = 0;
s_raRegionCount = 0;
s_raBigEndian = 0;
if (!bDrvOkay)
return;
s_raBigEndian = GetMainMemoryBigEndian();
BurnAcb = fbh_ra_acb;
BurnAreaScan(ACB_FULLSCAN, &nMin);
}
unsigned int FBHeadlessReadAchievementMemory(unsigned int address, unsigned char *out, unsigned int length)
{
if (out == NULL)
return 0;
unsigned int i;
for (i = 0; i < length; i++) {
unsigned int a = address + i;
int found = 0;
for (int r = 0; r < s_raRegionCount; r++) {
if (a >= s_raRegions[r].start && a < s_raRegions[r].start + s_raRegions[r].len) {
out[i] = s_raRegions[r].ptr[a - s_raRegions[r].start];
found = 1;
break;
}
}
if (!found)
return i; // stop at the first unmapped address
}
return length;
}
// Write a value into the achievement memory map (used to apply cheats). Bytes land
// at address+i for littleEndian, or MSB-first for big-endian. Returns 1 if anything
// was written. Direct buffer writes — the CPU sees them next frame (plain RAM).
int FBHeadlessWriteAchievementMemory(unsigned int address, unsigned int value, int size, int littleEndian)
{
if (size < 1 || size > 4)
return 0;
int wrote = 0;
for (int i = 0; i < size; i++) {
unsigned int a = littleEndian ? (address + i) : (address + (size - 1 - i));
unsigned char byte = (value >> (8 * i)) & 0xFF;
for (int r = 0; r < s_raRegionCount; r++) {
if (a >= s_raRegions[r].start && a < s_raRegions[r].start + s_raRegions[r].len) {
s_raRegions[r].ptr[a - s_raRegions[r].start] = byte;
wrote = 1;
break;
}
}
}
return wrote;
}
// Enumerate the mapped regions so the host can present cheat-search memory.
int FBHeadlessGetMemoryRegionCount(void)
{
return s_raRegionCount;
}
int FBHeadlessGetMemoryRegion(int index, unsigned int *start, unsigned int *length, int *bigEndian)
{
if (index < 0 || index >= s_raRegionCount)
return 0;
if (start) *start = s_raRegions[index].start;
if (length) *length = s_raRegions[index].len;
if (bigEndian) *bigEndian = s_raBigEndian;
return 1;
}
+49
View File
@@ -0,0 +1,49 @@
// Headless frontend helpers for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// Small frontend functions/globals the shared burner code expects, provided by
// each platform (the headless counterpart of burner/macos/misc.cpp). Subject to
// the FB Neo license (see src/license.txt).
#include "burner.h"
// General-purpose debug global referenced by various drivers.
int counter = 0;
TCHAR* ANSIToTCHAR(const char* pszInString, TCHAR* pszOutString, int /* nOutSize */)
{
if (pszOutString) {
_tcscpy(pszOutString, pszInString);
return pszOutString;
}
return (TCHAR*)pszInString;
}
char* TCHARToANSI(const TCHAR* pszInString, char* pszOutString, int /* nOutSize */)
{
if (pszOutString) {
_tcscpy(pszOutString, pszInString);
return pszOutString;
}
return (char*)pszInString;
}
TCHAR* AdaptiveEncodingReads(const TCHAR* /* pszFileName */)
{
return NULL;
}
bool AppProcessKeyboardInput()
{
// Input is always live for the headless core (the host gates pause/focus),
// and CinpState() zeroes keyboard-range codes (< 0x4000, which ours are)
// unless this returns true.
return true;
}
void UpdateMessage(char* /* message */)
{
}
+72
View File
@@ -0,0 +1,72 @@
#ifndef TCHAR_H
#define TCHAR_H
// Always available so non-_UNICODE code that still handles wide buffers
// (e.g. burn.cpp zip-name parsing) can call wcslen/wcscpy.
#include <wchar.h>
#ifdef _UNICODE
#include <wchar.h>
#define __TEXT(q) L##q
typedef wchar_t TCHAR;
typedef wchar_t _TCHAR;
#else /* ifndef _UNICODE */
#define __TEXT(q) q
typedef char TCHAR;
typedef char _TCHAR;
//#define wcslen(void)
#define _tcslen strlen
#define _tcscpy strcpy
#define _tcsncpy strncpy
#define _tprintf printf
#define _vstprintf vsprintf
#define _vsntprintf vsnprintf
#define _stprintf sprintf
#define _sntprintf snprintf
#define _ftprintf fprintf
#define _tsprintf sprintf
#define _tcscmp strcmp
#define _tcsncmp strncmp
#define _tcsicmp strcasecmp
#define _tcsnicmp strncasecmp
#define _tcstol strtol
#define _tcsrchr strrchr
#define _tcsstr strstr
#define _tcsstr strstr
#define _fgetts fgets
#define _fputts fputs
#define _istspace isspace
#define _tfopen fopen
#define _stricmp strcmp
#define _strnicmp strncmp
// Win32 string/char shims the shared code uses on POSIX builds.
#include <ctype.h>
#define stricmp strcasecmp
#define strnicmp strncasecmp
#define _totlower(c) tolower((unsigned char)(c))
#define _totupper(c) toupper((unsigned char)(c))
#define dprintf(...) fprintf (stderr, __VA_ARGS__)
#endif
#define _TEXT(x) __TEXT(x)
#define _T(x) __TEXT(x)
#endif
+14
View File
@@ -1316,6 +1316,7 @@ BEGIN
MENUITEM "Enable Windowed Fullscreen (DX9/DX11 Blitters)", MENU_WINFS
MENUITEM "Enable VSync (Windowed)", MENU_VIDEOVSYNC
MENUITEM "Enable DWM Sync (Windowed)", MENU_DWMFIX
MENUITEM "Enable Variable Refresh Rate (DX11, Win10+)", MENU_VRR
MENUITEM "Auto Frameskip", MENU_AUTOFRAMESKIP
MENUITEM "Enable RunAhead", MENU_RUNAHEAD
END
@@ -1325,6 +1326,7 @@ BEGIN
BEGIN
MENUITEM "DirectSound", MENU_AUD_PLUGIN_1
MENUITEM "XAudio2", MENU_AUD_PLUGIN_2
MENUITEM "WASAPI", MENU_AUD_PLUGIN_3
END
MENUITEM "Plugin &options", MENU_AUDIO_OPTIONS, GRAYED
POPUP "&Audio Volume"
@@ -1992,6 +1994,18 @@ BEGIN
END
END
IDR_MENU_AUD_PLUGIN_3 MENU
BEGIN
POPUP "WASAPI plugin"
BEGIN
MENUITEM "Use Low-pass filter", MENU_WASAPI_BASS
MENUITEM SEPARATOR
MENUITEM "Sound disabled", MENU_WASAPI_NOSOUND
MENUITEM "44100Hz samplerate", MENU_WASAPI_44100
MENUITEM "48000Hz samplerate", MENU_WASAPI_48000
END
END
IDR_MENU_GAMESEL MENU
BEGIN
POPUP "Game Selection Menu"
+1
View File
@@ -269,6 +269,7 @@ int RunFrame(int bDraw, int bPause);
int RunMessageLoop();
int RunReset();
void ToggleLayer(unsigned char thisLayer);
bool EmulatorAppIsFast();
// scrn.cpp
extern HWND hScrnWnd; // Handle to the screen window
+12 -1
View File
@@ -296,6 +296,7 @@ int ConfigAppLoad()
VAR(bVidDX9WinFullscreen);
VAR(bVidVSync);
VAR(bVidDWMSync);
VAR(bVidVRR);
VAR(bVidScanlines);
VAR(nVidScanIntensity);
@@ -376,6 +377,8 @@ int ConfigAppLoad()
VAR(nAudDSPModule[0]);
VAR(nAudSampleRate[1]);
VAR(nAudDSPModule[1]);
VAR(nAudSampleRate[2]);
VAR(nAudDSPModule[2]);
// Other
STR(szPlaceHolder);
@@ -685,6 +688,8 @@ int ConfigAppSave()
VAR(bVidVSync);
_ftprintf(h, _T("\n// If non-zero, try to synchronise to DWM on Windows 7+, this fixes frame stuttering problems.\n"));
VAR(bVidDWMSync);
_ftprintf(h, _T("\n// If non-zero, use variable refresh rate (G-Sync/FreeSync) with the DX11 blitter on Windows 10+\n"));
VAR(bVidVRR);
_ftprintf(h, _T("\n// Transfer method: 0 = blit from system memory / use driver/DirectX texture management;\n"));
_ftprintf(h, _T("// 1 = copy to a video memory surface, then use bltfast();\n"));
_ftprintf(h, _T("// -1 = autodetect for DirectDraw, equals 1 for Direct3D\n"));
@@ -784,7 +789,7 @@ int ConfigAppSave()
VAR(nInputSelect);
_ftprintf(h, _T("\n"));
_ftprintf(h, _T("// --- Sound ------------------------------------------------------------------\n"));
_ftprintf(h, _T("\n// The selected audio plugin\n"));
_ftprintf(h, _T("\n// The selected audio plugin (0 = DirectSound, 1 = XAudio2, 2 = WASAPI)\n"));
VAR(nAudSelect);
_ftprintf(h, _T("\n// Audio Volume\n"));
VAR(nAudVolume);
@@ -806,6 +811,12 @@ int ConfigAppSave()
VAR(nAudSampleRate[1]);
_ftprintf(h, _T("\n// DSP module to use for sound enhancement: 0 = none, 1 = low-pass filter, 2 = reverb\n"));
VAR(nAudDSPModule[1]);
_ftprintf(h, _T("\n"));
_ftprintf(h, _T("// --- WASAPI plugin settings -------------------------------------------------\n"));
_ftprintf(h, _T("\n// Sample rate\n"));
VAR(nAudSampleRate[2]);
_ftprintf(h, _T("\n// DSP module to use for sound enhancement: 0 = none, 1 = low-pass filter\n"));
VAR(nAudDSPModule[2]);
_ftprintf(h, _T("\n\n\n"));
_ftprintf(h, _T("// --- UI ---------------------------------------------------------------------\n"));
+65 -1
View File
@@ -140,6 +140,36 @@ static INT32 GetCurrentMonitorHigh() {
return monitorInfo.rcMonitor.bottom;
}
//In order to properly clean up the currentMenuInfo structs created to handle owner Drawn components it is necessary to iterate over all the menus and clean
//the mii.dwItemData variable
void CleanUpMenuInfos(HMENU hMenu)
{
MENUINFO mi = { sizeof(MENUINFO) };
int count = GetMenuItemCount(hMenu);
for (int i = 0; i < count; i++) {
HMENU hSub = GetSubMenu(hMenu, i);
if(hSub)
{
CleanUpMenuInfos(hSub);
}
MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
mii.fMask = MIIM_FTYPE | MIIM_DATA;
if (!GetMenuItemInfo(hMenu, i, TRUE, &mii))
continue;
if ((mii.fType & MFT_OWNERDRAW) && mii.dwItemData != 0)
{
delete (CurrentItemInfo*)mii.dwItemData;
mii.fMask = MIIM_DATA;
mii.dwItemData = 0;
SetMenuItemInfo(hMenu, i, TRUE, &mii);
}
}
}
void ApplyMenuBackground(HMENU hMenu, HBRUSH hbr)
{
MENUINFO mi = { sizeof(MENUINFO) };
@@ -438,6 +468,11 @@ void DisplayPopupMenu(int nMenu)
if (!bModelessMenu) {
UnhookWindowsHookEx(hMenuHook);
}
if (uiOwnerDrawActive) {
CleanUpMenuInfos(hPopupMenu);
}
}
}
@@ -693,6 +728,7 @@ int MenuCreate()
hAudioPluginMenu[0] = FBALoadMenu(hAppInst, MAKEINTRESOURCE(IDR_MENU_AUD_PLUGIN_1));
hAudioPluginMenu[1] = FBALoadMenu(hAppInst, MAKEINTRESOURCE(IDR_MENU_AUD_PLUGIN_2));
hAudioPluginMenu[2] = FBALoadMenu(hAppInst, MAKEINTRESOURCE(IDR_MENU_AUD_PLUGIN_3));
}
if (hMenuPopup == NULL) {
@@ -1036,6 +1072,7 @@ void MenuUpdate()
CheckMenuItem(hMenu, MENU_WINFS, bVidDX9WinFullscreen ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hMenu, MENU_DWMFIX, bVidDWMSync ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hMenu, MENU_VRR, bVidVRR ? MF_CHECKED : MF_UNCHECKED);
var = nVidSelect + MENU_BLITTER_1;
CheckMenuRadioItem(hMenu, MENU_BLITTER_1, MENU_BLITTER_8, var, MF_BYCOMMAND);
@@ -1382,6 +1419,25 @@ void MenuUpdate()
EnableMenuItem(hMenu, MENU_AUDIO_VOLUME_200, MF_ENABLED | MF_BYCOMMAND);
break;
}
case 2: {
var = MENU_WASAPI_NOSOUND;
if (nAudSampleRate[2] > 0) {
if (nAudSampleRate[2] <= 44100) {
var = MENU_WASAPI_44100;
nAudSampleRate[2] = 44100; // sanity
} else {
var = MENU_WASAPI_48000;
nAudSampleRate[2] = 48000;
}
}
CheckMenuRadioItem(hMenu, MENU_WASAPI_NOSOUND, MENU_WASAPI_48000, var, MF_BYCOMMAND);
CheckMenuItem(hMenu, MENU_WASAPI_BASS, (nAudDSPModule[2] & 1) ? MF_CHECKED : MF_UNCHECKED);
// WASAPI is able to amp volume above 0db, enable:
EnableMenuItem(hMenu, MENU_AUDIO_VOLUME_150, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_AUDIO_VOLUME_200, MF_ENABLED | MF_BYCOMMAND);
break;
}
}
var = MENU_INTERPOLATE_0 + nInterpolation;
@@ -1654,7 +1710,7 @@ void MenuEnableItems()
SetMenuItemInfo(GetSubMenu(hMenu, 1), 1, TRUE, &myMenuItemInfo);
}
if (hBlitterMenu[nAudSelect]) {
if (hAudioPluginMenu[nAudSelect]) {
MENUITEMINFO myMenuItemInfo;
myMenuItemInfo.cbSize = sizeof(MENUITEMINFO);
myMenuItemInfo.fMask = MIIM_SUBMENU | MIIM_STATE;
@@ -1731,6 +1787,9 @@ void MenuEnableItems()
EnableMenuItem(hMenu, MENU_XAUDIO_NOSOUND, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_XAUDIO_44100, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_XAUDIO_48000, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_WASAPI_NOSOUND, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_WASAPI_44100, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_WASAPI_48000, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_INTERPOLATE_FM_0, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_INTERPOLATE_FM_3, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_FRAMES, MF_GRAYED | MF_BYCOMMAND);
@@ -1748,6 +1807,7 @@ void MenuEnableItems()
EnableMenuItem(hMenu, MENU_AUD_PLUGIN_1, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_AUD_PLUGIN_2, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_AUD_PLUGIN_3, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_INP_PLUGIN_1, MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_INP_PLUGIN_2, MF_GRAYED | MF_BYCOMMAND);
@@ -2045,6 +2105,9 @@ void MenuEnableItems()
EnableMenuItem(hMenu, MENU_XAUDIO_NOSOUND, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_XAUDIO_44100, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_XAUDIO_48000, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_WASAPI_NOSOUND, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_WASAPI_44100, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_WASAPI_48000, MF_ENABLED | MF_BYCOMMAND);
// EnableMenuItem(hMenu, MENU_INTERPOLATE_1, MF_ENABLED | MF_BYCOMMAND);
// EnableMenuItem(hMenu, MENU_INTERPOLATE_3, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_WLOGSTART, MF_GRAYED | MF_BYCOMMAND);
@@ -2065,6 +2128,7 @@ void MenuEnableItems()
EnableMenuItem(hMenu, MENU_AUD_PLUGIN_1, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_AUD_PLUGIN_2, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_AUD_PLUGIN_3, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_INP_PLUGIN_1, MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu, MENU_INP_PLUGIN_2, MF_ENABLED | MF_BYCOMMAND);
+6
View File
@@ -68,6 +68,7 @@
#define IDR_MENU_BLITTER_6 115
#define IDR_MENU_AUD_PLUGIN_1 130
#define IDR_MENU_AUD_PLUGIN_2 131
#define IDR_MENU_AUD_PLUGIN_3 132
#define IDR_MENU_GAMESEL 140
#define IDR_MENU_LUAWINDOW 150
#define IDR_ACCELERATOR 160
@@ -601,6 +602,7 @@
#define MENU_WINFS 10101
#define MENU_FULL 10102
#define MENU_DWMFIX 10103
#define MENU_VRR 10104
#define MENU_NOSTRETCH 10110
#define MENU_STRETCH 10111
#define MENU_ASPECT 10112
@@ -658,12 +660,16 @@
#define MENU_DSOUND_BASS 10201
#define MENU_XAUDIO_BASS 10202
#define MENU_XAUDIO_REVERB 10203
#define MENU_WASAPI_BASS 10204
#define MENU_DSOUND_NOSOUND 10210
#define MENU_DSOUND_44100 10213
#define MENU_DSOUND_48000 10214
#define MENU_XAUDIO_NOSOUND 10220
#define MENU_XAUDIO_44100 10223
#define MENU_XAUDIO_48000 10224
#define MENU_WASAPI_NOSOUND 10225
#define MENU_WASAPI_44100 10226
#define MENU_WASAPI_48000 10227
#define MENU_INTERPOLATE_0 10230
#define MENU_INTERPOLATE_1 10231
#define MENU_INTERPOLATE_3 10233
+106 -14
View File
@@ -60,6 +60,10 @@ struct lua_hotkey_handler hotkey_debounces[] = {
{ NULL, 0, 0, NULL }
};
bool EmulatorAppIsFast() {
return bAppDoFast;
}
void EmulatorAppDoFast(bool dofast) {
bAppDoFast = dofast;
bAppDoFasttoggled = 0;
@@ -168,31 +172,59 @@ static int GetInput(bool bCopy)
return 0;
}
static time_t fpstimer;
static unsigned int nPreviousFrames;
static LARGE_INTEGER qpcFreq, qpcLast;
static UINT32 nLastEmu;
static void DisplayFPSInit()
{
nDoFPS = 0;
fpstimer = 0;
nPreviousFrames = (bAppDoFast) ? nFramesEmulated : nFramesRendered;
QueryPerformanceFrequency(&qpcFreq);
QueryPerformanceCounter(&qpcLast);
nLastEmu = nFramesEmulated;
}
static void DisplayFPS()
{
const int nFPSTotal = (bAppDoFast) ? nFramesEmulated : nFramesRendered;
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
double dt = (double)(now.QuadPart - qpcLast.QuadPart) / qpcFreq.QuadPart;
if (dt < 1.0) return; // update once per second
TCHAR fpsstring[20];
time_t temptime = clock();
double fps = (double)(nFPSTotal - nPreviousFrames) * CLOCKS_PER_SEC / (temptime - fpstimer);
double fps = (nFramesEmulated - nLastEmu) / dt;
_sntprintf(fpsstring, 7, _T("%2.2lf"), fps);
if (fpstimer && temptime - fpstimer>0) { // avoid strange fps values
VidSNewShortMsg(fpsstring, 0xDFDFFF, 480, 0);
TCHAR s[32];
_sntprintf(s, 32, _T("%2.2lf"), fps);
VidSNewShortMsg(s, 0xDFDFFF, 480, 0);
qpcLast = now;
nLastEmu = nFramesEmulated;
}
static void DisplayFPSCheckState()
{
static int bLastFast = -1, bLastPause = -1;
static LONGLONG nLastCall = 0;
static int timer = 0;
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
// frame normally runs every ~16.67ms (at 60hz)
// a gap over 100ms means something blocked the loop: menu, window drag, dialog, loading...
const bool bStalled = nLastCall && qpcFreq.QuadPart &&
(now.QuadPart - nLastCall) > qpcFreq.QuadPart / 10;
nLastCall = now.QuadPart;
if (bStalled || bAppDoFast != bLastFast || bRunPause != bLastPause) {
timer = 30;
bLastFast = bAppDoFast;
bLastPause = bRunPause;
}
if (timer > 0) {
// it takes a few frames to stabilize...
timer--;
DisplayFPSInit();
}
fpstimer = temptime;
nPreviousFrames = nFPSTotal;
}
// define this function somewhere above RunMessageLoop()
@@ -225,6 +257,62 @@ void do_shonky_profile()
}
#endif
// Present pacing when no video sync is active.
// Frames are produced when the audio engine signals a free segment, which happens on
// its own period (~10ms on Vista+), so frame times alternate e.g. 20/20/10ms.
// Presents are held back to a steady QPC schedule which follows the audio clock.
static LARGE_INTEGER qpcPaceFreq;
static LONGLONG nPaceNext = 0;
static bool RunPaceActive()
{
if (bVidVSync || (bVidDWMSync && !nVidFullscreen)) return false;
if (bAppDoFast || kNetGame) return false;
return true;
}
static void RunPacePresent()
{
if (!RunPaceActive()) {
nPaceNext = 0;
return;
}
if (qpcPaceFreq.QuadPart == 0) {
QueryPerformanceFrequency(&qpcPaceFreq);
}
LONGLONG nPeriod;
if (bAudPlaying && nBurnSoundRate > 0 && nBurnSoundLen > 0) {
nPeriod = qpcPaceFreq.QuadPart * nBurnSoundLen / nBurnSoundRate;
} else {
nPeriod = qpcPaceFreq.QuadPart * 100 / nAppVirtualFps;
}
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
LONGLONG nLead = nPaceNext - now.QuadPart;
if (nPaceNext == 0 || nLead < 0) {
// late (or first frame): present now, the schedule follows
nPaceNext = now.QuadPart;
} else if (nLead > nPeriod) {
// schedule drifted ahead of the frame source, pull it back
nPaceNext = now.QuadPart + nPeriod;
}
const LONGLONG nSleepMargin = qpcPaceFreq.QuadPart * 2 / 1000;
for (;;) {
QueryPerformanceCounter(&now);
LONGLONG nRemain = nPaceNext - now.QuadPart;
if (nRemain <= 0) break;
Sleep((bEnableHighResTimer && nRemain > nSleepMargin) ? 1 : 0);
}
nPaceNext += nPeriod;
}
// With or without sound, run one frame.
// If bDraw is true, it's the last frame before we are up to date, and so we should draw the screen
int RunFrame(int bDraw, int bPause)
@@ -232,7 +320,10 @@ int RunFrame(int bDraw, int bPause)
static int bPrevPause = 0;
static int bPrevDraw = 0;
if (bShowFPS) DisplayFPSCheckState();
if (bPrevDraw && !bPause) {
RunPacePresent();
VidPaint(0); // paint the screen (no need to validate)
if (!nVidFullscreen && bVidDWMSync) // Sync to DWM (Win7+, windowed)
@@ -489,6 +580,7 @@ int RunReset()
{
// Reset the speed throttling code
nNormalLast = 0; nNormalFrac = 0;
nPaceNext = 0;
// Reset FPS display
DisplayFPSInit();
+42
View File
@@ -2295,6 +2295,8 @@ static void OnCommand(HWND /*hDlg*/, int id, HWND /*hwndCtl*/, UINT codeNotify)
bVidDWMSync = !bVidDWMSync;
if (bVidDWMSync && bVidVSync)
bVidVSync = 0;
if (bVidDWMSync)
bVidVRR = 0;
POST_INITIALISE_MESSAGE;
break;
@@ -2909,6 +2911,18 @@ static void OnCommand(HWND /*hDlg*/, int id, HWND /*hwndCtl*/, UINT codeNotify)
bVidVSync = !bVidVSync;
if (bVidVSync && bVidDWMSync)
bVidDWMSync = 0;
if (bVidVSync)
bVidVRR = 0;
POST_INITIALISE_MESSAGE;
break;
case MENU_VRR:
bVidVRR = !bVidVRR;
if (bVidVRR) {
bVidVSync = 0;
bVidDWMSync = 0;
}
POST_INITIALISE_MESSAGE;
break;
@@ -2932,6 +2946,11 @@ static void OnCommand(HWND /*hDlg*/, int id, HWND /*hwndCtl*/, UINT codeNotify)
POST_INITIALISE_MESSAGE;
break;
case MENU_AUD_PLUGIN_3:
AudSelect(2);
POST_INITIALISE_MESSAGE;
break;
case MENU_DSOUND_NOSOUND:
if (!bDrvOkay) {
nAudSampleRate[0] = 0;
@@ -2970,6 +2989,25 @@ static void OnCommand(HWND /*hDlg*/, int id, HWND /*hwndCtl*/, UINT codeNotify)
}
break;
case MENU_WASAPI_NOSOUND:
if (!bDrvOkay) {
nAudSampleRate[2] = 0;
POST_INITIALISE_MESSAGE;
}
break;
case MENU_WASAPI_44100:
if (!bDrvOkay) {
nAudSampleRate[2] = 44100;
POST_INITIALISE_MESSAGE;
}
break;
case MENU_WASAPI_48000:
if (!bDrvOkay) {
nAudSampleRate[2] = 48000;
POST_INITIALISE_MESSAGE;
}
break;
case MENU_FRAMES:
if (UseDialogs()) {
if (!bDrvOkay) {
@@ -3012,6 +3050,10 @@ static void OnCommand(HWND /*hDlg*/, int id, HWND /*hwndCtl*/, UINT codeNotify)
nAudDSPModule[1] ^= 2;
break;
case MENU_WASAPI_BASS:
nAudDSPModule[2] ^= 1;
break;
case MENU_WLOGSTART:
AudBlankSound();
WaveLogStart();
+7 -1
View File
@@ -1,7 +1,7 @@
// Audio Output
#include "burner.h"
INT32 nAudSampleRate[8] = { 44100, 44100, 22050, 22050, 22050, 22050, 22050, 22050 }; // sample rate
INT32 nAudSampleRate[8] = { 44100, 44100, 48000, 22050, 22050, 22050, 22050, 22050 }; // sample rate
INT32 nAudVolume = 10000; // Sound volume (% * 100)
INT32 nAudSegCount = 6; // Segs in the pdsbLoop buffer
INT32 nAudSegLen = 0; // Seg length in samples (calculated from Rate/Fps)
@@ -19,8 +19,11 @@ static UINT32 nAudActive = 0;
#if defined (BUILD_WIN32)
extern struct AudOut AudOutDx;
extern struct AudOut AudOutXAudio2;
extern struct AudOut AudOutWASAPI;
#elif defined (BUILD_MACOS)
extern struct AudOut AudOutMacOS;
#elif defined (BUILD_HEADLESS)
extern struct AudOut AudOutHeadless;
#elif defined (BUILD_SDL)
extern struct AudOut AudOutSDL;
#elif defined (BUILD_SDL2)
@@ -43,8 +46,11 @@ static struct AudOut *pAudOut[]=
#if defined (BUILD_WIN32)
&AudOutDx,
&AudOutXAudio2,
&AudOutWASAPI,
#elif defined (BUILD_MACOS)
&AudOutMacOS,
#elif defined (BUILD_HEADLESS)
&AudOutHeadless,
#elif defined (BUILD_SDL)
&AudOutSDL,
#elif defined (BUILD_SDL2)
+49
View File
@@ -0,0 +1,49 @@
// Headless audio output for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// The frontend drives sound directly (it points pBurnSoundOut at its own buffer
// and reads it after BurnDrvFrame), so this plugin only satisfies the AudOut
// interface. Subject to the FB Neo license (see src/license.txt).
#include "burner.h"
static int HeadlessSoundBlank() { return 0; }
static int HeadlessSoundCheck() { return 0; }
static int HeadlessSoundInit()
{
if (nAudSampleRate[0] <= 0)
return 1;
bAudOkay = 1;
return 0;
}
static int HeadlessSetCallback(int (* /* pCallback */)(int)) { return 0; }
static int HeadlessSoundPlay() { bAudPlaying = 1; return 0; }
static int HeadlessSoundStop() { bAudPlaying = 0; return 0; }
static int HeadlessSoundExit()
{
bAudOkay = 0;
bAudPlaying = 0;
return 0;
}
static int HeadlessSoundSetVolume() { return 0; }
static int HeadlessSoundGetSettings(InterfaceInfo *) { return 0; }
struct AudOut AudOutHeadless = {
HeadlessSoundBlank,
HeadlessSoundCheck,
HeadlessSoundInit,
HeadlessSetCallback,
HeadlessSoundPlay,
HeadlessSoundStop,
HeadlessSoundExit,
HeadlessSoundSetVolume,
HeadlessSoundGetSettings,
_T("Headless audio output"),
};
+739
View File
@@ -0,0 +1,739 @@
// WASAPI (Windows Audio Session API) audio output module for FBNeo
// - dink 2026
#include "burner.h"
#include "aud_dsp.h"
#include <mmdeviceapi.h>
#include <audioclient.h>
#ifdef _MSC_VER
#pragma comment(lib, "ole32")
#endif
// These flags are missing from some older SDK / MinGW headers
#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#endif
#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
#endif
#ifndef AUDCLNT_E_DEVICE_INVALIDATED
#define AUDCLNT_E_DEVICE_INVALIDATED ((HRESULT)0x88890004L)
#endif
#ifndef AUDCLNT_E_RESOURCES_INVALIDATED
#define AUDCLNT_E_RESOURCES_INVALIDATED ((HRESULT)0x88890026L)
#endif
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
#ifndef WAVE_FORMAT_EXTENSIBLE
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#endif
// GUIDs are defined locally so we don't depend on __uuidof() or the uuid/ksuser libs
static const GUID FBN_CLSID_MMDeviceEnumerator = { 0xbcde0395, 0xe52f, 0x467c, { 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e } };
static const GUID FBN_IID_IMMDeviceEnumerator = { 0xa95664d2, 0x9614, 0x4f35, { 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6 } };
static const GUID FBN_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32, { 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
static const GUID FBN_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483, { 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2 } };
static const GUID FBN_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static const GUID FBN_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
// PKEY_Device_FriendlyName
static const PROPERTYKEY FBN_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd, { 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0 } }, 14 };
#define WASAPI_PLUGIN 2 // our index in nAudSampleRate[] / nAudDSPModule[]
#define REFTIMES_PER_SEC 10000000
static IMMDeviceEnumerator* pEnumerator = NULL;
static IMMDevice* pDevice = NULL;
static IAudioClient* pAudioClient = NULL;
static IAudioRenderClient* pRenderClient = NULL;
static HANDLE hWasapiEvent = NULL;
int (*WasapiGetNextSound)(int); // Callback used to request more sound
static int WasapiSetVolume(); // forward
static int nWasapiFps = 0; // Application fps * 100
static float fWasapiVol = 1.0f; // Software volume (allows > 100%)
static UINT32 nBufferFrames = 0; // Size of the WASAPI buffer (frames)
static UINT32 nTargetFrames = 0; // How full we keep the buffer (frames) = latency
static bool bStreamStarted = false;
static bool bEventDriven = false; // false: fall back to polling
static bool bBlanked = false; // AudBlankSound() was called during SoundCheck
// Output format actually used by the stream
enum { FMT_S16 = 0, FMT_S24, FMT_S32, FMT_F32 };
static int nOutFormat = FMT_S16;
static int nOutChannels = 2;
static int nOutBlockAlign = 4;
static bool bAutoConvert = false;
static TCHAR szDeviceName[128] = _T("");
// Device-lost handling
static bool bDeviceLost = false;
static DWORD nLastReopenTry = 0;
static DWORD nLostLastFrame = 0;
static int WasapiGetNextSoundFiller(int)
{
if (nAudNextSound == NULL) {
return 1;
}
AudWriteSilence();
return 0;
}
static int WasapiSetCallback(int (*pCallback)(int))
{
if (pCallback == NULL) {
WasapiGetNextSound = WasapiGetNextSoundFiller;
} else {
WasapiGetNextSound = pCallback;
}
return 0;
}
// Sample conversion: 16-bit stereo -> device format, with software volume
static inline INT32 WasapiClip16(INT32 s)
{
if (s > 32767) return 32767;
if (s < -32768) return -32768;
return s;
}
static void WasapiConvert(BYTE* pDst, const INT16* pSrc, UINT32 nFrames)
{
const bool bFullVol = (fWasapiVol == 1.0f);
const INT32 nVol = (INT32)(fWasapiVol * 65536.0f); // 16.16 fixed point
for (UINT32 i = 0; i < nFrames; i++) {
INT32 l = pSrc[i * 2 + 0];
INT32 r = pSrc[i * 2 + 1];
if (!bFullVol) {
l = WasapiClip16((INT32)(((INT64)l * nVol) >> 16));
r = WasapiClip16((INT32)(((INT64)r * nVol) >> 16));
}
switch (nOutFormat) {
case FMT_S16: {
INT16* d = (INT16*)pDst;
d[0] = (INT16)l;
d[1] = (INT16)r;
for (int c = 2; c < nOutChannels; c++) d[c] = 0;
break;
}
case FMT_S24: {
BYTE* d = pDst;
INT32 v[2] = { l << 8, r << 8 };
for (int c = 0; c < 2; c++) {
d[c * 3 + 0] = (BYTE)(v[c] & 0xff);
d[c * 3 + 1] = (BYTE)((v[c] >> 8) & 0xff);
d[c * 3 + 2] = (BYTE)((v[c] >> 16) & 0xff);
}
memset(d + 6, 0, (nOutChannels - 2) * 3);
break;
}
case FMT_S32: {
INT32* d = (INT32*)pDst;
d[0] = l << 16;
d[1] = r << 16;
for (int c = 2; c < nOutChannels; c++) d[c] = 0;
break;
}
case FMT_F32: {
float* d = (float*)pDst;
d[0] = (float)l * (1.0f / 32768.0f);
d[1] = (float)r * (1.0f / 32768.0f);
for (int c = 2; c < nOutChannels; c++) d[c] = 0.0f;
break;
}
}
pDst += nOutBlockAlign;
}
}
// Device / stream setup
static void WasapiReleaseStream()
{
if (pAudioClient && bStreamStarted) {
pAudioClient->Stop();
}
bStreamStarted = false;
RELEASE(pRenderClient);
RELEASE(pAudioClient);
RELEASE(pDevice);
RELEASE(pEnumerator);
}
static void WasapiGetDeviceName()
{
szDeviceName[0] = 0;
IPropertyStore* pProps = NULL;
if (pDevice && SUCCEEDED(pDevice->OpenPropertyStore(STGM_READ, &pProps))) {
PROPVARIANT varName;
PropVariantInit(&varName);
if (SUCCEEDED(pProps->GetValue(FBN_PKEY_Device_FriendlyName, &varName)) && varName.vt == VT_LPWSTR && varName.pwszVal) {
#if defined (_UNICODE)
wcsncpy(szDeviceName, varName.pwszVal, 127);
#else
WideCharToMultiByte(CP_ACP, 0, varName.pwszVal, -1, szDeviceName, 128, NULL, NULL);
#endif
szDeviceName[127] = 0;
}
PropVariantClear(&varName);
pProps->Release();
}
}
// Work out how to feed a given (mix) format; returns 0 if we can handle it
static int WasapiParseFormat(const WAVEFORMATEX* pwfx)
{
if (pwfx->nChannels < 2) {
return 1;
}
bool bFloat = false;
bool bPCM = false;
if (pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
bFloat = true;
} else if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
bPCM = true;
} else if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->cbSize >= 22) {
const WAVEFORMATEXTENSIBLE* pwfxe = (const WAVEFORMATEXTENSIBLE*)pwfx;
if (IsEqualGUID(pwfxe->SubFormat, FBN_SUBTYPE_IEEE_FLOAT)) bFloat = true;
if (IsEqualGUID(pwfxe->SubFormat, FBN_SUBTYPE_PCM)) bPCM = true;
}
if (bFloat && pwfx->wBitsPerSample == 32) {
nOutFormat = FMT_F32;
} else if (bPCM && pwfx->wBitsPerSample == 16) {
nOutFormat = FMT_S16;
} else if (bPCM && pwfx->wBitsPerSample == 24) {
nOutFormat = FMT_S24;
} else if (bPCM && pwfx->wBitsPerSample == 32) {
nOutFormat = FMT_S32;
} else {
return 1;
}
nOutChannels = pwfx->nChannels;
nOutBlockAlign = pwfx->nBlockAlign;
return 0;
}
// Activate a fresh IAudioClient on pDevice and initialise it. A client can only be
// Initialize()d once, so every attempt gets its own instance.
static HRESULT WasapiTryInit(const WAVEFORMATEX* pwfx, DWORD nFlags, REFERENCE_TIME hnsBuffer)
{
RELEASE(pAudioClient);
HRESULT hr = pDevice->Activate(FBN_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
if (FAILED(hr)) {
return hr;
}
hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, nFlags, hnsBuffer, 0, pwfx, NULL);
if (FAILED(hr)) {
RELEASE(pAudioClient);
}
return hr;
}
static int WasapiOpenStream()
{
HRESULT hr;
if (FAILED(hr = CoCreateInstance(FBN_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, FBN_IID_IMMDeviceEnumerator, (void**)&pEnumerator))) {
return 1;
}
if (FAILED(hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice))) {
WasapiReleaseStream();
return 1;
}
WasapiGetDeviceName();
// The buffer we ask for holds nAudSegCount frames of emulation - same latency as the other plugins.
REFERENCE_TIME hnsBuffer = (REFERENCE_TIME)REFTIMES_PER_SEC * nAudSegLen * nAudSegCount / nAudSampleRate[WASAPI_PLUGIN];
// Our native format: 16-bit stereo PCM at the selected rate
WAVEFORMATEX wfx;
memset(&wfx, 0, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = nAudSampleRate[WASAPI_PLUGIN];
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 4;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
const DWORD nAutoConv = AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
bEventDriven = true;
bAutoConvert = true;
nOutFormat = FMT_S16; nOutChannels = 2; nOutBlockAlign = 4;
// 1) 16-bit stereo, let Windows resample/convert to the mix format (Win7+)
hr = WasapiTryInit(&wfx, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | nAutoConv, hnsBuffer);
// 2) Device mix format, converted by us (only possible if the rate matches)
if (FAILED(hr)) {
WAVEFORMATEX* pMix = NULL;
IAudioClient* pTmp = NULL;
bAutoConvert = false;
if (SUCCEEDED(pDevice->Activate(FBN_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pTmp))) {
if (SUCCEEDED(pTmp->GetMixFormat(&pMix)) && pMix) {
if (pMix->nSamplesPerSec == (DWORD)nAudSampleRate[WASAPI_PLUGIN] && WasapiParseFormat(pMix) == 0) {
hr = WasapiTryInit(pMix, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, hnsBuffer);
if (FAILED(hr)) {
bEventDriven = false;
hr = WasapiTryInit(pMix, 0, hnsBuffer);
}
}
CoTaskMemFree(pMix);
}
pTmp->Release();
}
}
// 3) Last resort: auto-convert without event callback (polling)
if (FAILED(hr)) {
bEventDriven = false;
bAutoConvert = true;
nOutFormat = FMT_S16; nOutChannels = 2; nOutBlockAlign = 4;
hr = WasapiTryInit(&wfx, nAutoConv, hnsBuffer);
}
if (FAILED(hr) || pAudioClient == NULL) {
#ifdef PRINT_DEBUG_INFO
bprintf(0, _T("*** WASAPI: unable to initialise audio client (0x%08x).\n"), hr);
#endif
WasapiReleaseStream();
return 1;
}
if (bEventDriven) {
if (FAILED(pAudioClient->SetEventHandle(hWasapiEvent))) {
WasapiReleaseStream();
return 1;
}
}
if (FAILED(pAudioClient->GetBufferSize(&nBufferFrames))) {
WasapiReleaseStream();
return 1;
}
if (FAILED(pAudioClient->GetService(FBN_IID_IAudioRenderClient, (void**)&pRenderClient))) {
WasapiReleaseStream();
return 1;
}
// Keep the buffer filled up to nAudSegCount segs (or as much as fits)
nTargetFrames = nAudSegLen * nAudSegCount;
if (nTargetFrames > nBufferFrames) {
nTargetFrames = nBufferFrames;
}
if (nTargetFrames < (UINT32)nAudSegLen) {
// WASAPI gave us a buffer smaller than one frame of sound - can't work with that
WasapiReleaseStream();
return 1;
}
return 0;
}
// Fill the buffer up to the target with silence
static void WasapiPrefill()
{
UINT32 nPadding = 0;
BYTE* pData = NULL;
if (pAudioClient == NULL || pRenderClient == NULL) {
return;
}
if (FAILED(pAudioClient->GetCurrentPadding(&nPadding))) {
return;
}
// leave room for one seg so the first SoundCheck can run a frame immediately
INT32 nFill = (INT32)nTargetFrames - (INT32)nAudSegLen - (INT32)nPadding;
if (nFill > 0 && SUCCEEDED(pRenderClient->GetBuffer(nFill, &pData))) {
pRenderClient->ReleaseBuffer(nFill, AUDCLNT_BUFFERFLAGS_SILENT);
}
}
static int WasapiStartStream()
{
if (pAudioClient == NULL) {
return 1;
}
WasapiPrefill();
if (FAILED(pAudioClient->Start())) {
return 1;
}
bStreamStarted = true;
return 0;
}
// Default device changed / unplugged etc. Try to reopen on the (new) default device.
static int WasapiReopen()
{
WasapiReleaseStream();
ResetEvent(hWasapiEvent);
if (WasapiOpenStream()) {
return 1;
}
if (bAudPlaying) {
if (WasapiStartStream()) {
WasapiReleaseStream();
return 1;
}
}
return 0;
}
static void WasapiDeviceLost()
{
#ifdef PRINT_DEBUG_INFO
bprintf(0, _T("*** WASAPI: audio device lost, will try to reopen.\n"));
#endif
WasapiReleaseStream();
bDeviceLost = true;
nLastReopenTry = timeGetTime();
nLostLastFrame = nLastReopenTry;
}
// Plugin interface
static int WasapiBlankSound()
{
if (nAudNextSound) {
AudWriteSilence();
}
// Throw away whatever is queued in the device buffer and refill with silence
if (pAudioClient && pRenderClient) {
bBlanked = true;
if (bStreamStarted) {
pAudioClient->Stop();
pAudioClient->Reset();
WasapiPrefill();
pAudioClient->Start();
} else {
pAudioClient->Reset();
}
}
return 0;
}
// Write the seg in nAudNextSound to the device
static HRESULT WasapiWriteSeg()
{
BYTE* pData = NULL;
HRESULT hr = pRenderClient->GetBuffer(nAudSegLen, &pData);
if (FAILED(hr)) {
return hr;
}
WasapiConvert(pData, nAudNextSound, nAudSegLen);
return pRenderClient->ReleaseBuffer(nAudSegLen, 0);
}
// Called continuously by the run loop: blocks until there's room for at least one
// seg of sound, then runs the emulation for each free seg (drawing only the last one,
// unless bAlwaysDrawFrames) - same pacing model as the DirectSound plugin.
static int WasapiSoundCheck()
{
if (nAudNextSound == NULL) {
return 1;
}
if (bDeviceLost) {
DWORD nNow = timeGetTime();
if (nNow - nLastReopenTry >= 1000) {
nLastReopenTry = nNow;
if (WasapiReopen() == 0) {
bDeviceLost = false;
#ifdef PRINT_DEBUG_INFO
bprintf(0, _T("*** WASAPI: audio device reopened.\n"));
#endif
return 0;
}
}
// No device: keep the emulation running at roughly the right speed, without sound
DWORD nFrameMs = 100000 / (nWasapiFps ? nWasapiFps : 6000);
if (nNow - nLostLastFrame < nFrameMs) {
Sleep(1);
return 0;
}
nLostLastFrame += nFrameMs;
if (nNow - nLostLastFrame > nFrameMs * 4) nLostLastFrame = nNow; // don't try to catch up forever
WasapiGetNextSound(true);
return 0;
}
if (pAudioClient == NULL || pRenderClient == NULL) {
return 1;
}
if (!bAudPlaying) {
return 1;
}
UINT32 nPadding = 0;
HRESULT hr = pAudioClient->GetCurrentPadding(&nPadding);
if (FAILED(hr)) {
if (hr == AUDCLNT_E_DEVICE_INVALIDATED || hr == AUDCLNT_E_RESOURCES_INVALIDATED) {
WasapiDeviceLost();
}
return 1;
}
INT32 nFree = (INT32)nTargetFrames - (INT32)nPadding;
if (nFree < nAudSegLen) {
// Buffer is full enough - wait for the device to consume some
if (bEventDriven) {
// Event fires once per device period (~10ms); bail out after a while so the UI stays responsive
DWORD nWait = WaitForSingleObject(hWasapiEvent, 200);
#ifdef PRINT_DEBUG_INFO
if (nWait == WAIT_TIMEOUT) {
bprintf(0, _T("*** WASAPI playback notification timeout.\n"));
}
#else
(void)nWait;
#endif
} else {
Sleep(1);
}
return 0;
}
INT32 nSegs = nFree / nAudSegLen;
bBlanked = false;
for (INT32 i = 0; i < nSegs; i++) {
// get more sound into nAudNextSound
WasapiGetNextSound((i == nSegs - 1) || bAlwaysDrawFrames); // If this is the last seg of sound, draw the graphics (frameskipping)
if (nAudNextSound == NULL || pRenderClient == NULL) {
// sound was shut down from inside the callback
return 1;
}
if (nAudDSPModule[WASAPI_PLUGIN] & 1) {
if (bRunPause)
AudWriteSilence();
else
DspDo(nAudNextSound, nAudSegLen);
}
hr = WasapiWriteSeg();
if (FAILED(hr)) {
if (hr == AUDCLNT_E_DEVICE_INVALIDATED || hr == AUDCLNT_E_RESOURCES_INVALIDATED) {
WasapiDeviceLost();
}
// AUDCLNT_E_BUFFER_TOO_LARGE: the callback blanked/refilled the buffer, just drop this seg
return 0;
}
if (bBlanked) {
// buffer was flushed & re-primed from inside the callback (frame step etc.), start over
bBlanked = false;
break;
}
}
return 0;
}
static int WasapiExit()
{
DspExit();
WasapiReleaseStream();
if (hWasapiEvent) {
CloseHandle(hWasapiEvent);
hWasapiEvent = NULL;
}
if (nAudNextSound) {
free(nAudNextSound);
nAudNextSound = NULL;
}
WasapiGetNextSound = NULL;
bDeviceLost = false;
nBufferFrames = 0;
nTargetFrames = 0;
szDeviceName[0] = 0;
return 0;
}
static int WasapiInit()
{
if (nAudSampleRate[WASAPI_PLUGIN] <= 0) {
return 1;
}
if (FAILED(nCOMInit)) {
return 1;
}
nWasapiFps = nAppVirtualFps;
// Calculate the Seg Length (round to nearest sample)
nAudSegLen = (nAudSampleRate[WASAPI_PLUGIN] * 100 + (nWasapiFps >> 1)) / nWasapiFps;
nAudAllocSegLen = nAudSegLen << 2;
bDeviceLost = false;
bStreamStarted = false;
hWasapiEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset
if (hWasapiEvent == NULL) {
return 1;
}
if (WasapiOpenStream()) {
WasapiExit();
return 1;
}
// Note: +2 is a hacky work-around for crashy Midway games (mk2, etc) via Kaillera (same as DirectSound)
nAudNextSound = (INT16*)malloc(nAudSegLen << (2 + 2)); // The next sound block to put in the stream
if (nAudNextSound == NULL) {
WasapiExit();
return 1;
}
AudWriteSilence();
WasapiSetCallback(NULL);
DspInit();
return 0;
}
static int WasapiPlay()
{
if (bDeviceLost) {
// will be started when the device comes back
WasapiSetVolume();
return 0;
}
if (pAudioClient == NULL) {
return 1;
}
if (nAudNextSound) {
AudWriteSilence();
}
WasapiSetVolume();
if (bStreamStarted) {
pAudioClient->Stop();
bStreamStarted = false;
}
pAudioClient->Reset();
if (WasapiStartStream()) {
return 1;
}
return 0;
}
static int WasapiStop()
{
if (!bAudOkay) {
return 1;
}
if (pAudioClient && bStreamStarted) {
pAudioClient->Stop();
pAudioClient->Reset();
}
bStreamStarted = false;
return 0;
}
static int WasapiSetVolume()
{
// Same curve as the XAudio2 plugin, volume > 100% is allowed (samples are clipped)
if (nAudVolume == 10000) {
fWasapiVol = 1.0f;
} else if (nAudVolume <= 0) {
fWasapiVol = 0.0f;
} else {
fWasapiVol = (float)(((double)nAudVolume / 10000) * ((double)nAudVolume / 10000));
}
return 1; // 1 succeeds here (as XAudio2).
}
static int WasapiGetSettings(InterfaceInfo* pInfo)
{
TCHAR szString[MAX_PATH] = _T("");
if (bDeviceLost) {
_sntprintf(szString, MAX_PATH, _T("Audio device lost, waiting for it to return"));
IntInfoAddStringModule(pInfo, szString);
return 0;
}
if (szDeviceName[0]) {
_sntprintf(szString, MAX_PATH, _T("Device: %s"), szDeviceName);
IntInfoAddStringModule(pInfo, szString);
}
_sntprintf(szString, MAX_PATH, _T("Shared mode, %s, %s"),
bEventDriven ? _T("event driven") : _T("polled"),
bAutoConvert ? _T("converted by Windows") : _T("converted to device mix format"));
IntInfoAddStringModule(pInfo, szString);
if (nAudSampleRate[WASAPI_PLUGIN] > 0) {
_sntprintf(szString, MAX_PATH, _T("Audio is delayed by approx. %ims (device buffer %ims)"),
(int)((INT64)nTargetFrames * 1000 / nAudSampleRate[WASAPI_PLUGIN]),
(int)((INT64)nBufferFrames * 1000 / nAudSampleRate[WASAPI_PLUGIN]));
IntInfoAddStringModule(pInfo, szString);
}
return 0;
}
struct AudOut AudOutWASAPI = { WasapiBlankSound, WasapiSoundCheck, WasapiInit, WasapiSetCallback, WasapiPlay, WasapiStop, WasapiExit, WasapiSetVolume, WasapiGetSettings, _T("WASAPI audio output") };
+63
View File
@@ -0,0 +1,63 @@
// Headless input for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// Reads a digital switch state table populated by the host via
// FBHeadlessSetInputState(). InputMake() calls ReadSwitch() while building each
// frame's GameInp. Subject to the FB Neo license (see src/license.txt).
#include "burner.h"
#include "fbheadless.h"
// Indexed by FBNeo input switch code (masked); 0 = released, non-zero = pressed.
#define HEADLESS_INPUT_TABLE_SIZE 0x200
static unsigned char inputState[HEADLESS_INPUT_TABLE_SIZE];
static int HeadlessInpInit()
{
memset(inputState, 0, sizeof(inputState));
bInputOkay = 1;
return 0;
}
static int HeadlessInpExit()
{
bInputOkay = 0;
return 0;
}
static int HeadlessInpSetCooperativeLevel(bool /* bExclusive */, bool /* bForeground */) { return 0; }
static int HeadlessInpNewFrame() { return 0; }
static int HeadlessInpReadSwitch(int nCode)
{
return inputState[nCode & (HEADLESS_INPUT_TABLE_SIZE - 1)] ? 1 : 0;
}
static int HeadlessInpReadJoyAxis(int /* i */, int /* nAxis */) { return 0; }
static int HeadlessInpReadMouseAxis(int /* i */, int /* nAxis */) { return 0; }
static int HeadlessInpFind(bool /* createBaseline */) { return -1; }
static int HeadlessInpGetControlName(int /* nCode */, TCHAR * /* dev */, TCHAR * /* ctrl */) { return 0; }
static int HeadlessInpGetSettings(InterfaceInfo *) { return 0; }
struct InputInOut InputInOutHeadless = {
HeadlessInpInit,
HeadlessInpExit,
HeadlessInpSetCooperativeLevel,
HeadlessInpNewFrame,
HeadlessInpReadSwitch,
HeadlessInpReadJoyAxis,
HeadlessInpReadMouseAxis,
HeadlessInpFind,
HeadlessInpGetControlName,
HeadlessInpGetSettings,
_T("Headless input"),
};
extern "C" void FBHeadlessSetInputState(int code, int value)
{
inputState[code & (HEADLESS_INPUT_TABLE_SIZE - 1)] = value ? 1 : 0;
}
+4
View File
@@ -16,6 +16,8 @@ static bool bCinpOkay;
extern struct InputInOut InputInOutXInput;
#elif defined (BUILD_MACOS)
extern struct InputInOut InputInOutMacOS;
#elif defined (BUILD_HEADLESS)
extern struct InputInOut InputInOutHeadless;
#elif defined (BUILD_SDL)
extern struct InputInOut InputInOutSDL;
#elif defined (BUILD_SDL2)
@@ -33,6 +35,8 @@ static struct InputInOut *pInputInOut[]=
&InputInOutXInput,
#elif defined (BUILD_MACOS)
&InputInOutMacOS,
#elif defined (BUILD_HEADLESS)
&InputInOutHeadless,
#elif defined (BUILD_SDL2)
&InputInOutSDL2,
#elif defined (BUILD_SDL)
+1
View File
@@ -241,6 +241,7 @@ extern INT64 nVidBlitterOpt[];
extern INT32 bVidFullStretch;
extern INT32 bVidTripleBuffer;
extern INT32 bVidVSync;
extern INT32 bVidVRR;
extern double dVidCubicB;
extern double dVidCubicC;
extern INT32 bVidDX9Bilinear;
+192
View File
@@ -0,0 +1,192 @@
// Headless video output for FinalBurn Neo.
// Author: Leonardo Kasperavičius
//
// Adapted from the macOS video interface by Akop Karapetyan
// https://github.com/0xe1f/FinalBurn-X (Apache License 2.0)
//
// Built originally to support OpenEmu-Silicon
// (https://github.com/OpenEmu-Silicon/OpenEmu-Silicon).
//
// FBNeo renders every game in its native orientation (vertical games come out
// sideways), so this keeps a native render buffer for the emulator and presents
// an upright, correctly-pitched buffer to the host, rotating when needed.
// Subject to the FB Neo license (see src/license.txt).
#include "burner.h"
#include "fbheadless.h"
static unsigned char *nativeBuffer = NULL; // FBNeo renders here (pBurnDraw), nativeBpp deep
static unsigned char *displayBuffer = NULL; // exposed to the host, always 32bpp upright
static int nativeW = 0, nativeH = 0;
static int dispW = 0, dispH = 0;
static int nativeBpp = 0; // FBNeo render depth in bytes: 2 (BDF_16BIT_ONLY) or 4
static int rotate = 0; // 0 none, 1 CW90, 2 180, 3 CCW90
static void freeBuffers()
{
if (displayBuffer && displayBuffer != nativeBuffer)
free(displayBuffer);
free(nativeBuffer);
nativeBuffer = NULL;
displayBuffer = NULL;
}
static int HeadlessVideoInit()
{
int vw = 0, vh = 0;
int flags = BurnDrvGetFlags();
BurnDrvGetVisibleSize(&vw, &vh);
// Some drivers (Cave, CPS3, Megadrive) are BDF_16BIT_ONLY: their blitters only
// write RGB565, so render those at 16bpp and convert to 32bpp on present. All
// others render straight 32bpp XRGB8888, which the host consumes directly.
if (flags & BDF_16BIT_ONLY) {
nativeBpp = 2;
nVidImageDepth = 16;
} else {
nativeBpp = 4;
nVidImageDepth = 32;
}
nVidImageBPP = nativeBpp;
SetBurnHighCol(nVidImageDepth);
if (flags & BDF_ORIENTATION_VERTICAL) {
// Visible size is the upright (display) size; FBNeo renders it sideways.
nativeW = vh; nativeH = vw;
dispW = vw; dispH = vh;
rotate = (flags & BDF_ORIENTATION_FLIPPED) ? 1 : 3; // CW : CCW
} else {
nativeW = vw; nativeH = vh;
dispW = vw; dispH = vh;
rotate = (flags & BDF_ORIENTATION_FLIPPED) ? 2 : 0; // 180 : none
}
freeBuffers();
nativeBuffer = (unsigned char *)malloc(nativeW * nativeH * nativeBpp);
if (nativeBuffer == NULL)
return 1;
memset(nativeBuffer, 0, nativeW * nativeH * nativeBpp);
// The host always receives 32bpp. Zero-copy only when FBNeo already renders
// 32bpp AND upright; otherwise present() fills a dedicated 32bpp buffer
// (converting 16->32 and/or rotating).
if (nativeBpp == 4 && rotate == 0) {
displayBuffer = nativeBuffer;
} else {
displayBuffer = (unsigned char *)malloc(dispW * dispH * 4);
if (displayBuffer == NULL)
return 1;
memset(displayBuffer, 0, dispW * dispH * 4);
}
// FBNeo draws into the native buffer, pitch = native width.
nVidImageWidth = nativeW;
nVidImageHeight = nativeH;
nVidImagePitch = nativeW * nativeBpp;
nBurnBpp = nativeBpp;
nBurnPitch = nativeW * nativeBpp;
pVidImage = nativeBuffer;
return 0;
}
static int HeadlessVideoExit()
{
freeBuffers();
nativeW = nativeH = dispW = dispH = nativeBpp = rotate = 0;
return 0;
}
// RGB565 -> 0x00RRGGBB, matching SetBurnHighCol(32)'s component order.
static inline uint32_t rgb565_to_xrgb8888(uint16_t p)
{
uint32_t r = (p >> 11) & 0x1F;
uint32_t g = (p >> 5) & 0x3F;
uint32_t b = p & 0x1F;
r = (r << 3) | (r >> 2);
g = (g << 2) | (g >> 4);
b = (b << 3) | (b >> 2);
return (r << 16) | (g << 8) | b;
}
// Map a display pixel (dx,dy) back to its native-buffer coordinate for the
// current rotation. Native/display dims are swapped for the 90-degree cases.
static inline void src_coord(int dx, int dy, int *sx, int *sy)
{
switch (rotate) {
case 1: *sx = dy; *sy = nativeH - 1 - dx; break; // CW 90
case 3: *sx = nativeW - 1 - dy; *sy = dx; break; // CCW 90
case 2: *sx = dispW - 1 - dx; *sy = dispH - 1 - dy; break; // 180
default: *sx = dx; *sy = dy; break; // none
}
}
// Present the freshly rendered native frame to the host: convert 16->32bpp for
// BDF_16BIT_ONLY drivers and/or rotate vertical games upright. Called by the
// frontend after BurnDrvFrame. The zero-copy case (32bpp, upright) is a no-op.
void headless_video_present(void)
{
if (displayBuffer == nativeBuffer)
return;
uint32_t *dst = (uint32_t *)displayBuffer;
if (nativeBpp == 2) {
const uint16_t *src = (const uint16_t *)nativeBuffer;
for (int dy = 0; dy < dispH; dy++)
for (int dx = 0; dx < dispW; dx++) {
int sx, sy;
src_coord(dx, dy, &sx, &sy);
dst[dy * dispW + dx] = rgb565_to_xrgb8888(src[sy * nativeW + sx]);
}
} else {
const uint32_t *src = (const uint32_t *)nativeBuffer;
for (int dy = 0; dy < dispH; dy++)
for (int dx = 0; dx < dispW; dx++) {
int sx, sy;
src_coord(dx, dy, &sx, &sy);
dst[dy * dispW + dx] = src[sy * nativeW + sx];
}
}
}
static int HeadlessVideoFrame(bool redraw)
{
if (pVidImage == NULL || bRunPause)
return 0;
VidFrameCallback(redraw);
return 0;
}
static int HeadlessVideoPaint(int /* validate */)
{
return 0;
}
static int HeadlessVideoScale(RECT *, int, int)
{
return 0;
}
static int HeadlessVideoGetSettings(InterfaceInfo *)
{
return 0;
}
struct VidOut VidOutHeadless = {
HeadlessVideoInit,
HeadlessVideoExit,
HeadlessVideoFrame,
HeadlessVideoPaint,
HeadlessVideoScale,
HeadlessVideoGetSettings,
_T("Headless Video"),
};
// --- C accessors for the host wrapper ---
extern "C" const unsigned char *FBHeadlessGetVideoBuffer(void) { return displayBuffer; }
extern "C" int FBHeadlessGetVideoWidth(void) { return dispW; }
extern "C" int FBHeadlessGetVideoHeight(void) { return dispH; }
extern "C" int FBHeadlessGetVideoPitch(void) { return dispW * 4; }
extern "C" int FBHeadlessGetVideoBPP(void) { return 4; }
+5
View File
@@ -15,6 +15,8 @@
extern struct VidOut VidOutD3D11;
#elif defined (BUILD_MACOS)
extern struct VidOut VidOutMacOS;
#elif defined (BUILD_HEADLESS)
extern struct VidOut VidOutHeadless;
#elif defined (BUILD_PI)
extern struct VidOut VidOutPi;
#elif defined (BUILD_SDL2)
@@ -39,6 +41,8 @@ static struct VidOut *pVidOut[] = {
&VidOutD3D11,
#elif defined (BUILD_MACOS)
&VidOutMacOS,
#elif defined (BUILD_HEADLESS)
&VidOutHeadless,
#elif defined (BUILD_PI)
&VidOutPi,
#elif defined (BUILD_SDL2)
@@ -86,6 +90,7 @@ INT32 bVidFullStretch = 0; // 1 = stretch to fill the entire window/screen
INT32 bVidCorrectAspect = 1; // 1 = stretch to fill the window/screen while maintaining the correct aspect ratio
INT32 bVidIntegerScale = 0; // Wants integer scaling
INT32 bVidVSync = 0; // 1 = sync blits/pageflips/presents to the screen
INT32 bVidVRR = 0; // 1 = variable refresh rate (G-Sync/FreeSync), DX11 blitter only
INT32 bVidTripleBuffer = 0; // 1 = use triple buffering
INT32 bVidBilinear = 1; // 1 = enable bi-linear filtering (D3D blitter)
INT32 bVidScanlines = 0; // 1 = draw scanlines
+42 -2
View File
@@ -53,6 +53,7 @@
static const GUID FBNEO_IID_IDXGIDevice = { 0x54ec77fa, 0x1377, 0x44e6, { 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c } };
static const GUID FBNEO_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } };
static const GUID FBNEO_IID_IDXGIFactory = { 0x7b7166ec, 0x21c7, 0x44ae, { 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69 } };
static const GUID FBNEO_IID_IDXGIFactory5 = { 0x7632e1f5, 0xee65, 0x4dca, { 0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d } };
static const GUID FBNEO_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } };
// ID3D11ShaderReflection changed IID between d3dcompiler versions
static const GUID FBNEO_IID_ID3D11ShaderReflection_47 = { 0x8d536ca1, 0x0cca, 0x4956, { 0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84 } };
@@ -61,6 +62,9 @@ static const GUID FBNEO_IID_ID3D11ShaderReflection_43 = { 0x0a233719, 0x3960, 0x
// DXGI values that older headers may not have
#define FBNEO_DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL ((DXGI_SWAP_EFFECT)3)
#define FBNEO_DXGI_SWAP_EFFECT_FLIP_DISCARD ((DXGI_SWAP_EFFECT)4)
#define FBNEO_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING 0x800
#define FBNEO_DXGI_PRESENT_ALLOW_TEARING 0x200
#define FBNEO_DXGI_FEATURE_PRESENT_ALLOW_TEARING 0
// ----------------------------------------------------------------------------
// Runtime-loaded DLLs
@@ -165,6 +169,7 @@ static ID3D11RenderTargetView* pRenderTarget = NULL;
static D3D_FEATURE_LEVEL nFeatureLevel = D3D_FEATURE_LEVEL_9_1;
static bool bWarpDevice = false;
static DXGI_SWAP_EFFECT nSwapEffect = DXGI_SWAP_EFFECT_DISCARD;
static UINT nSwapChainFlags = 0;
static UINT nSwapChainWidth = 0, nSwapChainHeight = 0;
static UINT nDeviceGeneration = 0; // bumped every time a device is created (OSD textures follow it)
static bool bDeviceLost = false;
@@ -2579,7 +2584,7 @@ static int d3d11ResizeSwapChain(UINT nWidth, UINT nHeight)
pContext->OMSetRenderTargets(0, NULL, NULL);
D3D11_RELEASE(pRenderTarget);
if (FAILED(pSwapChain->ResizeBuffers(0, nWidth, nHeight, DXGI_FORMAT_UNKNOWN, 0))) {
if (FAILED(pSwapChain->ResizeBuffers(0, nWidth, nHeight, DXGI_FORMAT_UNKNOWN, nSwapChainFlags))) {
return 1;
}
@@ -2589,6 +2594,27 @@ static int d3d11ResizeSwapChain(UINT nWidth, UINT nHeight)
return d3d11CreateRenderTarget();
}
// IDXGIFactory5::CheckFeatureSupport() is called through the vtable, so no DXGI 1.5 headers are needed
static bool d3d11TearingSupported(IDXGIFactory* pFactory)
{
typedef HRESULT (STDMETHODCALLTYPE* pfnCheckFeatureSupport)(void*, UINT, void*, UINT);
void* pFactory5 = NULL;
BOOL bAllowTearing = FALSE;
if (FAILED(pFactory->QueryInterface(FBNEO_IID_IDXGIFactory5, &pFactory5))) {
return false;
}
pfnCheckFeatureSupport pCheckFeatureSupport = (pfnCheckFeatureSupport)((*(void***)pFactory5)[28]);
if (FAILED(pCheckFeatureSupport(pFactory5, FBNEO_DXGI_FEATURE_PRESENT_ALLOW_TEARING, &bAllowTearing, sizeof(bAllowTearing)))) {
bAllowTearing = FALSE;
}
((IUnknown*)pFactory5)->Release();
return bAllowTearing != FALSE;
}
static int d3d11CreateSwapChain()
{
IDXGIDevice* pDXGIDevice = NULL;
@@ -2613,6 +2639,9 @@ static int d3d11CreateSwapChain()
nSwapChainWidth = (rect.right > 0) ? rect.right : 1;
nSwapChainHeight = (rect.bottom > 0) ? rect.bottom : 1;
bool bTearing = bVidVRR && d3d11TearingSupported(pFactory);
nSwapChainFlags = 0;
// Prefer the flip model (Win10: FLIP_DISCARD, Win8: FLIP_SEQUENTIAL), fall back to the blt model (Win7)
static const DXGI_SWAP_EFFECT SwapEffects[] = { FBNEO_DXGI_SWAP_EFFECT_FLIP_DISCARD, FBNEO_DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_SWAP_EFFECT_DISCARD };
@@ -2630,9 +2659,11 @@ static int d3d11CreateSwapChain()
scd.OutputWindow = hD3D11View;
scd.Windowed = TRUE;
scd.SwapEffect = SwapEffects[i];
scd.Flags = (bFlip && bTearing) ? FBNEO_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
if (SUCCEEDED(pFactory->CreateSwapChain(pDevice, &scd, &pSwapChain))) {
nSwapEffect = SwapEffects[i];
nSwapChainFlags = scd.Flags;
} else {
pSwapChain = NULL;
}
@@ -3447,7 +3478,10 @@ static int d3d11Paint(int bValidate)
return 1;
}
HRESULT hr = pSwapChain->Present(bVidVSync ? 1 : 0, 0);
UINT nSyncInterval = (bVidVSync && !EmulatorAppIsFast()) ? 1 : 0;
// VRR: present immediately, the display follows our own frame pacing
UINT nPresentFlags = (nSyncInterval == 0 && (nSwapChainFlags & FBNEO_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)) ? FBNEO_DXGI_PRESENT_ALLOW_TEARING : 0;
HRESULT hr = pSwapChain->Present(nSyncInterval, nPresentFlags);
bInPaint = false;
@@ -3489,6 +3523,12 @@ static int d3d11GetSettings(InterfaceInfo* pInfo)
IntInfoAddStringModule(pInfo, _T("Using a flip-model swap chain"));
}
if (nSwapChainFlags & FBNEO_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) {
IntInfoAddStringModule(pInfo, _T("Variable refresh rate (tearing) presents enabled"));
} else if (bVidVRR) {
IntInfoAddStringModule(pInfo, _T("Variable refresh rate requested, but not supported"));
}
if (nVidFullscreen) {
if (bChangedDisplayMode) {
_sntprintf(szString, MAX_PATH, _T("Fullscreen (%i x %i, display mode changed)"), nVidScrnWidth, nVidScrnHeight);