- 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
27
Makefile
@ -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
|
||||
|
@ -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
|
2387
docs/changes.txt
@ -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.
|
@ -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
|
339
docs/gpl-2.0.txt
@ -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.
|
@ -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!
|
||||
|
||||
|
@ -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 “better C” 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("Joypad1 A"), 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>
|
||||
S9xMainLoop();<br>
|
||||
MyReportButttons();<br>
|
||||
}</code>
|
||||
</p>
|
||||
<p>
|
||||
<code>void MyReportButtons (void)<br>
|
||||
{<br>
|
||||
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 “switch-on” except the S-RAM area is preserved (“hardware reset”). 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 “software reset” 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 “q” 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(&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>
|
@ -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.
|
@ -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.
|
@ -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
After Width: | Height: | Size: 7.2 KiB |
10
executables/meta.xml
Normal 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>
|
@ -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];
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
141
src/wii/freeze.cpp
Normal 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
@ -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
@ -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
@ -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
357
src/wii/gui/gui_button.cpp
Normal 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
@ -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;
|
||||
}
|
457
src/wii/gui/gui_filebrowser.cpp
Normal 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
@ -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();
|
||||
}
|
51
src/wii/gui/gui_imagedata.cpp
Normal 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;
|
||||
}
|
372
src/wii/gui/gui_keyboard.cpp
Normal 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);
|
||||
}
|
||||
}
|
366
src/wii/gui/gui_optionbrowser.cpp
Normal 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);
|
||||
}
|
398
src/wii/gui/gui_savebrowser.cpp
Normal 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
@ -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
@ -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
@ -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
@ -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
After Width: | Height: | Size: 216 B |
BIN
src/wii/images/battery_bar.png
Normal file
After Width: | Height: | Size: 145 B |
BIN
src/wii/images/battery_red.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
src/wii/images/bg_bottom.png
Normal file
After Width: | Height: | Size: 838 B |
BIN
src/wii/images/bg_game_selection.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/wii/images/bg_game_selection_entry.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
src/wii/images/bg_options.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/wii/images/bg_options_entry.png
Normal file
After Width: | Height: | Size: 299 B |
BIN
src/wii/images/bg_top.png
Normal file
After Width: | Height: | Size: 771 B |
BIN
src/wii/images/button.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/wii/images/button_arrow_down.png
Normal file
After Width: | Height: | Size: 792 B |
BIN
src/wii/images/button_arrow_down_over.png
Normal file
After Width: | Height: | Size: 764 B |
BIN
src/wii/images/button_arrow_left.png
Normal file
After Width: | Height: | Size: 842 B |
BIN
src/wii/images/button_arrow_left_over.png
Normal file
After Width: | Height: | Size: 776 B |
BIN
src/wii/images/button_arrow_right.png
Normal file
After Width: | Height: | Size: 821 B |
BIN
src/wii/images/button_arrow_right_over.png
Normal file
After Width: | Height: | Size: 775 B |
BIN
src/wii/images/button_arrow_up.png
Normal file
After Width: | Height: | Size: 746 B |
BIN
src/wii/images/button_arrow_up_over.png
Normal file
After Width: | Height: | Size: 710 B |
BIN
src/wii/images/button_gamesave.png
Normal file
After Width: | Height: | Size: 549 B |
BIN
src/wii/images/button_gamesave_blank.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/wii/images/button_gamesave_over.png
Normal file
After Width: | Height: | Size: 546 B |
BIN
src/wii/images/button_large.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/wii/images/button_large_over.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
src/wii/images/button_long.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/wii/images/button_long_over.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/wii/images/button_over.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/wii/images/button_prompt.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/wii/images/button_prompt_over.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/wii/images/button_short.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/wii/images/button_short_over.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/wii/images/button_small.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/wii/images/button_small_over.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/wii/images/credits_box.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
src/wii/images/dialogue_box.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
src/wii/images/icon_dvd.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/wii/images/icon_folder.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/wii/images/icon_game_cheats.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
src/wii/images/icon_game_controllers.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/wii/images/icon_game_load.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
src/wii/images/icon_game_reset.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/wii/images/icon_game_save.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
src/wii/images/icon_game_settings.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/wii/images/icon_home.png
Normal file
After Width: | Height: | Size: 294 B |
BIN
src/wii/images/icon_sd.png
Normal file
After Width: | Height: | Size: 644 B |
BIN
src/wii/images/icon_settings.png
Normal file
After Width: | Height: | Size: 434 B |
BIN
src/wii/images/icon_settings_classic.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
src/wii/images/icon_settings_file.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
src/wii/images/icon_settings_gamecube.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
src/wii/images/icon_settings_justifier.png
Normal file
After Width: | Height: | Size: 7.4 KiB |