build fixes for mac

This commit is contained in:
Ian Curtis 2020-07-27 10:28:48 +00:00
parent 858b84f424
commit 5e434e2644
19 changed files with 538 additions and 319 deletions

View file

@ -1,18 +1,13 @@
#
# TODO: MacOS port is probably broken. Someone with MacOS needs to figure out
# how to compile with SDL2.
#
## ##
## Supermodel ## Supermodel
## A Sega Model 3 Arcade Emulator. ## A Sega Model 3 Arcade Emulator.
## Copyright 2011-2017 Bart Trzynadlowski, Nik Henson, Ian Curtis ## Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
## Harry Tuttle, and Spindizzi
## ##
## This file is part of Supermodel. ## This file is part of Supermodel.
## ##
## Supermodel is free software: you can redistribute it and/or modify it under ## Supermodel is free software: you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free ## the terms of the GNU General Public License as published by the Free
## Software Foundation, either version 3 of the License, or (at your option) ## Software Foundation, either version 3 of the License, or (at your option)
## any later version. ## any later version.
## ##
@ -28,7 +23,7 @@
# #
# Makefile.OSX # Makefile.OSX
# #
# Makefile for Mac OS X systems using gcc. # Makefile for Mac OS X systems using clang.
# #
@ -45,25 +40,33 @@ DELETE = rm -d -r -f
# Edit library and include paths as needed. # Edit library and include paths as needed.
############################################################################### ###############################################################################
#
# Must be included first
#
include Makefiles/Options.inc
# #
# Toolchain # Toolchain
# #
CC = gcc CC = clang
CXX = g++ CXX = clang
LD = gcc LD = clang
# #
# SDL # SDL
# #
SDL_CFLAGS = SDL_CFLAGS =
SDL_LIBS = -framework SDL2 -framework AGL -framework OpenGL -framework GLUT -framework Cocoa SDL_LIBS = -framework SDL2 -framework AGL -framework OpenGL -framework GLUT -framework Cocoa
ifeq ($(strip $(NET_BOARD)),1)
SDL_LIBS += -framework SDL2_net
endif
# #
# OSX-specific # OSX-specific
# #
PLATFORM_CFLAGS = $(SDL_CFLAGS) -DSUPERMODEL_OSX -DUSE_FILE32API -F/Library/Frameworks/ PLATFORM_CFLAGS = $(SDL_CFLAGS) -DSUPERMODEL_OSX -F/Library/Frameworks/
PLATFORM_LDFLAGS = $(SDL_LIBS) -lz -lm -lstdc++ -F/Library/Frameworks/ PLATFORM_LDFLAGS = $(SDL_LIBS) -lz -lm -lstdc++ -F/Library/Frameworks/
@ -71,9 +74,9 @@ PLATFORM_LDFLAGS = $(SDL_LIBS) -lz -lm -lstdc++ -F/Library/Frameworks/
# Core Makefile # Core Makefile
############################################################################### ###############################################################################
include Makefiles/Makefile.inc include Makefiles/Rules.inc
clean: clean:
$(SILENT)echo Cleaning up \"$(BIN_DIR)\" and \"$(OBJ_DIR)\"... $(SILENT)echo Cleaning up \"$(BIN_DIR)\" and \"$(OBJ_DIR)\"...
$(SILENT)$(DELETE) $(BIN_DIR) $(SILENT)$(DELETE) $(BIN_DIR)
$(SILENT)$(DELETE) $(OBJ_DIR) $(SILENT)$(DELETE) $(OBJ_DIR)

View file

@ -1,12 +1,13 @@
## ##
## Supermodel ## Supermodel
## A Sega Model 3 Arcade Emulator. ## A Sega Model 3 Arcade Emulator.
## Copyright 2011-2017 Bart Trzynadlowski, Nik Henson, Ian Curtis ## Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
## Harry Tuttle, and Spindizzi
## ##
## This file is part of Supermodel. ## This file is part of Supermodel.
## ##
## Supermodel is free software: you can redistribute it and/or modify it under ## Supermodel is free software: you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free ## the terms of the GNU General Public License as published by the Free
## Software Foundation, either version 3 of the License, or (at your option) ## Software Foundation, either version 3 of the License, or (at your option)
## any later version. ## any later version.
## ##
@ -39,6 +40,11 @@ DELETE = rm -d -r -f
# Edit library and include paths as needed. # Edit library and include paths as needed.
############################################################################### ###############################################################################
#
# Must be included first
#
include Makefiles/Options.inc
# #
# Toolchain # Toolchain
# #
@ -65,7 +71,7 @@ PLATFORM_LDFLAGS = $(SDL2_LIBS) -lGL -lGLU -lz -lm -lstdc++ -lpthread -lSDL2_net
# Core Makefile # Core Makefile
############################################################################### ###############################################################################
include Makefiles/Makefile.inc include Makefiles/Rules.inc
clean: clean:
$(SILENT)echo Cleaning up \"$(BIN_DIR)\" and \"$(OBJ_DIR)\"... $(SILENT)echo Cleaning up \"$(BIN_DIR)\" and \"$(OBJ_DIR)\"...

View file

@ -1,12 +1,13 @@
## ##
## Supermodel ## Supermodel
## A Sega Model 3 Arcade Emulator. ## A Sega Model 3 Arcade Emulator.
## Copyright 2011-2017 Bart Trzynadlowski, Nik Henson, Ian Curtis ## Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
## Harry Tuttle, and Spindizzi
## ##
## This file is part of Supermodel. ## This file is part of Supermodel.
## ##
## Supermodel is free software: you can redistribute it and/or modify it under ## Supermodel is free software: you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free ## the terms of the GNU General Public License as published by the Free
## Software Foundation, either version 3 of the License, or (at your option) ## Software Foundation, either version 3 of the License, or (at your option)
## any later version. ## any later version.
## ##
@ -36,6 +37,11 @@
# section as well, namely SDL2_LIBS and PLATFORM_LIBS. # section as well, namely SDL2_LIBS and PLATFORM_LIBS.
############################################################################### ###############################################################################
#
# Must be included first
#
include Makefiles/Options.inc
# #
# Bitness of build ('32' or '64') # Bitness of build ('32' or '64')
# #
@ -44,15 +50,12 @@ BITS = 64
# #
# Path to SDL2 # Path to SDL2
# #
SDL2_INCLUDE_DIR = c:/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/SDL2 SDL2_INCLUDE_DIR = C:\TDM-GCC-64\x86_64-w64-mingw32\include\SDL2
SDL2_LIB_DIR = c:/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/lib SDL2_LIB_DIR = C:\TDM-GCC-64\x86_64-w64-mingw32\lib
#SDL2_INCLUDE_DIR = $(MINGW)/include/SDL2
#SDL2_LIB_DIR = $(MINGW)/lib
# #
# Toolchain # Toolchain
# #
CC = gcc CC = gcc
CXX = g++ CXX = g++
LD = g++ LD = g++
@ -78,8 +81,11 @@ endif
# #
# SDL2 # SDL2
# #
SDL2_LIBS = -lmingw32 -lSDL2main -lSDL2 -luser32 -lgdi32 -lwinmm -limm32 -lversion -lsetupapi -lsdl2_net -liphlpapi SDL2_LIBS = -lmingw32 -lSDL2main -lSDL2 -luser32 -lgdi32 -lwinmm -limm32 -lversion -lsetupapi -liphlpapi
SDL2_CFLAGS = SDL2_CFLAGS =
ifeq ($(strip $(NET_BOARD)),1)
SDL2_LIBS += -lSDL2_net
endif
# #
# MinGW/Windows-specific # MinGW/Windows-specific
@ -100,9 +106,9 @@ PLATFORM_SRC_FILES = \
Src/OSD/Windows/DirectInputSystem.cpp \ Src/OSD/Windows/DirectInputSystem.cpp \
Src/OSD/Windows/WinOutputs.cpp Src/OSD/Windows/WinOutputs.cpp
include Makefiles/Makefile.inc include Makefiles/Rules.inc
clean: clean:
$(SILENT)echo Cleaning up $(BIN_DIR) and $(OBJ_DIR)... $(SILENT)echo Cleaning up $(BIN_DIR) and $(OBJ_DIR)...
$(SILENT)$(DELETE) $(BIN_DIR) $(SILENT)$(DELETE) $(BIN_DIR)
$(SILENT)$(DELETE) $(OBJ_DIR) $(SILENT)$(DELETE) $(OBJ_DIR)

76
Makefiles/Options.inc Normal file
View file

@ -0,0 +1,76 @@
##
## Supermodel
## A Sega Model 3 Arcade Emulator.
## Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
## Harry Tuttle, and Spindizzi
##
## This file is part of Supermodel.
##
## Supermodel is free software: you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free
## Software Foundation, either version 3 of the License, or (at your option)
## any later version.
##
## Supermodel is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
## more details.
##
## You should have received a copy of the GNU General Public License along
## with Supermodel. If not, see <http://www.gnu.org/licenses/>.
##
#
# Options.inc
#
# Build options.
#
###############################################################################
# Build Options
###############################################################################
#
# Verbose progression
#
VERBOSE =
ifneq ($(filter $(strip $(VERBOSE)),0 1),$(strip $(VERBOSE)))
override VERBOSE =
endif
SILENT = @
ifeq ($(strip $(VERBOSE)),1)
SILENT =
endif
#
# Enable render state analyser for the legacy 3D engine (will slow down emulation!)
#
DEBUG =
ifneq ($(filter $(strip $(DEBUG)),0 1),$(strip $(DEBUG)))
override DEBUG =
endif
#
# Enable support for Model3 Net Board emulation
#
NET_BOARD =
ifneq ($(filter $(strip $(NET_BOARD)),0 1),$(strip $(NET_BOARD)))
override NET_BOARD =
endif
#
# Enable Bart's new (experimental) Real3D frame timing
#
NEW_FRAME_TIMING =
ifneq ($(filter $(strip $(NEW_FRAME_TIMING)),0 1),$(strip $(NEW_FRAME_TIMING)))
override NEW_FRAME_TIMING =
endif
#
# Include console-based debugger in emulator ('yes' or 'no')
#
ENABLE_DEBUGGER =
ifneq ($(filter $(strip $(ENABLE_DEBUGGER)),0 1),$(strip $(ENABLE_DEBUGGER)))
override ENABLE_DEBUGGER =
endif

View file

@ -1,12 +1,13 @@
## ##
## Supermodel ## Supermodel
## A Sega Model 3 Arcade Emulator. ## A Sega Model 3 Arcade Emulator.
## Copyright 2011-2017 Bart Trzynadlowski, Nik Henson, Ian Curtis ## Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
## Harry Tuttle, and Spindizzi
## ##
## This file is part of Supermodel. ## This file is part of Supermodel.
## ##
## Supermodel is free software: you can redistribute it and/or modify it under ## Supermodel is free software: you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free ## the terms of the GNU General Public License as published by the Free
## Software Foundation, either version 3 of the License, or (at your option) ## Software Foundation, either version 3 of the License, or (at your option)
## any later version. ## any later version.
## ##
@ -20,61 +21,12 @@
## ##
# #
# Makefile.inc # Rules.inc
# #
# Core GNU Makefile, included by all (platform-specific) top-level Makefiles. # Build rules, included by all (platform-specific) top-level Makefiles.
# #
###############################################################################
# Build Options
###############################################################################
#
# Verbose progression
#
VERBOSE =
ifneq ($(filter $(strip $(VERBOSE)),0 1),$(strip $(VERBOSE)))
override VERBOSE =
endif
SILENT = @
ifeq ($(strip $(VERBOSE)),1)
SILENT =
endif
#
# Enable render state analyser for the legacy 3D engine (will slow down emulation!)
#
DEBUG =
ifneq ($(filter $(strip $(DEBUG)),0 1),$(strip $(DEBUG)))
override DEBUG =
endif
#
# Enable support for Model3 Net Board emulation
#
NET_BOARD =
ifneq ($(filter $(strip $(NET_BOARD)),0 1),$(strip $(NET_BOARD)))
override NET_BOARD =
endif
#
# Enable Bart's new (experimental) Real3D frame timing
#
NEW_FRAME_TIMING =
ifneq ($(filter $(strip $(NEW_FRAME_TIMING)),0 1),$(strip $(NEW_FRAME_TIMING)))
override NEW_FRAME_TIMING =
endif
#
# Include console-based debugger in emulator ('yes' or 'no')
#
ENABLE_DEBUGGER =
ifneq ($(filter $(strip $(ENABLE_DEBUGGER)),0 1),$(strip $(ENABLE_DEBUGGER)))
override ENABLE_DEBUGGER =
endif
############################################################################### ###############################################################################
# Source Files # Source Files
############################################################################### ###############################################################################
@ -185,7 +137,7 @@ endif
OBJ_FILES = $(foreach file,$(SRC_FILES),$(OBJ_DIR)/$(basename $(notdir $(file))).o) OBJ_FILES = $(foreach file,$(SRC_FILES),$(OBJ_DIR)/$(basename $(notdir $(file))).o)
# #
# Deduce include directories from the source file list. The sort function # Deduce include directories from the source file list. The sort function
# removes duplicates and is used to construct a set. # removes duplicates and is used to construct a set.
# #
INCLUDE_DIRS = $(sort $(foreach file,$(SRC_FILES),$(dir $(file)))) INCLUDE_DIRS = $(sort $(foreach file,$(SRC_FILES),$(dir $(file))))
@ -243,7 +195,7 @@ endif
# Targets # Targets
############################################################################### ###############################################################################
# #
# Default target: build Supermodel binary. Must be specified *before* the auto- # Default target: build Supermodel binary. Must be specified *before* the auto-
# generated dependencies because otherwise, make gets confused for some reason # generated dependencies because otherwise, make gets confused for some reason
# and thinks the default target is just one of the object files. # and thinks the default target is just one of the object files.
@ -258,7 +210,7 @@ $(BIN_DIR)/$(OUTFILE): $(BIN_DIR) $(OBJ_DIR) $(OBJ_FILES)
$(BIN_DIR): $(BIN_DIR):
$(info Creating directory : $(BIN_DIR)) $(info Creating directory : $(BIN_DIR))
$(SILENT)mkdir $(BIN_DIR) $(SILENT)mkdir $(BIN_DIR)
$(OBJ_DIR): $(OBJ_DIR):
$(info Creating directory : $(OBJ_DIR)) $(info Creating directory : $(OBJ_DIR))
@ -306,7 +258,7 @@ $(OBJ_DIR)/%.o: %.c
# All generated source files are emitted to the object directory. For MSVC, # All generated source files are emitted to the object directory. For MSVC,
# INLINE must be redefined as "static __inline", which is the syntax in C mode. # INLINE must be redefined as "static __inline", which is the syntax in C mode.
# #
# The .exe suffix is absolutely required for native Windows non-MSYS builds! # The .exe suffix is absolutely required for native Windows non-MSYS builds!
# #
MUSASHI_OUTFILE = $(OBJ_DIR)/m68kmake.exe # do not remove the .exe suffix! MUSASHI_OUTFILE = $(OBJ_DIR)/m68kmake.exe # do not remove the .exe suffix!
@ -323,23 +275,23 @@ $(MUSASHI_OUTFILE): Src/CPU/68K/Musashi/m68kmake.c Src/CPU/68K/Musashi/m68k_in.c
$(OBJ_DIR)/m68kops.h $(OBJ_DIR)/m68kops.c $(OBJ_DIR)/m68kopac.c $(OBJ_DIR)/m68kopdm.c $(OBJ_DIR)/m68kopnz.c: $(MUSASHI_OUTFILE) Src/CPU/68K/Musashi/m68k_in.c Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(OBJ_DIR)/m68kops.h $(OBJ_DIR)/m68kops.c $(OBJ_DIR)/m68kopac.c $(OBJ_DIR)/m68kopdm.c $(OBJ_DIR)/m68kopnz.c: $(MUSASHI_OUTFILE) Src/CPU/68K/Musashi/m68k_in.c Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h
$(info Generating 68K emulator: $@) $(info Generating 68K emulator: $@)
@$(MUSASHI_OUTFILE) $(OBJ_DIR) Src/CPU/68K/Musashi/m68k_in.c @$(MUSASHI_OUTFILE) $(OBJ_DIR) Src/CPU/68K/Musashi/m68k_in.c
$(OBJ_DIR)/m68kcpu.o: Src/CPU/68K/Musashi/m68kcpu.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(OBJ_DIR)/m68kcpu.o: Src/CPU/68K/Musashi/m68kcpu.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h
$(info Compiling : $< -> $@) $(info Compiling : $< -> $@)
@$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $(OBJ_DIR)/m68kcpu.o @$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $(OBJ_DIR)/m68kcpu.o
$(OBJ_DIR)/m68kops.o: $(OBJ_DIR)/m68kops.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE) $(OBJ_DIR)/m68kops.o: $(OBJ_DIR)/m68kops.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE)
$(info Compiling : $< -> $@) $(info Compiling : $< -> $@)
@$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@ @$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@
$(OBJ_DIR)/m68kopac.o: $(OBJ_DIR)/m68kopac.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE) $(OBJ_DIR)/m68kopac.o: $(OBJ_DIR)/m68kopac.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE)
$(info Compiling : $< -> $@) $(info Compiling : $< -> $@)
@$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@ @$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@
$(OBJ_DIR)/m68kopdm.o: $(OBJ_DIR)/m68kopdm.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE) $(OBJ_DIR)/m68kopdm.o: $(OBJ_DIR)/m68kopdm.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE)
$(info Compiling : $< -> $@) $(info Compiling : $< -> $@)
@$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@ @$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@
$(OBJ_DIR)/m68kopnz.o: $(OBJ_DIR)/m68kopnz.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE) $(OBJ_DIR)/m68kopnz.o: $(OBJ_DIR)/m68kopnz.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h $(MUSASHI_OUTFILE)
$(info Compiling : $< -> $@) $(info Compiling : $< -> $@)
@$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@ @$(CC) $< $(CFLAGS) $(MUSASHI_CFLAGS) -o $@

View file

@ -18,7 +18,7 @@ bool GameLoader::LoadZipArchive(ZipArchive *zip, const std::string &zipfilename)
} }
zip->zipfilenames.push_back(zipfilename); zip->zipfilenames.push_back(zipfilename);
zip->zfs.push_back(zf); zip->zfs.push_back(zf);
// Identify all files in zip archive // Identify all files in zip archive
int err = UNZ_OK; int err = UNZ_OK;
for (err = unzGoToFirstFile(zf); err == UNZ_OK; err = unzGoToNextFile(zf)) for (err = unzGoToFirstFile(zf); err == UNZ_OK; err = unzGoToNextFile(zf))
@ -50,7 +50,7 @@ bool GameLoader::FileExistsInZipArchive(const File::ptr_t &file, const ZipArchiv
auto it = zip.files_by_crc.find(file->crc32); auto it = zip.files_by_crc.find(file->crc32);
return it != zip.files_by_crc.end(); return it != zip.files_by_crc.end();
} }
// Try to lookup by name // Try to lookup by name
for (auto &v: zip.files_by_crc) for (auto &v: zip.files_by_crc)
{ {
@ -75,7 +75,7 @@ const GameLoader::ZippedFile *GameLoader::LookupFile(const File::ptr_t &file, co
} }
return &it->second; return &it->second;
} }
// Try to lookup by name // Try to lookup by name
for (auto &v: zip.files_by_crc) for (auto &v: zip.files_by_crc)
{ {
@ -100,7 +100,7 @@ bool GameLoader::LoadZippedFile(std::shared_ptr<uint8_t> *buffer, size_t *file_s
ErrorLog("Unable to locate '%s' in '%s'. Is zip file corrupt?", zipped_file->filename.c_str(), zipped_file->zipfilename.c_str()); ErrorLog("Unable to locate '%s' in '%s'. Is zip file corrupt?", zipped_file->filename.c_str(), zipped_file->zipfilename.c_str());
return true; return true;
} }
// Read it in // Read it in
if (UNZ_OK != unzOpenCurrentFile(zipped_file->zf)) if (UNZ_OK != unzOpenCurrentFile(zipped_file->zf))
{ {
@ -109,14 +109,14 @@ bool GameLoader::LoadZippedFile(std::shared_ptr<uint8_t> *buffer, size_t *file_s
} }
*file_size = zipped_file->uncompressed_size; *file_size = zipped_file->uncompressed_size;
buffer->reset(new uint8_t[*file_size], std::default_delete<uint8_t[]>()); buffer->reset(new uint8_t[*file_size], std::default_delete<uint8_t[]>());
ZPOS64_T bytes_read = unzReadCurrentFile(zipped_file->zf, buffer->get(), *file_size); size_t bytes_read = (size_t) unzReadCurrentFile(zipped_file->zf, buffer->get(), *file_size);
if (bytes_read != *file_size) if (bytes_read != *file_size)
{ {
ErrorLog("Unable to read '%s' from '%s'. Is zip file corrupt?", zipped_file->filename.c_str(), zipped_file->zipfilename.c_str()); ErrorLog("Unable to read '%s' from '%s'. Is zip file corrupt?", zipped_file->filename.c_str(), zipped_file->zipfilename.c_str());
unzCloseCurrentFile(zipped_file->zf); unzCloseCurrentFile(zipped_file->zf);
return true; return true;
} }
// And close it // And close it
if (UNZ_CRCERROR == unzCloseCurrentFile(zipped_file->zf)) if (UNZ_CRCERROR == unzCloseCurrentFile(zipped_file->zf))
ErrorLog("CRC error reading '%s' from '%s'. File may be corrupt.", zipped_file->filename.c_str(), zipped_file->zipfilename.c_str()); ErrorLog("CRC error reading '%s' from '%s'. File may be corrupt.", zipped_file->filename.c_str(), zipped_file->zipfilename.c_str());
@ -284,7 +284,7 @@ bool GameLoader::LoadGamesFromXML(const Util::Config::Node &xml)
{ {
if (region_node.Key() != "region") if (region_node.Key() != "region")
continue; continue;
// Look up region structure or create new one if needed // Look up region structure or create new one if needed
std::string region_name = region_node["name"].Value<std::string>(); std::string region_name = region_node["name"].Value<std::string>();
auto it = regions_by_name.find(region_name); auto it = regions_by_name.find(region_name);
@ -307,25 +307,25 @@ bool GameLoader::LoadGamesFromXML(const Util::Config::Node &xml)
continue; continue;
files.push_back(file); files.push_back(file);
} }
// Check to ensure that some files were defined in the region // Check to ensure that some files were defined in the region
if (files.empty()) if (files.empty())
ErrorLog("%s: No files defined in region '%s' of '%s'.", m_xml_filename.c_str(), region->region_name.c_str(), game_name.c_str()); ErrorLog("%s: No files defined in region '%s' of '%s'.", m_xml_filename.c_str(), region->region_name.c_str(), game_name.c_str());
else else
regions_by_name[region->region_name] = region; regions_by_name[region->region_name] = region;
} }
// ROM patches, if any // ROM patches, if any
for (auto &patches_node: roms_node) for (auto &patches_node: roms_node)
{ {
if (patches_node.Key() != "patches") if (patches_node.Key() != "patches")
continue; continue;
for (auto &patch_node: patches_node) for (auto &patch_node: patches_node)
{ {
if (MissingAttrib(*this, patch_node, "region") || if (MissingAttrib(*this, patch_node, "region") ||
MissingAttrib(*this, patch_node, "bits") || MissingAttrib(*this, patch_node, "bits") ||
MissingAttrib(*this, patch_node, "offset") || MissingAttrib(*this, patch_node, "offset") ||
MissingAttrib(*this, patch_node, "value")) MissingAttrib(*this, patch_node, "value"))
continue; continue;
std::string region = patch_node["region"].ValueAs<std::string>(); std::string region = patch_node["region"].ValueAs<std::string>();
@ -339,7 +339,7 @@ bool GameLoader::LoadGamesFromXML(const Util::Config::Node &xml)
} }
} }
} }
// Check to ensure that some ROM regions were defined for the game // Check to ensure that some ROM regions were defined for the game
if (regions_by_name.empty()) if (regions_by_name.empty())
ErrorLog("%s: No ROM regions defined for '%s'.", m_xml_filename.c_str(), game_name.c_str()); ErrorLog("%s: No ROM regions defined for '%s'.", m_xml_filename.c_str(), game_name.c_str());
@ -371,7 +371,7 @@ bool GameLoader::MergeChildrenWithParents()
auto &child_regions = v1.second; auto &child_regions = v1.second;
auto &parent_regions = m_regions_by_game[game.parent]; auto &parent_regions = m_regions_by_game[game.parent];
// Rebuild child regions by copying over all parent regions first, then // Rebuild child regions by copying over all parent regions first, then
// merge in files from equivalent child regions // merge in files from equivalent child regions
RegionsByName_t new_regions; RegionsByName_t new_regions;
@ -382,7 +382,7 @@ bool GameLoader::MergeChildrenWithParents()
auto &region_name = v2.first; auto &region_name = v2.first;
new_regions[region_name] = std::make_shared<Region>(*v2.second); new_regions[region_name] = std::make_shared<Region>(*v2.second);
auto &new_region = new_regions[region_name]; auto &new_region = new_regions[region_name];
// Replace equivalent files from child in parent region, appending any // Replace equivalent files from child in parent region, appending any
// new ones // new ones
if (child_regions.find(region_name) != child_regions.end()) if (child_regions.find(region_name) != child_regions.end())
@ -403,7 +403,7 @@ bool GameLoader::MergeChildrenWithParents()
} }
} }
} }
// Simply append any region in child that does *not* exist in parent // Simply append any region in child that does *not* exist in parent
for (auto &v2: child_regions) for (auto &v2: child_regions)
{ {
@ -413,11 +413,11 @@ bool GameLoader::MergeChildrenWithParents()
new_regions[v2.first] = v2.second; new_regions[v2.first] = v2.second;
} }
} }
// Save the final result // Save the final result
m_regions_by_merged_game[v1.first] = new_regions; m_regions_by_merged_game[v1.first] = new_regions;
} }
return error; return error;
} }
@ -518,7 +518,7 @@ void GameLoader::IdentifyGamesInZipArchive(
} }
} }
} }
/* /*
* Corner case: some child ROM sets legitimately share files, which can fool * Corner case: some child ROM sets legitimately share files, which can fool
* us into thinking two games are partially present. Need to remove the one * us into thinking two games are partially present. Need to remove the one
@ -541,7 +541,7 @@ void GameLoader::IdentifyGamesInZipArchive(
/* /*
* If the these two games have a different number of files in the zip * If the these two games have a different number of files in the zip
* archive, but one consists only of the overlapping files, we can safely * archive, but one consists only of the overlapping files, we can safely
* conclude that these files represent only the game with the larger * conclude that these files represent only the game with the larger
* number of files present. Otherwise, if only the overlapping files are * number of files present. Otherwise, if only the overlapping files are
* present for both, we have a genuine ambiguity and hence do nothing. * present for both, we have a genuine ambiguity and hence do nothing.
*/ */
@ -553,7 +553,7 @@ void GameLoader::IdentifyGamesInZipArchive(
{ {
files_found_by_game.erase(game_name); files_found_by_game.erase(game_name);
} }
// Find the missing files for each game we found in the zip archive, then use // Find the missing files for each game we found in the zip archive, then use
// this to determine whether the complete game exists // this to determine whether the complete game exists
auto compare = [](const File::ptr_t &a, const File::ptr_t &b) { return a->filename < b->filename; }; auto compare = [](const File::ptr_t &a, const File::ptr_t &b) { return a->filename < b->filename; };
@ -592,12 +592,12 @@ void GameLoader::ChooseGameInZipArchive(std::string *chosen_game, bool *missing_
std::set<std::string> complete_games; std::set<std::string> complete_games;
std::map<std::string, std::set<File::ptr_t>> files_missing_by_game; std::map<std::string, std::set<File::ptr_t>> files_missing_by_game;
IdentifyGamesInZipArchive(&complete_games, &files_missing_by_game, zip, m_regions_by_game); IdentifyGamesInZipArchive(&complete_games, &files_missing_by_game, zip, m_regions_by_game);
// Find complete, merged games // Find complete, merged games
std::set<std::string> complete_merged_games; std::set<std::string> complete_merged_games;
std::map<std::string, std::set<File::ptr_t>> files_missing_by_merged_game; std::map<std::string, std::set<File::ptr_t>> files_missing_by_merged_game;
IdentifyGamesInZipArchive(&complete_merged_games, &files_missing_by_merged_game, zip, m_regions_by_merged_game); IdentifyGamesInZipArchive(&complete_merged_games, &files_missing_by_merged_game, zip, m_regions_by_merged_game);
/* /*
* Find incomplete child games by sorting child games out from the unmerged * Find incomplete child games by sorting child games out from the unmerged
* games results and pruning out complete merged games. Don't care about * games results and pruning out complete merged games. Don't care about
@ -623,7 +623,7 @@ void GameLoader::ChooseGameInZipArchive(std::string *chosen_game, bool *missing_
{ {
incomplete_child_games.erase(game_name); incomplete_child_games.erase(game_name);
} }
// Complete merged games take highest precedence // Complete merged games take highest precedence
for (auto &game_name: complete_merged_games) for (auto &game_name: complete_merged_games)
{ {
@ -635,17 +635,17 @@ void GameLoader::ChooseGameInZipArchive(std::string *chosen_game, bool *missing_
// complete merged games from missing file list. // complete merged games from missing file list.
files_missing_by_game.erase(parent); files_missing_by_game.erase(parent);
} }
// Any remaining incomplete games from the unmerged set are legitimate errors // Any remaining incomplete games from the unmerged set are legitimate errors
for (auto &v: files_missing_by_game) for (auto &v: files_missing_by_game)
{ {
for (auto &file: v.second) for (auto &file: v.second)
{ {
ErrorLog("'%s' (CRC32 0x%08x) not found in '%s' for game '%s'.", file->filename.c_str(), file->crc32, zipfilename.c_str(), v.first.c_str()); ErrorLog("'%s' (CRC32 0x%08x) not found in '%s' for game '%s'.", file->filename.c_str(), file->crc32, zipfilename.c_str(), v.first.c_str());
} }
ErrorLog("Ignoring game '%s' in '%s' because it is missing files.", v.first.c_str(), zipfilename.c_str()); ErrorLog("Ignoring game '%s' in '%s' because it is missing files.", v.first.c_str(), zipfilename.c_str());
} }
// Choose game: complete merged game > incomplete child game > complete // Choose game: complete merged game > incomplete child game > complete
// unmerged game // unmerged game
if (!complete_merged_games.empty()) if (!complete_merged_games.empty())
@ -663,7 +663,7 @@ void GameLoader::ChooseGameInZipArchive(std::string *chosen_game, bool *missing_
ErrorLog("No complete Model 3 games found in '%s'.", zipfilename.c_str()); ErrorLog("No complete Model 3 games found in '%s'.", zipfilename.c_str());
return; return;
} }
// Print out which game we chose from valid candidates in the zip file // Print out which game we chose from valid candidates in the zip file
std::set<std::string> candidates(complete_games); std::set<std::string> candidates(complete_games);
candidates.insert(complete_merged_games.begin(), complete_merged_games.end()); candidates.insert(complete_merged_games.begin(), complete_merged_games.end());
@ -775,7 +775,7 @@ bool GameLoader::LoadROMs(ROMSet *rom_set, const std::string &game_name, const Z
error |= LoadRegion(&rom, region, zip); error |= LoadRegion(&rom, region, zip);
} }
} }
// Attach the patches and do some more error checking here // Attach the patches and do some more error checking here
auto &patches_by_region = m_patches_by_game.find(game_name)->second; auto &patches_by_region = m_patches_by_game.find(game_name)->second;
for (auto &v: patches_by_region) for (auto &v: patches_by_region)
@ -802,7 +802,7 @@ std::string StripFilename(const std::string &filepath)
break; break;
} }
} }
// If none found, there is directory component here // If none found, there is directory component here
if (last_slash == std::string::npos) if (last_slash == std::string::npos)
return ""; return "";
@ -814,12 +814,12 @@ std::string StripFilename(const std::string &filepath)
bool GameLoader::Load(Game *game, ROMSet *rom_set, const std::string &zipfilename) const bool GameLoader::Load(Game *game, ROMSet *rom_set, const std::string &zipfilename) const
{ {
*game = Game(); *game = Game();
// Read the zip contents // Read the zip contents
ZipArchive zip; ZipArchive zip;
if (LoadZipArchive(&zip, zipfilename)) if (LoadZipArchive(&zip, zipfilename))
return true; return true;
// Pick the game to load (there could be multiple ROM sets in a zip file) // Pick the game to load (there could be multiple ROM sets in a zip file)
std::string chosen_game; std::string chosen_game;
bool missing_parent_roms = false; bool missing_parent_roms = false;
@ -829,7 +829,7 @@ bool GameLoader::Load(Game *game, ROMSet *rom_set, const std::string &zipfilenam
// Return game information to caller // Return game information to caller
*game = m_game_info_by_game.find(chosen_game)->second; *game = m_game_info_by_game.find(chosen_game)->second;
// Bring in additional parent ROM set if needed // Bring in additional parent ROM set if needed
if (missing_parent_roms) if (missing_parent_roms)
{ {
@ -841,7 +841,7 @@ bool GameLoader::Load(Game *game, ROMSet *rom_set, const std::string &zipfilenam
} }
} }
// Load // Load
bool error = LoadROMs(rom_set, game->name, zip); bool error = LoadROMs(rom_set, game->name, zip);
if (error) if (error)
*game = Game(); *game = Game();

View file

@ -4,7 +4,7 @@
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <vector> #include <vector>
#include "SDL_net.h" #include "SDLIncludes.h"
class TCPReceive class TCPReceive
{ {

View file

@ -2,7 +2,7 @@
#define _TCPSEND_H_ #define _TCPSEND_H_
#include <string> #include <string>
#include "SDL_net.h" #include "SDLIncludes.h"
class TCPSend class TCPSend
{ {

View file

@ -6,7 +6,7 @@
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
** Supermodel is free software: you can redistribute it and/or modify it under ** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free ** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option) ** Software Foundation, either version 3 of the License, or (at your option)
** any later version. ** any later version.
** **
@ -18,22 +18,15 @@
** You should have received a copy of the GNU General Public License along ** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>. ** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/ **/
/* /*
* Audio.cpp * Audio.cpp
* *
* SDL audio playback. Implements the OSD audio interface. * SDL audio playback. Implements the OSD audio interface.
*/ */
#include "Supermodel.h" #include "Supermodel.h"
#include "SDLIncludes.h"
#ifdef SUPERMODEL_OSX
#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>
#else
#include <SDL.h>
#include <SDL_audio.h>
#endif
#include <cmath> #include <cmath>
#include <algorithm> #include <algorithm>
@ -45,7 +38,7 @@
#define BYTES_PER_SAMPLE (NUM_CHANNELS * sizeof(INT16)) #define BYTES_PER_SAMPLE (NUM_CHANNELS * sizeof(INT16))
#define SAMPLES_PER_FRAME (SAMPLE_RATE / SUPERMODEL_FPS) #define SAMPLES_PER_FRAME (SAMPLE_RATE / SUPERMODEL_FPS)
#define BYTES_PER_FRAME (SAMPLES_PER_FRAME * BYTES_PER_SAMPLE) #define BYTES_PER_FRAME (SAMPLES_PER_FRAME * BYTES_PER_SAMPLE)
#define MAX_LATENCY 100 #define MAX_LATENCY 100
@ -87,9 +80,9 @@ void SetAudioEnabled(bool newEnabled)
static void PlayCallback(void *data, Uint8 *stream, int len) static void PlayCallback(void *data, Uint8 *stream, int len)
{ {
//printf("PlayCallback(%d) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n", //printf("PlayCallback(%d) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n",
// len, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize); // len, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize);
// Get current write position and adjust it if write has wrapped but play position has not // Get current write position and adjust it if write has wrapped but play position has not
UINT32 adjWritePos = writePos; UINT32 adjWritePos = writePos;
if (writeWrapped) if (writeWrapped)
@ -102,7 +95,7 @@ static void PlayCallback(void *data, Uint8 *stream, int len)
//printf("Audio buffer under-run #%u in PlayCallback(%d) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n", //printf("Audio buffer under-run #%u in PlayCallback(%d) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n",
// underRuns, len, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize); // underRuns, len, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize);
// See what action to take on under-run // See what action to take on under-run
if (underRunLoop) if (underRunLoop)
{ {
@ -113,7 +106,7 @@ static void PlayCallback(void *data, Uint8 *stream, int len)
if (playPos >= audioBufferSize) if (playPos >= audioBufferSize)
// If so, wrap it around to beginning again (but keep write wrapped flag as before) // If so, wrap it around to beginning again (but keep write wrapped flag as before)
playPos -= audioBufferSize; playPos -= audioBufferSize;
else else
// Otherwise, set write wrapped flag as will now appear as if write has wrapped but play position has not // Otherwise, set write wrapped flag as will now appear as if write has wrapped but play position has not
writeWrapped = true; writeWrapped = true;
} }
@ -124,7 +117,7 @@ static void PlayCallback(void *data, Uint8 *stream, int len)
return; return;
} }
} }
INT8* src1; INT8* src1;
INT8* src2; INT8* src2;
UINT32 len1; UINT32 len1;
@ -153,7 +146,7 @@ static void PlayCallback(void *data, Uint8 *stream, int len)
{ {
// If so, copy play region into audio output stream // If so, copy play region into audio output stream
memcpy(stream, src1, len1); memcpy(stream, src1, len1);
// Also, if not looping on under-runs then blank region out // Also, if not looping on under-runs then blank region out
if (!underRunLoop) if (!underRunLoop)
memset(src1, 0, len1); memset(src1, 0, len1);
@ -193,10 +186,10 @@ static void PlayCallback(void *data, Uint8 *stream, int len)
static void MixChannels(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, void *dest, bool flipStereo) static void MixChannels(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, void *dest, bool flipStereo)
{ {
INT16 *p = (INT16*)dest; INT16 *p = (INT16*)dest;
#if (NUM_CHANNELS == 1) #if (NUM_CHANNELS == 1)
for (unsigned i = 0; i < numSamples; i++) for (unsigned i = 0; i < numSamples; i++)
*p++ = leftBuffer[i] + rightBuffer[i]; // TODO: these should probably be clipped! *p++ = leftBuffer[i] + rightBuffer[i]; // TODO: these should probably be clipped!
#else #else
if (flipStereo) // swap left and right channels if (flipStereo) // swap left and right channels
{ {
@ -242,7 +235,7 @@ bool OpenAudio()
fmt.format = AUDIO_S16SYS; fmt.format = AUDIO_S16SYS;
fmt.samples = playSamples; fmt.samples = playSamples;
fmt.callback = PlayCallback; fmt.callback = PlayCallback;
// Force SDL to use the format we requested; it will convert if necessary // Force SDL to use the format we requested; it will convert if necessary
if (SDL_OpenAudio(&fmt, nullptr) < 0) if (SDL_OpenAudio(&fmt, nullptr) < 0)
return ErrorLog("Unable to open 44.1KHz 2-channel audio with SDL: %s\n", SDL_GetError()); return ErrorLog("Unable to open 44.1KHz 2-channel audio with SDL: %s\n", SDL_GetError());
@ -255,10 +248,10 @@ bool OpenAudio()
if (audioBuffer == NULL) if (audioBuffer == NULL)
{ {
float audioBufMB = (float)audioBufferSize / (float)0x100000; float audioBufMB = (float)audioBufferSize / (float)0x100000;
return ErrorLog("Insufficient memory for audio latency buffer (need %1.1f MB).", audioBufMB); return ErrorLog("Insufficient memory for audio latency buffer (need %1.1f MB).", audioBufMB);
} }
memset(audioBuffer, 0, sizeof(INT8) * audioBufferSize); memset(audioBuffer, 0, sizeof(INT8) * audioBufferSize);
// Set initial play position to be beginning of buffer and initial write position to be half-way into buffer // Set initial play position to be beginning of buffer and initial write position to be half-way into buffer
playPos = 0; playPos = 0;
writePos = std::min<int>(audioBufferSize - BYTES_PER_FRAME, (BYTES_PER_FRAME + audioBufferSize) / 2); writePos = std::min<int>(audioBufferSize - BYTES_PER_FRAME, (BYTES_PER_FRAME + audioBufferSize) / 2);
@ -289,16 +282,16 @@ bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, boo
// Mix together left and right channels into single chunk of data // Mix together left and right channels into single chunk of data
INT16 mixBuffer[NUM_CHANNELS * SAMPLES_PER_FRAME]; INT16 mixBuffer[NUM_CHANNELS * SAMPLES_PER_FRAME];
MixChannels(numSamples, leftBuffer, rightBuffer, mixBuffer, flipStereo); MixChannels(numSamples, leftBuffer, rightBuffer, mixBuffer, flipStereo);
// Lock SDL audio callback so that it doesn't interfere with following code // Lock SDL audio callback so that it doesn't interfere with following code
SDL_LockAudio(); SDL_LockAudio();
// Calculate number of bytes for current sound chunk // Calculate number of bytes for current sound chunk
UINT32 numBytes = numSamples * BYTES_PER_SAMPLE; UINT32 numBytes = numSamples * BYTES_PER_SAMPLE;
// Get end of current play region (writing must occur past this point) // Get end of current play region (writing must occur past this point)
UINT32 playEndPos = playPos + BYTES_PER_FRAME; UINT32 playEndPos = playPos + BYTES_PER_FRAME;
// Undo any wrap-around of the write position that may have occured to create following ordering: playPos < playEndPos < writePos // Undo any wrap-around of the write position that may have occured to create following ordering: playPos < playEndPos < writePos
if (playEndPos > writePos && writeWrapped) if (playEndPos > writePos && writeWrapped)
writePos += audioBufferSize; writePos += audioBufferSize;
@ -310,18 +303,18 @@ bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, boo
//printf("Audio buffer under-run #%u in OutputAudio(%u) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u, numBytes = %u]\n", //printf("Audio buffer under-run #%u in OutputAudio(%u) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u, numBytes = %u]\n",
// underRuns, numSamples, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize, numBytes); // underRuns, numSamples, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize, numBytes);
// See what action to take on under-run // See what action to take on under-run
if (underRunLoop) if (underRunLoop)
{ {
// If loop, then move play position back to beginning of data in buffer // If loop, then move play position back to beginning of data in buffer
playPos = writePos + numBytes + BYTES_PER_FRAME; playPos = writePos + numBytes + BYTES_PER_FRAME;
// Check if play position has moved past end of buffer // Check if play position has moved past end of buffer
if (playPos >= audioBufferSize) if (playPos >= audioBufferSize)
// If so, wrap it around to beginning again (but keep write wrapped flag as before) // If so, wrap it around to beginning again (but keep write wrapped flag as before)
playPos -= audioBufferSize; playPos -= audioBufferSize;
else else
{ {
// Otherwise, set write wrapped flag as will now appear as if write has wrapped but play position has not // Otherwise, set write wrapped flag as will now appear as if write has wrapped but play position has not
writeWrapped = true; writeWrapped = true;
@ -341,7 +334,7 @@ bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, boo
// Check if write position has caught up with play region and now overlaps it (ie buffer over-run) // Check if write position has caught up with play region and now overlaps it (ie buffer over-run)
bool overRun = writePos + numBytes > playPos + audioBufferSize; bool overRun = writePos + numBytes > playPos + audioBufferSize;
bool bufferFull = writePos + 2 * BYTES_PER_FRAME > playPos + audioBufferSize; bool bufferFull = writePos + 2 * BYTES_PER_FRAME > playPos + audioBufferSize;
// Move write position back to within buffer // Move write position back to within buffer
@ -355,7 +348,7 @@ bool OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, boo
//printf("Audio buffer over-run #%u in OutputAudio(%u) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u, numBytes = %u]\n", //printf("Audio buffer over-run #%u in OutputAudio(%u) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u, numBytes = %u]\n",
// overRuns, numSamples, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize, numBytes); // overRuns, numSamples, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize, numBytes);
bufferFull = true; bufferFull = true;
// Discard current chunk of data // Discard current chunk of data

View file

@ -1,13 +1,13 @@
/** /**
** Supermodel ** Supermodel
** A Sega Model 3 Arcade Emulator. ** A Sega Model 3 Arcade Emulator.
** Copyright 2011-2019 Bart Trzynadlowski, Nik Henson, Ian Curtis, ** Copyright 2011-2020 Bart Trzynadlowski, Nik Henson, Ian Curtis,
** Harry Tuttle, and Spindizzi ** Harry Tuttle, and Spindizzi
** **
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
** Supermodel is free software: you can redistribute it and/or modify it under ** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free ** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option) ** Software Foundation, either version 3 of the License, or (at your option)
** any later version. ** any later version.
** **
@ -19,10 +19,10 @@
** You should have received a copy of the GNU General Public License along ** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>. ** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/ **/
/* /*
* Main.cpp * Main.cpp
* *
* Main program driver for the SDL port. * Main program driver for the SDL port.
* *
* To Do Before Next Release * To Do Before Next Release
@ -33,11 +33,11 @@
* - Standardize variable naming (recently introduced vars_like_this should be * - Standardize variable naming (recently introduced vars_like_this should be
* converted back to varsLikeThis). * converted back to varsLikeThis).
* - Update save state file revision (strings > 1024 chars are now supported). * - Update save state file revision (strings > 1024 chars are now supported).
* - Fix BlockFile.cpp to use fstream! * - Fix BlockFile.cpp to use fstream!
* - Check to make sure save states use explicitly-sized types for 32/64-bit * - Check to make sure save states use explicitly-sized types for 32/64-bit
* compatibility (i.e., size_t, int, etc. not allowed). * compatibility (i.e., size_t, int, etc. not allowed).
* - Make sure quitting while paused works. * - Make sure quitting while paused works.
* - Add UI keys for balance setting? * - Add UI keys for balance setting?
* - 5.1 audio support? * - 5.1 audio support?
* *
* Compile-Time Options * Compile-Time Options
@ -57,11 +57,6 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "Pkgs/glew.h" #include "Pkgs/glew.h"
#ifdef SUPERMODEL_OSX
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
#include "Supermodel.h" #include "Supermodel.h"
#include "Util/Format.h" #include "Util/Format.h"
@ -73,6 +68,7 @@
#include "DirectInputSystem.h" #include "DirectInputSystem.h"
#include "WinOutputs.h" #include "WinOutputs.h"
#endif #endif
#include "SDLIncludes.h"
#include <iostream> #include <iostream>
@ -112,7 +108,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
SDL_GetWindowSize(s_window, &actualWidth, &actualHeight); SDL_GetWindowSize(s_window, &actualWidth, &actualHeight);
*totalXResPtr = actualWidth; *totalXResPtr = actualWidth;
*totalYResPtr = actualHeight; *totalYResPtr = actualHeight;
// If required, fix the aspect ratio of the resolution that the user passed to match Model 3 ratio // If required, fix the aspect ratio of the resolution that the user passed to match Model 3 ratio
float xRes = float(*xResPtr); float xRes = float(*xResPtr);
float yRes = float(*yResPtr); float yRes = float(*yResPtr);
@ -124,17 +120,17 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
if (xRes < (yRes*model3Ratio)) if (xRes < (yRes*model3Ratio))
yRes = xRes/model3Ratio; yRes = xRes/model3Ratio;
} }
// Center the visible area // Center the visible area
*xOffsetPtr = (*xResPtr - (unsigned) xRes)/2; *xOffsetPtr = (*xResPtr - (unsigned) xRes)/2;
*yOffsetPtr = (*yResPtr - (unsigned) yRes)/2; *yOffsetPtr = (*yResPtr - (unsigned) yRes)/2;
// If the desired resolution is smaller than what we got, re-center again // If the desired resolution is smaller than what we got, re-center again
if (int(*xResPtr) < actualWidth) if (int(*xResPtr) < actualWidth)
*xOffsetPtr += (actualWidth - *xResPtr)/2; *xOffsetPtr += (actualWidth - *xResPtr)/2;
if (int(*yResPtr) < actualHeight) if (int(*yResPtr) < actualHeight)
*yOffsetPtr += (actualHeight - *yResPtr)/2; *yOffsetPtr += (actualHeight - *yResPtr)/2;
// OpenGL initialization // OpenGL initialization
glViewport(0,0,*xResPtr,*yResPtr); glViewport(0,0,*xResPtr,*yResPtr);
glClearColor(0.0,0.0,0.0,0.0); glClearColor(0.0,0.0,0.0,0.0);
@ -142,14 +138,14 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
glDepthFunc(GL_LESS); glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
// Clear both buffers to ensure a black border // Clear both buffers to ensure a black border
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
SDL_GL_SwapWindow(s_window); SDL_GL_SwapWindow(s_window);
} }
// Write back resolution parameters // Write back resolution parameters
*xResPtr = (unsigned) xRes; *xResPtr = (unsigned) xRes;
*yResPtr = (unsigned) yRes; *yResPtr = (unsigned) yRes;
@ -157,7 +153,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
UINT32 correction = (UINT32)(((yRes / 384.f) * 2) + 0.5f); UINT32 correction = (UINT32)(((yRes / 384.f) * 2) + 0.5f);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
// Scissor box (to clip visible area) // Scissor box (to clip visible area)
if (s_runtime_config["WideScreen"].ValueAsDefault<bool>(false)) if (s_runtime_config["WideScreen"].ValueAsDefault<bool>(false))
{ {
@ -175,7 +171,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
* *
* Creates an OpenGL display surface of the requested size. xOffset and yOffset * Creates an OpenGL display surface of the requested size. xOffset and yOffset
* are used to return a display surface offset (for OpenGL viewport commands) * are used to return a display surface offset (for OpenGL viewport commands)
* because the actual drawing area may need to be adjusted to preserve the * because the actual drawing area may need to be adjusted to preserve the
* Model 3 aspect ratio. The new resolution will be passed back as well -- both * Model 3 aspect ratio. The new resolution will be passed back as well -- both
* the adjusted viewable area resolution and the total resolution. * the adjusted viewable area resolution and the total resolution.
* *
@ -185,7 +181,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *xResPtr, unsigned *yResPtr, unsigned *totalXResPtr, unsigned *totalYResPtr, bool keepAspectRatio, bool fullScreen) static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *xResPtr, unsigned *yResPtr, unsigned *totalXResPtr, unsigned *totalYResPtr, bool keepAspectRatio, bool fullScreen)
{ {
GLenum err; GLenum err;
// Call only once per program session (this is because of issues with // Call only once per program session (this is because of issues with
// DirectInput when the window is destroyed and a new one created). Use // DirectInput when the window is destroyed and a new one created). Use
// ResizeGLScreen() to change resolutions instead. // ResizeGLScreen() to change resolutions instead.
@ -197,7 +193,7 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
// Initialize video subsystem // Initialize video subsystem
if (SDL_Init(SDL_INIT_VIDEO) != 0) if (SDL_Init(SDL_INIT_VIDEO) != 0)
return ErrorLog("Unable to initialize SDL video subsystem: %s\n", SDL_GetError()); return ErrorLog("Unable to initialize SDL video subsystem: %s\n", SDL_GetError());
// Important GL attributes // Important GL attributes
SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8); SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8);
@ -205,7 +201,7 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,24); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,8); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
// Set video mode // Set video mode
s_window = SDL_CreateWindow(caption.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, *xResPtr, *yResPtr, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullScreen ? SDL_WINDOW_FULLSCREEN : 0)); s_window = SDL_CreateWindow(caption.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, *xResPtr, *yResPtr, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullScreen ? SDL_WINDOW_FULLSCREEN : 0));
if (nullptr == s_window) if (nullptr == s_window)
@ -213,12 +209,12 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
ErrorLog("Unable to create an OpenGL display: %s\n", SDL_GetError()); ErrorLog("Unable to create an OpenGL display: %s\n", SDL_GetError());
return FAIL; return FAIL;
} }
if (focusWindow) if (focusWindow)
{ {
SDL_RaiseWindow(s_window); SDL_RaiseWindow(s_window);
} }
// Create OpenGL context // Create OpenGL context
SDL_GLContext context = SDL_GL_CreateContext(s_window); SDL_GLContext context = SDL_GL_CreateContext(s_window);
if (nullptr == context) if (nullptr == context)
@ -229,10 +225,10 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
// Set vsync // Set vsync
SDL_GL_SetSwapInterval(s_runtime_config["VSync"].ValueAsDefault<bool>(false) ? 1 : 0); SDL_GL_SetSwapInterval(s_runtime_config["VSync"].ValueAsDefault<bool>(false) ? 1 : 0);
// Set the context as the current window context // Set the context as the current window context
SDL_GL_MakeCurrent(s_window, context); SDL_GL_MakeCurrent(s_window, context);
// Initialize GLEW, allowing us to use features beyond OpenGL 1.2 // Initialize GLEW, allowing us to use features beyond OpenGL 1.2
err = glewInit(); err = glewInit();
if (GLEW_OK != err) if (GLEW_OK != err)
@ -240,7 +236,7 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
ErrorLog("OpenGL initialization failed: %s\n", glewGetErrorString(err)); ErrorLog("OpenGL initialization failed: %s\n", glewGetErrorString(err));
return FAIL; return FAIL;
} }
return SetGLGeometry(xOffsetPtr, yOffsetPtr, xResPtr, yResPtr, totalXResPtr, totalYResPtr, keepAspectRatio); return SetGLGeometry(xOffsetPtr, yOffsetPtr, xResPtr, yResPtr, totalXResPtr, totalYResPtr, keepAspectRatio);
} }
@ -261,7 +257,7 @@ static bool ResizeGLScreen(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned
ErrorLog("Unable to enter %s mode: %s\n", fullScreen ? "fullscreen" : "windowed", SDL_GetError()); ErrorLog("Unable to enter %s mode: %s\n", fullScreen ? "fullscreen" : "windowed", SDL_GetError());
return FAIL; return FAIL;
} }
return SetGLGeometry(xOffsetPtr, yOffsetPtr, xResPtr, yResPtr, totalXResPtr, totalYResPtr, keepAspectRatio); return SetGLGeometry(xOffsetPtr, yOffsetPtr, xResPtr, yResPtr, totalXResPtr, totalYResPtr, keepAspectRatio);
} }
@ -273,7 +269,7 @@ static bool ResizeGLScreen(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned
*/ */
static void PrintGLInfo(bool createScreen, bool infoLog, bool printExtensions) static void PrintGLInfo(bool createScreen, bool infoLog, bool printExtensions)
{ {
unsigned xOffset, yOffset, xRes=496, yRes=384, totalXRes, totalYRes; unsigned xOffset, yOffset, xRes=496, yRes=384, totalXRes, totalYRes;
if (createScreen) if (createScreen)
{ {
if (OKAY != CreateGLScreen("Supermodel - Querying OpenGL Information...", false, &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false)) if (OKAY != CreateGLScreen("Supermodel - Querying OpenGL Information...", false, &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false))
@ -282,7 +278,7 @@ static void PrintGLInfo(bool createScreen, bool infoLog, bool printExtensions)
return; return;
} }
} }
GLint value; GLint value;
if (infoLog) InfoLog("OpenGL information:"); if (infoLog) InfoLog("OpenGL information:");
else puts("OpenGL information:\n"); else puts("OpenGL information:\n");
@ -355,7 +351,7 @@ static void PrintBAT(unsigned regu, unsigned regl)
uint32_t ea_base = bepi << (31 - 14); uint32_t ea_base = bepi << (31 - 14);
uint32_t ea_limit = ea_base + size - 1; uint32_t ea_limit = ea_base + size - 1;
uint32_t pa_base = brpn << (31 - 14); uint32_t pa_base = brpn << (31 - 14);
uint32_t pa_limit = pa_base + size - 1; uint32_t pa_limit = pa_base + size - 1;
printf("%08X-%08X -> %08X-%08X ", ea_base, ea_limit, pa_base, pa_limit); printf("%08X-%08X -> %08X-%08X ", ea_base, ea_limit, pa_base, pa_limit);
printf("%c%c%c%c ", (wimg&8)?'W':'-', (wimg&4)?'I':'-', (wimg&2)?'M':'-', (wimg&1)?'G':'-'); printf("%c%c%c%c ", (wimg&8)?'W':'-', (wimg&4)?'I':'-', (wimg&2)?'M':'-', (wimg&1)?'G':'-');
printf("PP="); printf("PP=");
@ -431,7 +427,7 @@ static void DumpPPCRegisters(IBus *bus)
#include "Model3/Model3GraphicsState.h" #include "Model3/Model3GraphicsState.h"
#include "Util/BMPFile.h" #include "Util/BMPFile.h"
#include "OSD/SDL/PolyAnalysis.h" #include "OSD/SDL/PolyAnalysis.h"
#include <fstream> #include <fstream>
static void SaveFrameBuffer(const std::string &file) static void SaveFrameBuffer(const std::string &file)
{ {
@ -441,7 +437,7 @@ static void SaveFrameBuffer(const std::string &file)
} }
static std::string s_gfxStatePath; static std::string s_gfxStatePath;
static std::string GetFileBaseName(const std::string &file) static std::string GetFileBaseName(const std::string &file)
{ {
std::string base = file; std::string base = file;
@ -466,7 +462,7 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
0xffffff60, 0xffffff60,
0xff0300ff // contour, luminous, etc. 0xff0300ff // contour, luminous, etc.
}; };
const std::vector<uint32_t> unknownCullingNodeBits const std::vector<uint32_t> unknownCullingNodeBits
{ {
0xffffffff, 0xffffffff,
@ -502,7 +498,7 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
} }
} }
} }
for (int idx = 0; idx < 10; idx++) for (int idx = 0; idx < 10; idx++)
{ {
for (int bit = 0; bit < 32; bit++) for (int bit = 0; bit < 32; bit++)
@ -523,13 +519,13 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
// Generate the HTML GUI // Generate the HTML GUI
std::string file = Util::Format() << "Analysis/_" << GetFileBaseName(s_gfxStatePath) << ".html"; std::string file = Util::Format() << "Analysis/_" << GetFileBaseName(s_gfxStatePath) << ".html";
std::ofstream fs(file); std::ofstream fs(file);
if (!fs.good()) if (!fs.good())
ErrorLog("Unable to open '%s' for writing.", file.c_str()); ErrorLog("Unable to open '%s' for writing.", file.c_str());
else else
{ {
std::string contents = s_polyAnalysisHTMLPrologue; std::string contents = s_polyAnalysisHTMLPrologue;
contents += " var g_file_base_name = '" + GetFileBaseName(s_gfxStatePath) + "';\n"; contents += " var g_file_base_name = '" + GetFileBaseName(s_gfxStatePath) + "';\n";
contents += " var g_unknown_poly_bits = [" + std::string(Util::Format(",").Join(unknownPolyBits)) + "];\n"; contents += " var g_unknown_poly_bits = [" + std::string(Util::Format(",").Join(unknownPolyBits)) + "];\n";
contents += " var g_unknown_culling_bits = [" + std::string(Util::Format(",").Join(unknownCullingNodeBits)) + "];\n"; contents += " var g_unknown_culling_bits = [" + std::string(Util::Format(",").Join(unknownCullingNodeBits)) + "];\n";
contents += s_polyAnalysisHTMLEpilogue; contents += s_polyAnalysisHTMLEpilogue;
@ -543,15 +539,15 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
/****************************************************************************** /******************************************************************************
Save States and NVRAM Save States and NVRAM
Save states and NVRAM use the same basic format. When anything changes that Save states and NVRAM use the same basic format. When anything changes that
breaks compatibility with previous versions of Supermodel, the save state breaks compatibility with previous versions of Supermodel, the save state
and NVRAM version numbers must be incremented as needed. and NVRAM version numbers must be incremented as needed.
Header block name: "Supermodel Save State" or "Supermodel NVRAM State" Header block name: "Supermodel Save State" or "Supermodel NVRAM State"
Data: Save state file version (4-byte integer), ROM set ID (up to 9 bytes, Data: Save state file version (4-byte integer), ROM set ID (up to 9 bytes,
including terminating \0). including terminating \0).
Different subsystems output their own blocks. Different subsystems output their own blocks.
******************************************************************************/ ******************************************************************************/
@ -562,19 +558,19 @@ static unsigned s_saveSlot = 0; // save state slot #
static void SaveState(IEmulator *Model3) static void SaveState(IEmulator *Model3)
{ {
CBlockFile SaveState; CBlockFile SaveState;
std::string file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot; std::string file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot;
if (OKAY != SaveState.Create(file_path, "Supermodel Save State", "Supermodel Version " SUPERMODEL_VERSION)) if (OKAY != SaveState.Create(file_path, "Supermodel Save State", "Supermodel Version " SUPERMODEL_VERSION))
{ {
ErrorLog("Unable to save state to '%s'.", file_path.c_str()); ErrorLog("Unable to save state to '%s'.", file_path.c_str());
return; return;
} }
// Write file format version and ROM set ID to header block // Write file format version and ROM set ID to header block
int32_t fileVersion = STATE_FILE_VERSION; int32_t fileVersion = STATE_FILE_VERSION;
SaveState.Write(&fileVersion, sizeof(fileVersion)); SaveState.Write(&fileVersion, sizeof(fileVersion));
SaveState.Write(Model3->GetGame().name); SaveState.Write(Model3->GetGame().name);
// Save state // Save state
Model3->SaveState(&SaveState); Model3->SaveState(&SaveState);
SaveState.Close(); SaveState.Close();
@ -585,24 +581,24 @@ static void SaveState(IEmulator *Model3)
static void LoadState(IEmulator *Model3, std::string file_path = std::string()) static void LoadState(IEmulator *Model3, std::string file_path = std::string())
{ {
CBlockFile SaveState; CBlockFile SaveState;
// Generate file path // Generate file path
if (file_path.empty()) if (file_path.empty())
file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot; file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot;
// Open and check to make sure format is correct // Open and check to make sure format is correct
if (OKAY != SaveState.Load(file_path)) if (OKAY != SaveState.Load(file_path))
{ {
ErrorLog("Unable to load state from '%s'.", file_path.c_str()); ErrorLog("Unable to load state from '%s'.", file_path.c_str());
return; return;
} }
if (OKAY != SaveState.FindBlock("Supermodel Save State")) if (OKAY != SaveState.FindBlock("Supermodel Save State"))
{ {
ErrorLog("'%s' does not appear to be a valid save state file.", file_path.c_str()); ErrorLog("'%s' does not appear to be a valid save state file.", file_path.c_str());
return; return;
} }
int32_t fileVersion; int32_t fileVersion;
SaveState.Read(&fileVersion, sizeof(fileVersion)); SaveState.Read(&fileVersion, sizeof(fileVersion));
if (fileVersion != STATE_FILE_VERSION) if (fileVersion != STATE_FILE_VERSION)
@ -610,7 +606,7 @@ static void LoadState(IEmulator *Model3, std::string file_path = std::string())
ErrorLog("'%s' is incompatible with this version of Supermodel.", file_path.c_str()); ErrorLog("'%s' is incompatible with this version of Supermodel.", file_path.c_str());
return; return;
} }
// Load // Load
Model3->LoadState(&SaveState); Model3->LoadState(&SaveState);
SaveState.Close(); SaveState.Close();
@ -621,19 +617,19 @@ static void LoadState(IEmulator *Model3, std::string file_path = std::string())
static void SaveNVRAM(IEmulator *Model3) static void SaveNVRAM(IEmulator *Model3)
{ {
CBlockFile NVRAM; CBlockFile NVRAM;
std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv"; std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv";
if (OKAY != NVRAM.Create(file_path, "Supermodel NVRAM State", "Supermodel Version " SUPERMODEL_VERSION)) if (OKAY != NVRAM.Create(file_path, "Supermodel NVRAM State", "Supermodel Version " SUPERMODEL_VERSION))
{ {
ErrorLog("Unable to save NVRAM to '%s'. Make sure directory exists!", file_path.c_str()); ErrorLog("Unable to save NVRAM to '%s'. Make sure directory exists!", file_path.c_str());
return; return;
} }
// Write file format version and ROM set ID to header block // Write file format version and ROM set ID to header block
int32_t fileVersion = NVRAM_FILE_VERSION; int32_t fileVersion = NVRAM_FILE_VERSION;
NVRAM.Write(&fileVersion, sizeof(fileVersion)); NVRAM.Write(&fileVersion, sizeof(fileVersion));
NVRAM.Write(Model3->GetGame().name); NVRAM.Write(Model3->GetGame().name);
// Save NVRAM // Save NVRAM
Model3->SaveNVRAM(&NVRAM); Model3->SaveNVRAM(&NVRAM);
NVRAM.Close(); NVRAM.Close();
@ -643,23 +639,23 @@ static void SaveNVRAM(IEmulator *Model3)
static void LoadNVRAM(IEmulator *Model3) static void LoadNVRAM(IEmulator *Model3)
{ {
CBlockFile NVRAM; CBlockFile NVRAM;
// Generate file path // Generate file path
std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv"; std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv";
// Open and check to make sure format is correct // Open and check to make sure format is correct
if (OKAY != NVRAM.Load(file_path)) if (OKAY != NVRAM.Load(file_path))
{ {
//ErrorLog("Unable to restore NVRAM from '%s'.", filePath); //ErrorLog("Unable to restore NVRAM from '%s'.", filePath);
return; return;
} }
if (OKAY != NVRAM.FindBlock("Supermodel NVRAM State")) if (OKAY != NVRAM.FindBlock("Supermodel NVRAM State"))
{ {
ErrorLog("'%s' does not appear to be a valid NVRAM file.", file_path.c_str()); ErrorLog("'%s' does not appear to be a valid NVRAM file.", file_path.c_str());
return; return;
} }
int32_t fileVersion; int32_t fileVersion;
NVRAM.Read(&fileVersion, sizeof(fileVersion)); NVRAM.Read(&fileVersion, sizeof(fileVersion));
if (fileVersion != NVRAM_FILE_VERSION) if (fileVersion != NVRAM_FILE_VERSION)
@ -667,7 +663,7 @@ static void LoadNVRAM(IEmulator *Model3)
ErrorLog("'%s' is incompatible with this version of Supermodel.", file_path.c_str()); ErrorLog("'%s' is incompatible with this version of Supermodel.", file_path.c_str());
return; return;
} }
// Load // Load
Model3->LoadNVRAM(&NVRAM); Model3->LoadNVRAM(&NVRAM);
NVRAM.Close(); NVRAM.Close();
@ -677,7 +673,7 @@ static void LoadNVRAM(IEmulator *Model3)
/****************************************************************************** /******************************************************************************
UI Rendering UI Rendering
Currently, only does crosshairs for light gun games. Currently, only does crosshairs for light gun games.
******************************************************************************/ ******************************************************************************/
@ -692,11 +688,11 @@ static void DrawCrosshair(float x, float y, float r, float g, float b)
float base = 0.01f, height = 0.02f; // geometric parameters of each triangle float base = 0.01f, height = 0.02f; // geometric parameters of each triangle
float dist = 0.004f; // distance of triangle tip from center float dist = 0.004f; // distance of triangle tip from center
float a = (float)xRes/(float)yRes; // aspect ratio (to square the crosshair) float a = (float)xRes/(float)yRes; // aspect ratio (to square the crosshair)
glColor3f(r, g, b); glColor3f(r, g, b);
glVertex2f(x, y+dist); // bottom triangle glVertex2f(x, y+dist); // bottom triangle
glVertex2f(x+base/2.0f, y+(dist+height)*a); glVertex2f(x+base/2.0f, y+(dist+height)*a);
glVertex2f(x-base/2.0f, y+(dist+height)*a); glVertex2f(x-base/2.0f, y+(dist+height)*a);
glVertex2f(x, y-dist); // top triangle glVertex2f(x, y-dist); // top triangle
glVertex2f(x-base/2.0f, y-(dist+height)*a); glVertex2f(x-base/2.0f, y-(dist+height)*a);
glVertex2f(x+base/2.0f, y-(dist+height)*a); glVertex2f(x+base/2.0f, y-(dist+height)*a);
@ -746,7 +742,7 @@ static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned c
glLoadIdentity(); glLoadIdentity();
glDisable(GL_TEXTURE_2D); // no texture mapping glDisable(GL_TEXTURE_2D); // no texture mapping
glDisable(GL_BLEND); // no blending glDisable(GL_BLEND); // no blending
glDisable(GL_DEPTH_TEST); // no Z-buffering needed glDisable(GL_DEPTH_TEST); // no Z-buffering needed
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
// Convert gun coordinates to viewspace coordinates // Convert gun coordinates to viewspace coordinates
@ -776,7 +772,7 @@ static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned c
GunToViewCoords(&x[1], &y[1]); GunToViewCoords(&x[1], &y[1]);
offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0; offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0;
} }
// Draw visible crosshairs // Draw visible crosshairs
glBegin(GL_TRIANGLES); glBegin(GL_TRIANGLES);
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1 if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f); DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f);
@ -787,7 +783,7 @@ static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned c
//PrintGLError(glGetError()); //PrintGLError(glGetError());
} }
/****************************************************************************** /******************************************************************************
Video Callbacks Video Callbacks
******************************************************************************/ ******************************************************************************/
@ -830,7 +826,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
CLogger *oldLogger = 0; CLogger *oldLogger = 0;
#else #else
int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *Inputs, COutputs *Outputs) int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *Inputs, COutputs *Outputs)
{ {
#endif // SUPERMODEL_DEBUGGER #endif // SUPERMODEL_DEBUGGER
std::string initialState = s_runtime_config["InitStateFile"].ValueAs<std::string>(); std::string initialState = s_runtime_config["InitStateFile"].ValueAs<std::string>();
unsigned prevFPSTicks; unsigned prevFPSTicks;
@ -846,10 +842,10 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
if (Model3->LoadGame(game, *rom_set)) if (Model3->LoadGame(game, *rom_set))
return 1; return 1;
*rom_set = ROMSet(); // free up this memory we won't need anymore *rom_set = ROMSet(); // free up this memory we won't need anymore
// Load NVRAM // Load NVRAM
LoadNVRAM(Model3); LoadNVRAM(Model3);
// Set the video mode // Set the video mode
char baseTitleStr[128]; char baseTitleStr[128];
char titleStr[128]; char titleStr[128];
@ -864,9 +860,9 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
if (OKAY != ResizeGLScreen(&xOffset, &yOffset ,&xRes, &yRes, &totalXRes, &totalYRes, !stretch, fullscreen)) if (OKAY != ResizeGLScreen(&xOffset, &yOffset ,&xRes, &yRes, &totalXRes, &totalYRes, !stretch, fullscreen))
return 1; return 1;
// Info log GL information // Info log GL information
PrintGLInfo(false, true, false); PrintGLInfo(false, true, false);
// Initialize audio system // Initialize audio system
if (OKAY != OpenAudio()) if (OKAY != OpenAudio())
return 1; return 1;
@ -887,7 +883,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
// Attach the outputs to the emulator // Attach the outputs to the emulator
if (Outputs != NULL) if (Outputs != NULL)
Model3->AttachOutputs(Outputs); Model3->AttachOutputs(Outputs);
// Initialize the renderers // Initialize the renderers
CRender2D *Render2D = new CRender2D(s_runtime_config); CRender2D *Render2D = new CRender2D(s_runtime_config);
IRender3D *Render3D = s_runtime_config["New3DEngine"].ValueAs<bool>() ? ((IRender3D *) new New3D::CNew3D(s_runtime_config, Model3->GetGame().name)) : ((IRender3D *) new Legacy3D::CLegacy3D(s_runtime_config)); IRender3D *Render3D = s_runtime_config["New3DEngine"].ValueAs<bool>() ? ((IRender3D *) new New3D::CNew3D(s_runtime_config, Model3->GetGame().name)) : ((IRender3D *) new Legacy3D::CLegacy3D(s_runtime_config));
@ -899,11 +895,11 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
// Reset emulator // Reset emulator
Model3->Reset(); Model3->Reset();
// Load initial save state if requested // Load initial save state if requested
if (initialState.length() > 0) if (initialState.length() > 0)
LoadState(Model3, initialState); LoadState(Model3, initialState);
#ifdef SUPERMODEL_DEBUGGER #ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, set it as logger and attach it to system // If debugger was supplied, set it as logger and attach it to system
oldLogger = GetLogger(); oldLogger = GetLogger();
@ -936,11 +932,11 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
Model3->RenderFrame(); Model3->RenderFrame();
else else
Model3->RunFrame(); Model3->RunFrame();
// Poll the inputs // Poll the inputs
if (!Inputs->Poll(&game, xOffset, yOffset, xRes, yRes)) if (!Inputs->Poll(&game, xOffset, yOffset, xRes, yRes))
quit = true; quit = true;
#ifdef SUPERMODEL_DEBUGGER #ifdef SUPERMODEL_DEBUGGER
bool processUI = true; bool processUI = true;
if (Debugger != NULL) if (Debugger != NULL)
@ -953,7 +949,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
quit = true; quit = true;
processUI = false; processUI = false;
} }
else if (Debugger->CheckPause()) else if (Debugger->CheckPause())
{ {
paused = true; paused = true;
processUI = false; processUI = false;
@ -967,7 +963,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
if (Inputs->uiExit->Pressed()) if (Inputs->uiExit->Pressed())
{ {
// Quit emulator // Quit emulator
quit = true; quit = true;
} }
else if (Inputs->uiReset->Pressed()) else if (Inputs->uiReset->Pressed())
{ {
@ -979,7 +975,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
// Reset emulator // Reset emulator
Model3->Reset(); Model3->Reset();
#ifdef SUPERMODEL_DEBUGGER #ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, reset it too // If debugger was supplied, reset it too
if (Debugger != NULL) if (Debugger != NULL)
@ -1012,7 +1008,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
SetAudioEnabled(true); SetAudioEnabled(true);
SDL_SetWindowTitle(s_window, baseTitleStr); SDL_SetWindowTitle(s_window, baseTitleStr);
} }
// Send paused value as output // Send paused value as output
if (Outputs != NULL) if (Outputs != NULL)
Outputs->SetValue(OutputPause, paused); Outputs->SetValue(OutputPause, paused);
@ -1027,7 +1023,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
delete Render3D; delete Render3D;
Render2D = NULL; Render2D = NULL;
Render3D = NULL; Render3D = NULL;
// Resize screen // Resize screen
totalXRes = xRes = s_runtime_config["XResolution"].ValueAs<unsigned>(); totalXRes = xRes = s_runtime_config["XResolution"].ValueAs<unsigned>();
totalYRes = yRes = s_runtime_config["YResolution"].ValueAs<unsigned>(); totalYRes = yRes = s_runtime_config["YResolution"].ValueAs<unsigned>();
@ -1044,7 +1040,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
if (OKAY != Render3D->Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes)) if (OKAY != Render3D->Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes))
goto QuitError; goto QuitError;
Model3->AttachRenderers(Render2D,Render3D); Model3->AttachRenderers(Render2D,Render3D);
Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs<bool>()); Inputs->GetInputSystem()->SetMouseVisibility(!s_runtime_config["FullScreen"].ValueAs<bool>());
} }
else if (Inputs->uiSaveState->Pressed()) else if (Inputs->uiSaveState->Pressed())
@ -1081,7 +1077,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
// Load game state // Load game state
LoadState(Model3); LoadState(Model3);
#ifdef SUPERMODEL_DEBUGGER #ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, reset it after loading state // If debugger was supplied, reset it after loading state
if (Debugger != NULL) if (Debugger != NULL)
@ -1122,7 +1118,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
puts(" (muted)"); puts(" (muted)");
else else
printf("\n"); printf("\n");
} }
else else
puts("This game does not have an MPEG music board."); puts("This game does not have an MPEG music board.");
} }
@ -1191,8 +1187,8 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
} }
} }
#endif // SUPERMODEL_DEBUGGER #endif // SUPERMODEL_DEBUGGER
// Frame rate and limiting // Frame rate and limiting
unsigned currentFPSTicks = SDL_GetTicks(); unsigned currentFPSTicks = SDL_GetTicks();
if (s_runtime_config["ShowFrameRate"].ValueAs<bool>()) if (s_runtime_config["ShowFrameRate"].ValueAs<bool>())
@ -1206,7 +1202,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
fpsFramesElapsed = 0; // reset frame count fpsFramesElapsed = 0; // reset frame count
} }
} }
if (paused || s_runtime_config["Throttle"].ValueAs<bool>()) if (paused || s_runtime_config["Throttle"].ValueAs<bool>())
{ {
UINT32 endTime = SDL_GetTicks(); UINT32 endTime = SDL_GetTicks();
@ -1227,8 +1223,8 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
} }
// Make sure all threads are paused before shutting down // Make sure all threads are paused before shutting down
Model3->PauseThreads(); Model3->PauseThreads();
#ifdef SUPERMODEL_DEBUGGER #ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, detach it from system and restore old logger // If debugger was supplied, detach it from system and restore old logger
if (Debugger != NULL) if (Debugger != NULL)
@ -1237,10 +1233,10 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
SetLogger(oldLogger); SetLogger(oldLogger);
} }
#endif // SUPERMODEL_DEBUGGER #endif // SUPERMODEL_DEBUGGER
// Save NVRAM // Save NVRAM
SaveNVRAM(Model3); SaveNVRAM(Model3);
// Close audio // Close audio
CloseAudio(); CloseAudio();
@ -1273,9 +1269,9 @@ static bool ConfigureInputs(CInputs *Inputs, Util::Config::Node *fileConfig, Uti
"; Supermodel Configuration File\n" "; Supermodel Configuration File\n"
";\n" ";\n"
}; };
Inputs->LoadFromConfig(*runtimeConfig); Inputs->LoadFromConfig(*runtimeConfig);
// If the user wants to configure the inputs, do that now // If the user wants to configure the inputs, do that now
if (configure) if (configure)
{ {
@ -1294,14 +1290,14 @@ static bool ConfigureInputs(CInputs *Inputs, Util::Config::Node *fileConfig, Uti
{ {
fileConfigRoot = &fileConfig->Add(game.name); fileConfigRoot = &fileConfig->Add(game.name);
} }
// Configure the inputs // Configure the inputs
if (Inputs->ConfigureInputs(game, xOffset, yOffset, xRes, yRes)) if (Inputs->ConfigureInputs(game, xOffset, yOffset, xRes, yRes))
{ {
// Write input configuration and input system settings to config file // Write input configuration and input system settings to config file
Inputs->StoreToConfig(fileConfigRoot); Inputs->StoreToConfig(fileConfigRoot);
Util::Config::WriteINIFile(s_configFilePath, *fileConfig, configFileComment); Util::Config::WriteINIFile(s_configFilePath, *fileConfig, configFileComment);
// Also save to runtime configuration in case we proceed and play // Also save to runtime configuration in case we proceed and play
Inputs->StoreToConfig(runtimeConfig); Inputs->StoreToConfig(runtimeConfig);
} }
@ -1309,7 +1305,7 @@ static bool ConfigureInputs(CInputs *Inputs, Util::Config::Node *fileConfig, Uti
puts("Configuration aborted..."); puts("Configuration aborted...");
puts(""); puts("");
} }
return OKAY; return OKAY;
} }
@ -1379,7 +1375,7 @@ static Util::Config::Node DefaultConfig()
#ifdef SUPERMODEL_WIN32 #ifdef SUPERMODEL_WIN32
config.Set("ForceFeedback", false); config.Set("ForceFeedback", false);
#endif #endif
// Platform-specific/UI // Platform-specific/UI
config.Set("New3DEngine", true); config.Set("New3DEngine", true);
config.Set("QuadRendering", false); config.Set("QuadRendering", false);
config.Set("XResolution", "496"); config.Set("XResolution", "496");
@ -1418,7 +1414,7 @@ static Util::Config::Node DefaultConfig()
static void Title(void) static void Title(void)
{ {
puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")"); puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")");
puts("Copyright 2011-2019 by Bart Trzynadlowski, Nik Henson, Ian Curtis,"); puts("Copyright 2011-2020 by Bart Trzynadlowski, Nik Henson, Ian Curtis,");
puts(" Harry Tuttle, and Spindizzi\n"); puts(" Harry Tuttle, and Spindizzi\n");
} }
@ -1573,7 +1569,7 @@ static ParsedCommandLine ParseCommandLine(int argc, char **argv)
{ "-no-force-feedback", { "ForceFeedback", false } }, { "-no-force-feedback", { "ForceFeedback", false } },
{ "-force-feedback", { "ForceFeedback", true } }, { "-force-feedback", { "ForceFeedback", true } },
#endif #endif
}; };
for (int i = 1; i < argc; i++) for (int i = 1; i < argc; i++)
{ {
@ -1697,7 +1693,7 @@ int main(int argc, char **argv)
for (int i = 0; i < argc; i++) for (int i = 0; i < argc; i++)
InfoLog(" argv[%d] = %s", i, argv[i]); InfoLog(" argv[%d] = %s", i, argv[i]);
InfoLog(""); InfoLog("");
// Load config and parse command line // Load config and parse command line
auto cmd_line = ParseCommandLine(argc, argv); auto cmd_line = ParseCommandLine(argc, argv);
if (cmd_line.print_help) if (cmd_line.print_help)
@ -1718,7 +1714,7 @@ int main(int argc, char **argv)
bool rom_specified = !cmd_line.rom_files.empty(); bool rom_specified = !cmd_line.rom_files.empty();
if (!rom_specified && !print_games && !cmd_line.config_inputs && !cmd_line.print_inputs) if (!rom_specified && !print_games && !cmd_line.config_inputs && !cmd_line.print_inputs)
{ {
ErrorLog("No ROM file specified."); ErrorLog("No ROM file specified.");
return 0; return 0;
} }
@ -1760,7 +1756,7 @@ int main(int argc, char **argv)
return 1; return 1;
} }
// Begin initializing various subsystems... // Begin initializing various subsystems...
int exitCode = 0; int exitCode = 0;
IEmulator *Model3 = nullptr; IEmulator *Model3 = nullptr;
CInputSystem *InputSystem = nullptr; CInputSystem *InputSystem = nullptr;
@ -1769,7 +1765,7 @@ int main(int argc, char **argv)
#ifdef SUPERMODEL_DEBUGGER #ifdef SUPERMODEL_DEBUGGER
Debugger::CSupermodelDebugger *Debugger = NULL; Debugger::CSupermodelDebugger *Debugger = NULL;
#endif // SUPERMODEL_DEBUGGER #endif // SUPERMODEL_DEBUGGER
// Create a window // Create a window
xRes = 496; xRes = 496;
yRes = 384; yRes = 384;
@ -1778,7 +1774,7 @@ int main(int argc, char **argv)
exitCode = 1; exitCode = 1;
goto Exit; goto Exit;
} }
// Create Model 3 emulator // Create Model 3 emulator
#ifdef DEBUG #ifdef DEBUG
Model3 = s_gfxStatePath.empty() ? static_cast<IEmulator *>(new CModel3(s_runtime_config)) : static_cast<IEmulator *>(new CModel3GraphicsState(s_runtime_config, s_gfxStatePath)); Model3 = s_gfxStatePath.empty() ? static_cast<IEmulator *>(new CModel3(s_runtime_config)) : static_cast<IEmulator *>(new CModel3GraphicsState(s_runtime_config, s_gfxStatePath));
@ -1812,7 +1808,7 @@ int main(int argc, char **argv)
exitCode = 1; exitCode = 1;
goto Exit; goto Exit;
} }
// NOTE: fileConfig is passed so that the global section is used for input settings // NOTE: fileConfig is passed so that the global section is used for input settings
// and because this function may write out a new config file, which must preserve // and because this function may write out a new config file, which must preserve
// all sections. We don't want to pollute the output with built-in defaults. // all sections. We don't want to pollute the output with built-in defaults.
@ -1827,11 +1823,11 @@ int main(int argc, char **argv)
Inputs->PrintInputs(NULL); Inputs->PrintInputs(NULL);
InputSystem->PrintSettings(); InputSystem->PrintSettings();
} }
if (!rom_specified) if (!rom_specified)
goto Exit; goto Exit;
// Create outputs // Create outputs
#ifdef SUPERMODEL_WIN32 #ifdef SUPERMODEL_WIN32
{ {
std::string outputs = s_runtime_config["Outputs"].ValueAs<std::string>(); std::string outputs = s_runtime_config["Outputs"].ValueAs<std::string>();
@ -1855,7 +1851,7 @@ int main(int argc, char **argv)
exitCode = 1; exitCode = 1;
goto Exit; goto Exit;
} }
#ifdef SUPERMODEL_DEBUGGER #ifdef SUPERMODEL_DEBUGGER
// Create Supermodel debugger unless debugging is disabled // Create Supermodel debugger unless debugging is disabled
if (!cmd_line.disable_debugger) if (!cmd_line.disable_debugger)
@ -1884,11 +1880,11 @@ Exit:
delete Outputs; delete Outputs;
DestroyGLScreen(); DestroyGLScreen();
SDL_Quit(); SDL_Quit();
if (exitCode) if (exitCode)
InfoLog("Program terminated due to an error."); InfoLog("Program terminated due to an error.");
else else
InfoLog("Program terminated normally."); InfoLog("Program terminated normally.");
return exitCode; return exitCode;
} }

48
Src/OSD/SDL/SDLIncludes.h Normal file
View file

@ -0,0 +1,48 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011-2019 Bart Trzynadlowski, Nik Henson, Ian Curtis,
** Harry Tuttle, and Spindizzi
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* SDLIncludes.h
*
* Header file for SDL library.
*/
#ifndef INCLUDED_SDLINCLUDES_H
#define INCLUDED_SDLINCLUDES_H
#ifdef SUPERMODEL_OSX
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#else
#include <SDL.h>
#include <SDL_audio.h>
#endif
#ifdef NET_BOARD
#ifdef SUPERMODEL_OSX
#include <SDL2_net/SDL_net.h>
#else
#include <SDL_net.h>
#endif
#endif
#endif // INCLUDED_SDLINCLUDES_H

View file

@ -29,8 +29,8 @@
* - Implement multiple keyboard and mouse support. * - Implement multiple keyboard and mouse support.
*/ */
#include "SDLInputSystem.h"
#include "Supermodel.h" #include "Supermodel.h"
#include "SDLInputSystem.h"
#include <vector> #include <vector>
using namespace std; using namespace std;
@ -387,7 +387,7 @@ bool CSDLInputSystem::Poll()
default: default:
break; break;
case SDL_QUIT: case SDL_QUIT:
return false; return false;
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
if (e.button.y > 0) if (e.button.y > 0)
{ {

View file

@ -6,7 +6,7 @@
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
** Supermodel is free software: you can redistribute it and/or modify it under ** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free ** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option) ** Software Foundation, either version 3 of the License, or (at your option)
** any later version. ** any later version.
** **
@ -18,10 +18,10 @@
** You should have received a copy of the GNU General Public License along ** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>. ** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/ **/
/* /*
* SDLInputSystem.h * SDLInputSystem.h
* *
* Header file for SDL input system. * Header file for SDL input system.
*/ */
@ -31,12 +31,7 @@
#include "Types.h" #include "Types.h"
#include "Inputs/InputSource.h" #include "Inputs/InputSource.h"
#include "Inputs/InputSystem.h" #include "Inputs/InputSystem.h"
#include "SDLIncludes.h"
#ifdef SUPERMODEL_OSX
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
#include <vector> #include <vector>
using namespace std; using namespace std;
@ -74,7 +69,7 @@ private:
short m_mouseWheelDir; short m_mouseWheelDir;
Uint8 m_mouseButtons; Uint8 m_mouseButtons;
/* /*
* Opens all attached joysticks. * Opens all attached joysticks.
*/ */
void OpenJoysticks(); void OpenJoysticks();
@ -97,7 +92,7 @@ protected:
bool IsKeyPressed(int kbdNum, int keyIndex); bool IsKeyPressed(int kbdNum, int keyIndex);
int GetMouseAxisValue(int mseNum, int axisNum); int GetMouseAxisValue(int mseNum, int axisNum);
int GetMouseWheelDir(int mseNum); int GetMouseWheelDir(int mseNum);
bool IsMouseButPressed(int mseNum, int butNum); bool IsMouseButPressed(int mseNum, int butNum);
@ -118,10 +113,10 @@ public:
~CSDLInputSystem(); ~CSDLInputSystem();
int GetNumKeyboards(); int GetNumKeyboards();
int GetNumMice(); int GetNumMice();
int GetNumJoysticks(); int GetNumJoysticks();
const KeyDetails *GetKeyDetails(int kbdNum); const KeyDetails *GetKeyDetails(int kbdNum);

View file

@ -6,7 +6,7 @@
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
** Supermodel is free software: you can redistribute it and/or modify it under ** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free ** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option) ** Software Foundation, either version 3 of the License, or (at your option)
** any later version. ** any later version.
** **
@ -18,22 +18,15 @@
** You should have received a copy of the GNU General Public License along ** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>. ** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/ **/
/* /*
* Thread.cpp * Thread.cpp
* *
* SDL-based implementation of threading primitives. * SDL-based implementation of threading primitives.
*/ */
#include "Supermodel.h"
#ifdef SUPERMODEL_OSX #include "Supermodel.h"
#include <SDL/SDL.h> #include "SDLIncludes.h"
#include <SDL/SDL_thread.h>
#else
#include <SDL.h>
#include <SDL_thread.h>
#endif
void CThread::Sleep(UINT32 ms) void CThread::Sleep(UINT32 ms)
{ {
@ -85,7 +78,7 @@ const char *CThread::GetLastError()
CThread::CThread(const std::string &name, void *impl) CThread::CThread(const std::string &name, void *impl)
: m_name(name), : m_name(name),
m_impl(impl) m_impl(impl)
{ {
// //
} }
@ -95,7 +88,7 @@ CThread::~CThread()
// User should have called Wait() before thread object is destroyed // User should have called Wait() before thread object is destroyed
if (nullptr != m_impl) if (nullptr != m_impl)
{ {
ErrorLog("Runaway thread error. A thread was not properly halted: %s\n", GetName()); ErrorLog("Runaway thread error. A thread was not properly halted: %s\n", GetName().c_str());
} }
} }

131
Src/Pkgs/crypt.h Normal file
View file

@ -0,0 +1,131 @@
/* crypt.h -- base code for crypt/uncrypt ZIPfile
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
This code is a modified version of crypting code in Infozip distribution
The encryption/decryption parts of this source code (as opposed to the
non-echoing password parts) were originally written in Europe. The
whole source package can be freely distributed, including from the USA.
(Prior to January 2000, re-export from the US was a violation of US law.)
This encryption code is a direct transcription of the algorithm from
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
file (appnote.txt) is distributed with the PKZIP program (even in the
version without encryption capabilities).
If you don't need crypting in your application, just define symbols
NOCRYPT and NOUNCRYPT.
This code support the "Traditional PKWARE Encryption".
The new AES encryption added on Zip format by Winzip (see the page
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
Encryption is not supported.
*/
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
/***********************************************************************
* Return the next byte in the pseudo-random sequence
*/
static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab)
{
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
* unpredictable manner on 16-bit systems; not a problem
* with any known compiler so far, though */
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
}
/***********************************************************************
* Update the encryption keys with the next byte of plain text
*/
static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c)
{
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
{
register int keyshift = (int)((*(pkeys+1)) >> 24);
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
}
return c;
}
/***********************************************************************
* Initialize the encryption keys and the random header according to
* the given password.
*/
static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab)
{
*(pkeys+0) = 305419896L;
*(pkeys+1) = 591751049L;
*(pkeys+2) = 878082192L;
while (*passwd != '\0') {
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
passwd++;
}
}
#define zdecode(pkeys,pcrc_32_tab,c) \
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
#define zencode(pkeys,pcrc_32_tab,c,t) \
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
#define RAND_HEAD_LEN 12
/* "last resort" source for second part of crypt seed pattern */
# ifndef ZCR_SEED2
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
# endif
static int crypthead(const char* passwd, /* password string */
unsigned char* buf, /* where to write header */
int bufSize,
unsigned long* pkeys,
const z_crc_t* pcrc_32_tab,
unsigned long crcForCrypting)
{
int n; /* index in random header */
int t; /* temporary */
int c; /* random byte */
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
static unsigned calls = 0; /* ensure different random header each time */
if (bufSize<RAND_HEAD_LEN)
return 0;
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
* output of rand() to get less predictability, since rand() is
* often poorly implemented.
*/
if (++calls == 1)
{
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
}
init_keys(passwd, pkeys, pcrc_32_tab);
for (n = 0; n < RAND_HEAD_LEN-2; n++)
{
c = (rand() >> 7) & 0xff;
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
}
/* Encrypt random header (last two bytes is high word of crc) */
init_keys(passwd, pkeys, pcrc_32_tab);
for (n = 0; n < RAND_HEAD_LEN-2; n++)
{
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
}
buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
return n;
}
#endif

View file

@ -10,10 +10,22 @@
*/ */
#if (defined(_WIN32)) #if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#if defined(__APPLE__) || defined(IOAPI_NO_64)
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
#define FTELLO_FUNC(stream) ftello(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
#else
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
#define FTELLO_FUNC(stream) ftello64(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
#endif
#include "ioapi.h" #include "ioapi.h"
voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
@ -47,7 +59,7 @@ ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream
else else
{ {
uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
if ((tell_uLong) == ((uLong)-1)) if ((tell_uLong) == MAXU32)
return (ZPOS64_T)-1; return (ZPOS64_T)-1;
else else
return tell_uLong; return tell_uLong;
@ -112,7 +124,7 @@ static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename,
mode_fopen = "wb"; mode_fopen = "wb";
if ((filename!=NULL) && (mode_fopen != NULL)) if ((filename!=NULL) && (mode_fopen != NULL))
file = fopen64((const char*)filename, mode_fopen); file = FOPEN_FUNC((const char*)filename, mode_fopen);
return file; return file;
} }
@ -142,7 +154,7 @@ static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
{ {
ZPOS64_T ret; ZPOS64_T ret;
ret = ftello64((FILE *)stream); ret = FTELLO_FUNC((FILE *)stream);
return ret; return ret;
} }
@ -188,7 +200,7 @@ static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T
} }
ret = 0; ret = 0;
if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0)
ret = -1; ret = -1;
return ret; return ret;

View file

@ -21,7 +21,7 @@
#ifndef _ZLIBIOAPI64_H #ifndef _ZLIBIOAPI64_H
#define _ZLIBIOAPI64_H #define _ZLIBIOAPI64_H
#if (!defined(_WIN32)) && (!defined(WIN32)) #if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
// Linux needs this to support file operation on files larger then 4+GB // Linux needs this to support file operation on files larger then 4+GB
// But might need better if/def to select just the platforms that needs them. // But might need better if/def to select just the platforms that needs them.
@ -38,6 +38,7 @@
#ifndef _FILE_OFFSET_BIT #ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64 #define _FILE_OFFSET_BIT 64
#endif #endif
#endif #endif
#include <stdio.h> #include <stdio.h>
@ -49,6 +50,11 @@
#define ftello64 ftell #define ftello64 ftell
#define fseeko64 fseek #define fseeko64 fseek
#else #else
#ifdef __FreeBSD__
#define fopen64 fopen
#define ftello64 ftello
#define fseeko64 fseeko
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define fopen64 fopen #define fopen64 fopen
#if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
@ -85,6 +91,8 @@ typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
typedef uint64_t ZPOS64_T; typedef uint64_t ZPOS64_T;
#else #else
/* Maximum unsigned 32-bit value used as placeholder for zip64 */
#define MAXU32 0xffffffff
#if defined(_MSC_VER) || defined(__BORLANDC__) #if defined(_MSC_VER) || defined(__BORLANDC__)
typedef unsigned __int64 ZPOS64_T; typedef unsigned __int64 ZPOS64_T;

View file

@ -188,7 +188,7 @@ typedef struct
# ifndef NOUNCRYPT # ifndef NOUNCRYPT
unsigned long keys[3]; /* keys defining the pseudo-random sequence */ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
const unsigned long* pcrc_32_tab; const z_crc_t* pcrc_32_tab;
# endif # endif
} unz64_s; } unz64_s;
@ -200,7 +200,7 @@ typedef struct
/* =========================================================================== /* ===========================================================================
Read a byte from a gz_stream; update next_in and avail_in. Return EOF Read a byte from a gz_stream; update next_in and avail_in. Return EOF
for end of file. for end of file.
IN assertion: the stream s has been sucessfully opened for reading. IN assertion: the stream s has been successfully opened for reading.
*/ */
@ -801,9 +801,9 @@ extern unzFile ZEXPORT unzOpen64 (const void *path)
} }
/* /*
Close a ZipFile opened with unzipOpen. Close a ZipFile opened with unzOpen.
If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose. these files MUST be closed with unzCloseCurrentFile before call unzClose.
return UNZ_OK if there is no problem. */ return UNZ_OK if there is no problem. */
extern int ZEXPORT unzClose (unzFile file) extern int ZEXPORT unzClose (unzFile file)
{ {
@ -1040,26 +1040,26 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
{ {
uLong uL; uLong uL;
if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) if(file_info.uncompressed_size == MAXU32)
{ {
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
err=UNZ_ERRNO; err=UNZ_ERRNO;
} }
if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) if(file_info.compressed_size == MAXU32)
{ {
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
err=UNZ_ERRNO; err=UNZ_ERRNO;
} }
if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) if(file_info_internal.offset_curfile == MAXU32)
{ {
/* Relative Header offset */ /* Relative Header offset */
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
err=UNZ_ERRNO; err=UNZ_ERRNO;
} }
if(file_info.disk_num_start == (unsigned long)-1) if(file_info.disk_num_start == MAXU32)
{ {
/* Disk Start Number */ /* Disk Start Number */
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
@ -1145,7 +1145,7 @@ extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
szFileName,fileNameBufferSize, szFileName,fileNameBufferSize,
extraField,extraFieldBufferSize, extraField,extraFieldBufferSize,
szComment,commentBufferSize); szComment,commentBufferSize);
if (err==UNZ_OK) if ((err==UNZ_OK) && (pfile_info != NULL))
{ {
pfile_info->version = file_info64.version; pfile_info->version = file_info64.version;
pfile_info->version_needed = file_info64.version_needed; pfile_info->version_needed = file_info64.version_needed;
@ -1223,7 +1223,7 @@ extern int ZEXPORT unzGoToNextFile (unzFile file)
/* /*
Try locate the file szFileName in the zipfile. Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzipStringFileNameCompare For the iCaseSensitivity signification, see unzStringFileNameCompare
return value : return value :
UNZ_OK if the file is found. It becomes the current file. UNZ_OK if the file is found. It becomes the current file.
@ -1696,7 +1696,7 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
return UNZ_PARAMERROR; return UNZ_PARAMERROR;
if ((pfile_in_zip_read_info->read_buffer == NULL)) if (pfile_in_zip_read_info->read_buffer == NULL)
return UNZ_END_OF_LIST_OF_FILE; return UNZ_END_OF_LIST_OF_FILE;
if (len==0) if (len==0)
return 0; return 0;
@ -1998,7 +1998,7 @@ extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len)
} }
/* /*
Close the file in zip opened with unzipOpenCurrentFile Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/ */
extern int ZEXPORT unzCloseCurrentFile (unzFile file) extern int ZEXPORT unzCloseCurrentFile (unzFile file)

View file

@ -197,9 +197,9 @@ extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
extern int ZEXPORT unzClose OF((unzFile file)); extern int ZEXPORT unzClose OF((unzFile file));
/* /*
Close a ZipFile opened with unzipOpen. Close a ZipFile opened with unzOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later), If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose. these files MUST be closed with unzCloseCurrentFile before call unzClose.
return UNZ_OK if there is no problem. */ return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,