- Added Wii port - exits back to Homebrew Channel after loading ROM

right now - needs work
- Renamed Makefile-next-ps3 to Makefile - PS3 port new core now
default
This commit is contained in:
TwinAphex51224 2011-11-23 16:32:50 +01:00
parent cba59f9b40
commit e0c9ee862f
214 changed files with 34688 additions and 4552 deletions

View File

@ -14,7 +14,7 @@ CELL_BUILD_TOOLS = SNC
ifeq ($(CELL_DEBUG),1)
PPU_OPTIMIZE_LV := -O0
else
PPU_OPTIMIZE_LV := -O2
PPU_OPTIMIZE_LV := -O3
endif
# specify build tools
@ -43,7 +43,7 @@ CC = $(CELL_HOST_PATH)/ppu/bin/ppu-lv2-g++
UTILS_DIR = ./utils
SRC_DIR = ./src
SNES9X_API_DIR = ./src/snes9x
SNES9X_API_DIR = ./src/snes9x-next
CELL_FRAMEWORK_DIR = ./src/cellframework
CELL_FRAMEWORK2_DIR = ./src/cellframework2
EBOOT_LAUNCHER_DIR = eboot-launcher
@ -53,10 +53,10 @@ EMULATOR_VERSION = 1.0
PPU_SRCS += $(SNES9X_API_DIR)/tile.cpp \
$(SNES9X_API_DIR)/cpu.cpp \
$(SNES9X_API_DIR)/dma.cpp \
$(SNES9X_API_DIR)/gfx.cpp \
$(SNES9X_API_DIR)/ppu.cpp \
$(SNES9X_API_DIR)/sa1.cpp \
$(SNES9X_API_DIR)/sa1cpu.cpp \
$(SNES9X_API_DIR)/fxdbg.cpp \
$(SNES9X_API_DIR)/fxemu.cpp \
$(SNES9X_API_DIR)/fxinst.cpp \
$(SNES9X_API_DIR)/cpuexec.cpp \
@ -65,7 +65,9 @@ PPU_SRCS += $(SNES9X_API_DIR)/tile.cpp \
$(SNES9X_API_DIR)/memmap.cpp \
$(SNES9X_API_DIR)/apu/apu.cpp \
$(SNES9X_API_DIR)/apu/SNES_SPC.cpp \
$(foreach dir,$(SNES9X_API_DIR)/jma/,$(wildcard $(dir)/*.cpp)) \
$(SNES9X_API_DIR)/apu/SNES_SPC_misc.cpp \
$(SNES9X_API_DIR)/apu/SNES_SPC_state.cpp \
$(SNES9X_API_DIR)/apu/SPC_DSP.cpp \
$(SNES9X_API_DIR)/bsx.cpp \
$(SNES9X_API_DIR)/c4.cpp \
$(SNES9X_API_DIR)/c4emu.cpp \
@ -80,23 +82,19 @@ PPU_SRCS += $(SNES9X_API_DIR)/tile.cpp \
$(SNES9X_API_DIR)/dsp4.cpp \
$(SNES9X_API_DIR)/globals.cpp \
$(SNES9X_API_DIR)/loadzip.cpp \
$(SNES9X_API_DIR)/netplay.cpp \
$(SNES9X_API_DIR)/obc1.cpp \
$(SNES9X_API_DIR)/reader.cpp \
$(SNES9X_API_DIR)/sdd1.cpp \
$(SNES9X_API_DIR)/sdd1emu.cpp \
$(SNES9X_API_DIR)/server.cpp \
$(SNES9X_API_DIR)/seta.cpp \
$(SNES9X_API_DIR)/seta010.cpp \
$(SNES9X_API_DIR)/seta011.cpp \
$(SNES9X_API_DIR)/seta018.cpp \
$(SNES9X_API_DIR)/snapshot.cpp \
$(SNES9X_API_DIR)/snes9x.cpp \
$(SNES9X_API_DIR)/spc7110.cpp
PPU_SRCS += $(UTILS_DIR)/zlib/adler32.c \
$(UTILS_DIR)/zlib/compress.c \
$(UTILS_DIR)/zlib/crc32.c \
$(UTILS_DIR)/zlib/deflate.c \
$(UTILS_DIR)/zlib/gzclose.c \
@ -111,9 +109,8 @@ PPU_SRCS += $(UTILS_DIR)/zlib/adler32.c \
$(UTILS_DIR)/zlib/uncompr.c \
$(UTILS_DIR)/zlib/zutil.c \
$(UTILS_DIR)/zlib/contrib/minizip/ioapi.c \
$(UTILS_DIR)/zlib/contrib/minizip/mztools.c \
$(UTILS_DIR)/zlib/contrib/minizip/zip.c \
$(UTILS_DIR)/zlib/contrib/minizip/unzip.c
PPU_SRCS += $(CELL_FRAMEWORK2_DIR)/audio/rsound.c \
$(CELL_FRAMEWORK2_DIR)/audio/librsound.c \
$(CELL_FRAMEWORK2_DIR)/audio/buffer.c \
@ -127,11 +124,11 @@ PPU_SRCS += $(SRC_DIR)/ps3video.cpp \
$(CELL_FRAMEWORK2_DIR)/audio/resampler.c \
$(CELL_FRAMEWORK2_DIR)/audio/audioport.c \
$(SRC_DIR)/ps3input.c \
$(SRC_DIR)/emu-ps3.cpp \
$(SRC_DIR)/emu-ps3-next.cpp \
$(CELL_FRAMEWORK2_DIR)/utility/oskutil.c \
$(CELL_FRAMEWORK_DIR)/fileio/FileBrowser.cpp
PPU_TARGET = snes9x-ps3.ppu.elf
PPU_TARGET = snes9x-next-ps3.ppu.elf
ifeq ($(CELL_DEBUG),1)
DEBUGFLAGS = -D_DEBUG -g
@ -139,8 +136,10 @@ else
DEBUGFLAGS =
endif
PPU_CFLAGS += -I. -DUSE_FILE32API -Dunix -DPSGL -DCORRECT_VRAM_READS -DRIGHTSHIFT_IS_SAR -DSN_TARGET_PS3 -DNDEBUG=1 -DWORDS_BIGENDIAN -DBLARGG_BIG_ENDIAN=1 -DNO_LOGGER -D__POWERPC__ -D__ppc__ $(DEBUGFLAGS)
PPU_CXXFLAGS += -I./src/ -I./src/snes9x/ -DZLIB -DUNZIP_SUPPORT -DJMA_SUPPORT -DPSGL -DCORRECT_VRAM_READS -DRIGHTSHIFT_IS_SAR -DNO_LOGGER -DSN_TARGET_PS3 -DNDEBUG=1 -DWORDS_BIGENDIAN -DBLARGG_BIG_ENDIAN=1 -D__POWERPC__ -D__ppc__ $(DEBUGFLAGS)
ZLIB_DEFINES = -DUSE_FILE32API -DUnix -DFASTEST
DEFINES = -DBLARGG_BIG_ENDIAN=1 -DWORDS_BIGENDIAN -D__POWERPC__ -D__ppc__ -DCLUNKY_FILE_ABSTRACTION -DSNES9X_NEXT -DPSGL -DCORRECT_VRAM_READS -DRIGHTSHIFT_IS_SAR -DNDEBUG=1 -DSN_TARGET_PS3 -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DUNZIP_SUPPORT
PPU_CFLAGS += -I. $(ZLIB_DEFINES) $(DEFINES) $(DEBUGFLAGS)
PPU_CXXFLAGS += -I./src/ -I$(SNES_API_DIR) -I$(UTILS_DIR)/zlib -DZLIB $(DEFINES) $(DEBUGFLAGS)
ifeq ($(CELL_BUILD_TOOLS),SNC)
PARAMS = -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 -Xunroll=1 -Xautovecreg=1 -Xnotocrestore=2 -Xc-=rtti

View File

@ -1,230 +0,0 @@
#options, set 1 to enable
CELL_DEBUG = 0
CELL_DEBUG_CONSOLE = 0
CELL_DEBUG_FPS = 0
NO_FRAMESKIP = 0
MULTIMAN_SUPPORT = 0
TOC_LOG = 0
SDK_340 = 1
#which compiler to build with - GCC or SNC
#set to GCC for debug builds for use with debugger
CELL_BUILD_TOOLS = SNC
ifeq ($(CELL_DEBUG),1)
PPU_OPTIMIZE_LV := -O0
else
PPU_OPTIMIZE_LV := -O2
endif
# specify build tools
#explicitly set some cell sdk defaults
CELL_SDK ?= /usr/local/cell
# CELL_GPU_TYPE (currently RSX is only one option)
CELL_GPU_TYPE = RSX
#CELL_PSGL_VERSION is debug, dpm or opt
CELL_PSGL_VERSION = opt
#Python binary - only useful for PSL1ght scripts
PYTHONBIN = python2.7
CELL_MK_DIR ?= $(CELL_SDK)/samples/mk
include $(CELL_MK_DIR)/sdk.makedef.mk
# Geohot CFW defines
MKSELF_GEOHOT = make_self_npdrm
MKPKG_PSLIGHT = buildtools/PS3Py/pkg.py
PKG_FINALIZE = package_finalize
STRIP = $(CELL_HOST_PATH)/ppu/bin/ppu-lv2-strip
C = $(CELL_HOST_PATH)/ppu/bin/ppu-lv2-gcc
CC = $(CELL_HOST_PATH)/ppu/bin/ppu-lv2-g++
UTILS_DIR = ./utils
SRC_DIR = ./src
SNES9X_API_DIR = ./src/snes9x-next
CELL_FRAMEWORK_DIR = ./src/cellframework
CELL_FRAMEWORK2_DIR = ./src/cellframework2
EBOOT_LAUNCHER_DIR = eboot-launcher
EMULATOR_VERSION = 1.0
PPU_SRCS += $(SNES9X_API_DIR)/tile.cpp \
$(SNES9X_API_DIR)/cpu.cpp \
$(SNES9X_API_DIR)/dma.cpp \
$(SNES9X_API_DIR)/gfx.cpp \
$(SNES9X_API_DIR)/ppu.cpp \
$(SNES9X_API_DIR)/sa1.cpp \
$(SNES9X_API_DIR)/sa1cpu.cpp \
$(SNES9X_API_DIR)/fxemu.cpp \
$(SNES9X_API_DIR)/fxinst.cpp \
$(SNES9X_API_DIR)/cpuexec.cpp \
$(SNES9X_API_DIR)/cpuops.cpp \
$(SNES9X_API_DIR)/srtc.cpp \
$(SNES9X_API_DIR)/memmap.cpp \
$(SNES9X_API_DIR)/apu/apu.cpp \
$(SNES9X_API_DIR)/apu/SNES_SPC.cpp \
$(SNES9X_API_DIR)/apu/SNES_SPC_misc.cpp \
$(SNES9X_API_DIR)/apu/SNES_SPC_state.cpp \
$(SNES9X_API_DIR)/apu/SPC_DSP.cpp \
$(SNES9X_API_DIR)/bsx.cpp \
$(SNES9X_API_DIR)/c4.cpp \
$(SNES9X_API_DIR)/c4emu.cpp \
$(SNES9X_API_DIR)/cheats.cpp \
$(SNES9X_API_DIR)/cheats2.cpp \
$(SNES9X_API_DIR)/controls.cpp \
$(SNES9X_API_DIR)/crosshairs.cpp \
$(SNES9X_API_DIR)/dsp.cpp \
$(SNES9X_API_DIR)/dsp1.cpp \
$(SNES9X_API_DIR)/dsp2.cpp \
$(SNES9X_API_DIR)/dsp3.cpp \
$(SNES9X_API_DIR)/dsp4.cpp \
$(SNES9X_API_DIR)/globals.cpp \
$(SNES9X_API_DIR)/loadzip.cpp \
$(SNES9X_API_DIR)/obc1.cpp \
$(SNES9X_API_DIR)/reader.cpp \
$(SNES9X_API_DIR)/sdd1.cpp \
$(SNES9X_API_DIR)/sdd1emu.cpp \
$(SNES9X_API_DIR)/seta.cpp \
$(SNES9X_API_DIR)/seta010.cpp \
$(SNES9X_API_DIR)/seta011.cpp \
$(SNES9X_API_DIR)/seta018.cpp \
$(SNES9X_API_DIR)/snapshot.cpp \
$(SNES9X_API_DIR)/spc7110.cpp
PPU_SRCS += $(UTILS_DIR)/zlib/adler32.c \
$(UTILS_DIR)/zlib/compress.c \
$(UTILS_DIR)/zlib/crc32.c \
$(UTILS_DIR)/zlib/deflate.c \
$(UTILS_DIR)/zlib/gzclose.c \
$(UTILS_DIR)/zlib/gzlib.c \
$(UTILS_DIR)/zlib/gzread.c \
$(UTILS_DIR)/zlib/gzwrite.c \
$(UTILS_DIR)/zlib/infback.c \
$(UTILS_DIR)/zlib/inffast.c \
$(UTILS_DIR)/zlib/inflate.c \
$(UTILS_DIR)/zlib/inftrees.c \
$(UTILS_DIR)/zlib/trees.c \
$(UTILS_DIR)/zlib/uncompr.c \
$(UTILS_DIR)/zlib/zutil.c \
$(UTILS_DIR)/zlib/contrib/minizip/ioapi.c \
$(UTILS_DIR)/zlib/contrib/minizip/mztools.c \
$(UTILS_DIR)/zlib/contrib/minizip/zip.c \
$(UTILS_DIR)/zlib/contrib/minizip/unzip.c
PPU_SRCS += $(CELL_FRAMEWORK2_DIR)/audio/rsound.c \
$(CELL_FRAMEWORK2_DIR)/audio/librsound.c \
$(CELL_FRAMEWORK2_DIR)/audio/buffer.c \
$(CELL_FRAMEWORK2_DIR)/input/pad_input.c \
$(CELL_FRAMEWORK2_DIR)/input/mouse_input.c \
PPU_SRCS += $(SRC_DIR)/ps3video.cpp \
$(SRC_DIR)/snes_state/snes_state.c \
$(SRC_DIR)/snes_state/config_file.c \
$(SRC_DIR)/menu.cpp \
$(CELL_FRAMEWORK2_DIR)/audio/resampler.c \
$(CELL_FRAMEWORK2_DIR)/audio/audioport.c \
$(SRC_DIR)/ps3input.c \
$(SRC_DIR)/emu-ps3-next.cpp \
$(CELL_FRAMEWORK2_DIR)/utility/oskutil.c \
$(CELL_FRAMEWORK_DIR)/fileio/FileBrowser.cpp
PPU_TARGET = snes9x-next-ps3.ppu.elf
ifeq ($(CELL_DEBUG),1)
DEBUGFLAGS = -D_DEBUG -g
else
DEBUGFLAGS =
endif
PPU_CFLAGS += -I. -DUSE_FILE32API -Dunix -DPSGL -DCORRECT_VRAM_READS -DRIGHTSHIFT_IS_SAR -DSN_TARGET_PS3 -DNDEBUG=1 -DWORDS_BIGENDIAN -DBLARGG_BIG_ENDIAN=1 -DNO_LOGGER -D__POWERPC__ -D__ppc__ -DSNES9X_NEXT -DCLUNKY_FILE_ABSTRACTION $(DEBUGFLAGS)
PPU_CXXFLAGS += -I./src/ -I$(SNES_API_DIR) -I$(UTILS_DIR)/zlib -DZLIB -DUNZIP_SUPPORT -DJMA_SUPPORT -DPSGL -DCORRECT_VRAM_READS -DRIGHTSHIFT_IS_SAR -DNO_LOGGER -DSN_TARGET_PS3 -DNDEBUG=1 -DWORDS_BIGENDIAN -DBLARGG_BIG_ENDIAN=1 -D__POWERPC__ -D__ppc__ -DSNES9X_NEXT -DCLUNKY_FILE_ABSTRACTION $(DEBUGFLAGS)
ifeq ($(CELL_BUILD_TOOLS),SNC)
PARAMS = -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 -Xunroll=1 -Xautovecreg=1 -Xnotocrestore=2 -Xc-=rtti
PPU_CFLAGS += $(PARAMS)
PPU_CXXFLAGS += $(PARAMS)
NOTOCRESTORE = --notocrestore
else
PPU_CFLAGS += -funroll-loops -fno-rtti
PPU_CXXFLAGS += -funroll-loops -fno-rtti
NOTOCRESTORE =
endif
ifeq ($(CELL_DEBUG_CONSOLE),1)
PPU_CFLAGS += -DCELL_DEBUG_CONSOLE
PPU_CXXFLAGS += -DCELL_DEBUG_CONSOLE
L_CONTROL_CONSOLE_LDLIBS = -lcontrol_console_ppu
L_NET_CTL_LDLIBS = -lnetctl_stub
endif
ifeq ($(CELL_DEBUG_FPS),1)
PPU_CFLAGS += -DCELL_DEBUG_FPS
PPU_CXXFLAGS += -DCELL_DEBUG_FPS
endif
ifeq ($(NO_FRAMESKIP),1)
PPU_CFLAGS += -DNO_FRAMESKIP=1
PPU_CXXFLAGS += -DNO_FRAMESKIP=1
endif
ifeq ($(MULTIMAN_SUPPORT),1)
PPU_CFLAGS += -DMULTIMAN_SUPPORT=1
PPU_CXXFLAGS += -DMULTIMAN_SUPPORT=1
ifeq ($(shell uname), Linux)
MKFSELF_WC = $(HOME)/bin/make_self_wc
else
MKFSELF_WC = $(CELL_SDK)/../bin/make_self_wc
endif
endif
ifeq ($(TOC_LOG),1)
TOC_INFO = --print-toc-info
else
TOC_INFO =
endif
ifeq ($(SDK_340),1)
L_SYSUTIL_SCREENSHOT = -lsysutil_screenshot_stub
else
L_SYSUTIL_SCREENSHOT =
endif
PPU_LDLIBS += -L. -L$(CELL_SDK)/target/ppu/lib/PSGL/RSX/opt -ldbgfont -lPSGL -lPSGLcgc -lcgc \
-lgcm_cmd -lgcm_sys_stub -lresc_stub -lm -lio_stub -lfs_stub -lsysutil_stub -lsysutil_game_stub $(L_SYSUTIL_SCREENSHOT) $(L_CONTROL_CONSOLE_LDLIBS) -lpngdec_stub -ljpgdec_stub \
-lsysmodule_stub -laudio_stub -lpthread -lnet_stub $(L_NET_CTL_LDLIBS) $(TOC_INFO) $(NOTOCRESTORE)
include $(CELL_MK_DIR)/sdk.target.mk
.PHONY: pkg
#standard pkg packaging
pkg: $(PPU_TARGET)
ifeq ($(MULTIMAN_SUPPORT),1)
$(MKFSELF_WC) $(PPU_TARGET) pkg/USRDIR/RELOAD.SELF
else
$(MAKE_FSELF_NPDRM) $(PPU_TARGET) pkg/USRDIR/EBOOT.BIN
endif
$(MAKE_PACKAGE_NPDRM) pkg/package.conf pkg
#massively reduced filesize using MKSELF_GEOHOT - use this for normal jailbreak builds
.PHONY: pkg-signed
pkg-signed: $(PPU_TARGET)
ifeq ($(MULTIMAN_SUPPORT),1)
$(MKFSELF_WC) $(PPU_TARGET) pkg/USRDIR/RELOAD.SELF
else
$(MKSELF_GEOHOT) $(PPU_TARGET) pkg/USRDIR/EBOOT.BIN SNES900000
endif
$(PYTHONBIN) $(MKPKG_PSLIGHT) --contentid IV0002-SNES90000_00-SAMPLE0000000001 pkg/ snes9xnext-ps3-v$(EMULATOR_VERSION)-fw3.41.pkg
#use this to create a PKG for use with Geohot CFW 3.55
.PHONY: pkg-signed-cfw
pkg-signed-cfw:
ifeq ($(MULTIMAN_SUPPORT),1)
$(MKFSELF_WC) $(PPU_TARGET) pkg/USRDIR/RELOAD.SELF
else
$(MKSELF_GEOHOT) $(PPU_TARGET) pkg/USRDIR/EBOOT.BIN SNES900000
endif
$(PYTHONBIN) $(MKPKG_PSLIGHT) --contentid IV0002-SNES90000_00-SAMPLE0000000001 pkg/ snes9xnext-ps3-v$(EMULATOR_VERSION)-cfw3.55.pkg
$(PKG_FINALIZE) snes9xnext-ps3-v$(EMULATOR_VERSION)-cfw3.55.pkg

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +0,0 @@
Control input names are completely defined by the individual ports. This
document is intended to collect the rules for all ports.
The various meta-characters in the rules are:
# - A number. The range is detemined by the context
## - A two-digit number (i.e. with leading zeros)
[...] - Something optional
(...) - For grouping with |
| - "or", choose one of the options.
<...> - A named field
{...} - A list of possible values. Multiple values may be used, but they
must be in the order listed and joined with +-signs.
"" - 'ditto', used to indicate the same list as the above line.
================================================================================
Unix
================================================================================
Input names:
Jxx:Axis# Axis # on joystick xx. Axis0 may be
Up/Down, and Axis1 Left/Right.
Jxx:B# Button # on joystick xx.
Jxx:{M1,M2,M3,M4,M5,M6,M7,M8}+B# Used with the 'JSx Meta#' port
Jxx:{M1,M2,M3,M4,M5,M6,M7,M8}+Axis# command.
Jxx:X+B# Used to 'define' this key for all
Jxx:X+Axis# combinations of JS Meta.
Port-specific Commands:
JSx Meta# Used to specify modifier keys (i.e. Shift, Control) to
affect the specified joystick. For example, you could
map J00:B20 to "JS0 Meta1", then map J00:B0 to "Joypad1
A" and J00:M1+B0 to "Joypad1 Turbo A". '#' may range
from 1-8.
Jsx ToggleMeta# Like the above, but toggles the meta-state each time
the button is pressed.
================================================================================
Unix/X11
================================================================================
Keyboard Input:
Note that only one keyboard (K00) is currently supported. If you know how
to support multiple keyboards (and can test it!), feel free to fix x11.cpp
and delete this note.
Keyboard modifiers are S=Shift, C=Control, A=Alt, M=Meta. Combine them in
order, i.e. all 4 would be "SCAM".
Kxx:<keyname> Key names are as recognized by XStringToKeysym.
Kxx:<mods>+<keyname> Note however that keys are mapped by keycode,
so for example on a standard qwerty keyboard
"K00:colon" and "K00:semicolon" are identical.
Pointer Input:
Note that only one mouse (M00) is currently supported. If you know how to
support multiple pointing devices (and can test it!), feel free to fix
x11.cpp and delete this note.
Mxx:Pointer Map the mouse pointer. If someone has a mouse
Mxx:Pointer# device with multiple pointers, fix x11.cpp to
report that and you can use the second syntax.
Mxx:B# Mouse buttons.

View File

@ -1,97 +0,0 @@
This lists the available commands, excluding the ones you get back from
S9xGetAllSnes9xCommands(). The various meta-characters are:
# - A number. The range is detemined by the context
## - A two-digit number (i.e. with leading zeros)
[...] - Something optional
(...) - For grouping with |
| - "or", choose one of the options.
<...> - A named field
{...} - A list of possible values. Multiple values may be used, but they
must be in the order listed and joined with +-signs.
"" - 'ditto', used to indicate the same list as the above line.
Speeds are: Var, Slow, Med, and Fast. 'Var' starts slow and speeds up as the
button is held.
Axes are: Left/Right, Right/Left, Up/Down, Down/Up, Y/A, A/Y, X/B, B/X, L/R,
and R/L. Negative is listed first (i.e. "Y/A" means negative deflection is
towards Y, while "A/Y" means negative deflection is towards A).
AxisToPointer, ButtonToPointer, and AxisToButtons allow for translating
between different input types. There are 8 'pointers' with IDs
PseudoPointerBase+0 to PseudoPointerBase+7, and 256 'buttons' with IDs
PseudoButtonBase+0 to PseudoButtonBase+255. So for example,
"AxisToButtons 0/255 T=50%" would take the axis data, and do
S9xReportButton(PseudoButtonBase+0,1) when said axis goes past 50% in the
negative direction and S9xReportButton(PseudoButtonBase+255,1) when it goes
over 50% deflection in the positive direction. Similarly, it will do
S9xReportButton(...,0) when the deflection drops under 50% in either
direction. "ButtonToPointer 1u Slow" would move the pointer with ID
PseudoPointerBase+0 up one pixel per frame as long as the button is pressed
(reporting this change at the end of each frame).
---------------
Button Commands
---------------
Joypad# {Up, Down, Left, Right, A, B, X, Y, L, R, Start, Select}
Joypad# Turbo ""
Joypad# Sticky ""
Joypad# StickyTurbo ""
Joypad# ToggleTurbo ""
Joypad# ToggleSticky ""
Joypad# ToggleStickyTurbo ""
Mouse# (L|R|LR)
Superscope AimOffscreen
Superscope {Fire, Cursor, ToggleTurbo, Pause}
Superscope AimOffscreen ""
Justifier# AimOffscreen
Justifier# {Trigger, Start}
Justifier# AimOffscreen ""
ButtonToPointer #[u|d][l|r] <speed> ; NOTE: "# <speed>" is invalid
-------------
Axis Commands
-------------
Joypad# Axis <axis> T=#% ; T = 0.1 to 100 by tenths
AxisToButtons #/# T=#% ; neg then pos, range 0-255, T as above
AxisToPointer #(h|v) [-]<speed> ; NOTE: '-' inverts the axis
----------------
Pointer Commands
----------------
Pointer {Mouse1, Mouse2, Superscope, Justifier1, Justifier2}
------
Multis
------
Multis are a type of button command. The basic format of a multi is "{...}",
where the '...' consists of 1 or more valid non-multi button command
strings. The braces are literal, not metacharacters. Subcommands separated
by commas are executed one after the next. Semicolons skip one frame before
continuing subcommand execution. Semicolons may be repeated. When the multi
button is pressed, each subcommand is 'pressed', and when the multi button
is released each subcommand is 'released'.
There are also press-only multis, defined as "+{...}". These act just like
regular multis, with two differences: the multi is only run when you press
the button (release isignored), and each subcommand must be prefixed with
'+' or '-' to indicate whether the the subcommand should be pressed or
released.
For example: {Joypad1 A,Joypad2 A;Joypad3 A;;;;;QuickSave000}
This presses (or releases) A on pads 1 and 2, then waits one frame, then
presses A on pad 3, then waits 5 frames, then saves to snapshot 0 (on press
only).
You may access the multi number in the returned s9xcommand_t structure as
cmd.button.multi_idx. This may be used to assign the same multi to multiple
buttons:
MULTI#<num> ; NOTE: that's a literal octothorpe

View File

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -1,504 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -1,385 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en-US">
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta name="description" content="How to Port Snes9x to a New Platform">
<style type="text/css">
<!-- ul { list-style-type:none } h2 { margin-top:3em } h3 { margin-top:2em } -->
</style>
<title>Porting Snes9x</title>
</head>
<body>
<h1 style="text-align:center">How to Port Snes9x to a New Platform</h1>
<div style="text-align:right">
Version: 1.52<br>
(c) Copyright 1998 Gary Henderson
</div>
<h2>Introduction</h2>
<p>
This is brief description of the steps to port Snes9x to the new platform. It describes what code you have to write and what functions exist that you can make use of. It also gives some insights as to how Snes9x actually works, although that will be subject of another document yet to be written.
</p>
<h2>System Requirements</h2>
<p>
A C++ compiler. For the most part Snes9x really isn't written in C++, it just uses the C++ compiler as a &ldquo;better C&rdquo; compiler to get inline functions and so on. GCC is good for compiling Snes9x (<a href="http://gcc.gnu.org/">http://gcc.gnu.org/</a>).
</p>
<p>
A fast CPU. SNES emulation is very compute intensive; two, or sometimes three CPUs to emulate, an 8-channel 16-bit stereo sound digital signal processor with real-time sample decompression, filter and echo effects, two custom graphics processor chips that can produce transparency, scaling, rotation and window effects in 32768 colors, and finally hardware DMA all take their toll on the host CPU.
</p>
<p>
Enough RAM. Snes9x uses 8MB to load SNES ROM images and several MB for emulating sound, graphics, custom chips, and so on.
</p>
<p>
A 16-bit color (two bytes per pixel) or deeper display, at least 512*478 pixels in resolution. Pixel format conversion may be required before you place the rendered SNES screen on to the display.
</p>
<p>
Sound output requires spooling 8-bit or 16-bit, mono or stereo digital sound data to the host sound system. Some ports can use interrupts or callbacks from the sound system to know when more sound data is required, most other ports have to periodically poll the host sound system to see if more data is required; if it is then the sound mixing code is called to fill the sound buffer with SNES sound data, which then can be passed on to the host sound system. Sound data is generated as an array of bytes (<code>uint8</code>) for 8-bit sound or shorts (<code>int16</code>) for 16-bit data. Stereo sound data generates twice as many samples, with each channel's samples interleaved, first left's then right's.
</p>
<p>
For the user to be able to control and play SNES games, some form of input device is required, a joypad or keyboard, for example. The real SNES can have 2 eight-button digital joypads connected to it or 5 joypads when an optional multi-player adaptor is connected, although most games only require a single joypad. Access to all eight buttons and the direction pad, of course, are usually required by most games. Snes9x does emulate the multi-player adaptor hardware, if you were wondering, but its still up to you to provide the emulation of the individual joypads.
</p>
<p>
The real SNES also has a SNES mouse, Super Scope and Justifier (light-gun) available as optional extras. Snes9x can emulate all of these using some form of pointing device, usually the host system's mouse.
</p>
<p>
Some SNES game cartridges contains a small amount of extra RAM and a battery, so ROMs could save a player's progress through a game for games that takes many hours to play from start to finish. Snes9x simulates this S-RAM by saving the contents of the area of memory occupied by the S-RAM into a file then automatically restoring it again the next time the user plays the same game. If the hardware you're porting to doesn't have a storage media available then you could be in trouble.
</p>
<p>
Snes9x also implements freeze-game files which can record the state of the SNES hardware and RAM at a particular point in time and can restore it to that exact state at a later date - the result is that users can save a game at any point, not just at save-game or password points provided by the original game coders. Each freeze file is over 400k in size. To help save disk space, Snes9x can be compiled with zlib (<a href="http://www.zlib.net/">http://www.zlib.net/</a>), which is used to GZIP compress the freeze files, reducing the size to typically below 100k. zlib is also used to load GZIP or ZIP compressed ROM images. Additionally, Snes9x supports JMA archives compressed with NSRT (<a href="http://nsrt.edgeemu.com/">http://nsrt.edgeemu.com/</a>).
</p>
<h2>Compile-Time Options</h2>
<h3><code>DEBUGGER</code></h3>
<p>
Enables extra code to assist you in debugging SNES ROMs. The debugger has only ever been a quick-hack and user-interface to debugger facilities is virtually non-existent. Most of the debugger information is output via stdout and enabling the debugger slows the whole emulator down slightly. However, the debugger options available are very powerful; you could use it to help get your port working. You probably still want to ship the finished version with the debugger disabled, it will only confuse non-technical users.
</p>
<h3><code>RIGHTSHIFT_IS_SAR</code></h3>
<p>
Define this if your compiler uses shift right arithmetic for signed values. For example, GCC and Visual C++ use shift right arithmetic.
</p>
<h3><code>CPU_SHUTDOWN</code></h3>
<p>
This is a speed-up hack. When defined and if <code>Settings.ShutdownMaster</code> is <code>true</code>, Snes9x starts watching for when CPU is in a simply loop waiting for a known event to happen - like the end of the current scanline. If Snes9x spots CPU in such a loop, it simply skips the emulation of its instructions until the event happens. It can be a big win with lots of SNES games, but will break a small number of games. In this case, set <code>Settings.ShutdownMaster</code> to <code>false</code> before you load a ROM image. Note that this hack is forcibly disabled in some games. See <code>Memory.ApplyROMFixes</code> function for the list of such games.
</p>
<h3><code>CORRECT_VRAM_READS</code></h3>
<p>
You must define this. It allows correct VRAM reads.
</p>
<h3><code>ZLIB / UNZIP_SUPPORT / JMA_SUPPORT</code></h3>
<p>
Define these if you want to support GZIP/ZIP/JMA compressed ROM images and GZIP compressed freeze-game files.
</p>
<h3><code>ZSNES_FX / ZSNES_C4</code></h3>
<p>
Define these if your CPU is x86 compatible and you're going to use the ZSNES Super FX and C4 assembler codes.
</p>
<h3><code>USE_OPENGL</code></h3>
<p>
Define this and set <code>Settings.OpenGLEnable</code> to <code>true</code>, then you'll get the rendered SNES image as one OpenGL texture.
</p>
<h3>Typical Options Common for Most Platforms</h3>
<p><code>
ZLIB<br>
UNZIP_SUPPORT<br>
JMA_SUPPORT<br>
CPU_SHUTDOWN<br>
RIGHTSHIFT_IS_SAR<br>
CORRECT_VRAM_READS
</code></p>
<h2>Editing port.h</h2>
<p>
You may need to edit <code>port.h</code> to fit Snes9x to your system.
</p>
<p>
If the byte ordering of your system is least significant byte first, make sure <code>LSB_FIRST</code> is defined, otherwise make sure it's not defined.
</p>
<p>
You'll need to make sure what pixel format your system uses for 16-bit colors (<code>RGB565</code>, <code>RGB555</code>, <code>BGR565</code> or <code>BGR555</code>), and if it's not <code>RGB565</code>, define <code>PIXEL_FORMAT</code> to it so that Snes9x will use it to render the SNES screen. For example, Windows uses <code>RGB565</code>, Mac OS X uses <code>RGB555</code>. If your system supports more than one pixel format, you can define <code>GFX_MULTI_FORMAT</code> and change Snes9x's pixel format dynamically by calling <code>S9xSetRenderPixelFormat</code> function. If your system is 24 or 32-bit only, then don't define anything; instead write a conversion routine that will take a complete rendered 16-bit SNES screen in <code>RGB565</code> format and convert to the format required to be displayed on your system.
</p>
<p>
<code>port.h</code> also typedefs some types; <code>uint8</code> for an unsigned 8-bit quantity, <code>uint16</code> for an unsigned 16-bit quantity, <code>uint32</code> for a 32-bit unsigned quantity and <code>bool8</code> for a <code>true</code>/<code>false</code> type. Signed versions are also typedef'ed.
</p>
<h2>Controllers Management</h2>
<p>
Read <code>controls.h</code>, <code>crosshair.h</code>, <code>controls.txt</code> and <code>control-inputs.txt</code> for details. This section is the minimal explanation to get the SNES controls workable.
</p>
<p>
The real SNES allows several different types of devices to be plugged into the game controller ports. The devices Snes9x emulates are a joypad, multi-player adaptor known as the Multi Player 5 or Multi Tap (allowing a further 4 joypads to be plugged in), a 2-button mouse, a light gun known as the Super Scope, and a light gun known as the Justifier.
</p>
<p>
In your initialization code, call <code>S9xUnmapAllControl</code> function.
</p>
<p>
Map any IDs to each SNES controller's buttons and pointers. (ID 249-255 are reserved).
</p>
<p>
Typically, use <code>S9xMapPointer</code> function for the pointer of the SNES mouse, Super Scope and Justifier, <code>S9xMapButton</code> function for other buttons. Set <code>poll</code> to <code>false</code> for the joypad buttons, <code>true</code> for the other buttons and pointers.
</p>
<p>
<code>S9xMapButton(k1P_A_Button, s9xcommand_t cmd = S9xGetCommandT(&quot;Joypad1 A&quot;), false);</code>
</p>
<p>
In your main emulation loop, after <code>S9xMainLoop</code> function is called, check your system's keyboard/joypad, and call <code>S9xReportButton</code> function to report the states of the SNES joypad buttons to Snes9x.
</p>
<p>
<code>void MyMainLoop (void)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;S9xMainLoop();<br>
&nbsp;&nbsp;&nbsp;&nbsp;MyReportButttons();<br>
}</code>
</p>
<p>
<code>void MyReportButtons (void)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;S9xReportButton(k1P_A_Button, (key_is_pressed ? true : false));<br>
}</code>
</p>
<p>
Prepare your <code>S9xPollButton</code> and <code>S9xPollPointer</code> function to reply Snes9x's request for other buttons/cursors states.
</p>
<p>
Call <code>S9xSetController</code> function. It connects each input device to each SNES input port.<br>
Here's typical controller settings that is used by the real SNES games:
</p>
<p>Joypad<br>
<code>S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);<br>
S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0);</code>
</p>
<p>Mouse (port 1)<br>
<code>S9xSetController(0, CTL_MOUSE, 0, 0, 0, 0);<br>
S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0);</code>
</p>
<p>Mouse (port 2)<br>
<code>S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);<br>
S9xSetController(1, CTL_MOUSE, 1, 0, 0, 0);</code>
</p>
<p>Super Scope<br>
<code>S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);<br>
S9xSetController(1, CTL_SUPERSCOPE, 0, 0, 0, 0);</code>
</p>
<p>Multi Player 5<br>
<code>S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);<br>
S9xSetController(1, CTL_MP5, 1, 2, 3, 4);</code>
</p>
<p>Justifier<br>
<code>S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);<br>
S9xSetController(1, CTL_JUSTIFIER, 0, 0, 0, 0);</code>
</p>
<p>Justifier (2 players)<br>
<code>S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);<br>
S9xSetController(1, CTL_JUSTIFIER, 1, 0, 0, 0);</code>
</p>
<h2>Existing Interface Functions</h2>
<h3><code>bool8 Memory.Init (void)</code></h3>
<p>
Allocates and initializes several major lumps of memory, for example the SNES ROM and RAM arrays, tile cache arrays, etc. Returns <code>false</code> if memory allocation fails.
</p>
<h3><code>void Memory.Deinit (void)</code></h3>
<p>
Deallocates the memory allocations made by <code>Memory.Init</code> function.
</p>
<h3><code>bool8 S9xGraphicsInit (void)</code></h3>
<p>
Allocates and initializes several lookup tables used to speed up SNES graphics rendering. Call after you have initialized the <code>GFX.Screen</code> and <code>GFX.Pitch</code> values. Returns <code>false</code> if memory allocation fails.
</p>
<h3><code>void S9xGraphicsDeinit (void)</code></h3>
<p>
Deallocates the memory allocations made by <code>S9xGraphicsInit</code> function.
</p>
<h3><code>bool8 S9xInitAPU (void)</code></h3>
<p>
Allocates and initializes several arrays used by the sound CPU and sound generation code. Returns <code>false</code> if memory allocation fails.
</p>
<h3><code>void S9xDeinitAPU (void)</code></h3>
<p>
Deallocates the allocations made by <code>S9xInitAPU</code> function.
</p>
<h3><code>bool8 S9xInitSound (int buffer_ms, int lag_ms)</code></h3>
<p>
Allocates memory for mixing and queueing SNES sound data, does more sound code initialization and opens the host system's sound device by calling <code>S9xOpenSoundDevice</code>, a function you must provide. Before calling this function you must set up <code>Settings.SoundSync</code>, <code>Settings.SixteenBitSound</code>, <code>Settings.SoundPlaybackRate</code>, <code>Settings.SoundInputRate</code> (see section below) and <code>Settings.Stereo</code>.<br>
<code>buffer_ms</code>, given in milliseconds, is the memory buffer size for queueing sound data. <code>lag_ms</code> is allowable latency between when a sample is queued and when it is pulled in <code>S9xMixSamples</code>. Set <code>lag_ms</code> to zero if you have your own latency handling code in your port.
</p>
<h3><code>void S9xReset (void)</code></h3>
<p>
Resets the SNES emulated hardware back to the state it was in at &ldquo;switch-on&rdquo; except the S-RAM area is preserved (&ldquo;hardware reset&rdquo;). The effect is it resets the current game back to the start. This function is automatically called by <code>Memory.LoadROM</code> function.
</p>
<h3><code>void S9xSoftReset (void)</code></h3>
<p>
Similar to <code>S9xReset</code> function, but &ldquo;software reset&rdquo; as you press the SNES reset button.
</p>
<h3><code>bool8 Memory.LoadROM (const char *filepath)</code></h3>
<p>
Attempts to load the specified ROM image filename into the emulated ROM area. There are many different SNES ROM image formats and the code attempts to auto-detect as many different types as it can and in a vast majority of the cases gets it right.<br>
There are several ROM image options in the <code>Settings</code>structure; allow the user to set them before calling <code>Memory.LoadROM</code> function, or make sure they are all reset to default values before each call to <code>Memory.LoadROM</code> function. See <code>Settings.ForceXXX</code> in <code>snes9x.h</code>.
</p>
<h3><code>bool8 Memory.LoadMultiCart (const char *cartApath, const char *cartBpath)</code></h3>
<p>
Attempts to load multiple ROM images into the emulated ROM area, for the multiple cartridge systems such as Sufami Turbo, Same Game, etc.
</p>
<h3><code>bool8 Memory.LoadSRAM (const char *filepath)</code></h3>
<p>
Call this function to load the associated S-RAM save file (if any). The filename should be based on the ROM image name to allow easy linkage. The current ports change the directory and the filename extension of the ROM filename to derive the S-RAM filename.
</p>
<h3><code>bool8 Memory.SaveSRAM (const char *filepath)</code></h3>
<p>
Call this function to save the emulated S-RAM area into a file so it can be restored again the next time the user wants to play the game. Remember to call this when just before the emulator exits or when the user has been playing a game and is about to load another one.
</p>
<h3><code>void S9xMainLoop (void)</code></h3>
<p>
The emulator main loop. Call this from your own main loop that calls this function (if a ROM image is loaded and the game is not paused), processes any pending host system events, then goes back around the loop again until the emulator exits. <code>S9xMainLoop</code> function normally returns control to your main loop once every emulated frame, when it reaches the start of scan-line zero. However it may take a few frames when a huge memory transfer is being emulated. The function can return more often if the <code>DEBUGGER</code> compile-time flag is defined and the CPU has hit a break point, or the <code>DEBUG_MODE_FLAG</code> bit is set in <code>CPU.Flags</code> or instruction single-stepping is enabled.
</p>
<h3><code>void S9xMixSamples (uint8 *buffer, int sample_count)</code></h3>
<p>
Call this function from your host sound system handling code to fill <code>buffer</code> with ready-mixed SNES sound data. If 16-bit sound mode is chosen, then the buffer will be filled with an array of <code>sample_count</code> <code>int16</code>, otherwise an array of <code>sample_count</code> <code>uint8</code>. If stereo sound generation is selected the buffer is filled with the same number of samples, but in pairs, first a left channel sample followed by the right channel sample.<br>
If there are less queued samples than you request by <code>sample_count</code>, the function fills <code>buffer</code> with silent sound data and returns <code>false</code>. To avoid this shortage of queued samples, request larger buffer size when calling <code>S9xInitSound</code>, and handle sound latency safely.
</p>
<h3><code>int S9xGetSampleCount (void)</code></h3>
<p>
Returns the number of sound samples available in the buffer for your configured playback settings.
</p>
<h3><code>void S9xSetSamplesAvailableCallback (void (*) samples_available (void *), void *data)</code></h3>
<p>
Call this function to set up a callback that is run when sound samples are made available. <code>samples_available</code> is a function you provide that returns <code>void</code> and takes a pointer as an argument. <code>data</code> is a pointer that you may wish to pass to your callback or can be <code>NULL</code>. If you choose to provide a callback, you must call the provided <code>S9xFinalizeSamples</code> function inside it to actually buffer the samples. If you are using a callback-oriented sound API, it is recommended to set up a function that locks a common mutex during the calls to <code>S9xFinalizeSamples</code> and <code>S9xMixSamples</code> to prevent them from running at the same time and corrupting the sound buffer.<br>
If you wish to disable a callback you have set up or need to temporarily shut down your sound system, you may pass <code>NULL</code> for both arguments to revert to the built-in version.
</p>
<h3><code>bool8 S9xSyncSound (void)</code></h3>
<p>
Call this function to synchronize the sound buffers to the game state. If Snes9x is generating too much sound data, or a buffer-overrun is likely, this function will return <code>false</code>. In this case, you may wish to wait until your host sound system uses the available samples, and <code>S9xSyncSound</code> returns <code>true</code> before continuing to execute <code>S9xMainLoop</code>.
</p>
<h3><code>bool8 S9xSetSoundMute (bool8 mute)</code></h3>
<p>
Call with a <code>true</code> parameter to prevent <code>S9xMixSamples</code> function from processing SNES sample data and instead just filling the return buffer with silent sound data. Useful if your sound system is interrupt or callback driven and the game has been paused either directly or indirectly because the user interacting with the emulator's user interface in some way.
</p>
<h3><code>bool8 S9xFreezeGame (const char *filepath)</code></h3>
<p>
Call this function to record the current SNES hardware state into a file, the file can be loaded back using <code>S9xUnfreezeGame</code> function at a later date effectively restoring the current game to exact same spot. Call this function while you're processing any pending system events when <code>S9xMainLoop</code> function has returned control to you in your main loop.
</p>
<h3><code>bool8 S9xUnfreezeGame (const char *filepath)</code></h3>
<p>
Restore the SNES hardware back to the exactly the state it was in when <code>S9xFreezeGame</code> function was used to generate the file specified. You have to arrange the correct ROM is already loaded using <code>Memory.LoadROM</code> function, an easy way to arrange this is to base freeze-game filenames on the ROM image name. The UNIX/Linux ports load freeze-game files when the user presses a function key, with the names romfilename.000 for F1, romfilename.001 for F2, etc. Games are frozen in the first place when the user presses Shift-function key. You could choose some other scheme.
</p>
<h3><code>void S9xDumpSPCSnapshot (void)</code></h3>
<p>
Call this funtion to make a so-called SPC file, a snapshot of SNES sound state. Actual dump occurs at the first key-on event after this function is called.
</p>
<h3><code>void S9xSetInfoString (const char *string)</code></h3>
<p>
Call this function if you want to show a message onto the SNES screen.
</p>
<h3>Other Available Functions</h3>
<p>
See <code>movie.h</code> and <code>movie.cpp</code> to support the Snes9x movie feature.<br>
See <code>cheats.h</code>, <code>cheats.cpp</code> and <code>cheats2.cpp</code> to support the cheat feature.
</p>
<h2>Interface Functions You Need to Implement</h2>
<h3><code>bool8 S9xOpenSnapshotFile (const char *filepath, bool8 read_only, STREAM *file)</code></h3>
<p>
This function opens a freeze-game file. <code>STREAM</code> is defined as a <code>gzFile</code> if <code>ZLIB</code> is defined else it's defined as <code>FILE *</code>. The <code>read_only</code> parameter is set to <code>true</code> when reading a freeze-game file and <code>false</code> when writing a freeze-game file. Open the file <code>filepath</code> and return its pointer <code>file</code>.
</p>
<h3><code>void S9xCloseSnapshotFile (STREAM file)</code></h3>
<p>
This function closes the freeze-game file opened by <code>S9xOpenSnapshotFile</code> function.
</p>
<h3><code>void S9xExit (void)</code></h3>
<p>
Called when some fatal error situation arises or when the &ldquo;q&rdquo; debugger command is used.
</p>
<h3><code>bool8 S9xInitUpdate (void)</code></h3>
<p>
Called just before Snes9x begins to render an SNES screen. Use this function if you should prepare before drawing, otherwise let it empty.
</p>
<h3><code>bool8 S9xDeinitUpdate (int width, int height)</code></h3>
<p>
Called once a complete SNES screen has been rendered into the <code>GFX.Screen</code> memory buffer, now is your chance to copy the SNES rendered screen to the host computer's screen memory. The problem is that you have to cope with different sized SNES rendered screens: 256*224, 256*239, 512*224, 512*239, 512*448 and 512*478.
</p>
<h3><code>void S9xMessage (int type, int number, const char *message)</code></h3>
<p>
When Snes9x wants to display an error, information or warning message, it calls this function. Check in <code>messages.h</code> for the types and individual message numbers that Snes9x currently passes as parameters.<br>
The idea is display the message string so the user can see it, but you choose not to display anything at all, or change the message based on the message number or message type.<br>
Eventually all debug output will also go via this function, trace information already does.
</p>
<h3><code>bool8 S9xOpenSoundDevice (void)</code></h3>
<p>
<code>S9xInitSound</code> function calls this function to actually open the host sound device.
</p>
<h3><code>const char *S9xGetFilename (const char *extension, enum s9x_getdirtype dirtype)</code></h3>
<p>
When Snes9x needs to know the name of the cheat/IPS file and so on, this function is called. Check <code>extension</code> and <code>dirtype</code>, and return the appropriate filename. The current ports return the ROM file path with the given extension.
</p>
<h3><code>const char *S9xGetFilenameInc (const char *extension, enum s9x_getdirtype dirtype)</code></h3>
<p>
Almost the same as <code>S9xGetFilename</code> function, but used for saving SPC files etc. So you have to take care not to delete the previously saved file, by increasing the number of the filename; romname.000.spc, romname.001.spc, ...
</p>
<h3><code>const char *S9xGetDirectory (enum s9x_getdirtype dirtype)</code></h3>
<p>
Called when Snes9x wants to know the directory <code>dirtype</code>.
</p>
<h3><code>const char *S9xChooseFilename (bool8 read_only)</code></h3>
<p>
If your port can match Snes9x's built-in <code>LoadFreezeFile</code>/<code>SaveFreezeFile</code> command (see <code>controls.cpp</code>), you may choose to use this function. Otherwise return <code>NULL</code>.
</p>
<h3><code>const char *S9xChooseMovieFilename (bool8 read_only)</code></h3>
<p>
If your port can match Snes9x's built-in <code>BeginRecordingMovie</code>/<code>LoadMovie</code> command (see <code>controls.cpp</code>), you may choose to use this function. Otherwise return <code>NULL</code>.
</p>
<h3><code>const char *S9xBasename (const char *path)</code></h3>
<p>
Called when Snes9x wants to know the name of the ROM image. Typically, extract the filename from <code>path</code> and return it.
</p>
<h3><code>void S9xAutoSaveSRAM (void)</code></h3>
<p>
If <code>Settings.AutoSaveDelay</code> is not zero, Snes9x calls this function when the contents of the S-RAM has been changed. Typically, call <code>Memory.SaveSRAM</code> function from this function.
</p>
<h3><code>void S9xToggleSoundChannel (int c)</code></h3>
<p>
If your port can match Snes9x's built-in <code>SoundChannelXXX</code> command (see <code>controls.cpp</code>), you may choose to use this function. Otherwise return <code>NULL</code>. Basically, turn on/off the sound channel <code>c</code> (0-7), and turn on all channels if <code>c</code> is 8.
</p>
<h3><code>void S9xSetPalette (void)</code></h3>
<p>
Called when the SNES color palette has changed. Use this function if your system should change its color palette to match the SNES's. Otherwise let it empty.
</p>
<h3><code>void S9xSyncSpeed (void)</code></h3>
<p>
Called at the end of <code>S9xMainLoop</code> function, when emulating one frame has been done. You should adjust the frame rate in this function.
</p>
<h2>Global Variables</h2>
<h3><code>uint16 *GFX.Screen</code></h3>
<p>
A <code>uint16</code> array pointer to (at least) 2*512*478 bytes buffer where Snes9x puts the rendered SNES screen. However, if your port will not support hires mode (<code>Settings.SupportHiRes = false</code>), then a 2*256*239 bytes buffer is allowed. You should allocate the space by yourself. As well you can change the <code>GFX.Screen</code> value after <code>S9xDeinitUpdate</code> function is called so that double-buffering will be easy.
</p>
<h3><code>uint32 GFX.Pitch</code></h3>
<p>
Bytes per line (not pixels per line) of the <code>GFX.Screen</code> buffer. Typically set it to 1024. When the SNES screen is 256 pixels width and <code>Settings.OpenGLEnable</code> is <code>false</code>, last half 512 bytes per line are unused. When <code>Settings.OpenGLEnable</code> is <code>true</code>, <code>GFX.Pitch</code> is ignored.
</p>
<h3>Settings structure</h3>
<p>
There are various switches in the <code>Settings</code> structure. See <code>snes9x.h</code> for details. At least the settings below are required for good emulation.
</p>
<p><code>
memset(&amp;Settings, 0, sizeof(Settings));<br>
Settings.MouseMaster = true;<br>
Settings.SuperScopeMaster = true;<br>
Settings.JustifierMaster = true;<br>
Settings.MultiPlayer5Master = true;<br>
Settings.FrameTimePAL = 20000;<br>
Settings.FrameTimeNTSC = 16667;<br>
Settings.SixteenBitSound = true;<br>
Settings.Stereo = true;<br>
Settings.SoundPlaybackRate = 32000;<br>
Settings.SoundInputRate = 32000;<br>
Settings.SupportHiRes = true;<br>
Settings.Transparency = true;<br>
Settings.AutoDisplayMessages = true;<br>
Settings.InitialInfoStringTimeout = 120;<br>
Settings.HDMATimingHack = 100;<br>
Settings.BlockInvalidVRAMAccessMaster = true;
</code></p>
<h3><code>Settings.SoundInputRate</code></h3>
<p>
Adjusts the sound rate through resampling. For every <code>Settings.SoundInputRate</code> samples generated by the SNES, <code>Settings.SoundPlaybackRate</code> samples will be produced.<br>
The sound generation rate on a SNES is directly proportional to the video output rate. Displays that synchronize with the vertical refresh but have a slightly lower refresh-rate than the emulated system can experience sound drop-outs. It may be beneficial to provide an option for users to configure <code>Settings.SoundInputRate</code> to suit their own systems. Setting <code>Settings.SoundInputRate</code> to a value that matches the actual output rate (i.e. 31977hz for 59.96hz) or lower will allow the users to eliminate crackling. A range of 31000hz to 33000hz should be inclusive enough for all displays. Use of this setting paired with the <code>S9xSyncSound</code> function can eliminate sound discontinuity.
</p>
<div style="text-align:right; margin-top:3em">
Updated most recently by: 2009/12/20 zones
</div>
</body>
</html>

View File

@ -1,84 +0,0 @@
***** Important notice ********************************************************
This document describes the snapshot file format for Snes9x 1.52 and later,
not compatible with 1.51.
*******************************************************************************
Snes9x snapshot file format: (may be gzip-compressed)
Begins with fixed length signature, consisting of a string, ':', a 4-digit
decimal version, and a '\n'.
#!s9xsnp:0006 <-- '\n' after the 6
Then we have various blocks. The block format is: 3-character block name,
':', 6-digit length, ':', then the data. Blocks are written in a defined
order. Structs are written packed with their members in a defined order, in
big-endian order where applicable.
NAM:000019:Chrono Trigger.zip
Currently defined blocks (in order) are:
Essential parts:
NAM - ROM filename, from Memory.ROMFilename. 0-terminated string.
CPU - struct SCPUState, CPU internal state variables.
REG - struct SRegisters, emulated CPU registers.
PPU - struct SPPU, PPU internal variables. Note that IPPU is never saved.
DMA - struct SDMA, DMA/HDMA state variables.
VRA - Memory.VRAM, 0x10000 bytes.
RAM - Memory.RAM, 0x20000 bytes (WRAM).
SRA - Memory.SRAM, 0x20000 bytes.
FIL - Memory.FillRAM, 0x8000 bytes (register backing store).
SND - All of sound emulated registers and state valiables.
CTL - struct SControlSnapshot, controller emulation.
TIM - struct STimings, variables about timings between emulated events.
Optional parts:
SFX - struct FxRegs_s, Super FX.
SA1 - struct SSA1, SA1 internal state variables.
SAR - struct SSA1Registers, SA1 emulated registers.
DP1 - struct SDSP1, DSP-1.
DP2 - struct SDSP2, DSP-2.
DP4 - struct SDSP4, DSP-4.
CX4 - Memory.C4RAM, 0x2000 bytes.
ST0 - struct SST010, ST-010.
OBC - struct SOBC1, OBC1 internal state variables.
OBM - Memory.OBC1RAM, 0x2000 byts.
S71 - struct SSPC7110Snapshot, SPC7110.
SRT - struct SSRTCSnapshot, S-RTC internal state variables.
CLK - struct SRTCData, S-RTC emulated registers.
BSX - struct SBSX, BS-X.
SHO - rendered SNES screen.
MOV - struct SnapshotMovieInfo.
MID - Some block of data the movie subsystem.
==================
Without changing the snapshot version number:
---------------------------------------------
Blocks may be safely added at the END of the file, as anything after the last
block is ignored. Blocks may not be moved or removed.
Blocks may not decrease in size. Say you decrease from 10 bytes to 5. Then
later you increase back to 8. The only way you could safely do this is if
bytes 5-7 still mean the same thing they meant when the block was 10 bytes
long.
Blocks may increase in size as you wish, as long as you can handle old
savestates with the old shorter size.
Struct members may not change in interpretation. New struct members may be
added (at the END!) only if you can cope with them being binary-0 in older
savestates. Struct members may not be removed or changed in size/type.
With changing the snapshot version number:
------------------------------------------
Blocks may be added, moved, or removed at will.
Blocks may decrease in size.
Struct members may be added, moved, or deleted, and their
interpretations/types may be changed. Use the 'debuted_in' and 'deleted_in'
fields to indicate when the new member debuted or the old member went away.

View File

@ -1,173 +0,0 @@
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
Jerremy Koot (jkoot@snes9x.com)
(c) Copyright 2002 - 2004 Matthew Kendora
(c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
(c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
Kris Bleakley (codeviolation@hotmail.com)
(c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
Nach (n-a-c-h@users.sourceforge.net),
zones (kasumitokoduck@yahoo.com)
(c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2010 BearOso,
OV2
BS-X C emulator code
(c) Copyright 2005 - 2006 Dreamer Nom,
zones
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
Nach,
zsKnight (zsknight@zsnes.com)
C4 C++ code
(c) Copyright 2003 - 2006 Brad Jorsch,
Nach
DSP-1 emulator code
(c) Copyright 1998 - 2006 _Demo_,
Andreas Naive (andreasnaive@gmail.com),
Gary Henderson,
Ivar (ivar@snes9x.com),
John Weidman,
Kris Bleakley,
Matthew Kendora,
Nach,
neviksti (neviksti@hotmail.com)
DSP-2 emulator code
(c) Copyright 2003 John Weidman,
Kris Bleakley,
Lord Nightmare (lord_nightmare@users.sourceforge.net),
Matthew Kendora,
neviksti
DSP-3 emulator code
(c) Copyright 2003 - 2006 John Weidman,
Kris Bleakley,
Lancer,
z80 gaiden
DSP-4 emulator code
(c) Copyright 2004 - 2006 Dreamer Nom,
John Weidman,
Kris Bleakley,
Nach,
z80 gaiden
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight,
pagefault (pagefault@zsnes.com),
Kris Bleakley
Ported from x86 assembler to C by sanmaiwashi
SPC7110 and RTC C++ emulator code used in 1.39-1.51
(c) Copyright 2002 Matthew Kendora with research by
zsKnight,
John Weidman,
Dark Force
SPC7110 and RTC C++ emulator code used in 1.52+
(c) Copyright 2009 byuu,
neviksti
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive,
John Weidman
S-RTC C emulator code
(c) Copyright 2001 - 2006 byuu,
John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather,
John Weidman,
Kris Bleakley,
Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 _Demo_,
pagefault,
zsKnight
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar,
Gary Henderson,
John Weidman
Sound emulator code used in 1.5-1.51
(c) Copyright 1998 - 2003 Brad Martin
(c) Copyright 1998 - 2006 Charles Bilyue'
Sound emulator code used in 1.52+
(c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
2xSaI filter
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
HQ2x, HQ3x, HQ4x filters
(c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
NTSC filter
(c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code
(c) Copyright 2004 - 2010 BearOso
Win32 GUI code
(c) Copyright 2003 - 2006 blip,
funkyass,
Matthew Kendora,
Nach,
nitsuja
(c) Copyright 2009 - 2010 OV2
Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones
Specific ports contains the works of other authors. See headers in
individual files.
Snes9x homepage: http://www.snes9x.com/
Permission to use, copy, modify and/or distribute Snes9x in both binary
and source form, for non-commercial purposes, is hereby granted without
fee, providing that this license information and copyright notice appear
with all copies and any derived work.
This software is provided 'as-is', without any express or implied
warranty. In no event shall the authors be held liable for any damages
arising from the use of this software or it's derivatives.
Snes9x is freeware for PERSONAL USE only. Commercial users should
seek permission of the copyright holders first. Commercial use includes,
but is not limited to, charging money for Snes9x or software derived from
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
using Snes9x as a promotion for your commercial product.
The copyright holders request that bug fixes and improvements to the code
should be forwarded to them so everyone can benefit from the modifications
in future versions.
Super NES and Super Nintendo Entertainment System are trademarks of
Nintendo Co., Limited and its subsidiary companies.

View File

@ -1,241 +0,0 @@
#-----------------------------------------
# snes9x.conf : Snes9x Configuration file
#-----------------------------------------
[ROM]
# Filename =
LoROM = FALSE
HiROM = FALSE
PAL = FALSE
NTSC = FALSE
# Header = TRUE/FALSE to ForceHeader or ForceNoHeader
# Interleaved = TRUE/FALSE to ForceInterleaved or ForceNoInterleaved
Interleaved2 = FALSE
InterleaveGD24 = FALSE
Cheat = FALSE
Patch = TRUE
[Sound]
Sync = FALSE
16BitSound = TRUE
Stereo = TRUE
ReverseStereo = FALSE
Rate = 32000
InputRate = 32000
Mute = FALSE
[Display]
HiRes = TRUE
Transparency = TRUE
GraphicWindows = TRUE
DisplayFrameRate = FALSE
DisplayWatchedAddresses = FALSE
DisplayInput = FALSE
DisplayFrameCount = FALSE
MessagesInImage = TRUE
MessageDisplayTime = 120
[Settings]
BSXBootup = FALSE
# FrameTime =
FrameSkip = Auto
TurboMode = FALSE
TurboFrameSkip = 15
MovieTruncateAtEnd = FALSE
MovieNotifyIgnored = FALSE
WrongMovieStateProtection = TRUE
StretchScreenshots = 1
SnapshotScreenshots = TRUE
DontSaveOopsSnapshot = FALSE
AutoSaveDelay = 0
[Controls]
MouseMaster = TRUE
SuperscopeMaster = TRUE
JustifierMaster = TRUE
MP5Master = TRUE
AllowLeftRight = FALSE
Port1 = pad1
Port2 = none
Mouse1Crosshair = 1 White/Black
Mouse2Crosshair = 1 White/Black
SuperscopeCrosshair = 2 White/Black
Justifier1Crosshair = 4 Blue/Black
Justifier2Crosshair = 4 MagicPink/Black
[Hack]
EnableGameSpecificHacks = TRUE
AllowInvalidVRAMAccess = FALSE
SpeedHacks = FALSE
DisableIRQ = FALSE
DisableHDMA = FALSE
HDMATiming = 100
[Netplay]
Enable = FALSE
Port = 6096
Server = ""
[DEBUG]
Debugger = FALSE
Trace = FALSE
[Unix]
# BaseDir = ~/.snes9x
# SnapshotFilename =
# PlayMovieFilename =
# RecordMovieFilename =
EnableGamePad = TRUE
PadDevice1 = (null)
PadDevice2 = (null)
PadDevice3 = (null)
PadDevice4 = (null)
PadDevice5 = (null)
PadDevice6 = (null)
PadDevice7 = (null)
PadDevice8 = (null)
ThreadSound = FALSE
SoundBufferSize = 100
SoundFragmentSize = 2048
# SoundDevice =
ClearAllControls = FALSE
[Unix/X11]
SetKeyRepeat = TRUE
VideoMode = 1
[Unix/X11 Controls]
J00:Axis1 = Joypad1 Axis Up/Down T=50%
J00:Axis0 = Joypad1 Axis Left/Right T=50%
J00:B1 = Joypad1 A
J00:B2 = Joypad1 B
J00:B0 = Joypad1 X
J00:B3 = Joypad1 Y
J00:B6 = Joypad1 L
J00:B7 = Joypad1 R
J00:B8 = Joypad1 Select
J00:B11 = Joypad1 Start
K00:u = Joypad1 Up
K00:Up = Joypad1 Up
K00:j = Joypad1 Down
K00:n = Joypad1 Down
K00:Down = Joypad1 Down
K00:h = Joypad1 Left
K00:Left = Joypad1 Left
K00:k = Joypad1 Right
K00:Right = Joypad1 Right
K00:d = Joypad1 A
K00:S+d = Joypad1 ToggleTurbo A
K00:C+d = Joypad1 ToggleSticky A
K00:c = Joypad1 B
K00:S+c = Joypad1 ToggleTurbo B
K00:C+c = Joypad1 ToggleSticky B
K00:s = Joypad1 X
K00:S+s = Joypad1 ToggleTurbo X
K00:C+s = Joypad1 ToggleSticky X
K00:x = Joypad1 Y
K00:S+x = Joypad1 ToggleTurbo Y
K00:C+x = Joypad1 ToggleSticky Y
K00:a = Joypad1 L
K00:v = Joypad1 L
K00:S+a = Joypad1 ToggleTurbo L
K00:S+v = Joypad1 ToggleTurbo L
K00:C+a = Joypad1 ToggleSticky L
K00:C+v = Joypad1 ToggleSticky L
K00:z = Joypad1 R
K00:S+z = Joypad1 ToggleTurbo R
K00:C+z = Joypad1 ToggleSticky R
K00:space = Joypad1 Select
K00:Return = Joypad1 Start
K00:KP_Up = Joypad2 Up
K00:KP_Down = Joypad2 Down
K00:KP_Left = Joypad2 Left
K00:KP_Right = Joypad2 Right
K00:Prior = Joypad2 A
K00:Next = Joypad2 B
K00:Home = Joypad2 X
K00:End = Joypad2 Y
K00:Insert = Joypad2 L
K00:Delete = Joypad2 R
K00:KP_Add = Joypad2 Select
K00:KP_Enter = Joypad2 Start
K00:Escape = ExitEmu
K00:Pause = Pause
K00:Scroll_Lock = Pause
K00:CS+Escape = Reset
K00:S+Escape = SoftReset
K00:F12 = SaveFreezeFile
K00:A+F3 = SaveFreezeFile
K00:C+F3 = SaveFreezeFile
K00:F11 = LoadFreezeFile
K00:A+F2 = LoadFreezeFile
K00:C+F2 = LoadFreezeFile
K00:S+F1 = QuickSave000
K00:S+F2 = QuickSave001
K00:S+F3 = QuickSave002
K00:S+F4 = QuickSave003
K00:S+F5 = QuickSave004
K00:S+F6 = QuickSave005
K00:S+F7 = QuickSave006
K00:S+F8 = QuickSave007
K00:S+F9 = QuickSave008
K00:F1 = QuickLoad000
K00:F2 = QuickLoad001
K00:F3 = QuickLoad002
K00:F4 = QuickLoad003
K00:F5 = QuickLoad004
K00:F6 = QuickLoad005
K00:F7 = QuickLoad006
K00:F8 = QuickLoad007
K00:F9 = QuickLoad008
K00:F10 = LoadOopsFile
K00:A+F1 = SaveSPC
K00:C+F1 = SaveSPC
K00:Print = Screenshot
K00:S+1 = BeginRecordingMovie
K00:S+2 = EndRecordingMovie
K00:S+3 = LoadMovie
K00:Tab = EmuTurbo
K00:S+Tab = ToggleEmuTurbo
K00:equal = IncFrameRate
K00:minus = DecFrameRate
K00:S+equal = IncFrameTime
K00:S+minus = DecFrameTime
K00:A+equal = IncEmuTurbo
K00:A+minus = DecEmuTurbo
K00:C+equal = IncTurboSpeed
K00:C+minus = DecTurboSpeed
K00:6 = SwapJoypads
K00:A+F4 = SoundChannel0
K00:C+F4 = SoundChannel0
K00:A+F5 = SoundChannel1
K00:C+F5 = SoundChannel1
K00:A+F6 = SoundChannel2
K00:C+F6 = SoundChannel2
K00:A+F7 = SoundChannel3
K00:C+F7 = SoundChannel3
K00:A+F8 = SoundChannel4
K00:C+F8 = SoundChannel4
K00:A+F9 = SoundChannel5
K00:C+F9 = SoundChannel5
K00:A+F10 = SoundChannel6
K00:C+F10 = SoundChannel6
K00:A+F11 = SoundChannel7
K00:C+F11 = SoundChannel7
K00:A+F12 = SoundChannelsOn
K00:C+F12 = SoundChannelsOn
K00:1 = ToggleBG0
K00:2 = ToggleBG1
K00:3 = ToggleBG2
K00:4 = ToggleBG3
K00:5 = ToggleSprites
K00:9 = ToggleTransparency
K00:BackSpace = ClipWindows
K00:0 = ToggleHDMA
K00:A+Escape = Debugger
M00:Pointer = Pointer Mouse1+Superscope+Justifier1
M00:B0 = {Mouse1 L,Superscope Fire,Justifier1 Trigger}
M00:B2 = {Mouse1 R,Superscope Cursor,Justifier1 Start}
M00:B1 = {Justifier1 AimOffscreen Trigger,Superscope AimOffscreen}
K00:grave = Superscope ToggleTurbo
K00:slash = Superscope Pause

BIN
executables/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

10
executables/meta.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<app version="1">
<name>Snes9x GX Next</name>
<coder>Squarepusher2</coder>
<version>1.0.0</version>
<release_date>20110515</release_date>
<short_description>Super Nintendo Emulator</short_description>
<long_description>A port of SNES9x Next to the Wii.</long_description>
<no_ios_reload/>
</app>

View File

@ -90,7 +90,7 @@ bool audio_active = false;
extern bool8 pad_read_last;
//emulator-specific
s9xcommand_t keymap[1024];
extern s9xcommand_t keymap[1024];
extern uint16_t joypad[8];
static unsigned snes_devices[2];

View File

@ -265,12 +265,12 @@ static struct
} justifier;
static int8 mp5[2][4];
extern s9xcommand_t keymap[1024];
s9xcommand_t keymap[1024];
static bool8 FLAG_LATCH = FALSE;
static int32 curcontrollers[2] = { NONE, NONE };
static int32 newcontrollers[2] = { JOYPAD0, NONE };
static char buf[256];
uint16_t joypad[8];
uint16 joypad[8];
static void DoGunLatch (int x, int y)
{

View File

@ -17,7 +17,7 @@
</div>
<h2>Introduction</h2>
<p>
This is brief description of the steps to port Snes9x to the new platform. It describes what code you have to write and what functions exist that you can make use of. It also gives some insights as to how Snes9x actually works, although that will be subject of another document yet to be written.
This is brief description of the steps to port SNES9x Next (a fork of SNES9x) to the new platform. It describes what code you have to write and what functions exist that you can make use of. It also gives some insights as to how Snes9x actually works, although that will be subject of another document yet to be written.
</p>
<h2>System Requirements</h2>
<p>

View File

@ -571,12 +571,12 @@ void fx_computeScreenPointers (void)
// Make a list of pointers to the start of each screen column
uint8* pvScreenBase = GSU.pvScreenBase;
uint32_t vmode = GSU.vMode;
int32_t condition = vmode - 2;
int32_t mask = (condition | -condition) >> 31;
int32_t result = (vmode & mask) | (3 & ~mask);
uint32_t screenheight = GSU.vScreenHeight;
uint32_t incrementvalue = screenheight+screenheight;
uint32 vmode = GSU.vMode;
int32 condition = vmode - 2;
int32 mask = (condition | -condition) >> 31;
int32 result = (vmode & mask) | (3 & ~mask);
uint32 screenheight = GSU.vScreenHeight;
uint32 incrementvalue = screenheight+screenheight;
vmode = result;
vmode++;
switch (screenheight)
@ -585,7 +585,7 @@ void fx_computeScreenPointers (void)
case 160:
case 192:
{
uint32_t tempvalue[32];
uint32 tempvalue[32];
for(int i = 0; i < 32; i++)
{
tempvalue[i] = incrementvalue * i * vmode;
@ -627,7 +627,7 @@ void fx_computeScreenPointers (void)
}
break;
case 256:
const uint32_t mul_8192 = vmode << 13;
const uint32 mul_8192 = vmode << 13;
GSU.apvScreen[0] = GSU.apvScreen[16] = pvScreenBase;
GSU.apvScreen[1] = GSU.apvScreen[17] = pvScreenBase + (256 * vmode);
@ -662,7 +662,7 @@ void fx_computeScreenPointers (void)
GSU.apvScreen[30] += mul_8192;
GSU.apvScreen[31] += mul_8192;
const uint32_t mul_4096 = vmode << 12;
const uint32 mul_4096 = vmode << 12;
GSU.x[0] = GSU.x[16] = 0;
GSU.x[1] = GSU.x[17] = 16 * vmode;
GSU.x[2] = GSU.x[18] = 32 * vmode;

View File

@ -35,11 +35,11 @@ OBJECTS = ../apu/apu.o ../apu/SNES_SPC.o ../apu/SNES_SPC_misc.o ../apu/SNES_S
CXX = g++
CC = gcc
INCLUDES = -I. -I.. -I../apu/
DEFINES =
DEFINES = -DHAVE_STRINGS_H -DHAVE_STDINT_H -DHAVE_INTTYPES_H -D__LIBSNES__ -DRIGHTSHIFT_IS_SAR
COMMON_DEFINES += -O3 -fomit-frame-pointer -pedantic -Wall -W -Wno-unused-parameter -DNDEBUG=1 $(fpic)
CXXFLAGS += -O3 -fomit-frame-pointer -fno-exceptions -fno-rtti -pedantic -Wall -W -Wno-unused-parameter $(fpic)
CXXFLAGS += -DHAVE_STRINGS_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR -D__LIBSNES__ $(DEFINES)
CFLAGS = $(CXXFLAGS)
CXXFLAGS += $(COMMON_DEFINES) $(DEFINES) -fno-exceptions -fno-rtti
CFLAGS = $(DEFINES) $(COMMON_DEFINES)
all: $(TARGET)

View File

@ -362,7 +362,7 @@ static int16_t snes_mouse_state[2][2] = {{0}, {0}};
static int16_t snes_scope_state[2] = {0};
static int16_t snes_justifier_state[2][2] = {{0}, {0}};
extern uint16_t joypad[8];
s9xcommand_t keymap[1024];
extern s9xcommand_t keymap[1024];
extern bool8 pad_read_last;
static void report_buttons()

View File

@ -181,7 +181,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#ifdef __CELLOS_LV2__
#if defined(__CELLOS_LV2__) || defined(GEKKO)
#include <memory>
#else
#include <memory.h>
@ -201,7 +201,11 @@
#define SNES_JOY_READ_CALLBACKS
#endif
#ifdef GEKKO
#define PIXEL_FORMAT RGB565
#else
#define PIXEL_FORMAT RGB555
#endif
#ifndef snes9x_types_defined
#define snes9x_types_defined

View File

@ -411,7 +411,7 @@ struct SSettings
bool Paused;
uint32_t Throttled;
uint32 Throttled;
#ifdef __CELLOS_LV2__
uint32_t PS3KeepAspect;
@ -453,8 +453,8 @@ struct SSettings
int32_t PS3OverscanAmount;
int32_t ControlScheme;
#endif
uint32_t AccessoryType;
int32_t AccessoryAutoDetection;
uint32 AccessoryType;
int32 AccessoryAutoDetection;
bool ChronoTriggerFrameHack;
bool CurrentROMisMultitapCompatible;
bool CurrentROMisMouseCompatible;

165
src/wii/audio.cpp Normal file
View File

@ -0,0 +1,165 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* Tantric 2008-2010
*
* audio.cpp
*
* Audio driver
* Audio is fixed to 32Khz/16bit/Stereo
***************************************************************************/
#include <gccore.h>
#include <ogcsys.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <asndlib.h>
#include "video.h"
#include "snes9x-next/snes9x.h"
#include "snes9x-next/memmap.h"
#include "snes9x-next/cpuexec.h"
#include "snes9x-next/ppu.h"
#include "snes9x-next/apu/apu.h"
#include "snes9x-next/display.h"
#include "snes9x-next/gfx.h"
#include "snes9x-next/spc7110.h"
#include "snes9x-next/controls.h"
extern int ConfigRequested;
/*** Double buffered audio ***/
#define AUDIOBUFFER 2048
static short soundbuffer[2][AUDIOBUFFER] __attribute__ ((__aligned__ (32)));
static int whichab = 0; /*** Audio buffer flip switch ***/
#define AUDIOSTACK 16384
static lwpq_t audioqueue;
static lwp_t athread;
static uint8 astack[AUDIOSTACK];
static mutex_t audiomutex = LWP_MUTEX_NULL;
/****************************************************************************
* Audio Threading
***************************************************************************/
static void * AudioThread (void *arg)
{
LWP_InitQueue (&audioqueue);
while (1)
{
if (ConfigRequested)
memset (soundbuffer[whichab], 0, AUDIOBUFFER);
else
{
LWP_MutexLock(audiomutex);
S9xMixSamples (soundbuffer[whichab], AUDIOBUFFER >> 1);
LWP_MutexUnlock(audiomutex);
}
DCFlushRange (soundbuffer[whichab], AUDIOBUFFER);
LWP_ThreadSleep (audioqueue);
}
return NULL;
}
/****************************************************************************
* MixSamples
* This continually calls S9xMixSamples On each DMA Completion
***************************************************************************/
static void
GCMixSamples ()
{
if (!ConfigRequested)
{
whichab ^= 1;
AUDIO_InitDMA ((u32) soundbuffer[whichab], AUDIOBUFFER);
LWP_ThreadSignal (audioqueue);
}
}
static void FinalizeSamplesCallback()
{
LWP_MutexLock(audiomutex);
S9xFinalizeSamples();
LWP_MutexUnlock(audiomutex);
}
/****************************************************************************
* InitAudio
***************************************************************************/
void
InitAudio ()
{
#ifdef NO_SOUND
AUDIO_Init (NULL);
AUDIO_SetDSPSampleRate(AI_SAMPLERATE_32KHZ);
AUDIO_RegisterDMACallback(GCMixSamples);
#else
ASND_Init();
#endif
LWP_MutexInit(&audiomutex, false);
LWP_CreateThread (&athread, AudioThread, NULL, astack, AUDIOSTACK, 70);
}
/****************************************************************************
* SwitchAudioMode
*
* Switches between menu sound and emulator sound
***************************************************************************/
void
SwitchAudioMode(int mode)
{
if(mode == 0) // emulator
{
#ifndef NO_SOUND
ASND_Pause(1);
AUDIO_StopDMA();
AUDIO_SetDSPSampleRate(AI_SAMPLERATE_32KHZ);
AUDIO_RegisterDMACallback(GCMixSamples);
#endif
memset(soundbuffer[0],0,AUDIOBUFFER);
memset(soundbuffer[1],0,AUDIOBUFFER);
DCFlushRange(soundbuffer[0],AUDIOBUFFER);
DCFlushRange(soundbuffer[1],AUDIOBUFFER);
AUDIO_InitDMA((u32)soundbuffer[whichab],AUDIOBUFFER);
AUDIO_StartDMA();
S9xSetSamplesAvailableCallback(FinalizeSamplesCallback);
}
else // menu
{
S9xSetSamplesAvailableCallback(NULL);
#ifndef NO_SOUND
ASND_Init();
ASND_Pause(0);
#else
AUDIO_StopDMA();
#endif
}
}
/****************************************************************************
* ShutdownAudio
*
* Shuts down audio subsystem. Useful to avoid unpleasant sounds if a
* crash occurs during shutdown.
***************************************************************************/
void ShutdownAudio()
{
AUDIO_StopDMA();
}
/****************************************************************************
* AudioStart
*
* Called to kick off the Audio Queue
***************************************************************************/
void
AudioStart ()
{
GCMixSamples ();
}

16
src/wii/audio.h Normal file
View File

@ -0,0 +1,16 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* Tantric 2008-2010
*
* audio.h
*
* Audio driver
* Audio is fixed to 32Khz/16bit/Stereo
***************************************************************************/
void InitAudio ();
void AudioStart ();
void SwitchAudioMode(int mode);
void ShutdownAudio();

117
src/wii/button_mapping.c Normal file
View File

@ -0,0 +1,117 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* michniewski August 2008
* Tantric 2008-2010
*
* button_mapping.c
*
* Controller button mapping
***************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ogcsys.h>
#include <unistd.h>
#include <wiiuse/wpad.h>
#include "button_mapping.h"
/****************************************************************************
* Controller Button Descriptions:
* used for identifying which buttons have been pressed when configuring
* and for displaying the name of said button
***************************************************************************/
CtrlrMap ctrlr_def[4] = {
// Gamecube controller btn def
{
CTRLR_GCPAD,
13,
{
{PAD_BUTTON_DOWN, "DOWN"},
{PAD_BUTTON_UP, "UP"},
{PAD_BUTTON_LEFT, "LEFT"},
{PAD_BUTTON_RIGHT, "RIGHT"},
{PAD_BUTTON_A, "A"},
{PAD_BUTTON_B, "B"},
{PAD_BUTTON_X, "X"},
{PAD_BUTTON_Y, "Y"},
{PAD_BUTTON_MENU, "START"},
{PAD_BUTTON_START, "START"},
{PAD_TRIGGER_L, "L"},
{PAD_TRIGGER_R, "R"},
{PAD_TRIGGER_Z, "Z"},
{0, ""},
{0, ""}
}
},
// Wiimote btn def
{
CTRLR_WIIMOTE,
11,
{
{WPAD_BUTTON_DOWN, "DOWN"},
{WPAD_BUTTON_UP, "UP"},
{WPAD_BUTTON_LEFT, "LEFT"},
{WPAD_BUTTON_RIGHT, "RIGHT"},
{WPAD_BUTTON_A, "A"},
{WPAD_BUTTON_B, "B"},
{WPAD_BUTTON_1, "1"},
{WPAD_BUTTON_2, "2"},
{WPAD_BUTTON_PLUS, "PLUS"},
{WPAD_BUTTON_MINUS, "MINUS"},
{WPAD_BUTTON_HOME, "HOME"},
{0, ""},
{0, ""},
{0, ""},
{0, ""}
}
},
// Nunchuk btn def
{
CTRLR_NUNCHUK,
13,
{
{WPAD_BUTTON_DOWN, "DOWN"},
{WPAD_BUTTON_UP, "UP"},
{WPAD_BUTTON_LEFT, "LEFT"},
{WPAD_BUTTON_RIGHT, "RIGHT"},
{WPAD_BUTTON_A, "A"},
{WPAD_BUTTON_B, "B"},
{WPAD_BUTTON_1, "1"},
{WPAD_BUTTON_2, "2"},
{WPAD_BUTTON_PLUS, "PLUS"},
{WPAD_BUTTON_MINUS, "MINUS"},
{WPAD_BUTTON_HOME, "HOME"},
{WPAD_NUNCHUK_BUTTON_Z, "Z"},
{WPAD_NUNCHUK_BUTTON_C, "C"},
{0, ""},
{0, ""}
}
},
// Classic btn def
{
CTRLR_CLASSIC,
15,
{
{WPAD_CLASSIC_BUTTON_DOWN, "DOWN"},
{WPAD_CLASSIC_BUTTON_UP, "UP"},
{WPAD_CLASSIC_BUTTON_LEFT, "LEFT"},
{WPAD_CLASSIC_BUTTON_RIGHT, "RIGHT"},
{WPAD_CLASSIC_BUTTON_A, "A"},
{WPAD_CLASSIC_BUTTON_B, "B"},
{WPAD_CLASSIC_BUTTON_X, "X"},
{WPAD_CLASSIC_BUTTON_Y, "Y"},
{WPAD_CLASSIC_BUTTON_PLUS, "PLUS"},
{WPAD_CLASSIC_BUTTON_MINUS, "MINUS"},
{WPAD_CLASSIC_BUTTON_HOME, "HOME"},
{WPAD_CLASSIC_BUTTON_FULL_L, "L"},
{WPAD_CLASSIC_BUTTON_FULL_R, "R"},
{WPAD_CLASSIC_BUTTON_ZL, "ZL"},
{WPAD_CLASSIC_BUTTON_ZR, "ZR"}
}
}
};

39
src/wii/button_mapping.h Normal file
View File

@ -0,0 +1,39 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* michniewski August 2008
* Tantric 2008-2010
*
* button_mapping.h
*
* Controller button mapping
***************************************************************************/
#ifndef BTN_MAP_H
#define BTN_MAP_H
enum {
CTRLR_NONE = -1,
CTRLR_GCPAD,
CTRLR_WIIMOTE,
CTRLR_NUNCHUK,
CTRLR_CLASSIC
};
const char ctrlrName[4][20] =
{ "GameCube Controller", "Wiimote", "Nunchuk + Wiimote", "Classic Controller" };
typedef struct _btn_map {
u32 btn; // button 'id'
char* name; // button name
} BtnMap;
typedef struct _ctrlr_map {
u16 type; // controller type
int num_btns; // number of buttons on the controller
BtnMap map[15]; // controller button map
} CtrlrMap;
extern CtrlrMap ctrlr_def[4];
#endif

80
src/wii/cheatmgr.cpp Normal file
View File

@ -0,0 +1,80 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* Tantric 2008-2010
*
* cheatmgr.cpp
*
* Cheat handling
***************************************************************************/
#include "port.h"
#include "cheats.h"
#include "snes9xgx.h"
#include "fileop.h"
#include "filebrowser.h"
extern SCheatData Cheat;
/****************************************************************************
* LoadCheatFile
*
* Loads cheat file from save buffer
* Custom version of S9xLoadCheatFile()
***************************************************************************/
static bool LoadCheatFile (int length)
{
uint8 data [28];
int offset = 0;
while (offset < length)
{
if(Cheat.num_cheats >= MAX_CHEATS || (length - offset) < 28)
break;
memcpy (data, savebuffer+offset, 28);
offset += 28;
Cheat.c [Cheat.num_cheats].enabled = 0; // cheats always off
Cheat.c [Cheat.num_cheats].byte = data [1];
Cheat.c [Cheat.num_cheats].address = data [2] | (data [3] << 8) | (data [4] << 16);
Cheat.c [Cheat.num_cheats].saved_byte = data [5];
Cheat.c [Cheat.num_cheats].saved = (data [0] & 8) != 0;
memcpy (Cheat.c [Cheat.num_cheats].name, &data[8], 20);
Cheat.c [Cheat.num_cheats].name[20] = 0;
Cheat.num_cheats++;
}
return true;
}
/****************************************************************************
* SetupCheats
*
* Erases any prexisting cheats, loads cheats from a cheat file
* Called when a ROM is first loaded
***************************************************************************/
void
WiiSetupCheats()
{
memset(Cheat.c, 0, sizeof(Cheat.c));
Cheat.num_cheats = 0;
char filepath[1024];
int offset = 0;
if(!MakeFilePath(filepath, FILE_CHEAT))
return;
AllocSaveBuffer();
offset = LoadFile(filepath, SILENT);
// load cheat file if present
if(offset > 0)
LoadCheatFile (offset);
FreeSaveBuffer ();
}

654
src/wii/filebrowser.cpp Normal file
View File

@ -0,0 +1,654 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* svpe June 2007
* crunchy2 May-July 2007
* Michniewski 2008
* Tantric 2008-2010
*
* filebrowser.cpp
*
* Generic file routines - reading, writing, browsing
***************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiiuse/wpad.h>
#include <sys/dir.h>
#include <malloc.h>
#ifdef HW_RVL
#include <di/di.h>
#endif
#include "snes9xgx.h"
#include "filebrowser.h"
#include "menu.h"
#include "video.h"
#include "networkop.h"
#include "fileop.h"
#include "input.h"
#include "gcunzip.h"
#include "freeze.h"
#include "sram.h"
#include "snes9x-next/snes9x.h"
#include "snes9x-next/memmap.h"
#include "snes9x-next/cheats.h"
BROWSERINFO browser;
BROWSERENTRY * browserList = NULL; // list of files/folders in browser
static char szpath[MAXPATHLEN];
static bool inSz = false;
unsigned long SNESROMSize = 0;
bool loadingFile = false;
/****************************************************************************
* autoLoadMethod()
* Auto-determines and sets the load device
* Returns device set
****************************************************************************/
int autoLoadMethod()
{
ShowAction ("Attempting to determine load device...");
int device = DEVICE_AUTO;
if(ChangeInterface(DEVICE_SD, SILENT))
device = DEVICE_SD;
else if(ChangeInterface(DEVICE_USB, SILENT))
device = DEVICE_USB;
else if(ChangeInterface(DEVICE_SD_SLOTA, SILENT))
device = DEVICE_SD_SLOTA;
else if(ChangeInterface(DEVICE_SD_SLOTB, SILENT))
device = DEVICE_SD_SLOTB;
else if(ChangeInterface(DEVICE_DVD, SILENT))
device = DEVICE_DVD;
else if(ChangeInterface(DEVICE_SMB, SILENT))
device = DEVICE_SMB;
else
ErrorPrompt("Unable to locate a load device!");
if(GCSettings.LoadMethod == DEVICE_AUTO)
GCSettings.LoadMethod = device; // save device found for later use
CancelAction();
return device;
}
/****************************************************************************
* autoSaveMethod()
* Auto-determines and sets the save device
* Returns device set
****************************************************************************/
int autoSaveMethod(bool silent)
{
if(!silent)
ShowAction ("Attempting to determine save device...");
int device = DEVICE_AUTO;
if(ChangeInterface(DEVICE_SD, SILENT))
device = DEVICE_SD;
else if(ChangeInterface(DEVICE_USB, SILENT))
device = DEVICE_USB;
else if(ChangeInterface(DEVICE_SD_SLOTA, SILENT))
device = DEVICE_SD_SLOTA;
else if(ChangeInterface(DEVICE_SD_SLOTB, SILENT))
device = DEVICE_SD_SLOTB;
else if(ChangeInterface(DEVICE_SMB, SILENT))
device = DEVICE_SMB;
else if(!silent)
ErrorPrompt("Unable to locate a save device!");
if(GCSettings.SaveMethod == DEVICE_AUTO)
GCSettings.SaveMethod = device; // save device found for later use
CancelAction();
return device;
}
/****************************************************************************
* ResetBrowser()
* Clears the file browser memory, and allocates one initial entry
***************************************************************************/
void ResetBrowser()
{
browser.numEntries = 0;
browser.selIndex = 0;
browser.pageIndex = 0;
browser.size = 0;
}
bool AddBrowserEntry()
{
if(browser.size >= MAX_BROWSER_SIZE)
{
ErrorPrompt("Out of memory: too many files!");
return false; // out of space
}
memset(&(browserList[browser.size]), 0, sizeof(BROWSERENTRY)); // clear the new entry
browser.size++;
return true;
}
/****************************************************************************
* CleanupPath()
* Cleans up the filepath, removing double // and replacing \ with /
***************************************************************************/
static void CleanupPath(char * path)
{
if(!path || path[0] == 0)
return;
int pathlen = strlen(path);
int j = 0;
for(int i=0; i < pathlen && i < MAXPATHLEN; i++)
{
if(path[i] == '\\')
path[i] = '/';
if(j == 0 || !(path[j-1] == '/' && path[i] == '/'))
path[j++] = path[i];
}
path[j] = 0;
}
bool IsDeviceRoot(char * path)
{
if(path == NULL || path[0] == 0)
return false;
if( strcmp(path, "sd:/") == 0 ||
strcmp(path, "usb:/") == 0 ||
strcmp(path, "dvd:/") == 0 ||
strcmp(path, "smb:/") == 0 ||
strcmp(path, "carda:/") == 0 ||
strcmp(path, "cardb:/") == 0)
{
return true;
}
return false;
}
/****************************************************************************
* UpdateDirName()
* Update curent directory name for file browser
***************************************************************************/
int UpdateDirName()
{
int size=0;
char * test;
char temp[1024];
int device = 0;
if(browser.numEntries == 0)
return 1;
FindDevice(browser.dir, &device);
/* current directory doesn't change */
if (strcmp(browserList[browser.selIndex].filename,".") == 0)
{
return 0;
}
/* go up to parent directory */
else if (strcmp(browserList[browser.selIndex].filename,"..") == 0)
{
// already at the top level
if(IsDeviceRoot(browser.dir))
{
browser.dir[0] = 0; // remove device - we are going to the device listing screen
}
else
{
/* determine last subdirectory namelength */
sprintf(temp,"%s",browser.dir);
test = strtok(temp,"/");
while (test != NULL)
{
size = strlen(test);
test = strtok(NULL,"/");
}
/* remove last subdirectory name */
size = strlen(browser.dir) - size - 1;
browser.dir[size] = 0;
}
return 1;
}
/* Open a directory */
else
{
/* test new directory namelength */
if ((strlen(browser.dir)+1+strlen(browserList[browser.selIndex].filename)) < MAXPATHLEN)
{
/* update current directory name */
sprintf(browser.dir, "%s%s/",browser.dir, browserList[browser.selIndex].filename);
return 1;
}
else
{
ErrorPrompt("Directory name is too long!");
return -1;
}
}
}
bool MakeFilePath(char filepath[], int type, char * filename, int filenum)
{
char file[512];
char folder[1024];
char ext[4];
char temppath[MAXPATHLEN];
if(type == FILE_ROM)
{
// Check path length
if ((strlen(browser.dir)+1+strlen(browserList[browser.selIndex].filename)) >= MAXPATHLEN)
{
ErrorPrompt("Maximum filepath length reached!");
filepath[0] = 0;
return false;
}
else
{
sprintf(temppath, "%s%s",browser.dir,browserList[browser.selIndex].filename);
}
}
else
{
if(GCSettings.SaveMethod == DEVICE_AUTO)
GCSettings.SaveMethod = autoSaveMethod(SILENT);
if(GCSettings.SaveMethod == DEVICE_AUTO)
return false;
switch(type)
{
case FILE_SRAM:
case FILE_SNAPSHOT:
sprintf(folder, GCSettings.SaveFolder);
if(type == FILE_SRAM) sprintf(ext, "srm");
else sprintf(ext, "frz");
if(filenum >= -1)
{
if(filenum == -1)
sprintf(file, "%s.%s", filename, ext);
else if(filenum == 0)
sprintf(file, "%s Auto.%s", filename, ext);
else
sprintf(file, "%s %i.%s", filename, filenum, ext);
}
else
{
sprintf(file, "%s", filename);
}
break;
case FILE_CHEAT:
sprintf(folder, GCSettings.CheatFolder);
sprintf(file, "%s.cht", Memory.ROMFilename);
break;
}
sprintf (temppath, "%s%s/%s", pathPrefix[GCSettings.SaveMethod], folder, file);
}
CleanupPath(temppath); // cleanup path
snprintf(filepath, MAXPATHLEN, "%s", temppath);
return true;
}
/****************************************************************************
* FileSortCallback
*
* Quick sort callback to sort file entries with the following order:
* .
* ..
* <dirs>
* <files>
***************************************************************************/
int FileSortCallback(const void *f1, const void *f2)
{
/* Special case for implicit directories */
if(((BROWSERENTRY *)f1)->filename[0] == '.' || ((BROWSERENTRY *)f2)->filename[0] == '.')
{
if(strcmp(((BROWSERENTRY *)f1)->filename, ".") == 0) { return -1; }
if(strcmp(((BROWSERENTRY *)f2)->filename, ".") == 0) { return 1; }
if(strcmp(((BROWSERENTRY *)f1)->filename, "..") == 0) { return -1; }
if(strcmp(((BROWSERENTRY *)f2)->filename, "..") == 0) { return 1; }
}
/* If one is a file and one is a directory the directory is first. */
if(((BROWSERENTRY *)f1)->isdir && !(((BROWSERENTRY *)f2)->isdir)) return -1;
if(!(((BROWSERENTRY *)f1)->isdir) && ((BROWSERENTRY *)f2)->isdir) return 1;
return stricmp(((BROWSERENTRY *)f1)->filename, ((BROWSERENTRY *)f2)->filename);
}
/****************************************************************************
* IsValidROM
*
* Checks if the specified file is a valid ROM
* For now we will just check the file extension and file size
* If the file is a zip, we will check the file extension / file size of the
* first file inside
***************************************************************************/
static bool IsValidROM()
{
// file size should be between 96K and 8MB
if(browserList[browser.selIndex].length < (1024*96) ||
browserList[browser.selIndex].length > MAX_ROM_SIZE)
{
ErrorPrompt("Invalid file size!");
return false;
}
if (strlen(browserList[browser.selIndex].filename) > 4)
{
char * p = strrchr(browserList[browser.selIndex].filename, '.');
if (p != NULL)
{
char * zippedFilename = NULL;
if(stricmp(p, ".zip") == 0 && !inSz)
{
// we need to check the file extension of the first file in the archive
zippedFilename = GetFirstZipFilename ();
if(zippedFilename && strlen(zippedFilename) > 4)
p = strrchr(zippedFilename, '.');
else
p = NULL;
}
if(p != NULL)
{
if (stricmp(p, ".smc") == 0 ||
stricmp(p, ".fig") == 0 ||
stricmp(p, ".sfc") == 0 ||
stricmp(p, ".swc") == 0)
{
if(zippedFilename) free(zippedFilename);
return true;
}
}
if(zippedFilename) free(zippedFilename);
}
}
ErrorPrompt("Unknown file type!");
return false;
}
/****************************************************************************
* IsSz
*
* Checks if the specified file is a 7z
***************************************************************************/
bool IsSz()
{
if (strlen(browserList[browser.selIndex].filename) > 4)
{
char * p = strrchr(browserList[browser.selIndex].filename, '.');
if (p != NULL)
if(stricmp(p, ".7z") == 0)
return true;
}
return false;
}
/****************************************************************************
* StripExt
*
* Strips an extension from a filename
***************************************************************************/
void StripExt(char* returnstring, char * inputstring)
{
char* loc_dot;
snprintf (returnstring, MAXJOLIET, "%s", inputstring);
if(inputstring == NULL || strlen(inputstring) < 4)
return;
loc_dot = strrchr(returnstring,'.');
if (loc_dot != NULL)
*loc_dot = 0; // strip file extension
}
/****************************************************************************
* BrowserLoadSz
*
* Opens the selected 7z file, and parses a listing of the files within
***************************************************************************/
int BrowserLoadSz()
{
char filepath[MAXPATHLEN];
memset(filepath, 0, MAXPATHLEN);
// we'll store the 7z filepath for extraction later
if(!MakeFilePath(szpath, FILE_ROM))
return 0;
int szfiles = SzParse(szpath);
if(szfiles)
{
browser.numEntries = szfiles;
inSz = true;
}
else
ErrorPrompt("Error opening archive!");
return szfiles;
}
int WiiFileLoader()
{
int size;
char filepath[1024];
memset(Memory.NSRTHeader, 0, sizeof(Memory.NSRTHeader));
Memory.HeaderCount = 0;
loadingFile = true;
if(!inSz)
{
if(!MakeFilePath(filepath, FILE_ROM))
return 0;
size = LoadFile ((char *)Memory.ROM, filepath, browserList[browser.selIndex].length, NOTSILENT);
}
else
{
size = LoadSzFile(szpath, (unsigned char *)Memory.ROM);
if(size <= 0)
{
browser.selIndex = 0;
BrowserChangeFolder();
}
}
loadingFile = false;
if(size <= 0)
return 0;
SNESROMSize = Memory.HeaderRemove(size, Memory.HeaderCount, Memory.ROM);
return SNESROMSize;
}
/****************************************************************************
* BrowserLoadFile
*
* Loads the selected ROM
***************************************************************************/
int BrowserLoadFile()
{
int loaded = 0;
int device;
if(!FindDevice(browser.dir, &device))
return 0;
GetFileSize(browser.selIndex);
// check that this is a valid ROM
if(!IsValidROM())
goto done;
// store the filename (w/o ext) - used for sram/freeze naming
StripExt(Memory.ROMFilename, browserList[browser.selIndex].filename);
strcpy(loadedFile, browserList[browser.selIndex].filename);
SNESROMSize = 0;
S9xDeleteCheats();
Memory.LoadROM("ROM");
if (SNESROMSize <= 0)
{
ErrorPrompt("Error loading game!");
}
else
{
// load SRAM or snapshot
if (GCSettings.AutoLoad == 1)
LoadSRAMAuto(SILENT);
else if (GCSettings.AutoLoad == 2)
LoadSnapshotAuto(SILENT);
ResetBrowser();
loaded = 1;
}
done:
CancelAction();
return loaded;
}
/****************************************************************************
* BrowserChangeFolder
*
* Update current directory and set new entry list if directory has changed
***************************************************************************/
int BrowserChangeFolder()
{
int device = 0;
FindDevice(browser.dir, &device);
if(inSz && browser.selIndex == 0) // inside a 7z, requesting to leave
{
inSz = false;
SzClose();
}
if(!UpdateDirName())
return -1;
HaltParseThread(); // halt parsing
CleanupPath(browser.dir);
ResetBrowser(); // reset browser
if(browser.dir[0] != 0)
ParseDirectory();
if(browser.numEntries == 0)
{
browser.dir[0] = 0;
int i=0;
#ifdef HW_RVL
AddBrowserEntry();
sprintf(browserList[i].filename, "sd:/");
sprintf(browserList[i].displayname, "SD Card");
browserList[i].length = 0;
browserList[i].isdir = 1;
browserList[i].icon = ICON_SD;
i++;
AddBrowserEntry();
sprintf(browserList[i].filename, "usb:/");
sprintf(browserList[i].displayname, "USB Mass Storage");
browserList[i].length = 0;
browserList[i].isdir = 1;
browserList[i].icon = ICON_USB;
i++;
#else
AddBrowserEntry();
sprintf(browserList[i].filename, "carda:/");
sprintf(browserList[i].displayname, "SD Gecko Slot A");
browserList[i].length = 0;
browserList[i].isdir = 1;
browserList[i].icon = ICON_SD;
i++;
AddBrowserEntry();
sprintf(browserList[i].filename, "cardb:/");
sprintf(browserList[i].displayname, "SD Gecko Slot B");
browserList[i].length = 0;
browserList[i].isdir = 1;
browserList[i].icon = ICON_SD;
i++;
#endif
AddBrowserEntry();
sprintf(browserList[i].filename, "smb:/");
sprintf(browserList[i].displayname, "Network Share");
browserList[i].length = 0;
browserList[i].isdir = 1;
browserList[i].icon = ICON_SMB;
i++;
AddBrowserEntry();
sprintf(browserList[i].filename, "dvd:/");
sprintf(browserList[i].displayname, "Data DVD");
browserList[i].length = 0;
browserList[i].isdir = 1;
browserList[i].icon = ICON_DVD;
i++;
browser.numEntries += i;
}
if(browser.dir[0] == 0)
{
GCSettings.LoadFolder[0] = 0;
GCSettings.LoadMethod = 0;
}
else
{
char * path = StripDevice(browser.dir);
if(path != NULL)
strcpy(GCSettings.LoadFolder, path);
FindDevice(browser.dir, &GCSettings.LoadMethod);
}
return browser.numEntries;
}
/****************************************************************************
* OpenROM
* Displays a list of ROMS on load device
***************************************************************************/
int
OpenGameList ()
{
int device = GCSettings.LoadMethod;
if(device == DEVICE_AUTO && strlen(GCSettings.LoadFolder) > 0)
device = autoLoadMethod();
// change current dir to roms directory
if(device > 0)
sprintf(browser.dir, "%s%s/", pathPrefix[device], GCSettings.LoadFolder);
else
browser.dir[0] = 0;
BrowserChangeFolder();
return browser.numEntries;
}

77
src/wii/filebrowser.h Normal file
View File

@ -0,0 +1,77 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* crunchy2 May 2007
* Michniewski 2008
* Tantric 2008-2010
*
* filebrowser.h
*
* Generic file routines - reading, writing, browsing
****************************************************************************/
#ifndef _FILEBROWSER_H_
#define _FILEBROWSER_H_
#include <unistd.h>
#include <gccore.h>
#define MAXJOLIET 255
#ifdef HW_DOL
#define MAX_BROWSER_SIZE 1000
#else
#define MAX_BROWSER_SIZE 5000
#endif
typedef struct
{
char dir[MAXPATHLEN + 1]; // directory path of browserList
int numEntries; // # of entries in browserList
int selIndex; // currently selected index of browserList
int pageIndex; // starting index of browserList page display
int size; // # of entries browerList has space allocated to store
} BROWSERINFO;
typedef struct
{
size_t length; // file length
int isdir; // 0 - file, 1 - directory
char filename[MAXJOLIET + 1]; // full filename
char displayname[MAXJOLIET + 1]; // name for browser display
int filenum; // file # (for 7z support)
int icon; // icon to display
} BROWSERENTRY;
extern BROWSERINFO browser;
extern BROWSERENTRY * browserList;
enum
{
ICON_NONE,
ICON_FOLDER,
ICON_SD,
ICON_USB,
ICON_DVD,
ICON_SMB
};
extern unsigned long SNESROMSize;
extern bool loadingFile;
bool MakeFilePath(char filepath[], int type, char * filename = NULL, int filenum = -2);
int UpdateDirName();
int OpenGameList();
int autoLoadMethod();
int autoSaveMethod(bool silent);
int FileSortCallback(const void *f1, const void *f2);
void StripExt(char* returnstring, char * inputstring);
bool IsSz();
void ResetBrowser();
bool AddBrowserEntry();
bool IsDeviceRoot(char * path);
int BrowserLoadSz();
int BrowserChangeFolder();
int BrowserLoadFile();
#endif

320
src/wii/filelist.h Normal file
View File

@ -0,0 +1,320 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* Tantric 2009-2010
*
* filelist.h
*
* Contains a list of all of the files stored in the images/, fonts/, and
* sounds/ folders
***************************************************************************/
#ifndef _FILELIST_H_
#define _FILELIST_H_
#include <gccore.h>
// Fonts
extern const u8 font_ttf[];
extern const u32 font_ttf_size;
// Languages
extern const u8 jp_lang[];
extern const u32 jp_lang_size;
extern const u8 en_lang[];
extern const u32 en_lang_size;
extern const u8 de_lang[];
extern const u32 de_lang_size;
extern const u8 fr_lang[];
extern const u32 fr_lang_size;
extern const u8 es_lang[];
extern const u32 es_lang_size;
extern const u8 it_lang[];
extern const u32 it_lang_size;
extern const u8 nl_lang[];
extern const u32 nl_lang_size;
extern const u8 zh_lang[];
extern const u32 zh_lang_size;
extern const u8 ko_lang[];
extern const u32 ko_lang_size;
extern const u8 pt_lang[];
extern const u32 pt_lang_size;
extern const u8 pt_br_lang[];
extern const u32 pt_br_lang_size;
extern const u8 ca_lang[];
extern const u32 ca_lang_size;
extern const u8 tr_lang[];
extern const u32 tr_lang_size;
// Sounds
extern const u8 bg_music_ogg[];
extern const u32 bg_music_ogg_size;
extern const u8 enter_ogg[];
extern const u32 enter_ogg_size;
extern const u8 exit_ogg[];
extern const u32 exit_ogg_size;
extern const u8 button_over_pcm[];
extern const u32 button_over_pcm_size;
extern const u8 button_click_pcm[];
extern const u32 button_click_pcm_size;
// Graphics
extern const u8 logo_png[];
extern const u32 logo_png_size;
extern const u8 logo_over_png[];
extern const u32 logo_over_png_size;
extern const u8 bg_top_png[];
extern const u32 bg_top_png_size;
extern const u8 bg_bottom_png[];
extern const u32 bg_bottom_png_size;
extern const u8 icon_settings_png[];
extern const u32 icon_settings_png_size;
extern const u8 icon_home_png[];
extern const u32 icon_home_png_size;
extern const u8 icon_game_settings_png[];
extern const u32 icon_game_settings_png_size;
extern const u8 icon_game_cheats_png[];
extern const u32 icon_game_cheats_png_size;
extern const u8 icon_game_controllers_png[];
extern const u32 icon_game_controllers_png_size;
extern const u8 icon_game_load_png[];
extern const u32 icon_game_load_png_size;
extern const u8 icon_game_save_png[];
extern const u32 icon_game_save_png_size;
extern const u8 icon_game_reset_png[];
extern const u32 icon_game_reset_png_size;
extern const u8 icon_settings_wiimote_png[];
extern const u32 icon_settings_wiimote_png_size;
extern const u8 icon_settings_classic_png[];
extern const u32 icon_settings_classic_png_size;
extern const u8 icon_settings_gamecube_png[];
extern const u32 icon_settings_gamecube_png_size;
extern const u8 icon_settings_nunchuk_png[];
extern const u32 icon_settings_nunchuk_png_size;
extern const u8 icon_settings_snescontroller_png[];
extern const u32 icon_settings_snescontroller_png_size;
extern const u8 icon_settings_superscope_png[];
extern const u32 icon_settings_superscope_png_size;
extern const u8 icon_settings_justifier_png[];
extern const u32 icon_settings_justifier_png_size;
extern const u8 icon_settings_mouse_png[];
extern const u32 icon_settings_mouse_png_size;
extern const u8 icon_settings_file_png[];
extern const u32 icon_settings_file_png_size;
extern const u8 icon_settings_mappings_png[];
extern const u32 icon_settings_mappings_png_size;
extern const u8 icon_settings_menu_png[];
extern const u32 icon_settings_menu_png_size;
extern const u8 icon_settings_network_png[];
extern const u32 icon_settings_network_png_size;
extern const u8 icon_settings_video_png[];
extern const u32 icon_settings_video_png_size;
extern const u8 button_png[];
extern const u32 button_png_size;
extern const u8 button_over_png[];
extern const u32 button_over_png_size;
extern const u8 button_prompt_png[];
extern const u32 button_prompt_png_size;
extern const u8 button_prompt_over_png[];
extern const u32 button_prompt_over_png_size;
extern const u8 button_long_png[];
extern const u32 button_long_png_size;
extern const u8 button_long_over_png[];
extern const u32 button_long_over_png_size;
extern const u8 button_short_png[];
extern const u32 button_short_png_size;
extern const u8 button_short_over_png[];
extern const u32 button_short_over_png_size;
extern const u8 button_small_png[];
extern const u32 button_small_png_size;
extern const u8 button_small_over_png[];
extern const u32 button_small_over_png_size;
extern const u8 button_large_png[];
extern const u32 button_large_png_size;
extern const u8 button_large_over_png[];
extern const u32 button_large_over_png_size;
extern const u8 button_arrow_left_png[];
extern const u32 button_arrow_left_png_size;
extern const u8 button_arrow_right_png[];
extern const u32 button_arrow_right_png_size;
extern const u8 button_arrow_up_png[];
extern const u32 button_arrow_up_png_size;
extern const u8 button_arrow_down_png[];
extern const u32 button_arrow_down_png_size;
extern const u8 button_arrow_left_over_png[];
extern const u32 button_arrow_left_over_png_size;
extern const u8 button_arrow_right_over_png[];
extern const u32 button_arrow_right_over_png_size;
extern const u8 button_arrow_up_over_png[];
extern const u32 button_arrow_up_over_png_size;
extern const u8 button_arrow_down_over_png[];
extern const u32 button_arrow_down_over_png_size;
extern const u8 button_gamesave_png[];
extern const u32 button_gamesave_png_size;
extern const u8 button_gamesave_over_png[];
extern const u32 button_gamesave_over_png_size;
extern const u8 button_gamesave_blank_png[];
extern const u32 button_gamesave_blank_png_size;
extern const u8 screen_position_png[];
extern const u32 screen_position_png_size;
extern const u8 dialogue_box_png[];
extern const u32 dialogue_box_png_size;
extern const u8 credits_box_png[];
extern const u32 credits_box_png_size;
extern const u8 progressbar_png[];
extern const u32 progressbar_png_size;
extern const u8 progressbar_empty_png[];
extern const u32 progressbar_empty_png_size;
extern const u8 progressbar_outline_png[];
extern const u32 progressbar_outline_png_size;
extern const u8 throbber_png[];
extern const u32 throbber_png_size;
extern const u8 icon_folder_png[];
extern const u32 icon_folder_png_size;
extern const u8 icon_sd_png[];
extern const u32 icon_sd_png_size;
extern const u8 icon_usb_png[];
extern const u32 icon_usb_png_size;
extern const u8 icon_dvd_png[];
extern const u32 icon_dvd_png_size;
extern const u8 icon_smb_png[];
extern const u32 icon_smb_png_size;
extern const u8 battery_png[];
extern const u32 battery_png_size;
extern const u8 battery_red_png[];
extern const u32 battery_red_png_size;
extern const u8 battery_bar_png[];
extern const u32 battery_bar_png_size;
extern const u8 bg_options_png[];
extern const u32 bg_options_png_size;
extern const u8 bg_options_entry_png[];
extern const u32 bg_options_entry_png_size;
extern const u8 bg_game_selection_png[];
extern const u32 bg_game_selection_png_size;
extern const u8 bg_game_selection_entry_png[];
extern const u32 bg_game_selection_entry_png_size;
extern const u8 scrollbar_png[];
extern const u32 scrollbar_png_size;
extern const u8 scrollbar_arrowup_png[];
extern const u32 scrollbar_arrowup_png_size;
extern const u8 scrollbar_arrowup_over_png[];
extern const u32 scrollbar_arrowup_over_png_size;
extern const u8 scrollbar_arrowdown_png[];
extern const u32 scrollbar_arrowdown_png_size;
extern const u8 scrollbar_arrowdown_over_png[];
extern const u32 scrollbar_arrowdown_over_png_size;
extern const u8 scrollbar_box_png[];
extern const u32 scrollbar_box_png_size;
extern const u8 scrollbar_box_over_png[];
extern const u32 scrollbar_box_over_png_size;
extern const u8 keyboard_textbox_png[];
extern const u32 keyboard_textbox_png_size;
extern const u8 keyboard_key_png[];
extern const u32 keyboard_key_png_size;
extern const u8 keyboard_key_over_png[];
extern const u32 keyboard_key_over_png_size;
extern const u8 keyboard_mediumkey_png[];
extern const u32 keyboard_mediumkey_png_size;
extern const u8 keyboard_mediumkey_over_png[];
extern const u32 keyboard_mediumkey_over_png_size;
extern const u8 keyboard_largekey_png[];
extern const u32 keyboard_largekey_png_size;
extern const u8 keyboard_largekey_over_png[];
extern const u32 keyboard_largekey_over_png_size;
extern const u8 player1_point_png[];
extern const u32 player1_point_png_size;
extern const u8 player2_point_png[];
extern const u32 player2_point_png_size;
extern const u8 player3_point_png[];
extern const u32 player3_point_png_size;
extern const u8 player4_point_png[];
extern const u32 player4_point_png_size;
extern const u8 player1_grab_png[];
extern const u32 player1_grab_png_size;
extern const u8 player2_grab_png[];
extern const u32 player2_grab_png_size;
extern const u8 player3_grab_png[];
extern const u32 player3_grab_png_size;
extern const u8 player4_grab_png[];
extern const u32 player4_grab_png_size;
#endif

928
src/wii/fileop.cpp Normal file
View File

@ -0,0 +1,928 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* crunchy2 May 2007
* Michniewski 2008
* Tantric 2008-2010
*
* fileop.cpp
*
* File operations
***************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ogcsys.h>
#include <dirent.h>
#include <sys/stat.h>
#include <zlib.h>
#include <malloc.h>
#include <sdcard/wiisd_io.h>
#include <sdcard/gcsd.h>
#include <ogc/usbstorage.h>
#include <di/di.h>
#include <ogc/dvd.h>
#include <iso9660.h>
#include "snes9xgx.h"
#include "fileop.h"
#include "networkop.h"
#include "gcunzip.h"
#include "menu.h"
#include "filebrowser.h"
#include "gui/gui.h"
#define THREAD_SLEEP 100
unsigned char *savebuffer = NULL;
static mutex_t bufferLock = LWP_MUTEX_NULL;
FILE * file; // file pointer - the only one we should ever use!
bool unmountRequired[7] = { false, false, false, false, false, false, false };
bool isMounted[7] = { false, false, false, false, false, false, false };
#ifdef HW_RVL
const DISC_INTERFACE* sd = &__io_wiisd;
const DISC_INTERFACE* usb = &__io_usbstorage;
const DISC_INTERFACE* dvd = &__io_wiidvd;
#else
const DISC_INTERFACE* carda = &__io_gcsda;
const DISC_INTERFACE* cardb = &__io_gcsdb;
const DISC_INTERFACE* dvd = &__io_gcdvd;
#endif
// folder parsing thread
static lwp_t parsethread = LWP_THREAD_NULL;
static DIR *dir = NULL;
static bool parseHalt = true;
static bool parseFilter = true;
static bool ParseDirEntries();
int selectLoadedFile = 0;
// device thread
static lwp_t devicethread = LWP_THREAD_NULL;
static bool deviceHalt = true;
/****************************************************************************
* ResumeDeviceThread
*
* Signals the device thread to start, and resumes the thread.
***************************************************************************/
void
ResumeDeviceThread()
{
deviceHalt = false;
LWP_ResumeThread(devicethread);
}
/****************************************************************************
* HaltGui
*
* Signals the device thread to stop.
***************************************************************************/
void
HaltDeviceThread()
{
#ifdef HW_RVL
deviceHalt = true;
// wait for thread to finish
while(!LWP_ThreadIsSuspended(devicethread))
usleep(THREAD_SLEEP);
#endif
}
/****************************************************************************
* HaltParseThread
*
* Signals the parse thread to stop.
***************************************************************************/
void
HaltParseThread()
{
parseHalt = true;
while(!LWP_ThreadIsSuspended(parsethread))
usleep(THREAD_SLEEP);
}
/****************************************************************************
* devicecallback
*
* This checks our devices for changes (SD/USB/DVD removed)
***************************************************************************/
#ifdef HW_RVL
static int devsleep;
static void *
devicecallback (void *arg)
{
while (1)
{
if(isMounted[DEVICE_SD])
{
if(!sd->isInserted()) // check if the device was removed
{
unmountRequired[DEVICE_SD] = true;
isMounted[DEVICE_SD] = false;
}
}
if(isMounted[DEVICE_USB])
{
if(!usb->isInserted()) // check if the device was removed
{
unmountRequired[DEVICE_USB] = true;
isMounted[DEVICE_USB] = false;
}
}
if(isMounted[DEVICE_DVD])
{
if(!dvd->isInserted()) // check if the device was removed
{
unmountRequired[DEVICE_DVD] = true;
isMounted[DEVICE_DVD] = false;
}
}
devsleep = 1000*1000; // 1 sec
while(devsleep > 0)
{
if(deviceHalt)
LWP_SuspendThread(devicethread);
usleep(THREAD_SLEEP);
devsleep -= THREAD_SLEEP;
}
UpdateCheck();
}
return NULL;
}
#endif
static void *
parsecallback (void *arg)
{
while(1)
{
while(ParseDirEntries())
usleep(THREAD_SLEEP);
LWP_SuspendThread(parsethread);
}
return NULL;
}
/****************************************************************************
* InitDeviceThread
*
* libOGC provides a nice wrapper for LWP access.
* This function sets up a new local queue and attaches the thread to it.
***************************************************************************/
void
InitDeviceThread()
{
#ifdef HW_RVL
LWP_CreateThread (&devicethread, devicecallback, NULL, NULL, 0, 40);
#endif
LWP_CreateThread (&parsethread, parsecallback, NULL, NULL, 0, 80);
}
/****************************************************************************
* UnmountAllFAT
* Unmounts all FAT devices
***************************************************************************/
void UnmountAllFAT()
{
#ifdef HW_RVL
fatUnmount("sd:");
fatUnmount("usb:");
#else
fatUnmount("carda:");
fatUnmount("cardb:");
#endif
}
/****************************************************************************
* MountFAT
* Checks if the device needs to be (re)mounted
* If so, unmounts the device
* Attempts to mount the device specified
* Sets libfat to use the device by default
***************************************************************************/
static bool MountFAT(int device, int silent)
{
bool mounted = false;
int retry = 1;
char name[10], name2[10];
const DISC_INTERFACE* disc = NULL;
switch(device)
{
#ifdef HW_RVL
case DEVICE_SD:
sprintf(name, "sd");
sprintf(name2, "sd:");
disc = sd;
break;
case DEVICE_USB:
sprintf(name, "usb");
sprintf(name2, "usb:");
disc = usb;
break;
#else
case DEVICE_SD_SLOTA:
sprintf(name, "carda");
sprintf(name2, "carda:");
disc = carda;
break;
case DEVICE_SD_SLOTB:
sprintf(name, "cardb");
sprintf(name2, "cardb:");
disc = cardb;
break;
#endif
default:
return false; // unknown device
}
if(unmountRequired[device])
{
unmountRequired[device] = false;
fatUnmount(name2);
disc->shutdown();
isMounted[device] = false;
}
while(retry)
{
if(disc->startup() && fatMountSimple(name, disc))
mounted = true;
if(mounted || silent)
break;
#ifdef HW_RVL
if(device == DEVICE_SD)
retry = ErrorPromptRetry("SD card not found!");
else
retry = ErrorPromptRetry("USB drive not found!");
#else
retry = ErrorPromptRetry("SD card not found!");
#endif
}
isMounted[device] = mounted;
return mounted;
}
void MountAllFAT()
{
#ifdef HW_RVL
MountFAT(DEVICE_SD, SILENT);
MountFAT(DEVICE_USB, SILENT);
#else
MountFAT(DEVICE_SD_SLOTA, SILENT);
MountFAT(DEVICE_SD_SLOTB, SILENT);
#endif
}
/****************************************************************************
* MountDVD()
*
* Tests if a ISO9660 DVD is inserted and available, and mounts it
***************************************************************************/
bool MountDVD(bool silent)
{
bool mounted = false;
int retry = 1;
if(unmountRequired[DEVICE_DVD])
{
unmountRequired[DEVICE_DVD] = false;
ISO9660_Unmount("dvd:");
}
while(retry)
{
ShowAction("Loading DVD...");
if(!dvd->isInserted())
{
if(silent)
break;
retry = ErrorPromptRetry("No disc inserted!");
}
else if(!ISO9660_Mount("dvd", dvd))
{
if(silent)
break;
retry = ErrorPromptRetry("Unrecognized DVD format.");
}
else
{
mounted = true;
break;
}
}
CancelAction();
isMounted[DEVICE_DVD] = mounted;
return mounted;
}
bool FindDevice(char * filepath, int * device)
{
if(!filepath || filepath[0] == 0)
return false;
if(strncmp(filepath, "sd:", 3) == 0)
{
*device = DEVICE_SD;
return true;
}
else if(strncmp(filepath, "usb:", 4) == 0)
{
*device = DEVICE_USB;
return true;
}
else if(strncmp(filepath, "smb:", 4) == 0)
{
*device = DEVICE_SMB;
return true;
}
else if(strncmp(filepath, "carda:", 6) == 0)
{
*device = DEVICE_SD_SLOTA;
return true;
}
else if(strncmp(filepath, "cardb:", 6) == 0)
{
*device = DEVICE_SD_SLOTB;
return true;
}
else if(strncmp(filepath, "dvd:", 4) == 0)
{
*device = DEVICE_DVD;
return true;
}
return false;
}
char * StripDevice(char * path)
{
if(path == NULL)
return NULL;
char * newpath = strchr(path,'/');
if(newpath != NULL)
newpath++;
return newpath;
}
/****************************************************************************
* ChangeInterface
* Attempts to mount/configure the device specified
***************************************************************************/
bool ChangeInterface(int device, bool silent)
{
if(isMounted[device])
return true;
bool mounted = false;
switch(device)
{
#ifdef HW_RVL
case DEVICE_SD:
case DEVICE_USB:
#else
case DEVICE_SD_SLOTA:
case DEVICE_SD_SLOTB:
#endif
mounted = MountFAT(device, silent);
break;
case DEVICE_DVD:
mounted = MountDVD(silent);
break;
case DEVICE_SMB:
mounted = ConnectShare(silent);
break;
}
return mounted;
}
bool ChangeInterface(char * filepath, bool silent)
{
int device = -1;
if(!FindDevice(filepath, &device))
return false;
return ChangeInterface(device, silent);
}
void CreateAppPath(char * origpath)
{
if(!origpath || origpath[0] == 0)
return;
char * path = strdup(origpath); // make a copy so we don't mess up original
if(!path)
return;
char * loc = strrchr(path,'/');
if (loc != NULL)
*loc = 0; // strip file name
int pos = 0;
// replace fat:/ with sd:/
if(strncmp(path, "fat:/", 5) == 0)
{
pos++;
path[1] = 's';
path[2] = 'd';
}
if(ChangeInterface(&path[pos], SILENT))
snprintf(appPath, MAXPATHLEN-1, "%s", &path[pos]);
free(path);
}
static char *GetExt(char *file)
{
if(!file)
return NULL;
char *ext = strrchr(file,'.');
if(ext != NULL)
{
ext++;
int extlen = strlen(ext);
if(extlen > 5)
return NULL;
}
return ext;
}
bool GetFileSize(int i)
{
if(browserList[i].length > 0)
return true;
struct stat filestat;
char path[MAXPATHLEN+1];
snprintf(path, MAXPATHLEN, "%s%s", browser.dir, browserList[i].filename);
if(stat(path, &filestat) < 0)
return false;
browserList[i].length = filestat.st_size;
return true;
}
static bool ParseDirEntries()
{
if(!dir)
return false;
char *ext;
struct dirent *entry = NULL;
int isdir;
int i = 0;
while(i < 20 && !parseHalt)
{
entry = readdir(dir);
if(entry == NULL)
break;
if(entry->d_name[0] == '.' && entry->d_name[1] != '.')
continue;
if(strcmp(entry->d_name, "..") == 0)
{
isdir = 1;
}
else
{
if(entry->d_type==DT_DIR)
isdir = 1;
else
isdir = 0;
// don't show the file if it's not a valid ROM
if(parseFilter && !isdir)
{
ext = GetExt(entry->d_name);
if(ext == NULL)
continue;
if( stricmp(ext, "smc") != 0 && stricmp(ext, "fig") != 0 &&
stricmp(ext, "sfc") != 0 && stricmp(ext, "swc") != 0 &&
stricmp(ext, "zip") != 0 && stricmp(ext, "7z") != 0)
continue;
}
}
if(!AddBrowserEntry())
{
parseHalt = true;
break;
}
snprintf(browserList[browser.numEntries+i].filename, MAXJOLIET, "%s", entry->d_name);
browserList[browser.numEntries+i].isdir = isdir; // flag this as a dir
if(isdir)
{
if(strcmp(entry->d_name, "..") == 0)
sprintf(browserList[browser.numEntries+i].displayname, "Up One Level");
else
snprintf(browserList[browser.numEntries+i].displayname, MAXJOLIET, "%s", browserList[browser.numEntries+i].filename);
browserList[browser.numEntries+i].icon = ICON_FOLDER;
}
else
{
StripExt(browserList[browser.numEntries+i].displayname, browserList[browser.numEntries+i].filename); // hide file extension
}
i++;
}
if(!parseHalt)
{
// Sort the file list
if(i >= 0)
qsort(browserList, browser.numEntries+i, sizeof(BROWSERENTRY), FileSortCallback);
browser.numEntries += i;
}
if(entry == NULL || parseHalt)
{
closedir(dir); // close directory
dir = NULL;
// try to find and select the last loaded file
if(selectLoadedFile == 1 && !parseHalt && loadedFile[0] != 0 && browser.dir[0] != 0)
{
int indexFound = -1;
for(int j=1; j < browser.numEntries; j++)
{
if(strcmp(browserList[j].filename, loadedFile) == 0)
{
indexFound = j;
break;
}
}
// move to this file
if(indexFound > 0)
{
if(indexFound >= FILE_PAGESIZE)
{
int newIndex = (floor(indexFound/(float)FILE_PAGESIZE)) * FILE_PAGESIZE;
if(newIndex + FILE_PAGESIZE > browser.numEntries)
newIndex = browser.numEntries - FILE_PAGESIZE;
if(newIndex < 0)
newIndex = 0;
browser.pageIndex = newIndex;
}
browser.selIndex = indexFound;
}
selectLoadedFile = 2; // selecting done
}
return false; // no more entries
}
return true; // more entries
}
/***************************************************************************
* Browse subdirectories
**************************************************************************/
int
ParseDirectory(bool waitParse, bool filter)
{
int retry = 1;
bool mounted = false;
parseFilter = filter;
ResetBrowser(); // reset browser
// add trailing slash
if(browser.dir[strlen(browser.dir)-1] != '/')
strcat(browser.dir, "/");
// open the directory
while(dir == NULL && retry == 1)
{
mounted = ChangeInterface(browser.dir, NOTSILENT);
if(mounted)
dir = opendir(browser.dir);
else
return -1;
if(dir == NULL)
{
retry = ErrorPromptRetry("Error opening directory!");
}
}
// if we can't open the dir, try higher levels
if (dir == NULL)
{
char * devEnd = strrchr(browser.dir, '/');
while(!IsDeviceRoot(browser.dir))
{
devEnd[0] = 0; // strip slash
devEnd = strrchr(browser.dir, '/');
if(devEnd == NULL)
break;
devEnd[1] = 0; // strip remaining file listing
dir = opendir(browser.dir);
if (dir)
break;
}
}
if(dir == NULL)
return -1;
if(IsDeviceRoot(browser.dir))
{
AddBrowserEntry();
sprintf(browserList[0].filename, "..");
sprintf(browserList[0].displayname, "Up One Level");
browserList[0].length = 0;
browserList[0].isdir = 1; // flag this as a dir
browserList[0].icon = ICON_FOLDER;
browser.numEntries++;
}
parseHalt = false;
ParseDirEntries(); // index first 20 entries
LWP_ResumeThread(parsethread); // index remaining entries
if(waitParse) // wait for complete parsing
{
ShowAction("Loading...");
while(!LWP_ThreadIsSuspended(parsethread))
usleep(THREAD_SLEEP);
CancelAction();
}
return browser.numEntries;
}
/****************************************************************************
* AllocSaveBuffer ()
* Clear and allocate the savebuffer
***************************************************************************/
void
AllocSaveBuffer ()
{
if(bufferLock == LWP_MUTEX_NULL)
LWP_MutexInit(&bufferLock, false);
if(bufferLock != LWP_MUTEX_NULL)
LWP_MutexLock(bufferLock);
memset (savebuffer, 0, SAVEBUFFERSIZE);
}
/****************************************************************************
* FreeSaveBuffer ()
* Free the savebuffer memory
***************************************************************************/
void
FreeSaveBuffer ()
{
if(bufferLock != LWP_MUTEX_NULL)
LWP_MutexUnlock(bufferLock);
}
/****************************************************************************
* LoadSzFile
* Loads the selected file # from the specified 7z into rbuffer
* Returns file size
***************************************************************************/
size_t
LoadSzFile(char * filepath, unsigned char * rbuffer)
{
size_t size = 0;
// stop checking if devices were removed/inserted
// since we're loading a file
HaltDeviceThread();
// halt parsing
HaltParseThread();
file = fopen (filepath, "rb");
if (file > 0)
{
size = SzExtractFile(browserList[browser.selIndex].filenum, rbuffer);
fclose (file);
}
else
{
ErrorPrompt("Error opening file!");
}
// go back to checking if devices were inserted/removed
ResumeDeviceThread();
return size;
}
/****************************************************************************
* LoadFile
***************************************************************************/
size_t
LoadFile (char * rbuffer, char *filepath, size_t length, bool silent)
{
char zipbuffer[2048];
size_t size = 0, offset = 0, readsize = 0;
int retry = 1;
int device;
if(!FindDevice(filepath, &device))
return 0;
// stop checking if devices were removed/inserted
// since we're loading a file
HaltDeviceThread();
// halt parsing
HaltParseThread();
// open the file
while(retry)
{
if(!ChangeInterface(device, silent))
break;
file = fopen (filepath, "rb");
if(!file)
{
if(silent)
break;
retry = ErrorPromptRetry("Error opening file!");
continue;
}
if(length > 0 && length <= 2048) // do a partial read (eg: to check file header)
{
size = fread (rbuffer, 1, length, file);
}
else // load whole file
{
readsize = fread (zipbuffer, 1, 32, file);
if(!readsize)
{
unmountRequired[device] = true;
retry = ErrorPromptRetry("Error reading file!");
fclose (file);
continue;
}
if (IsZipFile (zipbuffer))
{
size = UnZipBuffer ((unsigned char *)rbuffer); // unzip
}
else
{
fseeko(file,0,SEEK_END);
size = ftello(file);
fseeko(file,0,SEEK_SET);
while(!feof(file))
{
ShowProgress ("Loading...", offset, size);
readsize = fread (rbuffer + offset, 1, 4096, file); // read in next chunk
if(readsize <= 0)
break; // reading finished (or failed)
offset += readsize;
}
size = offset;
CancelAction();
}
}
retry = 0;
fclose (file);
}
// go back to checking if devices were inserted/removed
ResumeDeviceThread();
CancelAction();
return size;
}
size_t LoadFile(char * filepath, bool silent)
{
return LoadFile((char *)savebuffer, filepath, 0, silent);
}
/****************************************************************************
* SaveFile
* Write buffer to file
***************************************************************************/
size_t
SaveFile (char * buffer, char *filepath, size_t datasize, bool silent)
{
size_t written = 0;
size_t writesize, nextwrite;
int retry = 1;
int device;
if(!FindDevice(filepath, &device))
return 0;
if(datasize == 0)
return 0;
// stop checking if devices were removed/inserted
// since we're saving a file
HaltDeviceThread();
// halt parsing
HaltParseThread();
ShowAction("Saving...");
while(!written && retry == 1)
{
if(!ChangeInterface(device, silent))
break;
file = fopen (filepath, "wb");
if(!file)
{
if(silent)
break;
retry = ErrorPromptRetry("Error creating file!");
continue;
}
while(written < datasize)
{
if(datasize - written > 4096) nextwrite=4096;
else nextwrite = datasize-written;
writesize = fwrite (buffer+written, 1, nextwrite, file);
if(writesize != nextwrite) break; // write failure
written += writesize;
}
fclose (file);
if(written != datasize) written = 0;
if(!written)
{
unmountRequired[device] = true;
if(silent) break;
retry = ErrorPromptRetry("Error saving file!");
}
}
// go back to checking if devices were inserted/removed
ResumeDeviceThread();
CancelAction();
return written;
}
size_t SaveFile(char * filepath, size_t datasize, bool silent)
{
return SaveFile((char *)savebuffer, filepath, datasize, silent);
}

53
src/wii/fileop.h Normal file
View File

@ -0,0 +1,53 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* crunchy2 May 2007
* Michniewski 2008
* Tantric 2008-2010
*
* fileop.h
*
* File operations
****************************************************************************/
#ifndef _FILEOP_H_
#define _FILEOP_H_
#include <gccore.h>
#include <stdio.h>
#include <string.h>
#include <ogcsys.h>
#include <fat.h>
#include <unistd.h>
#define SAVEBUFFERSIZE (1024 * 512)
void InitDeviceThread();
void ResumeDeviceThread();
void HaltDeviceThread();
void HaltParseThread();
void MountAllFAT();
void UnmountAllFAT();
bool FindDevice(char * filepath, int * device);
char * StripDevice(char * path);
bool ChangeInterface(int device, bool silent);
bool ChangeInterface(char * filepath, bool silent);
void CreateAppPath(char * origpath);
bool GetFileSize(int i);
int ParseDirectory(bool waitParse = false, bool filter = true);
void AllocSaveBuffer();
void FreeSaveBuffer();
size_t LoadFile(char * rbuffer, char *filepath, size_t length, bool silent);
size_t LoadFile(char * filepath, bool silent);
size_t LoadSzFile(char * filepath, unsigned char * rbuffer);
size_t SaveFile(char * buffer, char *filepath, size_t datasize, bool silent);
size_t SaveFile(char * filepath, size_t datasize, bool silent);
extern unsigned char *savebuffer;
extern FILE * file;
extern bool unmountRequired[];
extern bool isMounted[];
extern int selectLoadedFile;
#endif

545
src/wii/filter.cpp Normal file
View File

@ -0,0 +1,545 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* Michniewski 2008
*
* HQ2x, HQ3x, HQ4x filters
* (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
*
* filter.cpp
*
* Adapted from Snes9x Win32/MacOSX ports
* Video Filter Code (hq2x)
****************************************************************************/
#ifdef HW_RVL
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ogcsys.h>
#include <unistd.h>
#include <malloc.h>
#include "filter.h"
#include "video.h"
#include "snes9xgx.h"
#include "menu.h"
#include "snes9x-next/memmap.h"
#define NUMBITS (16)
static int RGBtoYUV[1<<NUMBITS];
static uint16 RGBtoBright[1<<NUMBITS];
TFilterMethod FilterMethod = RenderPlain;
//TFilterMethod FilterMethodHiRes = RenderPlain;
//
// Functions:
//
bool
GetFilterHiResSupport (RenderFilter filterID)
{
switch(filterID)
{
case FILTER_NONE:
return true;
default:
return false;
}
}
const char*
GetFilterName (RenderFilter filterID)
{
switch(filterID)
{
default: return "Unknown";
case FILTER_NONE: return "None";
case FILTER_HQ2X: return "hq2x";
case FILTER_HQ2XS: return "hq2x Soft";
case FILTER_HQ2XBOLD: return "hq2x Bold";
}
}
// Return pointer to appropriate function
TFilterMethod
FilterToMethod (RenderFilter filterID)
{
switch(filterID)
{
default:
case FILTER_NONE: return RenderPlain;
case FILTER_HQ2X: return RenderHQ2X<FILTER_HQ2X>;
case FILTER_HQ2XS: return RenderHQ2X<FILTER_HQ2XS>;
case FILTER_HQ2XBOLD: return RenderHQ2X<FILTER_HQ2XBOLD>;
}
}
int GetFilterScale(RenderFilter filterID)
{
switch(filterID)
{
case FILTER_NONE:
return 1;
default:
case FILTER_HQ2X:
case FILTER_HQ2XS:
case FILTER_HQ2XBOLD:
return 2;
}
}
void
SelectFilterMethod ()
{
//InfoPrompt((char*)"Select Filter Method."); // debug
FilterMethod = FilterToMethod((RenderFilter)GCSettings.FilterMethod);
//FilterMethodHiRes = FilterToMethod((RenderFilter)GCSettings.FilterMethodHiRes);
// check whether or not we need filter memory (alloc or free it)
}
//
// Filter Codes:
//
// No enlargement, just render to the screen
void
RenderPlain (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
if (dstPtr == NULL)
{
ErrorPrompt((char*)"dstPtr is NULL. exiting!");
exit(1);
}
//memcpy (dstPtr, srcPtr, width*height*srcPitch);
return;
}
//
// HQ2X Filter Code:
//
#define Mask_2 0x07E0 // 00000 111111 00000
#define Mask13 0xF81F // 11111 000000 11111
#define Ymask 0xFF0000
#define Umask 0x00FF00
#define Vmask 0x0000FF
#define trY 0x300000
#define trU 0x000700
#define trV 0x000006
#define Interp01(c1, c2) \
((((c1) == (c2)) ? (c1) : \
(((((((c1) & Mask_2) * 3) + ((c2) & Mask_2)) >> 2) & Mask_2) + \
((((((c1) & Mask13) * 3) + ((c2) & Mask13)) >> 2) & Mask13))))
#define Interp02(c1, c2, c3) \
((((((c1) & Mask_2) * 2 + ((c2) & Mask_2) + ((c3) & Mask_2) ) >> 2) & Mask_2) + \
(((((c1) & Mask13) * 2 + ((c2) & Mask13) + ((c3) & Mask13) ) >> 2) & Mask13))
#define Interp06(c1, c2, c3) \
((((((c1) & Mask_2) * 5 + ((c2) & Mask_2) * 2 + ((c3) & Mask_2) ) >> 3) & Mask_2) + \
(((((c1) & Mask13) * 5 + ((c2) & Mask13) * 2 + ((c3) & Mask13) ) >> 3) & Mask13))
#define Interp07(c1, c2, c3) \
((((((c1) & Mask_2) * 6 + ((c2) & Mask_2) + ((c3) & Mask_2) ) >> 3) & Mask_2) + \
(((((c1) & Mask13) * 6 + ((c2) & Mask13) + ((c3) & Mask13) ) >> 3) & Mask13))
#define Interp09(c1, c2, c3) \
((((((c1) & Mask_2) * 2 + ((c2) & Mask_2) * 3 + ((c3) & Mask_2) * 3) >> 3) & Mask_2) + \
(((((c1) & Mask13) * 2 + ((c2) & Mask13) * 3 + ((c3) & Mask13) * 3) >> 3) & Mask13))
#define Interp10(c1, c2, c3) \
((((((c1) & Mask_2) * 14 + ((c2) & Mask_2) + ((c3) & Mask_2) ) >> 4) & Mask_2) + \
(((((c1) & Mask13) * 14 + ((c2) & Mask13) + ((c3) & Mask13) ) >> 4) & Mask13))
#define PIXEL00_0 *(dp) = w5
#define PIXEL00_10 *(dp) = Interp01(w5, w1)
#define PIXEL00_11 *(dp) = Interp01(w5, w4)
#define PIXEL00_12 *(dp) = Interp01(w5, w2)
#define PIXEL00_20 *(dp) = Interp02(w5, w4, w2)
#define PIXEL00_21 *(dp) = Interp02(w5, w1, w2)
#define PIXEL00_22 *(dp) = Interp02(w5, w1, w4)
#define PIXEL00_60 *(dp) = Interp06(w5, w2, w4)
#define PIXEL00_61 *(dp) = Interp06(w5, w4, w2)
#define PIXEL00_70 *(dp) = Interp07(w5, w4, w2)
#define PIXEL00_90 *(dp) = Interp09(w5, w4, w2)
#define PIXEL00_100 *(dp) = Interp10(w5, w4, w2)
#define PIXEL01_0 *(dp + 1) = w5
#define PIXEL01_10 *(dp + 1) = Interp01(w5, w3)
#define PIXEL01_11 *(dp + 1) = Interp01(w5, w2)
#define PIXEL01_12 *(dp + 1) = Interp01(w5, w6)
#define PIXEL01_20 *(dp + 1) = Interp02(w5, w2, w6)
#define PIXEL01_21 *(dp + 1) = Interp02(w5, w3, w6)
#define PIXEL01_22 *(dp + 1) = Interp02(w5, w3, w2)
#define PIXEL01_60 *(dp + 1) = Interp06(w5, w6, w2)
#define PIXEL01_61 *(dp + 1) = Interp06(w5, w2, w6)
#define PIXEL01_70 *(dp + 1) = Interp07(w5, w2, w6)
#define PIXEL01_90 *(dp + 1) = Interp09(w5, w2, w6)
#define PIXEL01_100 *(dp + 1) = Interp10(w5, w2, w6)
#define PIXEL10_0 *(dp + dst1line) = w5
#define PIXEL10_10 *(dp + dst1line) = Interp01(w5, w7)
#define PIXEL10_11 *(dp + dst1line) = Interp01(w5, w8)
#define PIXEL10_12 *(dp + dst1line) = Interp01(w5, w4)
#define PIXEL10_20 *(dp + dst1line) = Interp02(w5, w8, w4)
#define PIXEL10_21 *(dp + dst1line) = Interp02(w5, w7, w4)
#define PIXEL10_22 *(dp + dst1line) = Interp02(w5, w7, w8)
#define PIXEL10_60 *(dp + dst1line) = Interp06(w5, w4, w8)
#define PIXEL10_61 *(dp + dst1line) = Interp06(w5, w8, w4)
#define PIXEL10_70 *(dp + dst1line) = Interp07(w5, w8, w4)
#define PIXEL10_90 *(dp + dst1line) = Interp09(w5, w8, w4)
#define PIXEL10_100 *(dp + dst1line) = Interp10(w5, w8, w4)
#define PIXEL11_0 *(dp + dst1line + 1) = w5
#define PIXEL11_10 *(dp + dst1line + 1) = Interp01(w5, w9)
#define PIXEL11_11 *(dp + dst1line + 1) = Interp01(w5, w6)
#define PIXEL11_12 *(dp + dst1line + 1) = Interp01(w5, w8)
#define PIXEL11_20 *(dp + dst1line + 1) = Interp02(w5, w6, w8)
#define PIXEL11_21 *(dp + dst1line + 1) = Interp02(w5, w9, w8)
#define PIXEL11_22 *(dp + dst1line + 1) = Interp02(w5, w9, w6)
#define PIXEL11_60 *(dp + dst1line + 1) = Interp06(w5, w8, w6)
#define PIXEL11_61 *(dp + dst1line + 1) = Interp06(w5, w6, w8)
#define PIXEL11_70 *(dp + dst1line + 1) = Interp07(w5, w6, w8)
#define PIXEL11_90 *(dp + dst1line + 1) = Interp09(w5, w6, w8)
#define PIXEL11_100 *(dp + dst1line + 1) = Interp10(w5, w6, w8)
#define Absolute(c) \
(!(c & (1 << 31)) ? c : (~c + 1))
static inline bool Diff(int c1, int c2)
{
int c1y = (c1 & Ymask) - (c2 & Ymask);
if (Absolute(c1y) > trY) return true;
int c1u = (c1 & Umask) - (c2 & Umask);
if (Absolute(c1u) > trU) return true;
int c1v = (c1 & Vmask) - (c2 & Vmask);
if (Absolute(c1v) > trV) return true;
return false;
}
void InitLUTs(void)
{
int c, r, g, b, y, u, v;
for (c = 0 ; c < (1<<NUMBITS) ; c++)
{
//#ifdef R5G6B5
b = (int)((c & 0x1F)) << 3;
g = (int)((c & 0x7E0)) >> 3;
r = (int)((c & 0xF800)) >> 8;
//#else
// b = (int)((c & 0x1F)) << 3;
// g = (int)((c & 0x3E0)) >> 2;
// r = (int)((c & 0x7C00)) >> 7;
//#endif
RGBtoBright[c] = r+r+r + g+g+g + b+b;
y = (int)( 0.256788f*r + 0.504129f*g + 0.097906f*b + 0.5f) + 16;
u = (int)(-0.148223f*r - 0.290993f*g + 0.439216f*b + 0.5f) + 128;
v = (int)( 0.439216f*r - 0.367788f*g - 0.071427f*b + 0.5f) + 128;
RGBtoYUV[c] = (y << 16) + (u << 8) + v;
}
}
#define HQ2XCASES \
case 0: case 1: case 4: case 32: case 128: case 5: case 132: case 160: case 33: case 129: case 36: case 133: case 164: case 161: case 37: case 165: PIXEL00_20; PIXEL01_20; PIXEL10_20; PIXEL11_20; break; \
case 2: case 34: case 130: case 162: PIXEL00_22; PIXEL01_21; PIXEL10_20; PIXEL11_20; break; \
case 16: case 17: case 48: case 49: PIXEL00_20; PIXEL01_22; PIXEL10_20; PIXEL11_21; break; \
case 64: case 65: case 68: case 69: PIXEL00_20; PIXEL01_20; PIXEL10_21; PIXEL11_22; break; \
case 8: case 12: case 136: case 140: PIXEL00_21; PIXEL01_20; PIXEL10_22; PIXEL11_20; break; \
case 3: case 35: case 131: case 163: PIXEL00_11; PIXEL01_21; PIXEL10_20; PIXEL11_20; break; \
case 6: case 38: case 134: case 166: PIXEL00_22; PIXEL01_12; PIXEL10_20; PIXEL11_20; break; \
case 20: case 21: case 52: case 53: PIXEL00_20; PIXEL01_11; PIXEL10_20; PIXEL11_21; break; \
case 144: case 145: case 176: case 177: PIXEL00_20; PIXEL01_22; PIXEL10_20; PIXEL11_12; break; \
case 192: case 193: case 196: case 197: PIXEL00_20; PIXEL01_20; PIXEL10_21; PIXEL11_11; break; \
case 96: case 97: case 100: case 101: PIXEL00_20; PIXEL01_20; PIXEL10_12; PIXEL11_22; break; \
case 40: case 44: case 168: case 172: PIXEL00_21; PIXEL01_20; PIXEL10_11; PIXEL11_20; break; \
case 9: case 13: case 137: case 141: PIXEL00_12; PIXEL01_20; PIXEL10_22; PIXEL11_20; break; \
case 18: case 50: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_20; PIXEL10_20; PIXEL11_21; break; \
case 80: case 81: PIXEL00_20; PIXEL01_22; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_20; break; \
case 72: case 76: PIXEL00_21; PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_20; PIXEL11_22; break; \
case 10: case 138: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_20; PIXEL01_21; PIXEL10_22; PIXEL11_20; break; \
case 66: PIXEL00_22; PIXEL01_21; PIXEL10_21; PIXEL11_22; break; \
case 24: PIXEL00_21; PIXEL01_22; PIXEL10_22; PIXEL11_21; break; \
case 7: case 39: case 135: PIXEL00_11; PIXEL01_12; PIXEL10_20; PIXEL11_20; break; \
case 148: case 149: case 180: PIXEL00_20; PIXEL01_11; PIXEL10_20; PIXEL11_12; break; \
case 224: case 228: case 225: PIXEL00_20; PIXEL01_20; PIXEL10_12; PIXEL11_11; break; \
case 41: case 169: case 45: PIXEL00_12; PIXEL01_20; PIXEL10_11; PIXEL11_20; break; \
case 22: case 54: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_20; PIXEL11_21; break; \
case 208: case 209: PIXEL00_20; PIXEL01_22; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 104: case 108: PIXEL00_21; PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_22; break; \
case 11: case 139: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_21; PIXEL10_22; PIXEL11_20; break; \
case 19: case 51: if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL00_11, PIXEL01_10; else PIXEL00_60, PIXEL01_90; PIXEL10_20; PIXEL11_21; break; \
case 146: case 178: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10, PIXEL11_12; else PIXEL01_90, PIXEL11_61; PIXEL10_20; break; \
case 84: case 85: PIXEL00_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL01_11, PIXEL11_10; else PIXEL01_60, PIXEL11_90; PIXEL10_21; break; \
case 112: case 113: PIXEL00_20; PIXEL01_22; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL10_12, PIXEL11_10; else PIXEL10_61, PIXEL11_90; break; \
case 200: case 204: PIXEL00_21; PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10, PIXEL11_11; else PIXEL10_90, PIXEL11_60; break; \
case 73: case 77: if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL00_12, PIXEL10_10; else PIXEL00_61, PIXEL10_90; PIXEL01_20; PIXEL11_22; break; \
case 42: case 170: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10, PIXEL10_11; else PIXEL00_90, PIXEL10_60; PIXEL01_21; PIXEL11_20; break; \
case 14: case 142: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10, PIXEL01_12; else PIXEL00_90, PIXEL01_61; PIXEL10_22; PIXEL11_20; break; \
case 67: PIXEL00_11; PIXEL01_21; PIXEL10_21; PIXEL11_22; break; \
case 70: PIXEL00_22; PIXEL01_12; PIXEL10_21; PIXEL11_22; break; \
case 28: PIXEL00_21; PIXEL01_11; PIXEL10_22; PIXEL11_21; break; \
case 152: PIXEL00_21; PIXEL01_22; PIXEL10_22; PIXEL11_12; break; \
case 194: PIXEL00_22; PIXEL01_21; PIXEL10_21; PIXEL11_11; break; \
case 98: PIXEL00_22; PIXEL01_21; PIXEL10_12; PIXEL11_22; break; \
case 56: PIXEL00_21; PIXEL01_22; PIXEL10_11; PIXEL11_21; break; \
case 25: PIXEL00_12; PIXEL01_22; PIXEL10_22; PIXEL11_21; break; \
case 26: case 31: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_22; PIXEL11_21; break; \
case 82: case 214: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 88: case 248: PIXEL00_21; PIXEL01_22; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 74: case 107: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_21; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_22; break; \
case 27: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_10; PIXEL10_22; PIXEL11_21; break; \
case 86: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_21; PIXEL11_10; break; \
case 216: PIXEL00_21; PIXEL01_22; PIXEL10_10; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 106: PIXEL00_10; PIXEL01_21; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_22; break; \
case 30: PIXEL00_10; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_22; PIXEL11_21; break; \
case 210: PIXEL00_22; PIXEL01_10; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 120: PIXEL00_21; PIXEL01_22; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_10; break; \
case 75: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_21; PIXEL10_10; PIXEL11_22; break; \
case 29: PIXEL00_12; PIXEL01_11; PIXEL10_22; PIXEL11_21; break; \
case 198: PIXEL00_22; PIXEL01_12; PIXEL10_21; PIXEL11_11; break; \
case 184: PIXEL00_21; PIXEL01_22; PIXEL10_11; PIXEL11_12; break; \
case 99: PIXEL00_11; PIXEL01_21; PIXEL10_12; PIXEL11_22; break; \
case 57: PIXEL00_12; PIXEL01_22; PIXEL10_11; PIXEL11_21; break; \
case 71: PIXEL00_11; PIXEL01_12; PIXEL10_21; PIXEL11_22; break; \
case 156: PIXEL00_21; PIXEL01_11; PIXEL10_22; PIXEL11_12; break; \
case 226: PIXEL00_22; PIXEL01_21; PIXEL10_12; PIXEL11_11; break; \
case 60: PIXEL00_21; PIXEL01_11; PIXEL10_11; PIXEL11_21; break; \
case 195: PIXEL00_11; PIXEL01_21; PIXEL10_21; PIXEL11_11; break; \
case 102: PIXEL00_22; PIXEL01_12; PIXEL10_12; PIXEL11_22; break; \
case 153: PIXEL00_12; PIXEL01_22; PIXEL10_22; PIXEL11_12; break; \
case 58: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_11; PIXEL11_21; break; \
case 83: PIXEL00_11; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 92: PIXEL00_21; PIXEL01_11; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 202: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; PIXEL01_21; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; PIXEL11_11; break; \
case 78: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; PIXEL01_12; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; PIXEL11_22; break; \
case 154: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_22; PIXEL11_12; break; \
case 114: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 89: PIXEL00_12; PIXEL01_22; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 90: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 55: case 23: if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL00_11, PIXEL01_0; else PIXEL00_60, PIXEL01_90; PIXEL10_20; PIXEL11_21; break; \
case 182: case 150: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0, PIXEL11_12; else PIXEL01_90, PIXEL11_61; PIXEL10_20; break; \
case 213: case 212: PIXEL00_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL01_11, PIXEL11_0; else PIXEL01_60, PIXEL11_90; PIXEL10_21; break; \
case 241: case 240: PIXEL00_20; PIXEL01_22; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL10_12, PIXEL11_0; else PIXEL10_61, PIXEL11_90; break; \
case 236: case 232: PIXEL00_21; PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0, PIXEL11_11; else PIXEL10_90, PIXEL11_60; break; \
case 109: case 105: if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL00_12, PIXEL10_0; else PIXEL00_61, PIXEL10_90; PIXEL01_20; PIXEL11_22; break; \
case 171: case 43: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0, PIXEL10_11; else PIXEL00_90, PIXEL10_60; PIXEL01_21; PIXEL11_20; break; \
case 143: case 15: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0, PIXEL01_12; else PIXEL00_90, PIXEL01_61; PIXEL10_22; PIXEL11_20; break; \
case 124: PIXEL00_21; PIXEL01_11; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_10; break; \
case 203: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_21; PIXEL10_10; PIXEL11_11; break; \
case 62: PIXEL00_10; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_11; PIXEL11_21; break; \
case 211: PIXEL00_11; PIXEL01_10; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 118: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_12; PIXEL11_10; break; \
case 217: PIXEL00_12; PIXEL01_22; PIXEL10_10; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 110: PIXEL00_10; PIXEL01_12; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_22; break; \
case 155: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_10; PIXEL10_22; PIXEL11_12; break; \
case 188: PIXEL00_21; PIXEL01_11; PIXEL10_11; PIXEL11_12; break; \
case 185: PIXEL00_12; PIXEL01_22; PIXEL10_11; PIXEL11_12; break; \
case 61: PIXEL00_12; PIXEL01_11; PIXEL10_11; PIXEL11_21; break; \
case 157: PIXEL00_12; PIXEL01_11; PIXEL10_22; PIXEL11_12; break; \
case 103: PIXEL00_11; PIXEL01_12; PIXEL10_12; PIXEL11_22; break; \
case 227: PIXEL00_11; PIXEL01_21; PIXEL10_12; PIXEL11_11; break; \
case 230: PIXEL00_22; PIXEL01_12; PIXEL10_12; PIXEL11_11; break; \
case 199: PIXEL00_11; PIXEL01_12; PIXEL10_21; PIXEL11_11; break; \
case 220: PIXEL00_21; PIXEL01_11; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 158: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_22; PIXEL11_12; break; \
case 234: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; PIXEL01_21; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_11; break; \
case 242: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 59: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_11; PIXEL11_21; break; \
case 121: PIXEL00_12; PIXEL01_22; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 87: PIXEL00_11; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 79: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_12; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; PIXEL11_22; break; \
case 122: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 94: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 218: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 91: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 229: PIXEL00_20; PIXEL01_20; PIXEL10_12; PIXEL11_11; break; \
case 167: PIXEL00_11; PIXEL01_12; PIXEL10_20; PIXEL11_20; break; \
case 173: PIXEL00_12; PIXEL01_20; PIXEL10_11; PIXEL11_20; break; \
case 181: PIXEL00_20; PIXEL01_11; PIXEL10_20; PIXEL11_12; break; \
case 186: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_11; PIXEL11_12; break; \
case 115: PIXEL00_11; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 93: PIXEL00_12; PIXEL01_11; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 206: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; PIXEL01_12; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; PIXEL11_11; break; \
case 205: case 201: PIXEL00_12; PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_10; else PIXEL10_70; PIXEL11_11; break; \
case 174: case 46: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_10; else PIXEL00_70; PIXEL01_12; PIXEL10_11; PIXEL11_20; break; \
case 179: case 147: PIXEL00_11; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_10; else PIXEL01_70; PIXEL10_20; PIXEL11_12; break; \
case 117: case 116: PIXEL00_20; PIXEL01_11; PIXEL10_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_10; else PIXEL11_70; break; \
case 189: PIXEL00_12; PIXEL01_11; PIXEL10_11; PIXEL11_12; break; \
case 231: PIXEL00_11; PIXEL01_12; PIXEL10_12; PIXEL11_11; break; \
case 126: PIXEL00_10; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_10; break; \
case 219: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_10; PIXEL10_10; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 125: if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL00_12, PIXEL10_0; else PIXEL00_61, PIXEL10_90; PIXEL01_11; PIXEL11_10; break; \
case 221: PIXEL00_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL01_11, PIXEL11_0; else PIXEL01_60, PIXEL11_90; PIXEL10_10; break; \
case 207: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0, PIXEL01_12; else PIXEL00_90, PIXEL01_61; PIXEL10_10; PIXEL11_11; break; \
case 238: PIXEL00_10; PIXEL01_12; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0, PIXEL11_11; else PIXEL10_90, PIXEL11_60; break; \
case 190: PIXEL00_10; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0, PIXEL11_12; else PIXEL01_90, PIXEL11_61; PIXEL10_11; break; \
case 187: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0, PIXEL10_11; else PIXEL00_90, PIXEL10_60; PIXEL01_10; PIXEL11_12; break; \
case 243: PIXEL00_11; PIXEL01_10; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL10_12, PIXEL11_0; else PIXEL10_61, PIXEL11_90; break; \
case 119: if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL00_11, PIXEL01_0; else PIXEL00_60, PIXEL01_90; PIXEL10_12; PIXEL11_10; break; \
case 237: case 233: PIXEL00_12; PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_100; PIXEL11_11; break; \
case 175: case 47: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_100; PIXEL01_12; PIXEL10_11; PIXEL11_20; break; \
case 183: case 151: PIXEL00_11; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_100; PIXEL10_20; PIXEL11_12; break; \
case 245: case 244: PIXEL00_20; PIXEL01_11; PIXEL10_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_100; break; \
case 250: PIXEL00_10; PIXEL01_10; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 123: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_10; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_10; break; \
case 95: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_10; PIXEL11_10; break; \
case 222: PIXEL00_10; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_10; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 252: PIXEL00_21; PIXEL01_11; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_100; break; \
case 249: PIXEL00_12; PIXEL01_22; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_100; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 235: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_21; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_100; PIXEL11_11; break; \
case 111: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_100; PIXEL01_12; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_22; break; \
case 63: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_100; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_11; PIXEL11_21; break; \
case 159: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_100; PIXEL10_22; PIXEL11_12; break; \
case 215: PIXEL00_11; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_100; PIXEL10_21; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 246: PIXEL00_22; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; PIXEL10_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_100; break; \
case 254: PIXEL00_10; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_100; break; \
case 253: PIXEL00_12; PIXEL01_11; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_100; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_100; break; \
case 251: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; PIXEL01_10; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_100; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 239: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_100; PIXEL01_12; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_100; PIXEL11_11; break; \
case 127: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_100; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_20; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_20; PIXEL11_10; break; \
case 191: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_100; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_100; PIXEL10_11; PIXEL11_12; break; \
case 223: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_20; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_100; PIXEL10_10; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_20; break; \
case 247: PIXEL00_11; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_100; PIXEL10_12; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_100; break; \
case 255: if (Diff(RGBtoYUVtable[w4], RGBtoYUVtable[w2])) PIXEL00_0; else PIXEL00_100; if (Diff(RGBtoYUVtable[w2], RGBtoYUVtable[w6])) PIXEL01_0; else PIXEL01_100; if (Diff(RGBtoYUVtable[w8], RGBtoYUVtable[w4])) PIXEL10_0; else PIXEL10_100; if (Diff(RGBtoYUVtable[w6], RGBtoYUVtable[w8])) PIXEL11_0; else PIXEL11_100; break;
template<int GuiScale>
void RenderHQ2X (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
// If Snes9x is rendering anything in HiRes, then just copy, don't interpolate
if (height > SNES_HEIGHT_EXTENDED || width == 512)
{
//RenderSimple2X (Src, Dst, rect);
return;
}
int w1, w2, w3, w4, w5, w6, w7, w8, w9;
uint32 src1line = srcPitch >> 1;
uint32 dst1line = dstPitch >> 1;
uint16 *sp = (uint16 *) srcPtr;
uint16 *dp = (uint16 *) dstPtr;
const int* RGBtoYUVtable = RGBtoYUV;
uint32 pattern;
int l, y;
while (height--)
{
sp--;
w1 = *(sp - src1line);
w4 = *(sp);
w7 = *(sp + src1line);
sp++;
w2 = *(sp - src1line);
w5 = *(sp);
w8 = *(sp + src1line);
for (l = width; l; l--)
{
sp++;
w3 = *(sp - src1line);
w6 = *(sp);
w9 = *(sp + src1line);
pattern = 0;
switch(GuiScale)
{
case FILTER_HQ2XBOLD: {
const uint16 avg = (RGBtoBright[w1] + RGBtoBright[w2] + RGBtoBright[w3] + RGBtoBright[w4] + RGBtoBright[w5] + RGBtoBright[w6] + RGBtoBright[w7] + RGBtoBright[w8] + RGBtoBright[w9]) / 9;
const bool diff5 = RGBtoBright[w5] > avg;
if ((w1 != w5) && ((RGBtoBright[w1] > avg) != diff5)) pattern |= (1 << 0);
if ((w2 != w5) && ((RGBtoBright[w2] > avg) != diff5)) pattern |= (1 << 1);
if ((w3 != w5) && ((RGBtoBright[w3] > avg) != diff5)) pattern |= (1 << 2);
if ((w4 != w5) && ((RGBtoBright[w4] > avg) != diff5)) pattern |= (1 << 3);
if ((w6 != w5) && ((RGBtoBright[w6] > avg) != diff5)) pattern |= (1 << 4);
if ((w7 != w5) && ((RGBtoBright[w7] > avg) != diff5)) pattern |= (1 << 5);
if ((w8 != w5) && ((RGBtoBright[w8] > avg) != diff5)) pattern |= (1 << 6);
if ((w9 != w5) && ((RGBtoBright[w9] > avg) != diff5)) pattern |= (1 << 7);
} break;
case FILTER_HQ2XS: {
bool nosame = true;
if(w1 == w5 || w3 == w5 || w7 == w5 || w9 == w5)
nosame = false;
if(nosame)
{
const uint16 avg = (RGBtoBright[w1] + RGBtoBright[w2] + RGBtoBright[w3] + RGBtoBright[w4] + RGBtoBright[w5] + RGBtoBright[w6] + RGBtoBright[w7] + RGBtoBright[w8] + RGBtoBright[w9]) / 9;
const bool diff5 = RGBtoBright[w5] > avg;
if((RGBtoBright[w1] > avg) != diff5) pattern |= (1 << 0);
if((RGBtoBright[w2] > avg) != diff5) pattern |= (1 << 1);
if((RGBtoBright[w3] > avg) != diff5) pattern |= (1 << 2);
if((RGBtoBright[w4] > avg) != diff5) pattern |= (1 << 3);
if((RGBtoBright[w6] > avg) != diff5) pattern |= (1 << 4);
if((RGBtoBright[w7] > avg) != diff5) pattern |= (1 << 5);
if((RGBtoBright[w8] > avg) != diff5) pattern |= (1 << 6);
if((RGBtoBright[w9] > avg) != diff5) pattern |= (1 << 7);
}
else
{
y = RGBtoYUV[w5];
if ((w1 != w5) && (Diff(y, RGBtoYUV[w1]))) pattern |= (1 << 0);
if ((w2 != w5) && (Diff(y, RGBtoYUV[w2]))) pattern |= (1 << 1);
if ((w3 != w5) && (Diff(y, RGBtoYUV[w3]))) pattern |= (1 << 2);
if ((w4 != w5) && (Diff(y, RGBtoYUV[w4]))) pattern |= (1 << 3);
if ((w6 != w5) && (Diff(y, RGBtoYUV[w6]))) pattern |= (1 << 4);
if ((w7 != w5) && (Diff(y, RGBtoYUV[w7]))) pattern |= (1 << 5);
if ((w8 != w5) && (Diff(y, RGBtoYUV[w8]))) pattern |= (1 << 6);
if ((w9 != w5) && (Diff(y, RGBtoYUV[w9]))) pattern |= (1 << 7);
}
} break;
default:
case FILTER_HQ2X:
y = RGBtoYUVtable[w5];
if ((w1 != w5) && (Diff(y, RGBtoYUVtable[w1]))) pattern |= (1 << 0);
if ((w2 != w5) && (Diff(y, RGBtoYUVtable[w2]))) pattern |= (1 << 1);
if ((w3 != w5) && (Diff(y, RGBtoYUVtable[w3]))) pattern |= (1 << 2);
if ((w4 != w5) && (Diff(y, RGBtoYUVtable[w4]))) pattern |= (1 << 3);
if ((w6 != w5) && (Diff(y, RGBtoYUVtable[w6]))) pattern |= (1 << 4);
if ((w7 != w5) && (Diff(y, RGBtoYUVtable[w7]))) pattern |= (1 << 5);
if ((w8 != w5) && (Diff(y, RGBtoYUVtable[w8]))) pattern |= (1 << 6);
if ((w9 != w5) && (Diff(y, RGBtoYUVtable[w9]))) pattern |= (1 << 7);
break;
}
switch (pattern)
{
HQ2XCASES
}
w1 = w2; w4 = w5; w7 = w8;
w2 = w3; w5 = w6; w8 = w9;
dp += 2;
}
dp += ((dst1line - width) << 1);
sp += (src1line - width);
}
}
#endif

62
src/wii/filter.h Normal file
View File

@ -0,0 +1,62 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* Michniewski 2008
*
* filter.h
*
* Filters Header File
****************************************************************************/
#ifndef _FILTER_H_
#define _FILTER_H_
#include <gccore.h>
#include <ogcsys.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "snes9x-next/snes9x.h"
enum RenderFilter{
FILTER_NONE = 0,
FILTER_HQ2X,
FILTER_HQ2XS,
FILTER_HQ2XBOLD,
NUM_FILTERS
};
#define EXT_WIDTH (MAX_SNES_WIDTH + 4)
#define EXT_PITCH (EXT_WIDTH * 2)
#define EXT_HEIGHT (MAX_SNES_HEIGHT + 4)
// Offset into buffer to allow a two pixel border around the whole rendered
// SNES image. This is a speed up hack to allow some of the image processing
// routines to access black pixel data outside the normal bounds of the buffer.
#define EXT_OFFSET (EXT_PITCH * 2 + 2 * 2)
typedef void (*TFilterMethod)(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
extern TFilterMethod FilterMethod;
extern TFilterMethod FilterMethodHiRes;
extern unsigned char * filtermem;
//
// Prototypes
//
void SelectFilterMethod ();
void RenderPlain (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
void SelectFilterMethod ();
TFilterMethod FilterToMethod (RenderFilter filterID);
const char* GetFilterName (RenderFilter filterID);
bool GetFilterHiResSupport (RenderFilter filterID);
int GetFilterScale(RenderFilter filterID);
template<int GuiScale> void RenderHQ2X (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
void InitLUTs();
#endif

BIN
src/wii/fonts/font.ttf Normal file

Binary file not shown.

141
src/wii/freeze.cpp Normal file
View File

@ -0,0 +1,141 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* crunchy2 May 2007-July 2007
* Michniewski 2008
* Tantric 2008-2010
*
* freeze.cpp
***************************************************************************/
#include <malloc.h>
#include <gccore.h>
#include <stdio.h>
#include "snes9xgx.h"
#include "fileop.h"
#include "filebrowser.h"
#include "menu.h"
#include "video.h"
#include "utils/pngu.h"
#include "snes9x-next/snes9x.h"
#include "snes9x-next/port.h"
#include "snes9x-next/memmap.h"
#include "snes9x-next/snapshot.h"
#include "snes9x-next/language.h"
bool8 S9xOpenSnapshotFile(const char *filepath, bool8 readonly, STREAM *file)
{
return FALSE;
}
void S9xCloseSnapshotFile(STREAM s)
{
}
/****************************************************************************
* SaveSnapshot
***************************************************************************/
int
SaveSnapshot (char * filepath, bool silent)
{
int device;
if(!FindDevice(filepath, &device))
return 0;
// save screenshot
if(gameScreenPngSize > 0)
{
char screenpath[1024];
strcpy(screenpath, filepath);
screenpath[strlen(screenpath)-4] = 0;
sprintf(screenpath, "%s.png", screenpath);
SaveFile((char *)gameScreenPng, screenpath, gameScreenPngSize, silent);
}
STREAM fp = OPEN_STREAM(filepath, "wb");
if(!fp)
{
if(!silent)
ErrorPrompt("Save failed!");
return 0;
}
S9xFreezeToStream(fp);
CLOSE_STREAM(fp);
if(!silent)
InfoPrompt("Save successful");
return 1;
}
int
SaveSnapshotAuto (bool silent)
{
char filepath[1024];
if(!MakeFilePath(filepath, FILE_SNAPSHOT, Memory.ROMFilename, 0))
return false;
return SaveSnapshot(filepath, silent);
}
/****************************************************************************
* LoadSnapshot
***************************************************************************/
int
LoadSnapshot (char * filepath, bool silent)
{
int device;
if(!FindDevice(filepath, &device))
return 0;
STREAM fp = OPEN_STREAM(filepath, "rb");
if(!fp)
{
if(!silent)
ErrorPrompt("Unable to open snapshot!");
return 0;
}
int result = S9xUnfreezeFromStream(fp);
CLOSE_STREAM(fp);
if (result == SUCCESS)
return 1;
switch (result)
{
case WRONG_FORMAT:
ErrorPrompt(SAVE_ERR_WRONG_FORMAT);
break;
case WRONG_VERSION:
ErrorPrompt(SAVE_ERR_WRONG_VERSION);
break;
case SNAPSHOT_INCONSISTENT:
ErrorPrompt(MOVIE_ERR_SNAPSHOT_INCONSISTENT);
break;
}
return 0;
}
int
LoadSnapshotAuto (bool silent)
{
char filepath[1024];
if(!MakeFilePath(filepath, FILE_SNAPSHOT, Memory.ROMFilename, 0))
return false;
return LoadSnapshot(filepath, silent);
}

20
src/wii/freeze.h Normal file
View File

@ -0,0 +1,20 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* crunchy2 May 2007-July 2007
* Michniewski 2008
* Tantric 2008-2010
*
* freeze.h
***************************************************************************/
#ifndef _FREEZE_H_
#define _FREEZE_H_
int SaveSnapshot (char * filepath, bool silent);
int SaveSnapshotAuto (bool silent);
int LoadSnapshot (char * filepath, bool silent);
int LoadSnapshotAuto (bool silent);
#endif

520
src/wii/gcunzip.cpp Normal file
View File

@ -0,0 +1,520 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* Michniewski 2008
* Tantric 2008-2010
*
* gcunzip.cpp
*
* File unzip routines
***************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include "snes9xgx.h"
#include "fileop.h"
#include "filebrowser.h"
#include "menu.h"
#include "gcunzip.h"
extern "C" {
#include "utils/sz/7zCrc.h"
#include "utils/sz/7zIn.h"
#include "utils/sz/7zExtract.h"
}
#define ZIPCHUNK 2048
/*
* Zip file header definition
*/
typedef struct
{
unsigned int zipid __attribute__ ((__packed__)); // 0x04034b50
unsigned short zipversion __attribute__ ((__packed__));
unsigned short zipflags __attribute__ ((__packed__));
unsigned short compressionMethod __attribute__ ((__packed__));
unsigned short lastmodtime __attribute__ ((__packed__));
unsigned short lastmoddate __attribute__ ((__packed__));
unsigned int crc32 __attribute__ ((__packed__));
unsigned int compressedSize __attribute__ ((__packed__));
unsigned int uncompressedSize __attribute__ ((__packed__));
unsigned short filenameLength __attribute__ ((__packed__));
unsigned short extraDataLength __attribute__ ((__packed__));
}
PKZIPHEADER;
/*
* Zip files are stored little endian
* Support functions for short and int types
*/
static u32
FLIP32 (u32 b)
{
unsigned int c;
c = (b & 0xff000000) >> 24;
c |= (b & 0xff0000) >> 8;
c |= (b & 0xff00) << 8;
c |= (b & 0xff) << 24;
return c;
}
static u16
FLIP16 (u16 b)
{
u16 c;
c = (b & 0xff00) >> 8;
c |= (b & 0xff) << 8;
return c;
}
/****************************************************************************
* IsZipFile
*
* Returns TRUE when 0x504b0304 is first four characters of buffer
***************************************************************************/
int
IsZipFile (char *buffer)
{
unsigned int *check = (unsigned int *) buffer;
if (check[0] == 0x504b0304)
return 1;
return 0;
}
/*****************************************************************************
* UnZipBuffer
******************************************************************************/
size_t
UnZipBuffer (unsigned char *outbuffer)
{
PKZIPHEADER pkzip;
size_t zipoffset = 0;
size_t zipchunk = 0;
char out[ZIPCHUNK];
z_stream zs;
int res;
size_t bufferoffset = 0;
size_t have = 0;
char readbuffer[ZIPCHUNK];
size_t sizeread = 0;
// Read Zip Header
fseek(file, 0, SEEK_SET);
sizeread = fread (readbuffer, 1, ZIPCHUNK, file);
if(sizeread <= 0)
return 0;
/*** Copy PKZip header to local, used as info ***/
memcpy (&pkzip, readbuffer, sizeof (PKZIPHEADER));
pkzip.uncompressedSize = FLIP32 (pkzip.uncompressedSize);
ShowProgress ("Loading...", 0, pkzip.uncompressedSize);
/*** Prepare the zip stream ***/
memset (&zs, 0, sizeof (z_stream));
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.avail_in = 0;
zs.next_in = Z_NULL;
res = inflateInit2 (&zs, -MAX_WBITS);
if (res != Z_OK)
goto done;
/*** Set ZipChunk for first pass ***/
zipoffset =
(sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) +
FLIP16 (pkzip.extraDataLength));
zipchunk = ZIPCHUNK - zipoffset;
/*** Now do it! ***/
do
{
zs.avail_in = zipchunk;
zs.next_in = (Bytef *) & readbuffer[zipoffset];
/*** Now inflate until input buffer is exhausted ***/
do
{
zs.avail_out = ZIPCHUNK;
zs.next_out = (Bytef *) & out;
res = inflate (&zs, Z_NO_FLUSH);
if (res == Z_MEM_ERROR)
{
goto done;
}
have = ZIPCHUNK - zs.avail_out;
if (have)
{
/*** Copy to normal block buffer ***/
memcpy (&outbuffer[bufferoffset], &out, have);
bufferoffset += have;
}
}
while (zs.avail_out == 0);
// Readup the next 2k block
zipoffset = 0;
zipchunk = ZIPCHUNK;
sizeread = fread (readbuffer, 1, ZIPCHUNK, file);
if(sizeread <= 0)
goto done; // read failure
ShowProgress ("Loading...", bufferoffset, pkzip.uncompressedSize);
}
while (res != Z_STREAM_END);
done:
inflateEnd (&zs);
CancelAction();
if (res == Z_STREAM_END)
return pkzip.uncompressedSize;
else
return 0;
}
/****************************************************************************
* GetFirstZipFilename
*
* Returns the filename of the first file in the zipped archive
* The idea here is to do the least amount of work required
***************************************************************************/
char *
GetFirstZipFilename ()
{
char * firstFilename = NULL;
char tempbuffer[ZIPCHUNK];
char filepath[1024];
if(!MakeFilePath(filepath, FILE_ROM))
return NULL;
// read start of ZIP
if(LoadFile (tempbuffer, filepath, ZIPCHUNK, NOTSILENT) < 35)
return NULL;
tempbuffer[28] = 0; // truncate - filename length is 2 bytes long (bytes 26-27)
int namelength = tempbuffer[26]; // filename length starts 26 bytes in
if(namelength < 0 || namelength > 200) // filename is not a reasonable length
{
ErrorPrompt("Error - Invalid ZIP file!");
return NULL;
}
firstFilename = &tempbuffer[30]; // first filename of a ZIP starts 31 bytes in
firstFilename[namelength] = 0; // truncate at filename length
return strdup(firstFilename);
}
/****************************************************************************
* 7z functions
***************************************************************************/
typedef struct _SzFileInStream
{
ISzInStream InStream;
u64 offset; // offset of the file
unsigned int len; // length of the file
u64 pos; // current position of the file pointer
} SzFileInStream;
// 7zip error list
static char szerrormsg[][100] = {
"File is corrupt.", // 7z: Data error
"Archive contains too many files.", // 7z: Out of memory
"File is corrupt (CRC mismatch).", // 7z: CRC Error
"File uses unsupported compression settings.", // 7z: Not implemented
"File is corrupt.", // 7z: Fail
"Failed to read file data.", // 7z: Data read failure
"File is corrupt.", // 7z: Archive error
"File uses too high of compression settings (dictionary size is too large).", // 7z: Dictionary too large
};
static SZ_RESULT SzRes;
static SzFileInStream SzArchiveStream;
static CArchiveDatabaseEx SzDb;
static ISzAlloc SzAllocImp;
static ISzAlloc SzAllocTempImp;
static UInt32 SzBlockIndex = 0xFFFFFFFF;
static size_t SzBufferSize;
static size_t SzOffset;
static size_t SzOutSizeProcessed;
static CFileItem *SzF;
static char sz_buffer[2048];
static int szMethod = 0;
/****************************************************************************
* Is7ZipFile
*
* Returns 1 when 7z signature is found
****************************************************************************/
int
Is7ZipFile (char *buffer)
{
// 7z signature
static Byte Signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
int i;
for(i = 0; i < 6; i++)
if(buffer[i] != Signature[i])
return 0;
return 1; // 7z archive found
}
// display an error message
static void SzDisplayError(SZ_RESULT res)
{
char msg[1024];
sprintf(msg, "7z decompression failed: %s", szerrormsg[(res - 1)]);
ErrorPrompt(msg);
}
// function used by the 7zip SDK to read data from SD/USB/DVD/SMB
static SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
{
size_t sizeread = 0;
if(maxRequiredSize == 0)
return SZ_OK;
// the void* object is a SzFileInStream
SzFileInStream *s = (SzFileInStream *) object;
if (maxRequiredSize > 2048)
maxRequiredSize = 2048;
// read data
sizeread = fread(sz_buffer, 1, maxRequiredSize, file);
if(sizeread <= 0)
return SZE_FAILREAD;
*buffer = sz_buffer;
*processedSize = sizeread;
s->pos += sizeread;
if(sizeread > 1024) // only show progress for large reads
// this isn't quite right, but oh well
ShowProgress ("Loading...", s->pos, browserList[browser.selIndex].length);
return SZ_OK;
}
// function used by the 7zip SDK to change the filepointer
static SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
{
// the void* object is a SzFileInStream
SzFileInStream *s = (SzFileInStream *) object;
// check if the 7z SDK wants to move the pointer to somewhere after the EOF
if (pos >= s->len)
return SZE_FAIL;
// save new position and return
if(fseek(file, (long)pos, SEEK_SET) != 0)
return SZE_FAIL;
s->pos = pos;
return SZ_OK;
}
/****************************************************************************
* SzClose
*
* Closes a 7z file
***************************************************************************/
void SzClose()
{
if(SzDb.Database.NumFiles > 0)
SzArDbExFree(&SzDb, SzAllocImp.Free);
}
/****************************************************************************
* SzParse
*
* Opens a 7z file, and parses it
* It parses the entire 7z for full browsing capability
***************************************************************************/
int SzParse(char * filepath)
{
if(!filepath)
return 0;
int device;
if(!FindDevice(browser.dir, &device) || !GetFileSize(browser.selIndex))
return 0;
int nbfiles = 0;
// save the length/offset of this file
unsigned int filelen = browserList[browser.selIndex].length;
// setup archive stream
SzArchiveStream.offset = 0;
SzArchiveStream.len = filelen;
SzArchiveStream.pos = 0;
// open file
file = fopen (filepath, "rb");
if(!file)
return 0;
// set szMethod to current chosen load device
szMethod = device;
// set handler functions for reading data from SD/USB/SMB/DVD
SzArchiveStream.InStream.Read = SzFileReadImp;
SzArchiveStream.InStream.Seek = SzFileSeekImp;
// set default 7Zip SDK handlers for allocation and freeing memory
SzAllocImp.Alloc = SzAlloc;
SzAllocImp.Free = SzFree;
SzAllocTempImp.Alloc = SzAllocTemp;
SzAllocTempImp.Free = SzFreeTemp;
// prepare CRC and 7Zip database structures
InitCrcTable();
SzArDbExInit(&SzDb);
// open the archive
SzRes = SzArchiveOpen(&SzArchiveStream.InStream, &SzDb, &SzAllocImp,
&SzAllocTempImp);
if (SzRes != SZ_OK)
{
SzDisplayError(SzRes);
// free memory used by the 7z SDK
SzClose();
}
else // archive opened successfully
{
if(SzDb.Database.NumFiles > 0)
{
// Parses the 7z into a full file listing
HaltParseThread(); // halt parsing
ResetBrowser(); // reset browser
// add '..' folder in case the user wants exit the 7z
AddBrowserEntry();
sprintf(browserList[0].displayname, "Up One Level");
browserList[0].isdir = 1;
browserList[0].length = filelen;
browserList[0].icon = ICON_FOLDER;
// get contents and parse them into file list structure
unsigned int SzI, SzJ;
SzJ = 1;
for (SzI = 0; SzI < SzDb.Database.NumFiles; SzI++)
{
SzF = SzDb.Database.Files + SzI;
// skip directories
if (SzF->IsDirectory)
continue;
if(!AddBrowserEntry())
{
ResetBrowser();
ErrorPrompt("Out of memory: too many files!");
SzClose();
SzJ = 0;
break;
}
// parse information about this file to the file list structure
snprintf(browserList[SzJ].filename, MAXJOLIET, "%s", SzF->Name);
StripExt(browserList[SzJ].displayname, browserList[SzJ].filename);
browserList[SzJ].length = SzF->Size; // filesize
browserList[SzJ].isdir = 0; // only files will be displayed (-> no flags)
browserList[SzJ].filenum = SzI; // the extraction function identifies the file with this number
SzJ++;
}
nbfiles = SzJ;
}
else
{
SzClose();
}
}
CancelAction();
// close file
fclose(file);
return nbfiles;
}
/****************************************************************************
* SzExtractFile
*
* Extracts the given file # into the buffer specified
* Must parse the 7z BEFORE running this function
***************************************************************************/
size_t SzExtractFile(int i, unsigned char *buffer)
{
// prepare some variables
SzBlockIndex = 0xFFFFFFFF;
SzOffset = 0;
// Unzip the file
SzRes = SzExtract2(
&SzArchiveStream.InStream,
&SzDb,
i, // index of file
&SzBlockIndex, // index of solid block
&buffer,
&SzBufferSize,
&SzOffset, // offset of stream for required file in *outBuffer
&SzOutSizeProcessed, // size of file in *outBuffer
&SzAllocImp,
&SzAllocTempImp);
// close 7Zip archive and free memory
SzClose();
CancelAction();
// check for errors
if(SzRes != SZ_OK)
{
// display error message
SzDisplayError(SzRes);
return 0;
}
else
{
return SzOutSizeProcessed;
}
}

22
src/wii/gcunzip.h Normal file
View File

@ -0,0 +1,22 @@
/****************************************************************************
* Snes9x Nintendo Wii/Gamecube Port
*
* softdev July 2006
* Michniewski 2008
* Tantric 2008-2010
*
* gcunzip.h
*
* File unzip routines
****************************************************************************/
#ifndef _GCUNZIP_H_
#define _GCUNZIP_H_
int IsZipFile (char *buffer);
char * GetFirstZipFilename();
size_t UnZipBuffer (unsigned char *outbuffer);
int SzParse(char * filepath);
size_t SzExtractFile(int i, unsigned char *buffer);
void SzClose();
#endif

1053
src/wii/gui/gui.h Normal file

File diff suppressed because it is too large Load Diff

357
src/wii/gui/gui_button.cpp Normal file
View File

@ -0,0 +1,357 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_button.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
/**
* Constructor for the GuiButton class.
*/
GuiButton::GuiButton(int w, int h)
{
width = w;
height = h;
image = NULL;
imageOver = NULL;
imageHold = NULL;
imageClick = NULL;
icon = NULL;
iconOver = NULL;
iconHold = NULL;
iconClick = NULL;
for(int i=0; i < 3; i++)
{
label[i] = NULL;
labelOver[i] = NULL;
labelHold[i] = NULL;
labelClick[i] = NULL;
}
soundOver = NULL;
soundHold = NULL;
soundClick = NULL;
tooltip = NULL;
selectable = true;
holdable = false;
clickable = true;
}
/**
* Destructor for the GuiButton class.
*/
GuiButton::~GuiButton()
{
}
void GuiButton::SetImage(GuiImage* img)
{
image = img;
if(img) img->SetParent(this);
}
void GuiButton::SetImageOver(GuiImage* img)
{
imageOver = img;
if(img) img->SetParent(this);
}
void GuiButton::SetImageHold(GuiImage* img)
{
imageHold = img;
if(img) img->SetParent(this);
}
void GuiButton::SetImageClick(GuiImage* img)
{
imageClick = img;
if(img) img->SetParent(this);
}
void GuiButton::SetIcon(GuiImage* img)
{
icon = img;
if(img) img->SetParent(this);
}
void GuiButton::SetIconOver(GuiImage* img)
{
iconOver = img;
if(img) img->SetParent(this);
}
void GuiButton::SetIconHold(GuiImage* img)
{
iconHold = img;
if(img) img->SetParent(this);
}
void GuiButton::SetIconClick(GuiImage* img)
{
iconClick = img;
if(img) img->SetParent(this);
}
void GuiButton::SetLabel(GuiText* txt, int n)
{
label[n] = txt;
if(txt) txt->SetParent(this);
}
void GuiButton::SetLabelOver(GuiText* txt, int n)
{
labelOver[n] = txt;
if(txt) txt->SetParent(this);
}
void GuiButton::SetLabelHold(GuiText* txt, int n)
{
labelHold[n] = txt;
if(txt) txt->SetParent(this);
}
void GuiButton::SetLabelClick(GuiText* txt, int n)
{
labelClick[n] = txt;
if(txt) txt->SetParent(this);
}
void GuiButton::SetSoundOver(GuiSound * snd)
{
soundOver = snd;
}
void GuiButton::SetSoundHold(GuiSound * snd)
{
soundHold = snd;
}
void GuiButton::SetSoundClick(GuiSound * snd)
{
soundClick = snd;
}
void GuiButton::SetTooltip(GuiTooltip* t)
{
tooltip = t;
if(t)
tooltip->SetParent(this);
}
/**
* Draw the button on screen
*/
void GuiButton::Draw()
{
if(!this->IsVisible())
return;
if(state == STATE_SELECTED || state == STATE_HELD)
{
if(imageOver)
imageOver->Draw();
else if(image) // draw image
image->Draw();
if(iconOver)
iconOver->Draw();
else if(icon) // draw icon
icon->Draw();
// draw text
if(labelOver[0])
labelOver[0]->Draw();
else if(label[0])
label[0]->Draw();
if(labelOver[1])
labelOver[1]->Draw();
else if(label[1])
label[1]->Draw();
if(labelOver[2])
labelOver[2]->Draw();
else if(label[2])
label[2]->Draw();
}
else
{
if(image) // draw image
image->Draw();
if(icon) // draw icon
icon->Draw();
// draw text
if(label[0])
label[0]->Draw();
if(label[1])
label[1]->Draw();
if(label[2])
label[2]->Draw();
}
this->UpdateEffects();
}
void GuiButton::DrawTooltip()
{
if(tooltip)
tooltip->DrawTooltip();
}
void GuiButton::ResetText()
{
for(int i=0; i<3; i++)
{
if(label[i])
label[i]->ResetText();
if(labelOver[i])
labelOver[i]->ResetText();
}
if(tooltip)
tooltip->ResetText();
}
void GuiButton::Update(GuiTrigger * t)
{
if(state == STATE_CLICKED || state == STATE_DISABLED || !t)
return;
else if(parentElement && parentElement->GetState() == STATE_DISABLED)
return;
#ifdef HW_RVL
// cursor
if(t->wpad->ir.valid && t->chan >= 0)
{
if(this->IsInside(t->wpad->ir.x, t->wpad->ir.y))
{
if(state == STATE_DEFAULT) // we weren't on the button before!
{
this->SetState(STATE_SELECTED, t->chan);
if(this->Rumble())
rumbleRequest[t->chan] = 1;
if(soundOver)
soundOver->Play();
if(effectsOver && !effects)
{
// initiate effects
effects = effectsOver;
effectAmount = effectAmountOver;
effectTarget = effectTargetOver;
}
}
}
else
{
if(state == STATE_SELECTED && (stateChan == t->chan || stateChan == -1))
this->ResetState();
if(effectTarget == effectTargetOver && effectAmount == effectAmountOver)
{
// initiate effects (in reverse)
effects = effectsOver;
effectAmount = -effectAmountOver;
effectTarget = 100;
}
}
}
#endif
// button triggers
if(this->IsClickable())
{
s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig;
for(int i=0; i<3; i++)
{
if(trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan))
{
// higher 16 bits only (wiimote)
wm_btns = t->wpad->btns_d << 16;
wm_btns_trig = trigger[i]->wpad->btns_d << 16;
// lower 16 bits only (classic controller)
cc_btns = t->wpad->btns_d >> 16;
cc_btns_trig = trigger[i]->wpad->btns_d >> 16;
if(
(t->wpad->btns_d > 0 &&
(wm_btns == wm_btns_trig ||
(cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
(t->pad.btns_d == trigger[i]->pad.btns_d && t->pad.btns_d > 0))
{
if(t->chan == stateChan || stateChan == -1)
{
if(state == STATE_SELECTED)
{
if(!t->wpad->ir.valid || this->IsInside(t->wpad->ir.x, t->wpad->ir.y))
{
this->SetState(STATE_CLICKED, t->chan);
if(soundClick)
soundClick->Play();
}
}
else if(trigger[i]->type == TRIGGER_BUTTON_ONLY)
{
this->SetState(STATE_CLICKED, t->chan);
}
else if(trigger[i]->type == TRIGGER_BUTTON_ONLY_IN_FOCUS &&
parentElement->IsFocused())
{
this->SetState(STATE_CLICKED, t->chan);
}
}
}
}
}
}
if(this->IsHoldable())
{
bool held = false;
s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig;
for(int i=0; i<3; i++)
{
if(trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan))
{
// higher 16 bits only (wiimote)
wm_btns = t->wpad->btns_d << 16;
wm_btns_h = t->wpad->btns_h << 16;
wm_btns_trig = trigger[i]->wpad->btns_h << 16;
// lower 16 bits only (classic controller)
cc_btns = t->wpad->btns_d >> 16;
cc_btns_h = t->wpad->btns_h >> 16;
cc_btns_trig = trigger[i]->wpad->btns_h >> 16;
if(
(t->wpad->btns_d > 0 &&
(wm_btns == wm_btns_trig ||
(cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
(t->pad.btns_d == trigger[i]->pad.btns_h && t->pad.btns_d > 0))
{
if(trigger[i]->type == TRIGGER_HELD && state == STATE_SELECTED &&
(t->chan == stateChan || stateChan == -1))
this->SetState(STATE_CLICKED, t->chan);
}
if(
(t->wpad->btns_h > 0 &&
(wm_btns_h == wm_btns_trig ||
(cc_btns_h == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
(t->pad.btns_h == trigger[i]->pad.btns_h && t->pad.btns_h > 0))
{
if(trigger[i]->type == TRIGGER_HELD)
held = true;
}
if(!held && state == STATE_HELD && stateChan == t->chan)
{
this->ResetState();
}
else if(held && state == STATE_CLICKED && stateChan == t->chan)
{
this->SetState(STATE_HELD, t->chan);
}
}
}
}
if(updateCB)
updateCB(this);
}

582
src/wii/gui/gui_element.cpp Normal file
View File

@ -0,0 +1,582 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_element.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
/**
* Constructor for the Object class.
*/
GuiElement::GuiElement()
{
xoffset = 0;
yoffset = 0;
xmin = 0;
xmax = 0;
ymin = 0;
ymax = 0;
width = 0;
height = 0;
alpha = 255;
xscale = 1;
yscale = 1;
state = STATE_DEFAULT;
stateChan = -1;
trigger[0] = NULL;
trigger[1] = NULL;
trigger[2] = NULL;
parentElement = NULL;
rumble = true;
selectable = false;
clickable = false;
holdable = false;
visible = true;
focus = -1; // cannot be focused
updateCB = NULL;
yoffsetDyn = 0;
xoffsetDyn = 0;
alphaDyn = -1;
scaleDyn = 1;
effects = 0;
effectAmount = 0;
effectTarget = 0;
effectsOver = 0;
effectAmountOver = 0;
effectTargetOver = 0;
// default alignment - align to top left
alignmentVert = ALIGN_TOP;
alignmentHor = ALIGN_LEFT;
}
/**
* Destructor for the GuiElement class.
*/
GuiElement::~GuiElement()
{
}
void GuiElement::SetParent(GuiElement * e)
{
parentElement = e;
}
GuiElement * GuiElement::GetParent()
{
return parentElement;
}
int GuiElement::GetLeft()
{
int x = 0;
int pWidth = 0;
int pLeft = 0;
if(parentElement)
{
pWidth = parentElement->GetWidth();
pLeft = parentElement->GetLeft();
}
if(effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT))
pLeft += xoffsetDyn;
switch(alignmentHor)
{
case ALIGN_LEFT:
x = pLeft;
break;
case ALIGN_CENTRE:
x = pLeft + pWidth/2.0 - (width*xscale)/2.0;
break;
case ALIGN_RIGHT:
x = pLeft + pWidth - width*xscale;
break;
}
x += (width*(xscale - 1))/2.0; // correct offset for scaled images
return x + xoffset;
}
int GuiElement::GetTop()
{
int y = 0;
int pHeight = 0;
int pTop = 0;
if(parentElement)
{
pHeight = parentElement->GetHeight();
pTop = parentElement->GetTop();
}
if(effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT))
pTop += yoffsetDyn;
switch(alignmentVert)
{
case ALIGN_TOP:
y = pTop;
break;
case ALIGN_MIDDLE:
y = pTop + pHeight/2.0 - (height*yscale)/2.0;
break;
case ALIGN_BOTTOM:
y = pTop + pHeight - height*yscale;
break;
}
y += (height*(yscale - 1))/2.0; // correct offset for scaled images
return y + yoffset;
}
void GuiElement::SetMinX(int x)
{
xmin = x;
}
int GuiElement::GetMinX()
{
return xmin;
}
void GuiElement::SetMaxX(int x)
{
xmax = x;
}
int GuiElement::GetMaxX()
{
return xmax;
}
void GuiElement::SetMinY(int y)
{
ymin = y;
}
int GuiElement::GetMinY()
{
return ymin;
}
void GuiElement::SetMaxY(int y)
{
ymax = y;
}
int GuiElement::GetMaxY()
{
return ymax;
}
int GuiElement::GetWidth()
{
return width;
}
int GuiElement::GetHeight()
{
return height;
}
void GuiElement::SetSize(int w, int h)
{
width = w;
height = h;
}
bool GuiElement::IsVisible()
{
return visible;
}
void GuiElement::SetVisible(bool v)
{
visible = v;
}
void GuiElement::SetAlpha(int a)
{
alpha = a;
}
int GuiElement::GetAlpha()
{
int a = alpha;
if(alphaDyn >= 0)
a = alphaDyn;
if(parentElement)
a *= float(parentElement->GetAlpha())/255.0f;
return a;
}
void GuiElement::SetScale(float s)
{
xscale = s;
yscale = s;
}
void GuiElement::SetScaleX(float s)
{
xscale = s;
}
void GuiElement::SetScaleY(float s)
{
yscale = s;
}
void GuiElement::SetScale(int mw, int mh)
{
xscale = 1.0f;
if(width > mw || height > mh)
{
if(width/(height*1.0) > mw/(mh*1.0))
xscale = mw/(width*1.0);
else
xscale = mh/(height*1.0);
}
yscale = xscale;
}
float GuiElement::GetScale()
{
float s = xscale * scaleDyn;
if(parentElement)
s *= parentElement->GetScale();
return s;
}
float GuiElement::GetScaleX()
{
float s = xscale * scaleDyn;
if(parentElement)
s *= parentElement->GetScale();
return s;
}
float GuiElement::GetScaleY()
{
float s = yscale * scaleDyn;
if(parentElement)
s *= parentElement->GetScaleY();
return s;
}
int GuiElement::GetState()
{
return state;
}
int GuiElement::GetStateChan()
{
return stateChan;
}
void GuiElement::SetState(int s, int c)
{
state = s;
stateChan = c;
}
void GuiElement::ResetState()
{
if(state != STATE_DISABLED)
{
state = STATE_DEFAULT;
stateChan = -1;
}
}
void GuiElement::SetClickable(bool c)
{
clickable = c;
}
void GuiElement::SetSelectable(bool s)
{
selectable = s;
}
void GuiElement::SetHoldable(bool d)
{
holdable = d;
}
bool GuiElement::IsSelectable()
{
if(state == STATE_DISABLED || state == STATE_CLICKED)
return false;
else
return selectable;
}
bool GuiElement::IsClickable()
{
if(state == STATE_DISABLED ||
state == STATE_CLICKED ||
state == STATE_HELD)
return false;
else
return clickable;
}
bool GuiElement::IsHoldable()
{
if(state == STATE_DISABLED)
return false;
else
return holdable;
}
void GuiElement::SetFocus(int f)
{
focus = f;
}
int GuiElement::IsFocused()
{
return focus;
}
void GuiElement::SetTrigger(GuiTrigger * t)
{
if(!trigger[0])
trigger[0] = t;
else if(!trigger[1])
trigger[1] = t;
else if(!trigger[2])
trigger[2] = t;
else // all were assigned, so we'll just overwrite the first one
trigger[0] = t;
}
void GuiElement::SetTrigger(u8 i, GuiTrigger * t)
{
trigger[i] = t;
}
bool GuiElement::Rumble()
{
return rumble;
}
void GuiElement::SetRumble(bool r)
{
rumble = r;
}
int GuiElement::GetEffect()
{
return effects;
}
void GuiElement::SetEffect(int eff, int amount, int target)
{
if(eff & EFFECT_SLIDE_IN)
{
// these calculations overcompensate a little
if(eff & EFFECT_SLIDE_TOP)
yoffsetDyn = -screenheight;
else if(eff & EFFECT_SLIDE_LEFT)
xoffsetDyn = -screenwidth;
else if(eff & EFFECT_SLIDE_BOTTOM)
yoffsetDyn = screenheight;
else if(eff & EFFECT_SLIDE_RIGHT)
xoffsetDyn = screenwidth;
}
if(eff & EFFECT_FADE)
{
if(amount > 0)
alphaDyn = 0;
else if(amount < 0)
alphaDyn = alpha;
}
effects |= eff;
effectAmount = amount;
effectTarget = target;
}
void GuiElement::SetEffectOnOver(int eff, int amount, int target)
{
effectsOver |= eff;
effectAmountOver = amount;
effectTargetOver = target;
}
void GuiElement::SetEffectGrow()
{
SetEffectOnOver(EFFECT_SCALE, 4, 110);
}
void GuiElement::UpdateEffects()
{
if(effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT))
{
if(effects & EFFECT_SLIDE_IN)
{
if(effects & EFFECT_SLIDE_LEFT)
{
xoffsetDyn += effectAmount;
if(xoffsetDyn >= 0)
{
xoffsetDyn = 0;
effects = 0;
}
}
else if(effects & EFFECT_SLIDE_RIGHT)
{
xoffsetDyn -= effectAmount;
if(xoffsetDyn <= 0)
{
xoffsetDyn = 0;
effects = 0;
}
}
else if(effects & EFFECT_SLIDE_TOP)
{
yoffsetDyn += effectAmount;
if(yoffsetDyn >= 0)
{
yoffsetDyn = 0;
effects = 0;
}
}
else if(effects & EFFECT_SLIDE_BOTTOM)
{
yoffsetDyn -= effectAmount;
if(yoffsetDyn <= 0)
{
yoffsetDyn = 0;
effects = 0;
}
}
}
else
{
if(effects & EFFECT_SLIDE_LEFT)
{
xoffsetDyn -= effectAmount;
if(xoffsetDyn <= -screenwidth)
effects = 0; // shut off effect
}
else if(effects & EFFECT_SLIDE_RIGHT)
{
xoffsetDyn += effectAmount;
if(xoffsetDyn >= screenwidth)
effects = 0; // shut off effect
}
else if(effects & EFFECT_SLIDE_TOP)
{
yoffsetDyn -= effectAmount;
if(yoffsetDyn <= -screenheight)
effects = 0; // shut off effect
}
else if(effects & EFFECT_SLIDE_BOTTOM)
{
yoffsetDyn += effectAmount;
if(yoffsetDyn >= screenheight)
effects = 0; // shut off effect
}
}
}
if(effects & EFFECT_FADE)
{
alphaDyn += effectAmount;
if(effectAmount < 0 && alphaDyn <= 0)
{
alphaDyn = 0;
effects = 0; // shut off effect
}
else if(effectAmount > 0 && alphaDyn >= alpha)
{
alphaDyn = alpha;
effects = 0; // shut off effect
}
}
if(effects & EFFECT_SCALE)
{
scaleDyn += f32(effectAmount)*0.01f;
f32 effTar100 = f32(effectTarget)*0.01f;
if((effectAmount < 0 && scaleDyn <= effTar100)
|| (effectAmount > 0 && scaleDyn >= effTar100))
{
scaleDyn = effTar100;
effects = 0; // shut off effect
}
}
}
void GuiElement::Update(GuiTrigger * t)
{
if(updateCB)
updateCB(this);
}
void GuiElement::SetUpdateCallback(UpdateCallback u)
{
updateCB = u;
}
void GuiElement::SetPosition(int xoff, int yoff)
{
xoffset = xoff;
yoffset = yoff;
}
void GuiElement::SetAlignment(int hor, int vert)
{
alignmentHor = hor;
alignmentVert = vert;
}
int GuiElement::GetSelected()
{
return -1;
}
void GuiElement::ResetText()
{
}
void GuiElement::Draw()
{
}
void GuiElement::DrawTooltip()
{
}
bool GuiElement::IsInside(int x, int y)
{
if(unsigned(x - this->GetLeft()) < unsigned(width)
&& unsigned(y - this->GetTop()) < unsigned(height))
return true;
return false;
}

View File

@ -0,0 +1,457 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_filebrowser.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
#include "../filebrowser.h"
/**
* Constructor for the GuiFileBrowser class.
*/
GuiFileBrowser::GuiFileBrowser(int w, int h)
{
width = w;
height = h;
numEntries = 0;
selectedItem = 0;
selectable = true;
listChanged = true; // trigger an initial list update
focus = 0; // allow focus
trigA = new GuiTrigger;
trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
trig2 = new GuiTrigger;
trig2->SetSimpleTrigger(-1, WPAD_BUTTON_2, 0);
trigHeldA = new GuiTrigger;
trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM);
btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM);
bgFileSelection = new GuiImageData(bg_game_selection_png);
bgFileSelectionImg = new GuiImage(bgFileSelection);
bgFileSelectionImg->SetParent(this);
bgFileSelectionImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
bgFileSelectionEntry = new GuiImageData(bg_game_selection_entry_png);
iconFolder = new GuiImageData(icon_folder_png);
iconSD = new GuiImageData(icon_sd_png);
iconUSB = new GuiImageData(icon_usb_png);
iconDVD = new GuiImageData(icon_dvd_png);
iconSMB = new GuiImageData(icon_smb_png);
scrollbar = new GuiImageData(scrollbar_png);
scrollbarImg = new GuiImage(scrollbar);
scrollbarImg->SetParent(this);
scrollbarImg->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
scrollbarImg->SetPosition(0, 30);
arrowDown = new GuiImageData(scrollbar_arrowdown_png);
arrowDownImg = new GuiImage(arrowDown);
arrowDownOver = new GuiImageData(scrollbar_arrowdown_over_png);
arrowDownOverImg = new GuiImage(arrowDownOver);
arrowUp = new GuiImageData(scrollbar_arrowup_png);
arrowUpImg = new GuiImage(arrowUp);
arrowUpOver = new GuiImageData(scrollbar_arrowup_over_png);
arrowUpOverImg = new GuiImage(arrowUpOver);
scrollbarBox = new GuiImageData(scrollbar_box_png);
scrollbarBoxImg = new GuiImage(scrollbarBox);
scrollbarBoxOver = new GuiImageData(scrollbar_box_over_png);
scrollbarBoxOverImg = new GuiImage(scrollbarBoxOver);
arrowUpBtn = new GuiButton(arrowUpImg->GetWidth(), arrowUpImg->GetHeight());
arrowUpBtn->SetParent(this);
arrowUpBtn->SetImage(arrowUpImg);
arrowUpBtn->SetImageOver(arrowUpOverImg);
arrowUpBtn->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
arrowUpBtn->SetSelectable(false);
arrowUpBtn->SetClickable(false);
arrowUpBtn->SetHoldable(true);
arrowUpBtn->SetTrigger(trigHeldA);
arrowUpBtn->SetSoundOver(btnSoundOver);
arrowUpBtn->SetSoundClick(btnSoundClick);
arrowDownBtn = new GuiButton(arrowDownImg->GetWidth(), arrowDownImg->GetHeight());
arrowDownBtn->SetParent(this);
arrowDownBtn->SetImage(arrowDownImg);
arrowDownBtn->SetImageOver(arrowDownOverImg);
arrowDownBtn->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
arrowDownBtn->SetSelectable(false);
arrowDownBtn->SetClickable(false);
arrowDownBtn->SetHoldable(true);
arrowDownBtn->SetTrigger(trigHeldA);
arrowDownBtn->SetSoundOver(btnSoundOver);
arrowDownBtn->SetSoundClick(btnSoundClick);
scrollbarBoxBtn = new GuiButton(scrollbarBoxImg->GetWidth(), scrollbarBoxImg->GetHeight());
scrollbarBoxBtn->SetParent(this);
scrollbarBoxBtn->SetImage(scrollbarBoxImg);
scrollbarBoxBtn->SetImageOver(scrollbarBoxOverImg);
scrollbarBoxBtn->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
scrollbarBoxBtn->SetMinY(0);
scrollbarBoxBtn->SetMaxY(156);
scrollbarBoxBtn->SetSelectable(false);
scrollbarBoxBtn->SetClickable(false);
scrollbarBoxBtn->SetHoldable(true);
scrollbarBoxBtn->SetTrigger(trigHeldA);
for(int i=0; i<FILE_PAGESIZE; ++i)
{
fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff});
fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
fileListText[i]->SetPosition(5,0);
fileListText[i]->SetMaxWidth(380);
fileListBg[i] = new GuiImage(bgFileSelectionEntry);
fileListIcon[i] = NULL;
fileList[i] = new GuiButton(380, 26);
fileList[i]->SetParent(this);
fileList[i]->SetLabel(fileListText[i]);
fileList[i]->SetImageOver(fileListBg[i]);
fileList[i]->SetPosition(2,26*i+3);
fileList[i]->SetTrigger(trigA);
fileList[i]->SetTrigger(trig2);
fileList[i]->SetSoundClick(btnSoundClick);
}
}
/**
* Destructor for the GuiFileBrowser class.
*/
GuiFileBrowser::~GuiFileBrowser()
{
delete arrowUpBtn;
delete arrowDownBtn;
delete scrollbarBoxBtn;
delete bgFileSelectionImg;
delete scrollbarImg;
delete arrowDownImg;
delete arrowDownOverImg;
delete arrowUpImg;
delete arrowUpOverImg;
delete scrollbarBoxImg;
delete scrollbarBoxOverImg;
delete bgFileSelection;
delete bgFileSelectionEntry;
delete iconFolder;
delete iconSD;
delete iconUSB;
delete iconDVD;
delete iconSMB;
delete scrollbar;
delete arrowDown;
delete arrowDownOver;
delete arrowUp;
delete arrowUpOver;
delete scrollbarBox;
delete scrollbarBoxOver;
delete btnSoundOver;
delete btnSoundClick;
delete trigHeldA;
delete trigA;
delete trig2;
for(int i=0; i<FILE_PAGESIZE; i++)
{
delete fileListText[i];
delete fileList[i];
delete fileListBg[i];
if(fileListIcon[i])
delete fileListIcon[i];
}
}
void GuiFileBrowser::SetFocus(int f)
{
focus = f;
for(int i=0; i<FILE_PAGESIZE; i++)
fileList[i]->ResetState();
if(f == 1)
fileList[selectedItem]->SetState(STATE_SELECTED);
}
void GuiFileBrowser::ResetState()
{
state = STATE_DEFAULT;
stateChan = -1;
selectedItem = 0;
for(int i=0; i<FILE_PAGESIZE; i++)
{
fileList[i]->ResetState();
}
}
void GuiFileBrowser::TriggerUpdate()
{
int newIndex = browser.selIndex-browser.pageIndex;
if(newIndex >= FILE_PAGESIZE)
newIndex = FILE_PAGESIZE-1;
else if(newIndex < 0)
newIndex = 0;
selectedItem = newIndex;
listChanged = true;
}
/**
* Draw the button on screen
*/
void GuiFileBrowser::Draw()
{
if(!this->IsVisible())
return;
bgFileSelectionImg->Draw();
for(u32 i=0; i<FILE_PAGESIZE; ++i)
{
fileList[i]->Draw();
}
scrollbarImg->Draw();
arrowUpBtn->Draw();
arrowDownBtn->Draw();
scrollbarBoxBtn->Draw();
this->UpdateEffects();
}
void GuiFileBrowser::DrawTooltip()
{
}
void GuiFileBrowser::Update(GuiTrigger * t)
{
if(state == STATE_DISABLED || !t)
return;
int position = 0;
int positionWiimote = 0;
arrowUpBtn->Update(t);
arrowDownBtn->Update(t);
scrollbarBoxBtn->Update(t);
// move the file listing to respond to wiimote cursor movement
if(scrollbarBoxBtn->GetState() == STATE_HELD &&
scrollbarBoxBtn->GetStateChan() == t->chan &&
t->wpad->ir.valid &&
browser.numEntries > FILE_PAGESIZE
)
{
scrollbarBoxBtn->SetPosition(0,0);
positionWiimote = t->wpad->ir.y - 60 - scrollbarBoxBtn->GetTop();
if(positionWiimote < scrollbarBoxBtn->GetMinY())
positionWiimote = scrollbarBoxBtn->GetMinY();
else if(positionWiimote > scrollbarBoxBtn->GetMaxY())
positionWiimote = scrollbarBoxBtn->GetMaxY();
browser.pageIndex = (positionWiimote * browser.numEntries)/156.0f - selectedItem;
if(browser.pageIndex <= 0)
{
browser.pageIndex = 0;
}
else if(browser.pageIndex+FILE_PAGESIZE >= browser.numEntries)
{
browser.pageIndex = browser.numEntries-FILE_PAGESIZE;
}
listChanged = true;
focus = false;
}
if(arrowDownBtn->GetState() == STATE_HELD && arrowDownBtn->GetStateChan() == t->chan)
{
t->wpad->btns_d |= WPAD_BUTTON_DOWN;
if(!this->IsFocused())
((GuiWindow *)this->GetParent())->ChangeFocus(this);
}
else if(arrowUpBtn->GetState() == STATE_HELD && arrowUpBtn->GetStateChan() == t->chan)
{
t->wpad->btns_d |= WPAD_BUTTON_UP;
if(!this->IsFocused())
((GuiWindow *)this->GetParent())->ChangeFocus(this);
}
// pad/joystick navigation
if(!focus)
{
goto endNavigation; // skip navigation
listChanged = false;
}
if(t->Right())
{
if(browser.pageIndex < browser.numEntries && browser.numEntries > FILE_PAGESIZE)
{
browser.pageIndex += FILE_PAGESIZE;
if(browser.pageIndex+FILE_PAGESIZE >= browser.numEntries)
browser.pageIndex = browser.numEntries-FILE_PAGESIZE;
listChanged = true;
}
}
else if(t->Left())
{
if(browser.pageIndex > 0)
{
browser.pageIndex -= FILE_PAGESIZE;
if(browser.pageIndex < 0)
browser.pageIndex = 0;
listChanged = true;
}
}
else if(t->Down())
{
if(browser.pageIndex + selectedItem + 1 < browser.numEntries)
{
if(selectedItem == FILE_PAGESIZE-1)
{
// move list down by 1
++browser.pageIndex;
listChanged = true;
}
else if(fileList[selectedItem+1]->IsVisible())
{
fileList[selectedItem]->ResetState();
fileList[++selectedItem]->SetState(STATE_SELECTED, t->chan);
}
}
}
else if(t->Up())
{
if(selectedItem == 0 && browser.pageIndex + selectedItem > 0)
{
// move list up by 1
--browser.pageIndex;
listChanged = true;
}
else if(selectedItem > 0)
{
fileList[selectedItem]->ResetState();
fileList[--selectedItem]->SetState(STATE_SELECTED, t->chan);
}
}
endNavigation:
for(int i=0; i<FILE_PAGESIZE; ++i)
{
if(listChanged || numEntries != browser.numEntries)
{
if(browser.pageIndex+i < browser.numEntries)
{
if(fileList[i]->GetState() == STATE_DISABLED)
fileList[i]->SetState(STATE_DEFAULT);
fileList[i]->SetVisible(true);
fileListText[i]->SetText(browserList[browser.pageIndex+i].displayname);
if(fileListIcon[i])
{
delete fileListIcon[i];
fileListIcon[i] = NULL;
fileListText[i]->SetPosition(5,0);
}
switch(browserList[browser.pageIndex+i].icon)
{
case ICON_FOLDER:
fileListIcon[i] = new GuiImage(iconFolder);
break;
case ICON_SD:
fileListIcon[i] = new GuiImage(iconSD);
break;
case ICON_USB:
fileListIcon[i] = new GuiImage(iconUSB);
break;
case ICON_DVD:
fileListIcon[i] = new GuiImage(iconDVD);
break;
case ICON_SMB:
fileListIcon[i] = new GuiImage(iconSMB);
break;
}
fileList[i]->SetIcon(fileListIcon[i]);
if(fileListIcon[i] != NULL)
fileListText[i]->SetPosition(30,0);
}
else
{
fileList[i]->SetVisible(false);
fileList[i]->SetState(STATE_DISABLED);
}
}
if(i != selectedItem && fileList[i]->GetState() == STATE_SELECTED)
fileList[i]->ResetState();
else if(focus && i == selectedItem && fileList[i]->GetState() == STATE_DEFAULT)
fileList[selectedItem]->SetState(STATE_SELECTED, t->chan);
int currChan = t->chan;
if(t->wpad->ir.valid && !fileList[i]->IsInside(t->wpad->ir.x, t->wpad->ir.y))
t->chan = -1;
fileList[i]->Update(t);
t->chan = currChan;
if(fileList[i]->GetState() == STATE_SELECTED)
{
selectedItem = i;
browser.selIndex = browser.pageIndex + i;
}
if(selectedItem == i)
fileListText[i]->SetScroll(SCROLL_HORIZONTAL);
else
fileListText[i]->SetScroll(SCROLL_NONE);
}
// update the location of the scroll box based on the position in the file list
if(positionWiimote > 0)
{
position = positionWiimote; // follow wiimote cursor
scrollbarBoxBtn->SetPosition(0,position+36);
}
else if(listChanged || numEntries != browser.numEntries)
{
if(float((browser.pageIndex<<1))/(float(FILE_PAGESIZE)) < 1.0)
{
position = 0;
}
else if(browser.pageIndex+FILE_PAGESIZE >= browser.numEntries)
{
position = 156;
}
else
{
position = 156 * (browser.pageIndex + FILE_PAGESIZE/2) / (float)browser.numEntries;
}
scrollbarBoxBtn->SetPosition(0,position+36);
}
listChanged = false;
numEntries = browser.numEntries;
if(updateCB)
updateCB(this);
}

255
src/wii/gui/gui_image.cpp Normal file
View File

@ -0,0 +1,255 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_image.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
/**
* Constructor for the GuiImage class.
*/
GuiImage::GuiImage()
{
image = NULL;
width = 0;
height = 0;
imageangle = 0;
tile = -1;
stripe = 0;
imgType = IMAGE_DATA;
}
GuiImage::GuiImage(GuiImageData * img)
{
image = NULL;
width = 0;
height = 0;
if(img)
{
image = img->GetImage();
width = img->GetWidth();
height = img->GetHeight();
}
imageangle = 0;
tile = -1;
stripe = 0;
imgType = IMAGE_DATA;
}
GuiImage::GuiImage(u8 * img, int w, int h)
{
image = img;
width = w;
height = h;
imageangle = 0;
tile = -1;
stripe = 0;
imgType = IMAGE_TEXTURE;
}
GuiImage::GuiImage(int w, int h, GXColor c)
{
image = (u8 *)memalign (32, w * h << 2);
width = w;
height = h;
imageangle = 0;
tile = -1;
stripe = 0;
imgType = IMAGE_COLOR;
if(!image)
return;
int x, y;
for(y=0; y < h; ++y)
{
for(x=0; x < w; ++x)
{
this->SetPixel(x, y, c);
}
}
int len = w * h << 2;
if(len%32) len += (32-len%32);
DCFlushRange(image, len);
}
/**
* Destructor for the GuiImage class.
*/
GuiImage::~GuiImage()
{
if(imgType == IMAGE_COLOR && image)
free(image);
}
u8 * GuiImage::GetImage()
{
return image;
}
void GuiImage::SetImage(GuiImageData * img)
{
image = NULL;
width = 0;
height = 0;
if(img)
{
image = img->GetImage();
width = img->GetWidth();
height = img->GetHeight();
}
imgType = IMAGE_DATA;
}
void GuiImage::SetImage(u8 * img, int w, int h)
{
image = img;
width = w;
height = h;
imgType = IMAGE_TEXTURE;
}
void GuiImage::SetAngle(float a)
{
imageangle = a;
}
void GuiImage::SetTile(int t)
{
tile = t;
}
GXColor GuiImage::GetPixel(int x, int y)
{
if(!image || this->GetWidth() <= 0 || x < 0 || y < 0)
return (GXColor){0, 0, 0, 0};
u32 offset = (((y >> 2)<<4)*this->GetWidth()) + ((x >> 2)<<6) + (((y%4 << 2) + x%4 ) << 1);
GXColor color;
color.a = *(image+offset);
color.r = *(image+offset+1);
color.g = *(image+offset+32);
color.b = *(image+offset+33);
return color;
}
void GuiImage::SetPixel(int x, int y, GXColor color)
{
if(!image || this->GetWidth() <= 0 || x < 0 || y < 0)
return;
u32 offset = (((y >> 2)<<4)*this->GetWidth()) + ((x >> 2)<<6) + (((y%4 << 2) + x%4 ) << 1);
*(image+offset) = color.a;
*(image+offset+1) = color.r;
*(image+offset+32) = color.g;
*(image+offset+33) = color.b;
}
void GuiImage::SetStripe(int s)
{
stripe = s;
}
void GuiImage::ColorStripe(int shift)
{
GXColor color;
int x, y=0;
int alt = 0;
int thisHeight = this->GetHeight();
int thisWidth = this->GetWidth();
for(; y < thisHeight; ++y)
{
if(y % 3 == 0)
alt ^= 1;
if(alt)
{
for(x=0; x < thisWidth; ++x)
{
color = GetPixel(x, y);
if(color.r < 255-shift)
color.r += shift;
else
color.r = 255;
if(color.g < 255-shift)
color.g += shift;
else
color.g = 255;
if(color.b < 255-shift)
color.b += shift;
else
color.b = 255;
color.a = 255;
SetPixel(x, y, color);
}
}
else
{
for(x=0; x < thisWidth; ++x)
{
color = GetPixel(x, y);
if(color.r > shift)
color.r -= shift;
else
color.r = 0;
if(color.g > shift)
color.g -= shift;
else
color.g = 0;
if(color.b > shift)
color.b -= shift;
else
color.b = 0;
color.a = 255;
SetPixel(x, y, color);
}
}
}
}
/**
* Draw the button on screen
*/
void GuiImage::Draw()
{
if(!image || !this->IsVisible() || tile == 0)
return;
float currScaleX = this->GetScaleX();
float currScaleY = this->GetScaleY();
int currLeft = this->GetLeft();
int thisTop = this->GetTop();
if(tile > 0)
{
int alpha = this->GetAlpha();
for(int i=0; i<tile; ++i)
{
Menu_DrawImg(currLeft+width*i, thisTop, width, height, image, imageangle, currScaleX, currScaleY, alpha);
}
}
else
{
Menu_DrawImg(currLeft, thisTop, width, height, image, imageangle, currScaleX, currScaleY, this->GetAlpha());
}
if(stripe > 0)
{
int thisHeight = this->GetHeight();
int thisWidth = this->GetWidth();
for(int y=0; y < thisHeight; y+=6)
Menu_DrawRectangle(currLeft,thisTop+y,thisWidth,3,(GXColor){0, 0, 0, stripe},1);
}
this->UpdateEffects();
}

View File

@ -0,0 +1,51 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_imagedata.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
/**
* Constructor for the GuiImageData class.
*/
GuiImageData::GuiImageData(const u8 * i, int maxw, int maxh)
{
data = NULL;
width = 0;
height = 0;
if(i)
data = DecodePNG(i, &width, &height, data, maxw, maxh);
}
/**
* Destructor for the GuiImageData class.
*/
GuiImageData::~GuiImageData()
{
if(data)
{
free(data);
data = NULL;
}
}
u8 * GuiImageData::GetImage()
{
return data;
}
int GuiImageData::GetWidth()
{
return width;
}
int GuiImageData::GetHeight()
{
return height;
}

View File

@ -0,0 +1,372 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_keyboard.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
static char tmptxt[MAX_KEYBOARD_DISPLAY];
static char * GetDisplayText(char * t)
{
if(!t)
return NULL;
int len = strlen(t);
if(len < MAX_KEYBOARD_DISPLAY)
return t;
snprintf(tmptxt, MAX_KEYBOARD_DISPLAY, "%s", &t[len-MAX_KEYBOARD_DISPLAY]);
return &tmptxt[0];
}
/**
* Constructor for the GuiKeyboard class.
*/
GuiKeyboard::GuiKeyboard(char * t, u32 max)
{
width = 540;
height = 400;
shift = 0;
caps = 0;
selectable = true;
focus = 0; // allow focus
alignmentHor = ALIGN_CENTRE;
alignmentVert = ALIGN_MIDDLE;
snprintf(kbtextstr, 255, "%s", t);
kbtextmaxlen = max;
Key thekeys[4][11] = {
{
{'1','!'},
{'2','@'},
{'3','#'},
{'4','$'},
{'5','%'},
{'6','^'},
{'7','&'},
{'8','*'},
{'9','('},
{'0',')'},
{'\0','\0'}
},
{
{'q','Q'},
{'w','W'},
{'e','E'},
{'r','R'},
{'t','T'},
{'y','Y'},
{'u','U'},
{'i','I'},
{'o','O'},
{'p','P'},
{'-','_'}
},
{
{'a','A'},
{'s','S'},
{'d','D'},
{'f','F'},
{'g','G'},
{'h','H'},
{'j','J'},
{'k','K'},
{'l','L'},
{';',':'},
{'\'','"'}
},
{
{'z','Z'},
{'x','X'},
{'c','C'},
{'v','V'},
{'b','B'},
{'n','N'},
{'m','M'},
{',','<'},
{'.','>'},
{'/','?'},
{'\0','\0'}
}
};
memcpy(keys, thekeys, sizeof(thekeys));
keyTextbox = new GuiImageData(keyboard_textbox_png);
keyTextboxImg = new GuiImage(keyTextbox);
keyTextboxImg->SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
keyTextboxImg->SetPosition(0, 0);
this->Append(keyTextboxImg);
kbText = new GuiText(GetDisplayText(kbtextstr), 22, (GXColor){0, 0, 0, 0xff});
kbText->SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
kbText->SetPosition(0, 13);
this->Append(kbText);
key = new GuiImageData(keyboard_key_png);
keyOver = new GuiImageData(keyboard_key_over_png);
keyMedium = new GuiImageData(keyboard_mediumkey_png);
keyMediumOver = new GuiImageData(keyboard_mediumkey_over_png);
keyLarge = new GuiImageData(keyboard_largekey_png);
keyLargeOver = new GuiImageData(keyboard_largekey_over_png);
keySoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM);
keySoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM);
trigA = new GuiTrigger;
trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
trig2 = new GuiTrigger;
trig2->SetSimpleTrigger(-1, WPAD_BUTTON_2, 0);
keyBackImg = new GuiImage(keyMedium);
keyBackOverImg = new GuiImage(keyMediumOver);
keyBackText = new GuiText("Back", 22, (GXColor){0, 0, 0, 0xff});
keyBack = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
keyBack->SetImage(keyBackImg);
keyBack->SetImageOver(keyBackOverImg);
keyBack->SetLabel(keyBackText);
keyBack->SetSoundOver(keySoundOver);
keyBack->SetSoundClick(keySoundClick);
keyBack->SetTrigger(trigA);
keyBack->SetTrigger(trig2);
keyBack->SetPosition(10*42+40, 0*42+80);
keyBack->SetEffectGrow();
this->Append(keyBack);
keyCapsImg = new GuiImage(keyMedium);
keyCapsOverImg = new GuiImage(keyMediumOver);
keyCapsText = new GuiText("Caps", 22, (GXColor){0, 0, 0, 0xff});
keyCaps = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
keyCaps->SetImage(keyCapsImg);
keyCaps->SetImageOver(keyCapsOverImg);
keyCaps->SetLabel(keyCapsText);
keyCaps->SetSoundOver(keySoundOver);
keyCaps->SetSoundClick(keySoundClick);
keyCaps->SetTrigger(trigA);
keyCaps->SetTrigger(trig2);
keyCaps->SetPosition(0, 2*42+80);
keyCaps->SetEffectGrow();
this->Append(keyCaps);
keyShiftImg = new GuiImage(keyMedium);
keyShiftOverImg = new GuiImage(keyMediumOver);
keyShiftText = new GuiText("Shift", 22, (GXColor){0, 0, 0, 0xff});
keyShift = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
keyShift->SetImage(keyShiftImg);
keyShift->SetImageOver(keyShiftOverImg);
keyShift->SetLabel(keyShiftText);
keyShift->SetSoundOver(keySoundOver);
keyShift->SetSoundClick(keySoundClick);
keyShift->SetTrigger(trigA);
keyShift->SetTrigger(trig2);
keyShift->SetPosition(21, 3*42+80);
keyShift->SetEffectGrow();
this->Append(keyShift);
keySpaceImg = new GuiImage(keyLarge);
keySpaceOverImg = new GuiImage(keyLargeOver);
keySpace = new GuiButton(keyLarge->GetWidth(), keyLarge->GetHeight());
keySpace->SetImage(keySpaceImg);
keySpace->SetImageOver(keySpaceOverImg);
keySpace->SetSoundOver(keySoundOver);
keySpace->SetSoundClick(keySoundClick);
keySpace->SetTrigger(trigA);
keySpace->SetTrigger(trig2);
keySpace->SetPosition(0, 4*42+80);
keySpace->SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
keySpace->SetEffectGrow();
this->Append(keySpace);
char txt[2] = { 0, 0 };
for(int i=0; i<4; i++)
{
for(int j=0; j<11; j++)
{
if(keys[i][j].ch != '\0')
{
txt[0] = keys[i][j].ch;
keyImg[i][j] = new GuiImage(key);
keyImgOver[i][j] = new GuiImage(keyOver);
keyTxt[i][j] = new GuiText(txt, 22, (GXColor){0, 0, 0, 0xff});
keyTxt[i][j]->SetAlignment(ALIGN_CENTRE, ALIGN_BOTTOM);
keyTxt[i][j]->SetPosition(0, -8);
keyBtn[i][j] = new GuiButton(key->GetWidth(), key->GetHeight());
keyBtn[i][j]->SetImage(keyImg[i][j]);
keyBtn[i][j]->SetImageOver(keyImgOver[i][j]);
keyBtn[i][j]->SetSoundOver(keySoundOver);
keyBtn[i][j]->SetSoundClick(keySoundClick);
keyBtn[i][j]->SetTrigger(trigA);
keyBtn[i][j]->SetTrigger(trig2);
keyBtn[i][j]->SetLabel(keyTxt[i][j]);
keyBtn[i][j]->SetPosition(j*42+21*i+40, i*42+80);
keyBtn[i][j]->SetEffectGrow();
this->Append(keyBtn[i][j]);
}
}
}
}
/**
* Destructor for the GuiKeyboard class.
*/
GuiKeyboard::~GuiKeyboard()
{
delete kbText;
delete keyTextbox;
delete keyTextboxImg;
delete keyCapsText;
delete keyCapsImg;
delete keyCapsOverImg;
delete keyCaps;
delete keyShiftText;
delete keyShiftImg;
delete keyShiftOverImg;
delete keyShift;
delete keyBackText;
delete keyBackImg;
delete keyBackOverImg;
delete keyBack;
delete keySpaceImg;
delete keySpaceOverImg;
delete keySpace;
delete key;
delete keyOver;
delete keyMedium;
delete keyMediumOver;
delete keyLarge;
delete keyLargeOver;
delete keySoundOver;
delete keySoundClick;
delete trigA;
delete trig2;
for(int i=0; i<4; i++)
{
for(int j=0; j<11; j++)
{
if(keys[i][j].ch != '\0')
{
delete keyImg[i][j];
delete keyImgOver[i][j];
delete keyTxt[i][j];
delete keyBtn[i][j];
}
}
}
}
void GuiKeyboard::Update(GuiTrigger * t)
{
if(_elements.size() == 0 || (state == STATE_DISABLED && parentElement))
return;
for (u8 i = 0; i < _elements.size(); i++)
{
try { _elements.at(i)->Update(t); }
catch (const std::exception& e) { }
}
bool update = false;
if(keySpace->GetState() == STATE_CLICKED)
{
if(strlen(kbtextstr) < kbtextmaxlen)
{
kbtextstr[strlen(kbtextstr)] = ' ';
kbText->SetText(kbtextstr);
}
keySpace->SetState(STATE_SELECTED, t->chan);
}
else if(keyBack->GetState() == STATE_CLICKED)
{
if(strlen(kbtextstr) > 0)
{
kbtextstr[strlen(kbtextstr)-1] = 0;
kbText->SetText(GetDisplayText(kbtextstr));
}
keyBack->SetState(STATE_SELECTED, t->chan);
}
else if(keyShift->GetState() == STATE_CLICKED)
{
shift ^= 1;
keyShift->SetState(STATE_SELECTED, t->chan);
update = true;
}
else if(keyCaps->GetState() == STATE_CLICKED)
{
caps ^= 1;
keyCaps->SetState(STATE_SELECTED, t->chan);
update = true;
}
char txt[2] = { 0, 0 };
startloop:
for(int i=0; i<4; i++)
{
for(int j=0; j<11; j++)
{
if(keys[i][j].ch != '\0')
{
if(update)
{
if(shift || caps)
txt[0] = keys[i][j].chShift;
else
txt[0] = keys[i][j].ch;
keyTxt[i][j]->SetText(txt);
}
if(keyBtn[i][j]->GetState() == STATE_CLICKED)
{
if(strlen(kbtextstr) < kbtextmaxlen)
{
if(shift || caps)
{
kbtextstr[strlen(kbtextstr)] = keys[i][j].chShift;
}
else
{
kbtextstr[strlen(kbtextstr)] = keys[i][j].ch;
}
}
kbText->SetText(GetDisplayText(kbtextstr));
keyBtn[i][j]->SetState(STATE_SELECTED, t->chan);
if(shift)
{
shift ^= 1;
update = true;
goto startloop;
}
}
}
}
}
this->ToggleFocus(t);
if(focus) // only send actions to this window if it's in focus
{
// pad/joystick navigation
if(t->Right())
this->MoveSelectionHor(1);
else if(t->Left())
this->MoveSelectionHor(-1);
else if(t->Down())
this->MoveSelectionVert(1);
else if(t->Up())
this->MoveSelectionVert(-1);
}
}

View File

@ -0,0 +1,366 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_optionbrowser.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
/**
* Constructor for the GuiOptionBrowser class.
*/
GuiOptionBrowser::GuiOptionBrowser(int w, int h, OptionList * l)
{
width = w;
height = h;
options = l;
selectable = true;
listOffset = this->FindMenuItem(-1, 1);
listChanged = true; // trigger an initial list update
selectedItem = 0;
focus = 0; // allow focus
trigA = new GuiTrigger;
trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
trig2 = new GuiTrigger;
trig2->SetSimpleTrigger(-1, WPAD_BUTTON_2, 0);
btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM);
btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM);
bgOptions = new GuiImageData(bg_options_png);
bgOptionsImg = new GuiImage(bgOptions);
bgOptionsImg->SetParent(this);
bgOptionsImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
bgOptionsEntry = new GuiImageData(bg_options_entry_png);
scrollbar = new GuiImageData(scrollbar_png);
scrollbarImg = new GuiImage(scrollbar);
scrollbarImg->SetParent(this);
scrollbarImg->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
scrollbarImg->SetPosition(0, 30);
arrowDown = new GuiImageData(scrollbar_arrowdown_png);
arrowDownImg = new GuiImage(arrowDown);
arrowDownOver = new GuiImageData(scrollbar_arrowdown_over_png);
arrowDownOverImg = new GuiImage(arrowDownOver);
arrowUp = new GuiImageData(scrollbar_arrowup_png);
arrowUpImg = new GuiImage(arrowUp);
arrowUpOver = new GuiImageData(scrollbar_arrowup_over_png);
arrowUpOverImg = new GuiImage(arrowUpOver);
arrowUpBtn = new GuiButton(arrowUpImg->GetWidth(), arrowUpImg->GetHeight());
arrowUpBtn->SetParent(this);
arrowUpBtn->SetImage(arrowUpImg);
arrowUpBtn->SetImageOver(arrowUpOverImg);
arrowUpBtn->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
arrowUpBtn->SetSelectable(false);
arrowUpBtn->SetTrigger(trigA);
arrowUpBtn->SetSoundOver(btnSoundOver);
arrowUpBtn->SetSoundClick(btnSoundClick);
arrowDownBtn = new GuiButton(arrowDownImg->GetWidth(), arrowDownImg->GetHeight());
arrowDownBtn->SetParent(this);
arrowDownBtn->SetImage(arrowDownImg);
arrowDownBtn->SetImageOver(arrowDownOverImg);
arrowDownBtn->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
arrowDownBtn->SetSelectable(false);
arrowDownBtn->SetTrigger(trigA);
arrowDownBtn->SetSoundOver(btnSoundOver);
arrowDownBtn->SetSoundClick(btnSoundClick);
for(int i=0; i<PAGESIZE; i++)
{
optionTxt[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff});
optionTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
optionTxt[i]->SetPosition(8,0);
optionVal[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff});
optionVal[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
optionVal[i]->SetPosition(250,0);
optionBg[i] = new GuiImage(bgOptionsEntry);
optionBtn[i] = new GuiButton(512,30);
optionBtn[i]->SetParent(this);
optionBtn[i]->SetLabel(optionTxt[i], 0);
optionBtn[i]->SetLabel(optionVal[i], 1);
optionBtn[i]->SetImageOver(optionBg[i]);
optionBtn[i]->SetPosition(0,30*i+3);
optionBtn[i]->SetTrigger(trigA);
optionBtn[i]->SetTrigger(trig2);
optionBtn[i]->SetSoundClick(btnSoundClick);
}
}
/**
* Destructor for the GuiOptionBrowser class.
*/
GuiOptionBrowser::~GuiOptionBrowser()
{
delete arrowUpBtn;
delete arrowDownBtn;
delete bgOptionsImg;
delete scrollbarImg;
delete arrowDownImg;
delete arrowDownOverImg;
delete arrowUpImg;
delete arrowUpOverImg;
delete bgOptions;
delete bgOptionsEntry;
delete scrollbar;
delete arrowDown;
delete arrowDownOver;
delete arrowUp;
delete arrowUpOver;
delete trigA;
delete trig2;
delete btnSoundOver;
delete btnSoundClick;
for(int i=0; i<PAGESIZE; i++)
{
delete optionTxt[i];
delete optionVal[i];
delete optionBg[i];
delete optionBtn[i];
}
}
void GuiOptionBrowser::SetCol1Position(int x)
{
for(int i=0; i<PAGESIZE; i++)
optionTxt[i]->SetPosition(x,0);
}
void GuiOptionBrowser::SetCol2Position(int x)
{
for(int i=0; i<PAGESIZE; i++)
optionVal[i]->SetPosition(x,0);
}
void GuiOptionBrowser::SetFocus(int f)
{
focus = f;
for(int i=0; i<PAGESIZE; i++)
optionBtn[i]->ResetState();
if(f == 1)
optionBtn[selectedItem]->SetState(STATE_SELECTED);
}
void GuiOptionBrowser::ResetState()
{
if(state != STATE_DISABLED)
{
state = STATE_DEFAULT;
stateChan = -1;
}
for(int i=0; i<PAGESIZE; i++)
{
optionBtn[i]->ResetState();
}
}
int GuiOptionBrowser::GetClickedOption()
{
int found = -1;
for(int i=0; i<PAGESIZE; i++)
{
if(optionBtn[i]->GetState() == STATE_CLICKED)
{
optionBtn[i]->SetState(STATE_SELECTED);
found = optionIndex[i];
break;
}
}
return found;
}
/****************************************************************************
* FindMenuItem
*
* Help function to find the next visible menu item on the list
***************************************************************************/
int GuiOptionBrowser::FindMenuItem(int currentItem, int direction)
{
int nextItem = currentItem + direction;
if(nextItem < 0 || nextItem >= options->length)
return -1;
if(strlen(options->name[nextItem]) > 0)
return nextItem;
else
return FindMenuItem(nextItem, direction);
}
/**
* Draw the button on screen
*/
void GuiOptionBrowser::Draw()
{
if(!this->IsVisible())
return;
bgOptionsImg->Draw();
int next = listOffset;
for(int i=0; i<PAGESIZE; ++i)
{
if(next >= 0)
{
optionBtn[i]->Draw();
next = this->FindMenuItem(next, 1);
}
else
break;
}
scrollbarImg->Draw();
arrowUpBtn->Draw();
arrowDownBtn->Draw();
this->UpdateEffects();
}
void GuiOptionBrowser::TriggerUpdate()
{
listChanged = true;
}
void GuiOptionBrowser::ResetText()
{
int next = listOffset;
for(int i=0; i<PAGESIZE; i++)
{
if(next >= 0)
{
optionBtn[i]->ResetText();
next = this->FindMenuItem(next, 1);
}
else
break;
}
}
void GuiOptionBrowser::Update(GuiTrigger * t)
{
if(state == STATE_DISABLED || !t)
return;
int next, prev;
arrowUpBtn->Update(t);
arrowDownBtn->Update(t);
next = listOffset;
if(listChanged)
{
listChanged = false;
for(int i=0; i<PAGESIZE; ++i)
{
if(next >= 0)
{
if(optionBtn[i]->GetState() == STATE_DISABLED)
{
optionBtn[i]->SetVisible(true);
optionBtn[i]->SetState(STATE_DEFAULT);
}
optionTxt[i]->SetText(options->name[next]);
optionVal[i]->SetText(options->value[next]);
optionIndex[i] = next;
next = this->FindMenuItem(next, 1);
}
else
{
optionBtn[i]->SetVisible(false);
optionBtn[i]->SetState(STATE_DISABLED);
}
}
}
for(int i=0; i<PAGESIZE; ++i)
{
if(i != selectedItem && optionBtn[i]->GetState() == STATE_SELECTED)
optionBtn[i]->ResetState();
else if(focus && i == selectedItem && optionBtn[i]->GetState() == STATE_DEFAULT)
optionBtn[selectedItem]->SetState(STATE_SELECTED, t->chan);
int currChan = t->chan;
if(t->wpad->ir.valid && !optionBtn[i]->IsInside(t->wpad->ir.x, t->wpad->ir.y))
t->chan = -1;
optionBtn[i]->Update(t);
t->chan = currChan;
if(optionBtn[i]->GetState() == STATE_SELECTED)
selectedItem = i;
}
// pad/joystick navigation
if(!focus)
return; // skip navigation
if(t->Down() || arrowDownBtn->GetState() == STATE_CLICKED)
{
next = this->FindMenuItem(optionIndex[selectedItem], 1);
if(next >= 0)
{
if(selectedItem == PAGESIZE-1)
{
// move list down by 1
listOffset = this->FindMenuItem(listOffset, 1);
listChanged = true;
}
else if(optionBtn[selectedItem+1]->IsVisible())
{
optionBtn[selectedItem]->ResetState();
optionBtn[selectedItem+1]->SetState(STATE_SELECTED, t->chan);
++selectedItem;
}
}
arrowDownBtn->ResetState();
}
else if(t->Up() || arrowUpBtn->GetState() == STATE_CLICKED)
{
prev = this->FindMenuItem(optionIndex[selectedItem], -1);
if(prev >= 0)
{
if(selectedItem == 0)
{
// move list up by 1
listOffset = prev;
listChanged = true;
}
else
{
optionBtn[selectedItem]->ResetState();
optionBtn[selectedItem-1]->SetState(STATE_SELECTED, t->chan);
--selectedItem;
}
}
arrowUpBtn->ResetState();
}
if(updateCB)
updateCB(this);
}

View File

@ -0,0 +1,398 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_savebrowser.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
#include "../filebrowser.h"
/**
* Constructor for the GuiSaveBrowser class.
*/
GuiSaveBrowser::GuiSaveBrowser(int w, int h, SaveList * s, int a)
{
width = w;
height = h;
saves = s;
action = a;
selectable = true;
if(action == 0) // load
listOffset = 0;
else
listOffset = -2; // save - reserve -2 & -1 for new slots
selectedItem = 0;
focus = 0; // allow focus
trigA = new GuiTrigger;
trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
trig2 = new GuiTrigger;
trig2->SetSimpleTrigger(-1, WPAD_BUTTON_2, 0);
btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM);
btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM);
gameSave = new GuiImageData(button_gamesave_png);
gameSaveOver = new GuiImageData(button_gamesave_over_png);
gameSaveBlank = new GuiImageData(button_gamesave_blank_png);
scrollbar = new GuiImageData(scrollbar_png);
scrollbarImg = new GuiImage(scrollbar);
scrollbarImg->SetParent(this);
scrollbarImg->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
scrollbarImg->SetPosition(0, 30);
arrowDown = new GuiImageData(scrollbar_arrowdown_png);
arrowDownImg = new GuiImage(arrowDown);
arrowDownOver = new GuiImageData(scrollbar_arrowdown_over_png);
arrowDownOverImg = new GuiImage(arrowDownOver);
arrowUp = new GuiImageData(scrollbar_arrowup_png);
arrowUpImg = new GuiImage(arrowUp);
arrowUpOver = new GuiImageData(scrollbar_arrowup_over_png);
arrowUpOverImg = new GuiImage(arrowUpOver);
arrowUpBtn = new GuiButton(arrowUpImg->GetWidth(), arrowUpImg->GetHeight());
arrowUpBtn->SetParent(this);
arrowUpBtn->SetImage(arrowUpImg);
arrowUpBtn->SetImageOver(arrowUpOverImg);
arrowUpBtn->SetAlignment(ALIGN_RIGHT, ALIGN_TOP);
arrowUpBtn->SetSelectable(false);
arrowUpBtn->SetTrigger(trigA);
arrowUpBtn->SetSoundOver(btnSoundOver);
arrowUpBtn->SetSoundClick(btnSoundClick);
arrowDownBtn = new GuiButton(arrowDownImg->GetWidth(), arrowDownImg->GetHeight());
arrowDownBtn->SetParent(this);
arrowDownBtn->SetImage(arrowDownImg);
arrowDownBtn->SetImageOver(arrowDownOverImg);
arrowDownBtn->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
arrowDownBtn->SetSelectable(false);
arrowDownBtn->SetTrigger(trigA);
arrowDownBtn->SetSoundOver(btnSoundOver);
arrowDownBtn->SetSoundClick(btnSoundClick);
for(int i=0; i<SAVELISTSIZE; i++)
{
saveDate[i] = new GuiText(NULL, 18, (GXColor){0, 0, 0, 0xff});
saveDate[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
saveDate[i]->SetPosition(80,5);
saveTime[i] = new GuiText(NULL, 18, (GXColor){0, 0, 0, 0xff});
saveTime[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
saveTime[i]->SetPosition(80,27);
saveType[i] = new GuiText(NULL, 18, (GXColor){0, 0, 0, 0xff});
saveType[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
saveType[i]->SetPosition(80,50);
saveBgImg[i] = new GuiImage(gameSave);
saveBgOverImg[i] = new GuiImage(gameSaveOver);
savePreviewImg[i] = new GuiImage(gameSaveBlank);
savePreviewImg[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
savePreviewImg[i]->SetPosition(5,0);
saveBtn[i] = new GuiButton(saveBgImg[i]->GetWidth(),saveBgImg[i]->GetHeight());
saveBtn[i]->SetParent(this);
saveBtn[i]->SetLabel(saveDate[i], 0);
saveBtn[i]->SetLabel(saveTime[i], 1);
saveBtn[i]->SetLabel(saveType[i], 2);
saveBtn[i]->SetImage(saveBgImg[i]);
saveBtn[i]->SetImageOver(saveBgOverImg[i]);
saveBtn[i]->SetIcon(savePreviewImg[i]);
saveBtn[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
saveBtn[i]->SetPosition(257*(i % 2),87*(i>>1));
saveBtn[i]->SetTrigger(trigA);
saveBtn[i]->SetTrigger(trig2);
saveBtn[i]->SetState(STATE_DISABLED);
saveBtn[i]->SetEffectGrow();
saveBtn[i]->SetVisible(false);
saveBtn[i]->SetSoundOver(btnSoundOver);
saveBtn[i]->SetSoundClick(btnSoundClick);
saveBtnLastOver[i] = false;
}
saveBtn[0]->SetState(STATE_SELECTED, -1);
saveBtn[0]->SetVisible(true);
}
/**
* Destructor for the GuiSaveBrowser class.
*/
GuiSaveBrowser::~GuiSaveBrowser()
{
delete arrowUpBtn;
delete arrowDownBtn;
delete scrollbarImg;
delete arrowDownImg;
delete arrowDownOverImg;
delete arrowUpImg;
delete arrowUpOverImg;
delete gameSave;
delete gameSaveOver;
delete gameSaveBlank;
delete scrollbar;
delete arrowDown;
delete arrowDownOver;
delete arrowUp;
delete arrowUpOver;
delete btnSoundOver;
delete btnSoundClick;
delete trigA;
delete trig2;
for(int i=0; i<SAVELISTSIZE; i++)
{
delete saveBtn[i];
delete saveDate[i];
delete saveTime[i];
delete saveType[i];
delete saveBgImg[i];
delete saveBgOverImg[i];
delete savePreviewImg[i];
}
}
void GuiSaveBrowser::SetFocus(int f)
{
focus = f;
for(int i=0; i<SAVELISTSIZE; i++)
saveBtn[i]->ResetState();
if(f == 1 && selectedItem >= 0)
saveBtn[selectedItem]->SetState(STATE_SELECTED);
}
void GuiSaveBrowser::ResetState()
{
if(state != STATE_DISABLED)
{
state = STATE_DEFAULT;
stateChan = -1;
}
for(int i=0; i<SAVELISTSIZE; i++)
{
saveBtn[i]->ResetState();
}
}
int GuiSaveBrowser::GetClickedSave()
{
int found = -3;
for(int i=0; i<SAVELISTSIZE; i++)
{
if(saveBtn[i]->GetState() == STATE_CLICKED)
{
saveBtn[i]->SetState(STATE_SELECTED);
found = listOffset+i;
break;
}
}
return found;
}
/**
* Draw the button on screen
*/
void GuiSaveBrowser::Draw()
{
if(!this->IsVisible())
return;
for(int i=0; i<SAVELISTSIZE; i++)
saveBtn[i]->Draw();
scrollbarImg->Draw();
arrowUpBtn->Draw();
arrowDownBtn->Draw();
this->UpdateEffects();
}
void GuiSaveBrowser::Update(GuiTrigger * t)
{
if(state == STATE_DISABLED || !t)
return;
int i, len;
char savetext[50];
arrowUpBtn->Update(t);
arrowDownBtn->Update(t);
// pad/joystick navigation
if(!focus)
goto endNavigation; // skip navigation
if(selectedItem < 0) selectedItem = 0;
if(t->Right())
{
if(selectedItem == SAVELISTSIZE-1)
{
if(listOffset + SAVELISTSIZE < saves->length)
{
// move list down by 1 row
listOffset += 2;
selectedItem -= 1;
}
}
else if(saveBtn[selectedItem+1]->IsVisible())
{
saveBtn[selectedItem]->ResetState();
saveBtn[selectedItem+1]->SetState(STATE_SELECTED, t->chan);
selectedItem += 1;
}
}
else if(t->Left())
{
if(selectedItem == 0)
{
if((listOffset - 2 >= 0 && action == 0) ||
(listOffset >= 0 && action == 1))
{
// move list up by 1
listOffset -= 2;
selectedItem = SAVELISTSIZE-1;
}
}
else
{
selectedItem -= 1;
}
}
else if(t->Down() || arrowDownBtn->GetState() == STATE_CLICKED)
{
if(selectedItem >= SAVELISTSIZE-2)
{
if(listOffset + SAVELISTSIZE + 1 < saves->length)
{
listOffset += 2;
}
else if(listOffset + SAVELISTSIZE < saves->length)
{
listOffset += 2;
if(selectedItem == SAVELISTSIZE-1)
selectedItem -= 1;
}
}
else if(saveBtn[selectedItem+2]->IsVisible())
{
selectedItem += 2;
}
}
else if(t->Up() || arrowUpBtn->GetState() == STATE_CLICKED)
{
if(selectedItem < 2)
{
if((listOffset - 2 >= 0 && action == 0) ||
(listOffset >= 0 && action == 1))
{
// move list up by 1
listOffset -= 2;
}
}
else
{
selectedItem -= 2;
}
}
endNavigation:
if(arrowDownBtn->GetState() == STATE_CLICKED)
arrowDownBtn->ResetState();
if(arrowUpBtn->GetState() == STATE_CLICKED)
arrowUpBtn->ResetState();
for(i=0; i<SAVELISTSIZE; i++)
{
if(listOffset+i < 0 && action == 1)
{
saveDate[0]->SetText(NULL);
saveDate[1]->SetText(NULL);
saveTime[0]->SetText("New");
saveTime[1]->SetText("New");
saveType[0]->SetText("SRAM");
saveType[1]->SetText("Snapshot");
savePreviewImg[0]->SetImage(gameSaveBlank);
savePreviewImg[1]->SetImage(gameSaveBlank);
saveBtn[0]->SetVisible(true);
saveBtn[1]->SetVisible(true);
if(saveBtn[0]->GetState() == STATE_DISABLED)
saveBtn[0]->SetState(STATE_DEFAULT);
if(saveBtn[1]->GetState() == STATE_DISABLED)
saveBtn[1]->SetState(STATE_DEFAULT);
}
else if(listOffset+i < saves->length)
{
if(saveBtn[i]->GetState() == STATE_DISABLED || !saveBtn[i]->IsVisible())
{
saveBtn[i]->SetVisible(true);
saveBtn[i]->SetState(STATE_DEFAULT);
}
saveDate[i]->SetText(saves->date[listOffset+i]);
saveTime[i]->SetText(saves->time[listOffset+i]);
if(saves->type[listOffset+i] == FILE_SRAM)
sprintf(savetext, "SRAM");
else
sprintf(savetext, "Snapshot");
len = strlen(saves->filename[listOffset+i]);
if(len > 10 &&
((saves->filename[listOffset+i][len-8] == 'A' &&
saves->filename[listOffset+i][len-7] == 'u' &&
saves->filename[listOffset+i][len-6] == 't' &&
saves->filename[listOffset+i][len-5] == 'o') ||
saves->filename[listOffset+i][len-5] == '0')
)
{
strcat(savetext, " (Auto)");
}
saveType[i]->SetText(savetext);
if(saves->previewImg[listOffset+i] != NULL)
savePreviewImg[i]->SetImage(saves->previewImg[listOffset+i]);
else
savePreviewImg[i]->SetImage(gameSaveBlank);
}
else
{
saveBtn[i]->SetVisible(false);
saveBtn[i]->SetState(STATE_DISABLED);
}
if(i != selectedItem && saveBtn[i]->GetState() == STATE_SELECTED)
saveBtn[i]->ResetState();
else if(focus && i == selectedItem && saveBtn[i]->GetState() == STATE_DEFAULT)
saveBtn[selectedItem]->SetState(STATE_SELECTED, t->chan);
if(t->wpad->ir.valid)
{
if(!saveBtnLastOver[i] && saveBtn[i]->IsInside(t->wpad->ir.x, t->wpad->ir.y))
saveBtn[i]->ResetState();
saveBtnLastOver[i] = saveBtn[i]->IsInside(t->wpad->ir.x, t->wpad->ir.y);
}
saveBtn[i]->Update(t);
if(saveBtn[i]->GetState() == STATE_SELECTED)
selectedItem = i;
}
if(updateCB)
updateCB(this);
}

155
src/wii/gui/gui_sound.cpp Normal file
View File

@ -0,0 +1,155 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_sound.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
/**
* Constructor for the GuiSound class.
*/
GuiSound::GuiSound(const u8 * s, s32 l, int t)
{
sound = s;
length = l;
type = t;
voice = -1;
volume = 100;
loop = false;
}
/**
* Destructor for the GuiSound class.
*/
GuiSound::~GuiSound()
{
#ifndef NO_SOUND
if(type == SOUND_OGG)
StopOgg();
#endif
}
void GuiSound::Play()
{
#ifndef NO_SOUND
int vol;
switch(type)
{
case SOUND_PCM:
vol = 0.0255f*(volume*GCSettings.SFXVolume);
voice = ASND_GetFirstUnusedVoice();
if(voice >= 0)
ASND_SetVoice(voice, VOICE_STEREO_16BIT, 48000, 0,
(u8 *)sound, length, vol, vol, NULL);
break;
case SOUND_OGG:
voice = 0;
if(loop)
PlayOgg((char *)sound, length, 0, OGG_INFINITE_TIME);
else
PlayOgg((char *)sound, length, 0, OGG_ONE_TIME);
SetVolumeOgg(2.55f*(volume));
break;
}
#endif
}
void GuiSound::Stop()
{
#ifndef NO_SOUND
if(voice < 0)
return;
switch(type)
{
case SOUND_PCM:
ASND_StopVoice(voice);
break;
case SOUND_OGG:
StopOgg();
break;
}
#endif
}
void GuiSound::Pause()
{
#ifndef NO_SOUND
if(voice < 0)
return;
switch(type)
{
case SOUND_PCM:
ASND_PauseVoice(voice, 1);
break;
case SOUND_OGG:
PauseOgg(1);
break;
}
#endif
}
void GuiSound::Resume()
{
#ifndef NO_SOUND
if(voice < 0)
return;
switch(type)
{
case SOUND_PCM:
ASND_PauseVoice(voice, 0);
break;
case SOUND_OGG:
PauseOgg(0);
break;
}
#endif
}
bool GuiSound::IsPlaying()
{
if(ASND_StatusVoice(voice) == SND_WORKING || ASND_StatusVoice(voice) == SND_WAITING)
return true;
else
return false;
}
void GuiSound::SetVolume(int vol)
{
#ifndef NO_SOUND
volume = vol;
if(voice < 0)
return;
int newvol = 0.0255f*(volume*GCSettings.SFXVolume);
switch(type)
{
case SOUND_PCM:
ASND_ChangeVolumeVoice(voice, newvol, newvol);
break;
case SOUND_OGG:
SetVolumeOgg(2.55f*(volume));
break;
}
#endif
}
void GuiSound::SetLoop(bool l)
{
loop = l;
}

480
src/wii/gui/gui_text.cpp Normal file
View File

@ -0,0 +1,480 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_text.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
#include "../utils/gettext.h"
static GXColor presetColor = (GXColor){255, 255, 255, 255};
static int currentSize = 0;
static int presetSize = 0;
static int presetMaxWidth = 0;
static int presetAlignmentHor = 0;
static int presetAlignmentVert = 0;
static u16 presetStyle = 0;
#define TEXT_SCROLL_DELAY 8
#define TEXT_SCROLL_INITIAL_DELAY 6
/**
* Constructor for the GuiText class.
*/
GuiText::GuiText(const char * t, int s, GXColor c)
{
origText = NULL;
text = NULL;
size = s;
color = c;
alpha = c.a;
style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE;
maxWidth = 0;
wrap = false;
textDynNum = 0;
textScroll = SCROLL_NONE;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
alignmentHor = ALIGN_CENTRE;
alignmentVert = ALIGN_MIDDLE;
if(t)
{
origText = strdup(t);
text = charToWideChar(gettext(t));
}
for(int i=0; i < 20; i++)
textDyn[i] = NULL;
}
/**
* Constructor for the GuiText class, uses presets
*/
GuiText::GuiText(const char * t)
{
origText = NULL;
text = NULL;
size = presetSize;
color = presetColor;
alpha = presetColor.a;
style = presetStyle;
maxWidth = presetMaxWidth;
wrap = false;
textDynNum = 0;
textScroll = SCROLL_NONE;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
alignmentHor = presetAlignmentHor;
alignmentVert = presetAlignmentVert;
if(t)
{
origText = strdup(t);
text = charToWideChar(gettext(t));
}
for(int i=0; i < 20; i++)
textDyn[i] = NULL;
}
/**
* Destructor for the GuiText class.
*/
GuiText::~GuiText()
{
if(origText)
free(origText);
if(text)
delete[] text;
if(textDynNum > 0)
{
for(int i=0; i < textDynNum; i++)
if(textDyn[i])
delete[] textDyn[i];
}
}
void GuiText::SetText(const char * t)
{
if(origText)
free(origText);
if(text)
delete[] text;
if(textDynNum > 0)
{
for(int i=0; i < textDynNum; i++)
if(textDyn[i])
delete[] textDyn[i];
}
origText = NULL;
text = NULL;
textDynNum = 0;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
if(t)
{
origText = strdup(t);
text = charToWideChar(gettext(t));
}
}
void GuiText::SetWText(wchar_t * t)
{
if(origText)
free(origText);
if(text)
delete[] text;
if(textDynNum > 0)
{
for(int i=0; i < textDynNum; i++)
if(textDyn[i])
delete[] textDyn[i];
}
origText = NULL;
text = NULL;
textDynNum = 0;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
if(t)
text = wcsdup(t);
}
int GuiText::GetLength()
{
if(!text)
return 0;
return wcslen(text);
}
void GuiText::SetPresets(int sz, GXColor c, int w, u16 s, int h, int v)
{
presetSize = sz;
presetColor = c;
presetStyle = s;
presetMaxWidth = w;
presetAlignmentHor = h;
presetAlignmentVert = v;
}
void GuiText::SetFontSize(int s)
{
size = s;
}
void GuiText::SetMaxWidth(int width)
{
maxWidth = width;
for(int i=0; i < textDynNum; i++)
{
if(textDyn[i])
{
delete[] textDyn[i];
textDyn[i] = NULL;
}
}
textDynNum = 0;
}
int GuiText::GetTextWidth()
{
if(!text)
return 0;
if(currentSize != size)
{
ChangeFontSize(size);
if(!fontSystem[size])
fontSystem[size] = new FreeTypeGX(size);
currentSize = size;
}
return fontSystem[size]->getWidth(text);
}
void GuiText::SetWrap(bool w, int width)
{
wrap = w;
maxWidth = width;
for(int i=0; i < textDynNum; i++)
{
if(textDyn[i])
{
delete[] textDyn[i];
textDyn[i] = NULL;
}
}
textDynNum = 0;
}
void GuiText::SetScroll(int s)
{
if(textScroll == s)
return;
for(int i=0; i < textDynNum; i++)
{
if(textDyn[i])
{
delete[] textDyn[i];
textDyn[i] = NULL;
}
}
textDynNum = 0;
textScroll = s;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
}
void GuiText::SetColor(GXColor c)
{
color = c;
alpha = c.a;
}
void GuiText::SetStyle(u16 s)
{
style = s;
}
void GuiText::SetAlignment(int hor, int vert)
{
style = 0;
switch(hor)
{
case ALIGN_LEFT:
style |= FTGX_JUSTIFY_LEFT;
break;
case ALIGN_RIGHT:
style |= FTGX_JUSTIFY_RIGHT;
break;
default:
style |= FTGX_JUSTIFY_CENTER;
break;
}
switch(vert)
{
case ALIGN_TOP:
style |= FTGX_ALIGN_TOP;
break;
case ALIGN_BOTTOM:
style |= FTGX_ALIGN_BOTTOM;
break;
default:
style |= FTGX_ALIGN_MIDDLE;
break;
}
alignmentHor = hor;
alignmentVert = vert;
}
void GuiText::ResetText()
{
if(!origText)
return;
if(text)
delete[] text;
text = charToWideChar(gettext(origText));
for(int i=0; i < textDynNum; i++)
{
if(textDyn[i])
{
delete[] textDyn[i];
textDyn[i] = NULL;
}
}
textDynNum = 0;
currentSize = 0;
}
/**
* Draw the text on screen
*/
void GuiText::Draw()
{
if(!text)
return;
if(!this->IsVisible())
return;
GXColor c = color;
c.a = this->GetAlpha();
int newSize = size*this->GetScale();
if(newSize > MAX_FONT_SIZE)
newSize = MAX_FONT_SIZE;
if(newSize != currentSize)
{
ChangeFontSize(newSize);
if(!fontSystem[newSize])
fontSystem[newSize] = new FreeTypeGX(newSize);
currentSize = newSize;
}
if(maxWidth == 0)
{
fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), text, c, style);
this->UpdateEffects();
return;
}
u32 textlen = wcslen(text);
if(wrap)
{
if(textDynNum == 0)
{
u32 n = 0, ch = 0;
int linenum = 0;
int lastSpace = -1;
int lastSpaceIndex = -1;
while(ch < textlen && linenum < 20)
{
if(n == 0)
textDyn[linenum] = new wchar_t[textlen + 1];
textDyn[linenum][n] = text[ch];
textDyn[linenum][n+1] = 0;
if(text[ch] == ' ' || ch == textlen-1)
{
if(fontSystem[currentSize]->getWidth(textDyn[linenum]) > maxWidth)
{
if(lastSpace >= 0)
{
textDyn[linenum][lastSpaceIndex] = 0; // discard space, and everything after
ch = lastSpace; // go backwards to the last space
lastSpace = -1; // we have used this space
lastSpaceIndex = -1;
}
++linenum;
n = -1;
}
else if(ch == textlen-1)
{
++linenum;
}
}
if(text[ch] == ' ' && n >= 0)
{
lastSpace = ch;
lastSpaceIndex = n;
}
++ch;
++n;
}
textDynNum = linenum;
}
int lineheight = newSize + 6;
int voffset = 0;
if(alignmentVert == ALIGN_MIDDLE)
voffset = (lineheight >> 1) * (1-textDynNum);
int left = this->GetLeft();
int top = this->GetTop() + voffset;
for(int i=0; i < textDynNum; ++i)
fontSystem[currentSize]->drawText(left, top+i*lineheight, textDyn[i], c, style);
}
else
{
if(textDynNum == 0)
{
textDynNum = 1;
textDyn[0] = wcsdup(text);
int len = wcslen(textDyn[0]);
while(fontSystem[currentSize]->getWidth(textDyn[0]) > maxWidth)
textDyn[0][--len] = 0;
}
if(textScroll == SCROLL_HORIZONTAL)
{
if(fontSystem[currentSize]->getWidth(text) > maxWidth && (FrameTimer % textScrollDelay == 0))
{
if(textScrollInitialDelay)
{
--textScrollInitialDelay;
}
else
{
++textScrollPos;
if((u32)textScrollPos > textlen-1)
{
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
}
wcscpy(textDyn[0], &text[textScrollPos]);
u32 dynlen = wcslen(textDyn[0]);
if(dynlen+2 < textlen)
{
textDyn[0][dynlen] = ' ';
textDyn[0][dynlen+1] = ' ';
textDyn[0][dynlen+2] = 0;
dynlen += 2;
}
if(fontSystem[currentSize]->getWidth(textDyn[0]) > maxWidth)
{
while(fontSystem[currentSize]->getWidth(textDyn[0]) > maxWidth)
textDyn[0][--dynlen] = 0;
}
else
{
int i = 0;
while(fontSystem[currentSize]->getWidth(textDyn[0]) < maxWidth && dynlen+1 < textlen)
{
textDyn[0][dynlen] = text[i++];
textDyn[0][++dynlen] = 0;
}
if(fontSystem[currentSize]->getWidth(textDyn[0]) > maxWidth)
textDyn[0][dynlen-2] = 0;
else
textDyn[0][dynlen-1] = 0;
}
}
}
}
fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn[0], c, style);
}
this->UpdateEffects();
}

286
src/wii/gui/gui_trigger.cpp Normal file
View File

@ -0,0 +1,286 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_trigger.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
#include <ogc/lwp_watchdog.h>
#include <gctypes.h>
static u64 prev[4];
static u64 now[4];
static u32 delay[4];
/**
* Constructor for the GuiTrigger class.
*/
GuiTrigger::GuiTrigger()
{
chan = -1;
memset(&wpaddata, 0, sizeof(WPADData));
memset(&pad, 0, sizeof(PADData));
wpad = &wpaddata;
}
/**
* Destructor for the GuiTrigger class.
*/
GuiTrigger::~GuiTrigger()
{
}
/**
* Sets a simple trigger. Requires:
* - Element is selected
* - Trigger button is pressed
*/
void GuiTrigger::SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{
type = TRIGGER_SIMPLE;
chan = ch;
wpaddata.btns_d = wiibtns;
pad.btns_d = gcbtns;
}
/**
* Sets a held trigger. Requires:
* - Element is selected
* - Trigger button is pressed and held
*/
void GuiTrigger::SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{
type = TRIGGER_HELD;
chan = ch;
wpaddata.btns_h = wiibtns;
pad.btns_h = gcbtns;
}
/**
* Sets a button trigger. Requires:
* - Trigger button is pressed
*/
void GuiTrigger::SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{
type = TRIGGER_BUTTON_ONLY;
chan = ch;
wpaddata.btns_d = wiibtns;
pad.btns_d = gcbtns;
}
/**
* Sets a button trigger. Requires:
* - Trigger button is pressed
* - Parent window is in focus
*/
void GuiTrigger::SetButtonOnlyInFocusTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{
type = TRIGGER_BUTTON_ONLY_IN_FOCUS;
chan = ch;
wpaddata.btns_d = wiibtns;
pad.btns_d = gcbtns;
}
/****************************************************************************
* WPAD_Stick
*
* Get X/Y value from Wii Joystick (classic, nunchuk) input
***************************************************************************/
s8 GuiTrigger::WPAD_Stick(u8 stick, int axis)
{
#ifdef HW_RVL
float mag = 0.0;
float ang = 0.0;
switch (wpad->exp.type)
{
case WPAD_EXP_NUNCHUK:
case WPAD_EXP_GUITARHERO3:
if (stick == 0)
{
mag = wpad->exp.nunchuk.js.mag;
ang = wpad->exp.nunchuk.js.ang;
}
break;
case WPAD_EXP_CLASSIC:
if (stick == 0)
{
mag = wpad->exp.classic.ljs.mag;
ang = wpad->exp.classic.ljs.ang;
}
else
{
mag = wpad->exp.classic.rjs.mag;
ang = wpad->exp.classic.rjs.ang;
}
break;
default:
break;
}
/* calculate x/y value (angle need to be converted into radian) */
if (mag > 1.0) mag = 1.0;
else if (mag < -1.0) mag = -1.0;
double val;
if(axis == 0) // x-axis
val = mag * sin((PI * ang)/180.0f);
else // y-axis
val = mag * cos((PI * ang)/180.0f);
return (s8)(val * 128.0f);
#else
return 0;
#endif
}
s8 GuiTrigger::WPAD_StickX(u8 stick)
{
return WPAD_Stick(stick, 0);
}
s8 GuiTrigger::WPAD_StickY(u8 stick)
{
return WPAD_Stick(stick, 1);
}
bool GuiTrigger::Left()
{
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_UP : WPAD_BUTTON_LEFT;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_LEFT
|| pad.stickX < -PADCAL
|| WPAD_StickX(0) < -PADCAL)
{
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)
|| pad.btns_d & PAD_BUTTON_LEFT)
{
prev[chan] = gettime();
delay[chan] = SCROLL_DELAY_INITIAL; // reset scroll delay
return true;
}
now[chan] = gettime();
if(diff_usec(prev[chan], now[chan]) > delay[chan])
{
prev[chan] = now[chan];
if(delay[chan] == SCROLL_DELAY_INITIAL)
delay[chan] = SCROLL_DELAY_LOOP;
else if(delay[chan] > SCROLL_DELAY_DECREASE)
delay[chan] -= SCROLL_DELAY_DECREASE;
return true;
}
}
return false;
}
bool GuiTrigger::Right()
{
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_DOWN : WPAD_BUTTON_RIGHT;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_RIGHT
|| pad.stickX > PADCAL
|| WPAD_StickX(0) > PADCAL)
{
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)
|| pad.btns_d & PAD_BUTTON_RIGHT)
{
prev[chan] = gettime();
delay[chan] = SCROLL_DELAY_INITIAL; // reset scroll delay
return true;
}
now[chan] = gettime();
if(diff_usec(prev[chan], now[chan]) > delay[chan])
{
prev[chan] = now[chan];
if(delay[chan] == SCROLL_DELAY_INITIAL)
delay[chan] = SCROLL_DELAY_LOOP;
else if(delay[chan] > SCROLL_DELAY_DECREASE)
delay[chan] -= SCROLL_DELAY_DECREASE;
return true;
}
}
return false;
}
bool GuiTrigger::Up()
{
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_RIGHT : WPAD_BUTTON_UP;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP)
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_UP
|| pad.stickY > PADCAL
|| WPAD_StickY(0) > PADCAL)
{
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP)
|| pad.btns_d & PAD_BUTTON_UP)
{
prev[chan] = gettime();
delay[chan] = SCROLL_DELAY_INITIAL; // reset scroll delay
return true;
}
now[chan] = gettime();
if(diff_usec(prev[chan], now[chan]) > delay[chan])
{
prev[chan] = now[chan];
if(delay[chan] == SCROLL_DELAY_INITIAL)
delay[chan] = SCROLL_DELAY_LOOP;
else if(delay[chan] > SCROLL_DELAY_DECREASE)
delay[chan] -= SCROLL_DELAY_DECREASE;
return true;
}
}
return false;
}
bool GuiTrigger::Down()
{
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_LEFT : WPAD_BUTTON_DOWN;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_DOWN
|| pad.stickY < -PADCAL
|| WPAD_StickY(0) < -PADCAL)
{
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)
|| pad.btns_d & PAD_BUTTON_DOWN)
{
prev[chan] = gettime();
delay[chan] = SCROLL_DELAY_INITIAL; // reset scroll delay
return true;
}
now[chan] = gettime();
if(diff_usec(prev[chan], now[chan]) > delay[chan])
{
prev[chan] = now[chan];
if(delay[chan] == SCROLL_DELAY_INITIAL)
delay[chan] = SCROLL_DELAY_LOOP;
else if(delay[chan] > SCROLL_DELAY_DECREASE)
delay[chan] -= SCROLL_DELAY_DECREASE;
return true;
}
}
return false;
}

451
src/wii/gui/gui_window.cpp Normal file
View File

@ -0,0 +1,451 @@
/****************************************************************************
* libwiigui
*
* Tantric 2009
*
* gui_window.cpp
*
* GUI class definitions
***************************************************************************/
#include "gui.h"
GuiWindow::GuiWindow()
{
width = 0;
height = 0;
focus = 0; // allow focus
}
GuiWindow::GuiWindow(int w, int h)
{
width = w;
height = h;
focus = 0; // allow focus
}
GuiWindow::~GuiWindow()
{
}
void GuiWindow::Append(GuiElement* e)
{
if (e == NULL)
return;
Remove(e);
_elements.push_back(e);
e->SetParent(this);
}
void GuiWindow::Insert(GuiElement* e, u32 index)
{
if (e == NULL || index > (_elements.size() - 1))
return;
Remove(e);
_elements.insert(_elements.begin()+index, e);
e->SetParent(this);
}
void GuiWindow::Remove(GuiElement* e)
{
if (e == NULL)
return;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
if(e == _elements.at(i))
{
_elements.erase(_elements.begin()+i);
break;
}
}
}
void GuiWindow::RemoveAll()
{
_elements.clear();
}
bool GuiWindow::Find(GuiElement* e)
{
if (e == NULL)
return false;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
if(e == _elements.at(i))
return true;
return false;
}
GuiElement* GuiWindow::GetGuiElementAt(u32 index) const
{
if (index >= _elements.size())
return NULL;
return _elements.at(index);
}
u32 GuiWindow::GetSize()
{
return _elements.size();
}
void GuiWindow::Draw()
{
if(_elements.size() == 0 || !this->IsVisible())
return;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
try { _elements.at(i)->Draw(); }
catch (const std::exception& e) { }
}
this->UpdateEffects();
if(parentElement && state == STATE_DISABLED)
Menu_DrawRectangle(0,0,screenwidth,screenheight,(GXColor){0xbe, 0xca, 0xd5, 0x70},1);
}
void GuiWindow::DrawTooltip()
{
if(_elements.size() == 0 || !this->IsVisible())
return;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; i++)
{
try { _elements.at(i)->DrawTooltip(); }
catch (const std::exception& e) { }
}
}
void GuiWindow::ResetState()
{
if(state != STATE_DISABLED)
state = STATE_DEFAULT;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
try { _elements.at(i)->ResetState(); }
catch (const std::exception& e) { }
}
}
void GuiWindow::SetState(int s)
{
state = s;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
try { _elements.at(i)->SetState(s); }
catch (const std::exception& e) { }
}
}
void GuiWindow::SetVisible(bool v)
{
visible = v;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
try { _elements.at(i)->SetVisible(v); }
catch (const std::exception& e) { }
}
}
void GuiWindow::SetFocus(int f)
{
focus = f;
if(f == 1)
this->MoveSelectionVert(1);
else
this->ResetState();
}
void GuiWindow::ChangeFocus(GuiElement* e)
{
if(parentElement)
return; // this is only intended for the main window
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
if(e == _elements.at(i))
_elements.at(i)->SetFocus(1);
else if(_elements.at(i)->IsFocused() == 1)
_elements.at(i)->SetFocus(0);
}
}
void GuiWindow::ToggleFocus(GuiTrigger * t)
{
if(parentElement)
return; // this is only intended for the main window
int found = -1;
int newfocus = -1;
int i;
int elemSize = _elements.size();
// look for currently in focus element
for (i = 0; i < elemSize; ++i)
{
try
{
if(_elements.at(i)->IsFocused() == 1)
{
found = i;
break;
}
}
catch (const std::exception& e) { }
}
// element with focus not found, try to give focus
if(found == -1)
{
for (i = 0; i < elemSize; ++i)
{
try
{
if(_elements.at(i)->IsFocused() == 0 && _elements.at(i)->GetState() != STATE_DISABLED) // focus is possible (but not set)
{
_elements.at(i)->SetFocus(1); // give this element focus
break;
}
}
catch (const std::exception& e) { }
}
}
// change focus
else if(t->wpad->btns_d & (WPAD_BUTTON_1 | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)
|| t->pad.btns_d & PAD_BUTTON_B)
{
for (i = found; i < elemSize; ++i)
{
try
{
if(_elements.at(i)->IsFocused() == 0 && _elements.at(i)->GetState() != STATE_DISABLED) // focus is possible (but not set)
{
newfocus = i;
_elements.at(i)->SetFocus(1); // give this element focus
_elements.at(found)->SetFocus(0); // disable focus on other element
break;
}
}
catch (const std::exception& e) { }
}
if(newfocus == -1)
{
for (i = 0; i < found; ++i)
{
try
{
if(_elements.at(i)->IsFocused() == 0 && _elements.at(i)->GetState() != STATE_DISABLED) // focus is possible (but not set)
{
_elements.at(i)->SetFocus(1); // give this element focus
_elements.at(found)->SetFocus(0); // disable focus on other element
break;
}
}
catch (const std::exception& e) { }
}
}
}
}
int GuiWindow::GetSelected()
{
// find selected element
int found = -1;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
try
{
if(_elements.at(i)->GetState() == STATE_SELECTED)
{
found = int(i);
break;
}
}
catch (const std::exception& e) { }
}
return found;
}
// set element to left/right as selected
// there's probably a more clever way to do this, but this way works
void GuiWindow::MoveSelectionHor(int dir)
{
int found = -1;
u16 left = 0;
u16 top = 0;
u32 i;
u32 elemSize = _elements.size();
int selected = this->GetSelected();
if(selected >= 0)
{
left = _elements.at(selected)->GetLeft();
top = _elements.at(selected)->GetTop();
}
// look for a button on the same row, to the left/right
for (i = 0; i < elemSize; ++i)
{
try
{
if(_elements.at(i)->IsSelectable())
{
if(_elements.at(i)->GetLeft()*dir > left*dir && _elements.at(i)->GetTop() == top)
{
if(found == -1)
found = int(i);
else if(_elements.at(i)->GetLeft()*dir < _elements.at(found)->GetLeft()*dir)
found = int(i); // this is a better match
}
}
}
catch (const std::exception& e) { }
}
if(found >= 0)
goto matchfound;
// match still not found, let's try the first button in the next row
for (i = 0; i < elemSize; ++i)
{
try
{
if(_elements.at(i)->IsSelectable())
{
if(_elements.at(i)->GetTop()*dir > top*dir)
{
if(found == -1)
found = i;
else if(_elements.at(i)->GetTop()*dir < _elements.at(found)->GetTop()*dir)
found = i; // this is a better match
else if(_elements.at(i)->GetTop()*dir == _elements.at(found)->GetTop()*dir
&&
_elements.at(i)->GetLeft()*dir < _elements.at(found)->GetLeft()*dir)
found = i; // this is a better match
}
}
}
catch (const std::exception& e) { }
}
// match found
matchfound:
if(found >= 0)
{
_elements.at(found)->SetState(STATE_SELECTED);
if(selected >= 0)
_elements.at(selected)->ResetState();
}
}
void GuiWindow::MoveSelectionVert(int dir)
{
int found = -1;
u16 left = 0;
u16 top = 0;
int selected = this->GetSelected();
if(selected >= 0)
{
left = _elements.at(selected)->GetLeft();
top = _elements.at(selected)->GetTop();
}
// look for a button above/below, with the least horizontal difference
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
try
{
if(_elements.at(i)->IsSelectable())
{
if(_elements.at(i)->GetTop()*dir > top*dir)
{
if(found == -1)
found = i;
else if(_elements.at(i)->GetTop()*dir < _elements.at(found)->GetTop()*dir)
found = i; // this is a better match
else if(_elements.at(i)->GetTop()*dir == _elements.at(found)->GetTop()*dir
&&
abs(_elements.at(i)->GetLeft() - left) <
abs(_elements.at(found)->GetLeft() - left))
found = i;
}
}
}
catch (const std::exception& e) { }
}
if(found >= 0)
goto matchfound;
// match found
matchfound:
if(found >= 0)
{
_elements.at(found)->SetState(STATE_SELECTED);
if(selected >= 0)
_elements.at(selected)->ResetState();
}
}
void GuiWindow::ResetText()
{
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; i++)
{
try { _elements.at(i)->ResetText(); }
catch (const std::exception& e) { }
}
}
void GuiWindow::Update(GuiTrigger * t)
{
if(_elements.size() == 0 || (state == STATE_DISABLED && parentElement))
return;
u32 elemSize = _elements.size();
for (u32 i = 0; i < elemSize; ++i)
{
try { _elements.at(i)->Update(t); }
catch (const std::exception& e) { }
}
this->ToggleFocus(t);
if(focus) // only send actions to this window if it's in focus
{
// pad/joystick navigation
if(t->Right())
this->MoveSelectionHor(1);
else if(t->Left())
this->MoveSelectionHor(-1);
else if(t->Down())
this->MoveSelectionVert(1);
else if(t->Up())
this->MoveSelectionVert(-1);
}
if(updateCB)
updateCB(this);
}

BIN
src/wii/images/battery.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

BIN
src/wii/images/bg_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

BIN
src/wii/images/button.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
src/wii/images/icon_dvd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

BIN
src/wii/images/icon_sd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Some files were not shown because too many files have changed in this diff Show More