mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-20 12:41:39 +02:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9fd379613a | ||
|
aabf52d678 | ||
|
c9ca01fe20 | ||
|
becf122aaa | ||
|
1e130d7872 | ||
|
c57c733d7d | ||
|
e41aa25887 | ||
|
435f7d4371 | ||
|
a1980fab09 | ||
|
ebb234ba5f |
63
license.txt
Normal file
63
license.txt
Normal file
@@ -0,0 +1,63 @@
|
||||
bsnes (TM) Open Source Reference License
|
||||
Copyright (C) 2004 - 2007 byuu
|
||||
All rights reserved
|
||||
|
||||
1. Definitions
|
||||
|
||||
The terms "reproduce", "reproduction", "distribute" and "distribution" have the
|
||||
same meaning here as under U.S. copyright law.
|
||||
|
||||
"The software" means this software package as a whole, including, but not
|
||||
limited to, this license, binaries, source code, documentation, and data.
|
||||
|
||||
"You" means the licensee of the software.
|
||||
|
||||
"The licensor" means the copyright holder of the software, byuu.
|
||||
|
||||
2. Grant of Rights
|
||||
|
||||
Subject to the terms of this license, the licensor grants you a
|
||||
non-transferable, non-exclusive, worldwide, royalty-free copyright license to
|
||||
reproduce the software for non-commercial use only, provided the software
|
||||
remains unmodified, and there is no charge for the software itself, its' use,
|
||||
nor for the medium upon which the software is distributed. The reproduction of
|
||||
modified or derivative works of the software is strictly prohibited, except when
|
||||
transmitted solely to the licensor.
|
||||
|
||||
3. Limitations
|
||||
|
||||
This license does not grant you any rights to use the licensor's name, logo or
|
||||
trademarks.
|
||||
|
||||
The software is provided "as is", and any express or implied warranties,
|
||||
including, but not limited to, the implied warranties of merchantability and
|
||||
fitness for a particular purpose are disclaimed. In no event shall the licensor
|
||||
be liable for any direct, indirect, incidental, special, exemplary, or
|
||||
consequential damages (including, but not limited to, procurement of substitute
|
||||
goods or services; loss of use, data, or profits; or business interruption)
|
||||
however caused and on any theory of liability, whether in contract, strict
|
||||
liability, or tort (including negligence or otherwise) arising in any way out of
|
||||
the use of the software, even if advised of the possibility of such damage.
|
||||
|
||||
In the event that this license is determined to be invalid or unenforceable, the
|
||||
Grant of Rights will become null and void, and no rights shall be granted to the
|
||||
licensee, within the scope of U.S. copyright law.
|
||||
|
||||
4. Exemptions
|
||||
|
||||
The software includes the work of other copyright holders, which is licensed
|
||||
under different agreements, and exempt from this license. Below is a complete
|
||||
list of all such software, and their respective copyright holders and licenses.
|
||||
Further, respective source code files are labeled with their correct licensing
|
||||
information in the header. The lack of such a header indicates said file falls
|
||||
under the bsnes license.
|
||||
|
||||
HQ2x Filter, author: MaxST, license: LGPL
|
||||
JMA, author: NSRT Team, license: GPL (*)
|
||||
libco, author: byuu, license: public domain
|
||||
libui, author: byuu, license: public domain
|
||||
NTSC Filter, author: blargg, license: LGPL
|
||||
S-DD1, author: Andreas Naive, license: public domain
|
||||
zlib, license: zlib license
|
||||
|
||||
(*) bsnes has received an exemption from the copyright holder to use this work.
|
97
readme.txt
Normal file
97
readme.txt
Normal file
@@ -0,0 +1,97 @@
|
||||
bsnes
|
||||
Version 0.024
|
||||
Author: byuu
|
||||
|
||||
--------
|
||||
General:
|
||||
--------
|
||||
bsnes is a Super Nintendo / Super Famicom emulator that began on
|
||||
October 14th, 2004.
|
||||
|
||||
The latest version can be downloaded from:
|
||||
http://byuu.org/
|
||||
|
||||
Please see license.txt for important licensing information.
|
||||
|
||||
--------------
|
||||
Shortcut Keys:
|
||||
--------------
|
||||
Esc - Toggle menubar visibility
|
||||
F11 - Toggle fullscreen
|
||||
|
||||
------------------
|
||||
Known Limitations:
|
||||
------------------
|
||||
S-CPU
|
||||
- Invalid DMA / HDMA transfers not fully emulated
|
||||
- Multiply / Divide register delays not implemented
|
||||
|
||||
S-PPU
|
||||
- Uses scanline-based renderer. This is very inaccurate, but few (if any)
|
||||
games rely on mid-scanline writes to function correctly
|
||||
- Does not support FirstSprite+Y priority
|
||||
- OAM / CGRAM accesses during active display not supported correctly
|
||||
- RTO flags are not calculated on frames that are skipped when frameskipping
|
||||
is enabled. This provides a major speedup, however it will cause in issues
|
||||
in games that test these flags, eg the SNES Test Program Electronics Test.
|
||||
Turning frameskipping off will allow RTO flag calculation on every frame
|
||||
|
||||
Hardware Bugs
|
||||
- S-CPU.r1 HDMA crashing bug not emulated
|
||||
- S-CPU<>S-SMP communication bus conflicts not emulated
|
||||
|
||||
---------------------
|
||||
Unsupported Hardware:
|
||||
---------------------
|
||||
SA-1
|
||||
Coprocessor used in many popular games, including:
|
||||
- Dragon Ball Z Hyper Dimension
|
||||
- Kirby Super Star
|
||||
- Kirby's Dreamland 3
|
||||
- Marvelous
|
||||
- SD Gundam G-NEXT
|
||||
- Super Mario RPG
|
||||
|
||||
Super FX
|
||||
Coprocessor used in many popular games, including:
|
||||
- Doom
|
||||
- Star Fox
|
||||
- Star Fox 2 (unreleased beta)
|
||||
- Super Mario World 2: Yoshi's Island
|
||||
|
||||
SPC7110
|
||||
Coprocessor used only by the following games:
|
||||
- Far East of Eden Zero
|
||||
- Far East of Eden Zero: Shounen Jump no Shou
|
||||
- Momotarou Densetsu Happy
|
||||
- Super Power League 4
|
||||
|
||||
DSP-3
|
||||
Coprocessor used only by SD Gundam GX
|
||||
|
||||
DSP-4
|
||||
Coprocessor used only by Top Gear 3000
|
||||
|
||||
ST011
|
||||
SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita
|
||||
|
||||
ST018
|
||||
SETA RISC CPU used only by Quick-move Shogi Match with Nidan Rank-holder Morita 2
|
||||
|
||||
BS-X (Broadcast Satellite)
|
||||
Add-on unit sold only in Japan that played specially-made games that were
|
||||
downloaded via satellite
|
||||
|
||||
BS-X Flashcart
|
||||
Flash cartridge used by BS-X, as well as some standalone games by Asciisoft
|
||||
|
||||
Super Gameboy
|
||||
Cartridge passthrough used for playing Gameboy games
|
||||
|
||||
------------------------
|
||||
Unsupported Controllers:
|
||||
------------------------
|
||||
Mouse
|
||||
Super Scope
|
||||
Justifier
|
||||
Multitap (4-port and 5-port)
|
64
src/Makefile
64
src/Makefile
@@ -13,7 +13,7 @@ endif
|
||||
ifeq ($(PLATFORM),x-gcc-lui)
|
||||
OS = unix
|
||||
CC = gcc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0`
|
||||
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0`
|
||||
AS = nasm
|
||||
ASFLAGS = -f elf
|
||||
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
|
||||
@@ -24,7 +24,7 @@ endif
|
||||
ifeq ($(PLATFORM),x-gcc-lui-x64)
|
||||
OS = unix
|
||||
CC = gcc
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_LUI `pkg-config --cflags gtk+-2.0`
|
||||
CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_LUI `pkg-config --cflags gtk+-2.0`
|
||||
AS = yasm
|
||||
ASFLAGS = -f elf64
|
||||
LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao
|
||||
@@ -38,7 +38,7 @@ CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
@@ -49,7 +49,7 @@ CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
LINK = /link /PGD:bsnes.pgd /LTCG:PGINSTRUMENT
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
@@ -61,12 +61,34 @@ CC = cl
|
||||
CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib
|
||||
LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
LINK = /link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-mingw-lui)
|
||||
OS = win
|
||||
CC = mingw32-gcc
|
||||
CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),win-mingw4-lui)
|
||||
OS = win
|
||||
CC = mingw32-gcc-sjlj
|
||||
CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI
|
||||
AS = nasm
|
||||
ASFLAGS = -f win32 -DWIN32
|
||||
LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32
|
||||
LIBCO = libco_x86
|
||||
LIBUI = libui_win
|
||||
endif
|
||||
|
||||
#####################################
|
||||
### compiler / assembler switches ###
|
||||
#####################################
|
||||
@@ -79,6 +101,22 @@ CARGS = -c $< -o $@
|
||||
DEFINE = -D
|
||||
endif
|
||||
|
||||
ifeq ($(CC),mingw32-gcc)
|
||||
OUT = -obsnes
|
||||
CPP = mingw32-g++
|
||||
OBJ = o
|
||||
CARGS = -c $< -o $@
|
||||
DEFINE = -D
|
||||
endif
|
||||
|
||||
ifeq ($(CC),mingw32-gcc-sjlj)
|
||||
OUT = -obsnes
|
||||
CPP = mingw32-g++-sjlj
|
||||
OBJ = o
|
||||
CARGS = -c $< -o $@
|
||||
DEFINE = -D
|
||||
endif
|
||||
|
||||
ifeq ($(CC),cl)
|
||||
OUT = /Febsnes
|
||||
CPP = cl
|
||||
@@ -106,7 +144,6 @@ endif
|
||||
ifeq ($(OS),win)
|
||||
OUT := $(OUT).exe
|
||||
RM = del
|
||||
LIBS += kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib
|
||||
endif
|
||||
|
||||
####################################
|
||||
@@ -118,7 +155,7 @@ OBJECTS = main.$(OBJ) $(LIBCO).$(OBJ) $(LIBUI).$(OBJ) \
|
||||
reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) bmemory.$(OBJ) \
|
||||
cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \
|
||||
bppu.$(OBJ) snes.$(OBJ) srtc.$(OBJ) sdd1.$(OBJ) c4.$(OBJ) dsp1.$(OBJ) \
|
||||
dsp2.$(OBJ) obc1.$(OBJ)
|
||||
dsp2.$(OBJ) obc1.$(OBJ) st010.$(OBJ)
|
||||
|
||||
ifeq ($(GZIP_SUPPORT),true)
|
||||
OBJECTS += adler32.$(OBJ) compress.$(OBJ) crc32.$(OBJ) deflate.$(OBJ) \
|
||||
@@ -222,12 +259,13 @@ snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* sne
|
||||
#####################
|
||||
### special chips ###
|
||||
#####################
|
||||
srtc.$(OBJ): chip/srtc/srtc.cpp chip/srtc/*
|
||||
sdd1.$(OBJ): chip/sdd1/sdd1.cpp chip/sdd1/*
|
||||
c4.$(OBJ) : chip/c4/c4.cpp chip/c4/*
|
||||
dsp1.$(OBJ): chip/dsp1/dsp1.cpp chip/dsp1/*
|
||||
dsp2.$(OBJ): chip/dsp2/dsp2.cpp chip/dsp2/*
|
||||
obc1.$(OBJ): chip/obc1/obc1.cpp chip/obc1/*
|
||||
srtc.$(OBJ) : chip/srtc/srtc.cpp chip/srtc/*
|
||||
sdd1.$(OBJ) : chip/sdd1/sdd1.cpp chip/sdd1/*
|
||||
c4.$(OBJ) : chip/c4/c4.cpp chip/c4/*
|
||||
dsp1.$(OBJ) : chip/dsp1/dsp1.cpp chip/dsp1/*
|
||||
dsp2.$(OBJ) : chip/dsp2/dsp2.cpp chip/dsp2/*
|
||||
obc1.$(OBJ) : chip/obc1/obc1.cpp chip/obc1/*
|
||||
st010.$(OBJ): chip/st010/st010.cpp chip/st010/*
|
||||
|
||||
############
|
||||
### zlib ###
|
||||
|
11
src/base.h
11
src/base.h
@@ -1,4 +1,4 @@
|
||||
#define BSNES_VERSION "0.020"
|
||||
#define BSNES_VERSION "0.024"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define MEMCORE bMemBus
|
||||
@@ -31,18 +31,17 @@
|
||||
#error "unsupported processor"
|
||||
#endif
|
||||
|
||||
#include "lib/libinterp.h"
|
||||
#include "lib/libfunctor.h"
|
||||
#include "lib/libsort.h"
|
||||
#include "lib/libarray.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libfile.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
//platform-specific global functions
|
||||
void alert(char*, ...);
|
||||
void dprintf(char*, ...);
|
||||
void dprintf(uint, char*, ...);
|
||||
void alert(const char*, ...);
|
||||
void dprintf(const char*, ...);
|
||||
void dprintf(uint, const char*, ...);
|
||||
|
||||
namespace source {
|
||||
enum {
|
||||
|
@@ -15,12 +15,13 @@ void Cartridge::load_begin(uint cart_type) {
|
||||
|
||||
info.type = cart_type;
|
||||
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.c4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
info.obc1 = false;
|
||||
info.st010 = false;
|
||||
|
||||
info.dsp1_mapper = 0;
|
||||
|
||||
|
@@ -87,6 +87,7 @@ struct {
|
||||
bool dsp1;
|
||||
bool dsp2;
|
||||
bool obc1;
|
||||
bool st010;
|
||||
|
||||
uint dsp1_mapper;
|
||||
|
||||
|
@@ -69,6 +69,10 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE];
|
||||
info.obc1 = true;
|
||||
}
|
||||
|
||||
if(mapper == 0x30 && rom_type == 0xf6) {
|
||||
info.st010 = true;
|
||||
}
|
||||
|
||||
info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1;
|
||||
|
||||
if(rom[info.header_index + RAM_SIZE] & 7) {
|
||||
|
@@ -1,3 +1,4 @@
|
||||
@make -r PLATFORM=win-visualc-lui
|
||||
::@make -r PLATFORM=win-visualc-lui
|
||||
@make -r PLATFORM=win-visualc-lui GZIP_SUPPORT=true JMA_SUPPORT=true
|
||||
@move bsnes.exe ../bsnes.exe>nul
|
||||
@pause
|
@@ -43,10 +43,10 @@ uint8 b = (addr >> 16) & 0xff;
|
||||
uint8 SDD1::mmio_read(uint16 addr) {
|
||||
switch(addr) {
|
||||
//>>20 == 0x100000 == 1mb
|
||||
case 0x4804:return (sdd1.index[0] >> 20) & 7;
|
||||
case 0x4805:return (sdd1.index[1] >> 20) & 7;
|
||||
case 0x4806:return (sdd1.index[2] >> 20) & 7;
|
||||
case 0x4807:return (sdd1.index[3] >> 20) & 7;
|
||||
case 0x4804: return (sdd1.index[0] >> 20) & 7;
|
||||
case 0x4805: return (sdd1.index[1] >> 20) & 7;
|
||||
case 0x4806: return (sdd1.index[2] >> 20) & 7;
|
||||
case 0x4807: return (sdd1.index[3] >> 20) & 7;
|
||||
}
|
||||
|
||||
return r_cpu->regs.mdr;
|
||||
@@ -60,10 +60,10 @@ void SDD1::mmio_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
break;
|
||||
//<<20 == 0x100000 == 1mb
|
||||
case 0x4804:sdd1.index[0] = (data & 7) << 20;break;
|
||||
case 0x4805:sdd1.index[1] = (data & 7) << 20;break;
|
||||
case 0x4806:sdd1.index[2] = (data & 7) << 20;break;
|
||||
case 0x4807:sdd1.index[3] = (data & 7) << 20;break;
|
||||
case 0x4804: sdd1.index[0] = (data & 7) << 20; break;
|
||||
case 0x4805: sdd1.index[1] = (data & 7) << 20; break;
|
||||
case 0x4806: sdd1.index[2] = (data & 7) << 20; break;
|
||||
case 0x4807: sdd1.index[3] = (data & 7) << 20; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
86
src/chip/st010/st010.cpp
Normal file
86
src/chip/st010/st010.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#include "../../base.h"
|
||||
#include "st010_data.h"
|
||||
#include "st010_op.cpp"
|
||||
|
||||
ST010 *st010;
|
||||
|
||||
int16 ST010::sin(int16 theta) {
|
||||
return sin_table[(theta >> 8) & 0xff];
|
||||
}
|
||||
|
||||
int16 ST010::cos(int16 theta) {
|
||||
return sin_table[((theta + 0x4000) >> 8) & 0xff];
|
||||
}
|
||||
|
||||
uint8 ST010::readb(uint16 addr) {
|
||||
return ram[addr & 0xfff];
|
||||
}
|
||||
|
||||
uint16 ST010::readw(uint16 addr) {
|
||||
return (readb(addr + 0) << 0) |
|
||||
(readb(addr + 1) << 8);
|
||||
}
|
||||
|
||||
uint32 ST010::readd(uint16 addr) {
|
||||
return (readb(addr + 0) << 0) |
|
||||
(readb(addr + 1) << 8) |
|
||||
(readb(addr + 2) << 16) |
|
||||
(readb(addr + 3) << 24);
|
||||
}
|
||||
|
||||
void ST010::writeb(uint16 addr, uint8 data) {
|
||||
ram[addr & 0xfff] = data;
|
||||
}
|
||||
|
||||
void ST010::writew(uint16 addr, uint16 data) {
|
||||
writeb(addr + 0, data);
|
||||
writeb(addr + 1, data >> 8);
|
||||
}
|
||||
|
||||
void ST010::writed(uint16 addr, uint32 data) {
|
||||
writeb(addr + 0, data);
|
||||
writeb(addr + 1, data >> 8);
|
||||
writeb(addr + 2, data >> 16);
|
||||
writeb(addr + 3, data >> 24);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void ST010::init() {
|
||||
}
|
||||
|
||||
void ST010::enable() {
|
||||
}
|
||||
|
||||
void ST010::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void ST010::reset() {
|
||||
memset(ram, 0x00, sizeof ram);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8 ST010::read(uint16 addr) {
|
||||
return readb(addr);
|
||||
}
|
||||
|
||||
void ST010::write(uint16 addr, uint8 data) {
|
||||
writeb(addr, data);
|
||||
|
||||
if(addr == 0x0021 && data & 0x80) {
|
||||
switch(ram[0x0020]) {
|
||||
case 0x01: op_01(); break;
|
||||
case 0x02: op_02(); break;
|
||||
case 0x03: op_03(); break;
|
||||
case 0x04: op_04(); break;
|
||||
case 0x05: op_05(); break;
|
||||
case 0x06: op_06(); break;
|
||||
case 0x07: op_07(); break;
|
||||
case 0x08: op_08(); break;
|
||||
}
|
||||
|
||||
ram[0x0021] &= ~0x80;
|
||||
}
|
||||
}
|
40
src/chip/st010/st010.h
Normal file
40
src/chip/st010/st010.h
Normal file
@@ -0,0 +1,40 @@
|
||||
class ST010 { public:
|
||||
uint8 ram[0x1000];
|
||||
static const int16 sin_table[256];
|
||||
static const int16 mode7_scale[176];
|
||||
static const uint8 arctan[32][32];
|
||||
//interfaces to sin table
|
||||
int16 sin(int16 theta);
|
||||
int16 cos(int16 theta);
|
||||
|
||||
//interfaces to ram buffer
|
||||
uint8 readb (uint16 addr);
|
||||
uint16 readw (uint16 addr);
|
||||
uint32 readd (uint16 addr);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
void writed(uint16 addr, uint32 data);
|
||||
|
||||
//opcodes
|
||||
void op_01();
|
||||
void op_02();
|
||||
void op_03();
|
||||
void op_04();
|
||||
void op_05();
|
||||
void op_06();
|
||||
void op_07();
|
||||
void op_08();
|
||||
|
||||
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
|
||||
|
||||
//base
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 read (uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
};
|
||||
|
||||
extern ST010 *st010;
|
126
src/chip/st010/st010_data.h
Normal file
126
src/chip/st010/st010_data.h
Normal file
@@ -0,0 +1,126 @@
|
||||
const int16 ST010::sin_table[256] = {
|
||||
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
|
||||
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
|
||||
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
|
||||
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
|
||||
0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
|
||||
0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
|
||||
0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
|
||||
0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
|
||||
0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
|
||||
0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
|
||||
0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
|
||||
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
|
||||
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
|
||||
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
|
||||
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
|
||||
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
|
||||
0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
|
||||
-0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
|
||||
-0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
|
||||
-0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
|
||||
-0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
|
||||
-0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
|
||||
-0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
|
||||
-0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
|
||||
-0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
|
||||
-0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
|
||||
-0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
|
||||
-0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
|
||||
-0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
|
||||
-0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
|
||||
-0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
|
||||
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
|
||||
};
|
||||
|
||||
const int16 ST010::mode7_scale[176] = {
|
||||
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
|
||||
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
|
||||
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
|
||||
0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
|
||||
0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
|
||||
0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
|
||||
0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
|
||||
0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
|
||||
0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
|
||||
0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
|
||||
0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
|
||||
0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
|
||||
0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
|
||||
0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
|
||||
0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
|
||||
0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
|
||||
0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
|
||||
0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
|
||||
0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
|
||||
0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
|
||||
0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
|
||||
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
|
||||
};
|
||||
|
||||
const uint8 ST010::arctan[32][32] = {
|
||||
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
|
||||
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
|
||||
0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
|
||||
{ 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
|
||||
0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
|
||||
{ 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
|
||||
0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
|
||||
{ 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
|
||||
0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
|
||||
{ 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
|
||||
0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
|
||||
{ 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
|
||||
0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
|
||||
{ 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
|
||||
0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
|
||||
{ 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
|
||||
0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
|
||||
{ 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
|
||||
0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
|
||||
{ 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
|
||||
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
|
||||
{ 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
|
||||
0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
|
||||
{ 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
|
||||
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
|
||||
{ 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
|
||||
0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
|
||||
{ 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
|
||||
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
|
||||
{ 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
|
||||
0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
|
||||
{ 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
|
||||
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
|
||||
0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
|
||||
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
|
||||
0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
|
||||
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
|
||||
0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
|
||||
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
|
||||
{ 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
|
||||
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
|
||||
{ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
|
||||
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
|
||||
0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
|
||||
0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
|
||||
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
|
||||
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
|
||||
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
|
||||
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
|
||||
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
|
||||
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
|
||||
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
|
||||
};
|
257
src/chip/st010/st010_op.cpp
Normal file
257
src/chip/st010/st010_op.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
//ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
|
||||
//bsnes port - Copyright (C) 2007 byuu
|
||||
|
||||
void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
|
||||
if((x0 < 0) && (y0 < 0)) {
|
||||
x1 = -x0;
|
||||
y1 = -y0;
|
||||
quadrant = -0x8000;
|
||||
} else if(x0 < 0) {
|
||||
x1 = y0;
|
||||
y1 = -x0;
|
||||
quadrant = -0x4000;
|
||||
} else if(y0 < 0) {
|
||||
x1 = -y0;
|
||||
y1 = x0;
|
||||
quadrant = 0x4000;
|
||||
} else {
|
||||
x1 = x0;
|
||||
y1 = y0;
|
||||
quadrant = 0x0000;
|
||||
}
|
||||
|
||||
while((x1 > 0x1f) || (y1 > 0x1f)) {
|
||||
if(x1 > 1) { x1 >>= 1; }
|
||||
if(y1 > 1) { y1 >>= 1; }
|
||||
}
|
||||
|
||||
if(y1 == 0) { quadrant += 0x4000; }
|
||||
|
||||
theta = (arctan[y1][x1] << 8) ^ quadrant;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void ST010::op_01() {
|
||||
int16 x0 = readw(0x0000);
|
||||
int16 y0 = readw(0x0002);
|
||||
int16 x1, y1, quadrant, theta;
|
||||
|
||||
op_01(x0, y0, x1, y1, quadrant, theta);
|
||||
|
||||
writew(0x0000, x1);
|
||||
writew(0x0002, y1);
|
||||
writew(0x0004, quadrant);
|
||||
//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
|
||||
writew(0x0010, theta);
|
||||
}
|
||||
|
||||
void ST010::op_02() {
|
||||
int16 positions = readw(0x0024);
|
||||
uint16 *places = (uint16*)(ram + 0x0040);
|
||||
uint16 *drivers = (uint16*)(ram + 0x0080);
|
||||
|
||||
bool sorted;
|
||||
uint16 temp;
|
||||
if(positions > 1) {
|
||||
do {
|
||||
sorted = true;
|
||||
for(int i = 0; i < positions - 1; i++) {
|
||||
if(places[i] < places[i + 1]) {
|
||||
temp = places[i + 1];
|
||||
places[i + 1] = places[i];
|
||||
places[i] = temp;
|
||||
|
||||
temp = drivers[i + 1];
|
||||
drivers[i + 1] = drivers[i];
|
||||
drivers[i] = temp;
|
||||
|
||||
sorted = false;
|
||||
}
|
||||
}
|
||||
positions--;
|
||||
} while(!sorted);
|
||||
}
|
||||
}
|
||||
|
||||
void ST010::op_03() {
|
||||
int16 x0 = readw(0x0000);
|
||||
int16 y0 = readw(0x0002);
|
||||
int16 multiplier = readw(0x0004);
|
||||
int32 x1, y1;
|
||||
|
||||
x1 = x0 * multiplier << 1;
|
||||
y1 = y0 * multiplier << 1;
|
||||
|
||||
writed(0x0010, x1);
|
||||
writed(0x0014, y1);
|
||||
}
|
||||
|
||||
void ST010::op_04() {
|
||||
int16 x = readw(0x0000);
|
||||
int16 y = readw(0x0002);
|
||||
int16 square;
|
||||
//calculate the vector length of (x,y)
|
||||
square = (int16)sqrt((double)(y * y + x * x));
|
||||
|
||||
writew(0x0010, square);
|
||||
}
|
||||
|
||||
void ST010::op_05() {
|
||||
int32 dx, dy;
|
||||
int16 a1, b1, c1;
|
||||
uint16 o1;
|
||||
bool wrap = false;
|
||||
|
||||
//target (x,y) coordinates
|
||||
int16 ypos_max = readw(0x00c0);
|
||||
int16 xpos_max = readw(0x00c2);
|
||||
|
||||
//current coordinates and direction
|
||||
int32 ypos = readd(0x00c4);
|
||||
int32 xpos = readd(0x00c8);
|
||||
uint16 rot = readw(0x00cc);
|
||||
|
||||
//physics
|
||||
uint16 speed = readw(0x00d4);
|
||||
uint16 accel = readw(0x00d6);
|
||||
uint16 speed_max = readw(0x00d8);
|
||||
|
||||
//special condition acknowledgement
|
||||
int16 system = readw(0x00da);
|
||||
int16 flags = readw(0x00dc);
|
||||
|
||||
//new target coordinates
|
||||
int16 ypos_new = readw(0x00de);
|
||||
int16 xpos_new = readw(0x00e0);
|
||||
|
||||
//mask upper bit
|
||||
xpos_new &= 0x7fff;
|
||||
|
||||
//get the current distance
|
||||
dx = xpos_max - (xpos >> 16);
|
||||
dy = ypos_max - (ypos >> 16);
|
||||
|
||||
//quirk: clear and move in9
|
||||
writew(0x00d2, 0xffff);
|
||||
writew(0x00da, 0x0000);
|
||||
|
||||
//grab the target angle
|
||||
op_01(dy, dx, a1, b1, c1, (int16&)o1);
|
||||
|
||||
//check for wrapping
|
||||
if(abs(o1 - rot) > 0x8000) {
|
||||
o1 += 0x8000;
|
||||
rot += 0x8000;
|
||||
wrap = true;
|
||||
}
|
||||
|
||||
uint16 old_speed = speed;
|
||||
|
||||
//special case
|
||||
if(abs(o1 - rot) == 0x8000) {
|
||||
speed = 0x100;
|
||||
}
|
||||
|
||||
//slow down for sharp curves
|
||||
else if(abs(o1 - rot) >= 0x1000) {
|
||||
uint32 slow = abs(o1 - rot);
|
||||
slow >>= 4; //scaling
|
||||
speed -= slow;
|
||||
}
|
||||
|
||||
//otherwise accelerate
|
||||
else {
|
||||
speed += accel;
|
||||
if(speed > speed_max) {
|
||||
speed = speed_max; //clip speed
|
||||
}
|
||||
}
|
||||
|
||||
//prevent negative/positive overflow
|
||||
if(abs(old_speed - speed) > 0x8000) {
|
||||
if(old_speed < speed) { speed = 0; }
|
||||
else speed = 0xff00;
|
||||
}
|
||||
|
||||
//adjust direction by so many degrees
|
||||
//be careful of negative adjustments
|
||||
if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
|
||||
if(o1 < rot) { rot -= 0x280; }
|
||||
else if(o1 > rot) { rot += 0x280; }
|
||||
}
|
||||
|
||||
//turn of wrapping
|
||||
if(wrap) { rot -= 0x8000; }
|
||||
|
||||
//now check the distances (store for later)
|
||||
dx = (xpos_max << 16) - xpos;
|
||||
dy = (ypos_max << 16) - ypos;
|
||||
dx >>= 16;
|
||||
dy >>= 16;
|
||||
|
||||
//if we're in so many units of the target, signal it
|
||||
if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
|
||||
//announce our new destination and flag it
|
||||
xpos_max = xpos_new & 0x7fff;
|
||||
ypos_max = ypos_new;
|
||||
flags |= 0x08;
|
||||
}
|
||||
|
||||
//update position
|
||||
xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
|
||||
ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
|
||||
|
||||
//quirk: mask upper byte
|
||||
xpos &= 0x1fffffff;
|
||||
ypos &= 0x1fffffff;
|
||||
|
||||
writew(0x00c0, ypos_max);
|
||||
writew(0x00c2, xpos_max);
|
||||
writed(0x00c4, ypos);
|
||||
writed(0x00c8, xpos);
|
||||
writew(0x00cc, rot);
|
||||
writew(0x00d4, speed);
|
||||
writew(0x00dc, flags);
|
||||
}
|
||||
|
||||
void ST010::op_06() {
|
||||
int16 multiplicand = readw(0x0000);
|
||||
int16 multiplier = readw(0x0002);
|
||||
int32 product;
|
||||
|
||||
product = multiplicand * multiplier << 1;
|
||||
|
||||
writed(0x0010, product);
|
||||
}
|
||||
|
||||
void ST010::op_07() {
|
||||
int16 theta = readw(0x0000);
|
||||
|
||||
int16 data;
|
||||
for(int i = 0, offset = 0; i < 176; i++) {
|
||||
data = mode7_scale[i] * cos(theta) >> 15;
|
||||
writew(0x00f0 + offset, data);
|
||||
writew(0x0510 + offset, data);
|
||||
|
||||
data = mode7_scale[i] * sin(theta) >> 15;
|
||||
writew(0x0250 + offset, data);
|
||||
if(data) { data = ~data; }
|
||||
writew(0x03b0 + offset, data);
|
||||
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void ST010::op_08() {
|
||||
int16 x0 = readw(0x0000);
|
||||
int16 y0 = readw(0x0002);
|
||||
int16 theta = readw(0x0004);
|
||||
int16 x1, y1;
|
||||
|
||||
x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
|
||||
y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
|
||||
|
||||
writew(0x0010, x1);
|
||||
writew(0x0012, y1);
|
||||
}
|
@@ -1,7 +1,10 @@
|
||||
Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
Config& config() {
|
||||
static Config config;
|
||||
return config;
|
||||
}
|
||||
|
||||
string file_updatepath(const char *req_file, const char *req_path) {
|
||||
string file(req_file);
|
||||
replace(file, "\\", "/");
|
||||
@@ -27,68 +30,83 @@ stringarray part;
|
||||
|
||||
StringSetting Path::base(0, "fs.base_path",
|
||||
"Path that bsnes resides in", "");
|
||||
StringSetting Path::rom(&config_file, "path.rom",
|
||||
StringSetting Path::rom(&config(), "path.rom",
|
||||
"Default path to look for ROM files in (\"\" = use default directory)", "");
|
||||
StringSetting Path::save(&config_file, "path.save",
|
||||
StringSetting Path::save(&config(), "path.save",
|
||||
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
|
||||
StringSetting Path::bios(&config_file, "path.bios",
|
||||
StringSetting Path::bios(&config(), "path.bios",
|
||||
"Path where BIOS file(s) are located\n"
|
||||
"Supported BIOS files:\n"
|
||||
"stbios.bin - Bandai Sufami Turbo"
|
||||
"", "./bios");
|
||||
|
||||
StringSetting Path::save_ext(&config_file, "path.save_ext",
|
||||
StringSetting Path::save_ext(&config(), "path.save_ext",
|
||||
"Extension to be used for all save RAM files", "srm");
|
||||
|
||||
IntegerSetting SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
|
||||
IntegerSetting SNES::gamma_ramp(&config(), "snes.colorfilter.gamma_ramp",
|
||||
"Use precalculated TV-style gamma ramp", IntegerSetting::Boolean, true);
|
||||
IntegerSetting SNES::sepia(&config_file, "snes.colorfilter.sepia",
|
||||
IntegerSetting SNES::sepia(&config(), "snes.colorfilter.sepia",
|
||||
"Convert color to sepia tone", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
|
||||
IntegerSetting SNES::grayscale(&config(), "snes.colorfilter.grayscale",
|
||||
"Convert color to grayscale tone", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::invert(&config_file, "snes.colorfilter.invert",
|
||||
IntegerSetting SNES::invert(&config(), "snes.colorfilter.invert",
|
||||
"Invert output image colors", IntegerSetting::Boolean, false);
|
||||
IntegerSetting SNES::contrast(&config_file, "snes.colorfilter.contrast",
|
||||
IntegerSetting SNES::contrast(&config(), "snes.colorfilter.contrast",
|
||||
"Contrast", IntegerSetting::Decimal, 0);
|
||||
IntegerSetting SNES::brightness(&config_file, "snes.colorfilter.brightness",
|
||||
IntegerSetting SNES::brightness(&config(), "snes.colorfilter.brightness",
|
||||
"Brightness", IntegerSetting::Decimal, 0);
|
||||
IntegerSetting SNES::gamma(&config_file, "snes.colorfilter.gamma",
|
||||
IntegerSetting SNES::gamma(&config(), "snes.colorfilter.gamma",
|
||||
"Gamma", IntegerSetting::Decimal, 80);
|
||||
|
||||
IntegerSetting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
|
||||
IntegerSetting SNES::ntsc_merge_fields(&config(), "snes.ntsc_merge_fields",
|
||||
"Merge fields in NTSC video filter\n"
|
||||
"Set to true if using filter at any refresh rate other than 60hz\n"
|
||||
"", IntegerSetting::Boolean, true);
|
||||
|
||||
IntegerSetting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
|
||||
IntegerSetting SNES::mute(&config(), "snes.mute", "Mutes SNES audio output when enabled",
|
||||
IntegerSetting::Boolean, false);
|
||||
|
||||
IntegerSetting SNES::controller_port0(&config_file, "snes.controller_port_1",
|
||||
IntegerSetting SNES::controller_port0(&config(), "snes.controller_port_1",
|
||||
"Controller attached to SNES port 1", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD1);
|
||||
IntegerSetting SNES::controller_port1(&config_file, "snes.controller_port_2",
|
||||
IntegerSetting SNES::controller_port1(&config(), "snes.controller_port_2",
|
||||
"Controller attached to SNES port 2", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD2);
|
||||
|
||||
IntegerSetting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate",
|
||||
IntegerSetting CPU::ntsc_clock_rate(&config(), "cpu.ntsc_clock_rate",
|
||||
"NTSC S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21477272);
|
||||
IntegerSetting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate",
|
||||
IntegerSetting CPU::pal_clock_rate(&config(), "cpu.pal_clock_rate",
|
||||
"PAL S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21281370);
|
||||
|
||||
IntegerSetting CPU::hdma_enable(0, "cpu.hdma_enable",
|
||||
"Enable HDMA effects", IntegerSetting::Boolean, true);
|
||||
|
||||
IntegerSetting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate",
|
||||
IntegerSetting SMP::ntsc_clock_rate(&config(), "smp.ntsc_clock_rate",
|
||||
"NTSC S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
|
||||
IntegerSetting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate",
|
||||
IntegerSetting SMP::pal_clock_rate(&config(), "smp.pal_clock_rate",
|
||||
"PAL S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720);
|
||||
|
||||
IntegerSetting PPU::Hack::render_scanline_position(&config_file, "ppu.hack.render_scanline_position",
|
||||
IntegerSetting PPU::Hack::render_scanline_position(&config(), "ppu.hack.render_scanline_position",
|
||||
"Approximate HCLOCK position to render at for scanline-based renderers",
|
||||
IntegerSetting::Decimal, 512);
|
||||
IntegerSetting PPU::Hack::obj_cache(&config_file, "ppu.hack.obj_cache",
|
||||
IntegerSetting PPU::Hack::obj_cache(&config(), "ppu.hack.obj_cache",
|
||||
"Cache OAM OBJ attributes one scanline before rendering\n"
|
||||
"This is technically closer to the actual operation of the SNES,\n"
|
||||
"but can cause problems in some games if enabled",
|
||||
IntegerSetting::Boolean, false);
|
||||
IntegerSetting PPU::Hack::oam_address_invalidation(&config(), "ppu.hack.oam_address_invalidation",
|
||||
"OAM access address changes during active display, as the S-PPU reads\n"
|
||||
"data to render the display. Thusly, the address retrieved when accessing\n"
|
||||
"OAM during active display is unpredictable. Unfortunately, the exact\n"
|
||||
"algorithm for this is completely unknown at this time. It is more hardware\n"
|
||||
"accurate to enable this setting, but one must *not* rely on the actual\n"
|
||||
"address to match hardware under emulation.",
|
||||
IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::Hack::cgram_address_invalidation(&config(), "ppu.hack.cgram_address_invalidation",
|
||||
"CGRAM access address changes during active display (excluding hblank), as\n"
|
||||
"the S-PPU reads data to render the display. Thusly, as with OAM, the access\n"
|
||||
"address is unpredictable. Again, enabling this setting is more hardware\n"
|
||||
"accurate, but one must *not* rely on the actual address to match hardware\n"
|
||||
"under emulation.",
|
||||
IntegerSetting::Boolean, true);
|
||||
|
||||
IntegerSetting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", IntegerSetting::Boolean, true);
|
||||
IntegerSetting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", IntegerSetting::Boolean, true);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
extern Config config_file;
|
||||
|
||||
namespace config {
|
||||
|
||||
extern Config& config();
|
||||
|
||||
string file_updatepath(const char *, const char *);
|
||||
|
||||
extern struct Path {
|
||||
@@ -30,6 +30,8 @@ extern struct PPU {
|
||||
struct Hack {
|
||||
static IntegerSetting render_scanline_position;
|
||||
static IntegerSetting obj_cache;
|
||||
static IntegerSetting oam_address_invalidation;
|
||||
static IntegerSetting cgram_address_invalidation;
|
||||
} hack;
|
||||
|
||||
static IntegerSetting opt_enable;
|
||||
|
@@ -662,7 +662,9 @@ void bDSP::power()
|
||||
{
|
||||
ram = (uint8*) r_smp->get_spcram_handle();
|
||||
memset( &m, 0, sizeof m );
|
||||
memcpy( m.regs, initial_regs, sizeof m.regs );
|
||||
//memcpy( m.regs, initial_regs, sizeof m.regs );
|
||||
memset(m.regs, 0, sizeof m.regs);
|
||||
REG(flg) = 0xe0;
|
||||
|
||||
// Internal state
|
||||
for ( int i = voice_count; --i >= 0; )
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include "chip/dsp1/dsp1.h"
|
||||
#include "chip/dsp2/dsp2.h"
|
||||
#include "chip/obc1/obc1.h"
|
||||
#include "chip/st010/st010.h"
|
||||
|
||||
extern MMIO mmio_unmapped;
|
||||
#ifdef POLYMORPHISM
|
||||
|
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
libarray : version 0.08 ~byuu (2006-12-16)
|
||||
libarray : version 0.09 ~byuu (2007-03-06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBARRAY
|
||||
#define __LIBARRAY
|
||||
#ifndef LIBARRAY_H
|
||||
#define LIBARRAY_H
|
||||
|
||||
template<typename T> class array {
|
||||
protected:
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libbase : version 0.10 ~byuu (2007-05-27)
|
||||
libbase : version 0.11 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <new>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <shlobj.h>
|
||||
@@ -32,6 +34,10 @@
|
||||
|
||||
#define NOMINMAX
|
||||
#define PATH_MAX _MAX_PATH
|
||||
#define va_copy(dst, src) ((dst) = (src))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define getcwd _getcwd
|
||||
#define ftruncate _chsize
|
||||
#define mkdir _mkdir
|
||||
@@ -39,11 +45,10 @@
|
||||
#define rmdir _rmdir
|
||||
#define vsnprintf _vsnprintf
|
||||
|
||||
#define va_copy(dst, src) ((dst) = (src))
|
||||
static char *realpath(const char *file_name, char *resolved_name) {
|
||||
return _fullpath(resolved_name, file_name, PATH_MAX);
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
#else
|
||||
#define mkdir(path) (mkdir)(path, 0755);
|
||||
#endif
|
||||
|
||||
@@ -55,17 +60,14 @@
|
||||
#define noinline __declspec(noinline)
|
||||
#define inline inline
|
||||
#define alwaysinline __forceinline
|
||||
#define fastcall __fastcall
|
||||
#elif defined(__GNUC__)
|
||||
#define noinline __attribute__((noinline))
|
||||
#define inline inline
|
||||
#define alwaysinline __attribute__((always_inline))
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#else
|
||||
#define noinline
|
||||
#define inline inline
|
||||
#define alwaysinline inline
|
||||
#define fastcall
|
||||
#endif
|
||||
|
||||
/*****
|
||||
@@ -91,13 +93,13 @@ typedef int64_t int64;
|
||||
//userpath(output) retrieves path to user's home folder
|
||||
//output must be at least as large as PATH_MAX
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
SHGetFolderPath(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, output);
|
||||
return output;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
#else
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
@@ -137,14 +139,10 @@ T z = x;
|
||||
y = z;
|
||||
}
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#define max(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
template<int min, int max, typename T> inline T minmax(const T x) {
|
||||
@@ -171,6 +169,8 @@ enum { b = 1U << (bits - 1), m = (1U << bits) - 1 };
|
||||
return ((x & m) ^ b) - b;
|
||||
}
|
||||
|
||||
//bit shifting functions are deprecated
|
||||
|
||||
template<int n, typename T> inline T rol(const T x) {
|
||||
enum { s = (sizeof(T) << 3) - n };
|
||||
return (x << n) | (x >> s);
|
||||
|
@@ -1,14 +1,14 @@
|
||||
;*****
|
||||
;libco_x86 : version 0.10 ~byuu (2007-04-18)
|
||||
;libco_x86 : version 0.10 ~byuu (2007-09-08)
|
||||
;cross-platform x86 implementation of libco
|
||||
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- visual c++; windows-x86
|
||||
;- mingw; windows-x86
|
||||
;- gcc; osx86
|
||||
;- gcc; linux-x86
|
||||
;- gcc; freebsd-x86
|
||||
;- visual c++; windows; x86
|
||||
;- mingw; windows; x86
|
||||
;- gcc; mac os x; x86
|
||||
;- gcc; linux; x86
|
||||
;- gcc; freebsd; x86
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- esp, ebp, edi, esi, ebx
|
||||
@@ -28,7 +28,7 @@
|
||||
%define free _free
|
||||
|
||||
%define co_active @co_active@0
|
||||
%define co_create @co_create@12
|
||||
%define co_create @co_create@8
|
||||
%define co_delete @co_delete@4
|
||||
%define co_switch @co_switch@4
|
||||
%endif
|
||||
@@ -76,11 +76,10 @@ co_active:
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)(void *data), void *data);
|
||||
;ecx = heapsize
|
||||
;edx = coentry
|
||||
;[esp+4] = data
|
||||
;return = eax
|
||||
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
|
||||
;ecx = heapsize
|
||||
;edx = coentry
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
@@ -101,7 +100,7 @@ co_create:
|
||||
and ecx,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov dword[ecx-4],co_entrypoint ;entry point
|
||||
mov dword[ecx-4],edx ;entry point
|
||||
mov dword[ecx-8],0 ;ebp
|
||||
mov dword[ecx-12],0 ;esi
|
||||
mov dword[ecx-16],0 ;edi
|
||||
@@ -109,11 +108,8 @@ co_create:
|
||||
sub ecx,20
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [eax],ecx ;cothread_t[ 0- 3] = stack heap pointer (esp)
|
||||
mov [eax+4],edx ;cothread_t[ 4- 7] = coentry
|
||||
mov ecx,[esp+4]
|
||||
mov [eax+8],ecx ;cothread_t[ 8-11] = data
|
||||
ret 4 ;return allocated memory block as thread handle
|
||||
mov [eax],ecx ;*cothread_t = stack heap pointer (esp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_delete(cothread_t cothread);
|
||||
@@ -150,18 +146,3 @@ co_switch:
|
||||
pop ebp
|
||||
|
||||
ret
|
||||
|
||||
;*****
|
||||
;void fastcall co_entrypoint();
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_entrypoint:
|
||||
mov ebp,esp
|
||||
.loop
|
||||
mov eax,[co_active_context]
|
||||
mov ecx,[eax+8] ;fastcall
|
||||
push ecx ;stdcall
|
||||
call [eax+4]
|
||||
mov esp,ebp ;cdecl
|
||||
jmp .loop
|
||||
|
@@ -1,16 +1,26 @@
|
||||
/*
|
||||
libco_x86 : version 0.10 ~byuu (2007-04-18)
|
||||
libco_x86 : version 0.10 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef LIBCO_H
|
||||
#define LIBCO_H
|
||||
|
||||
#define cocall fastcall
|
||||
typedef void (*cothread_t);
|
||||
#if !defined(fastcall)
|
||||
#if defined(_MSC_VER)
|
||||
#define fastcall __fastcall
|
||||
#elif defined(__GNUC__)
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#else
|
||||
#error "fastcall undefined"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern "C" cothread_t cocall co_active();
|
||||
extern "C" cothread_t cocall co_create(unsigned int heapsize, void (cocall *coentry)(void *data), void *data);
|
||||
extern "C" void cocall co_delete(cothread_t cothread);
|
||||
extern "C" void cocall co_switch(cothread_t cothread);
|
||||
typedef void *cothread_t;
|
||||
|
||||
extern "C" cothread_t fastcall co_active();
|
||||
extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
|
||||
extern "C" void fastcall co_delete(cothread_t cothread);
|
||||
extern "C" void fastcall co_switch(cothread_t cothread);
|
||||
|
||||
#endif
|
||||
|
@@ -1,12 +1,12 @@
|
||||
;*****
|
||||
;libco_x86_64 : version 0.10 ~byuu (2007-04-18)
|
||||
;libco_x86_64 : version 0.10 ~byuu (2007-09-08)
|
||||
;cross-platform x86-64 implementation of libco
|
||||
;special thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf )
|
||||
;- gcc; linux-x86-64
|
||||
;- gcc; freebsd-x86-64
|
||||
;- gcc; linux; x86-64
|
||||
;- gcc; freebsd; x86-64
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- rsp, rbp, rbx, r12, r13, r14, r15
|
||||
@@ -50,10 +50,9 @@ co_active:
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)(void *data), void *data);
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;rdi = heapsize
|
||||
;rsi = coentry
|
||||
;rdx = data
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
@@ -63,11 +62,9 @@ co_create:
|
||||
add rdi,512 ;allocate extra memory for contextual info
|
||||
push rdi
|
||||
push rsi
|
||||
push rdx
|
||||
|
||||
call malloc ;rax = malloc(rdi)
|
||||
|
||||
pop rdx
|
||||
pop rsi
|
||||
pop rdi
|
||||
|
||||
@@ -75,7 +72,7 @@ co_create:
|
||||
and rdi,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov qword[rdi-8],co_entrypoint ;entry point
|
||||
mov qword[rdi-8],rsi ;entry point
|
||||
mov qword[rdi-16],0 ;r15
|
||||
mov qword[rdi-24],0 ;r14
|
||||
mov qword[rdi-32],0 ;r13
|
||||
@@ -85,9 +82,7 @@ co_create:
|
||||
sub rdi,56
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [rax],rdi ;cothread_t[ 0- 7] = stack heap pointer (rsp)
|
||||
mov [rax+8],rsi ;cothread_t[ 8-15] = coentry
|
||||
mov [rax+16],rdx ;cothread_t[16-23] = data
|
||||
mov [rax],rdi ;*cothread_t = stack heap pointer (rsp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
@@ -126,14 +121,3 @@ co_switch:
|
||||
pop rbp
|
||||
|
||||
ret
|
||||
|
||||
;*****
|
||||
;void co_entrypoint();
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_entrypoint:
|
||||
mov rax,[co_active_context wrt rip]
|
||||
mov rdi,[rax+16]
|
||||
call [rax+8]
|
||||
jmp co_entrypoint
|
||||
|
@@ -1,15 +1,15 @@
|
||||
/*
|
||||
libco_x86_64 : version 0.10 ~byuu (2007-04-18)
|
||||
libco_x86_64 : version 0.10 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef LIBCO_H
|
||||
#define LIBCO_H
|
||||
|
||||
#define cocall
|
||||
typedef void (*cothread_t);
|
||||
typedef void *cothread_t;
|
||||
|
||||
extern "C" cothread_t co_active();
|
||||
extern "C" cothread_t co_create(unsigned int heapsize, void (cocall *coentry)(void *data), void *data);
|
||||
extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
extern "C" void co_delete(cothread_t cothread);
|
||||
extern "C" void co_switch(cothread_t cothread);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libconfig : version 0.14 ~byuu (2007-05-27)
|
||||
libconfig : version 0.14 ~byuu (2007-06-12)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
@@ -72,7 +72,7 @@ enum Format {
|
||||
template<typename T> bool operator<=(T x) { return (T(data) <= x); }
|
||||
template<typename T> bool operator< (T x) { return (T(data) < x); }
|
||||
|
||||
IntegerSetting(Config *parent, char *r_name, char *r_desc, uint r_format, uint r_data) {
|
||||
IntegerSetting(Config *parent, const char *r_name, const char *r_desc, uint r_format, uint r_data) {
|
||||
type = Setting::Integer;
|
||||
name = strdup(r_name);
|
||||
desc = strdup(r_desc);
|
||||
@@ -103,7 +103,7 @@ string data;
|
||||
bool operator==(const char *x) { return !strcmp(data, x); }
|
||||
bool operator!=(const char *x) { return strcmp(data, x); }
|
||||
|
||||
StringSetting(Config *parent, char *r_name, char *r_desc, char *r_data) {
|
||||
StringSetting(Config *parent, const char *r_name, const char *r_desc, const char *r_data) {
|
||||
type = Setting::String;
|
||||
name = strdup(r_name);
|
||||
desc = strdup(r_desc);
|
||||
|
@@ -1,455 +0,0 @@
|
||||
/*
|
||||
libfile : version 0.07 ~byuu (2007-03-01)
|
||||
*/
|
||||
|
||||
#ifndef __LIBFILE
|
||||
#define __LIBFILE
|
||||
|
||||
//FreeBSD fix: do not use defines for libc functions
|
||||
#undef feof
|
||||
#undef ferror
|
||||
|
||||
/*****
|
||||
* file object
|
||||
*****/
|
||||
|
||||
class file {
|
||||
public:
|
||||
enum { mode_read, mode_write, mode_readwrite, mode_writeread };
|
||||
enum { seek_start, seek_end, seek_back, seek_forward };
|
||||
virtual void read(uint8 *data, uint length) = 0;
|
||||
virtual uint8 read() = 0;
|
||||
|
||||
virtual void write(uint8 *data, uint length) = 0;
|
||||
virtual void write(uint8 data) = 0;
|
||||
|
||||
virtual uint32 crc32();
|
||||
|
||||
virtual void seek(uint offset, uint mode = seek_start) = 0;
|
||||
virtual void resize(uint size) = 0;
|
||||
virtual uint offset() = 0;
|
||||
virtual uint size() = 0;
|
||||
virtual bool eof() = 0;
|
||||
|
||||
virtual bool open(const char *filename, uint mode) = 0;
|
||||
virtual bool open() = 0;
|
||||
virtual bool flush() = 0;
|
||||
virtual bool close() = 0;
|
||||
};
|
||||
|
||||
inline uint32 file::crc32() {
|
||||
uint pos = offset(), i = size();
|
||||
seek(0);
|
||||
uint32 crc32 = 0xffffffff;
|
||||
while(i--) {
|
||||
crc32 = crc32_adjust(crc32, read());
|
||||
}
|
||||
seek(pos);
|
||||
return ~crc32;
|
||||
}
|
||||
|
||||
/*****
|
||||
* c++ wrappers
|
||||
*****/
|
||||
|
||||
inline void fread(file &s, uint8 *data, uint length) { s.read(data, length); }
|
||||
inline uint8 fread(file &s) { return s.read(); }
|
||||
inline uint8 fgetc(file &s) { return s.read(); }
|
||||
inline uint fgetb(file &s) { return s.read(); }
|
||||
|
||||
inline void fwrite(file &s, uint8 *data, uint length) { s.write(data, length); }
|
||||
inline void fwrite(file &s, uint8 data) { s.write(data); }
|
||||
inline void fputc(uint8 data, file &s) { s.write(data); }
|
||||
inline void fputb(file &s, uint8 data) { s.write(data); }
|
||||
|
||||
inline uint32 fcrc32(file &s) { return s.crc32(); }
|
||||
|
||||
inline void fseek(file &s, uint offset, uint mode = file::seek_start) { s.seek(offset, mode); }
|
||||
inline void fresize(file &s, uint size) { s.resize(size); }
|
||||
inline uint ftell(file &s) { return s.offset(); }
|
||||
inline uint fsize(file &s) { return s.size(); }
|
||||
inline bool feof(file &s) { return s.eof(); }
|
||||
|
||||
inline bool fopen(file &s, const char *filename, uint mode) { return s.open(filename, mode); }
|
||||
inline bool fopen(file &s) { return s.open(); }
|
||||
inline bool fflush(file &s) { return s.flush(); }
|
||||
inline bool fclose(file &s) { return s.close(); }
|
||||
|
||||
|
||||
/*****
|
||||
* endian wrappers
|
||||
*****/
|
||||
|
||||
inline uint8 fgetlb(file &s) { return fgetc(s); }
|
||||
inline uint8 fgetmb(file &s) { return fgetc(s); }
|
||||
|
||||
inline uint16 fgetlw(file &s) {
|
||||
return (fgetc(s)) | (fgetc(s) << 8);
|
||||
}
|
||||
|
||||
inline uint16 fgetmw(file &s) {
|
||||
return (fgetc(s) << 8) | (fgetc(s) << 8);
|
||||
}
|
||||
|
||||
inline uint32 fgetld(file &s) {
|
||||
return (fgetc(s)) | (fgetc(s) << 8) | (fgetc(s) << 16) | (fgetc(s) << 24);
|
||||
}
|
||||
|
||||
inline uint32 fgetmd(file &s) {
|
||||
return (fgetc(s) << 24) | (fgetc(s) << 16) | (fgetc(s) << 8) | (fgetc(s));
|
||||
}
|
||||
|
||||
inline uint64 fgetlq(file &s) {
|
||||
return ((uint64)fgetc(s) << 0) | ((uint64)fgetc(s) << 8) |
|
||||
((uint64)fgetc(s) << 16) | ((uint64)fgetc(s) << 24) |
|
||||
((uint64)fgetc(s) << 32) | ((uint64)fgetc(s) << 40) |
|
||||
((uint64)fgetc(s) << 48) | ((uint64)fgetc(s) << 56);
|
||||
}
|
||||
|
||||
inline uint64 fgetmq(file &s) {
|
||||
return ((uint64)fgetc(s) << 56) | ((uint64)fgetc(s) << 48) |
|
||||
((uint64)fgetc(s) << 40) | ((uint64)fgetc(s) << 32) |
|
||||
((uint64)fgetc(s) << 24) | ((uint64)fgetc(s) << 16) |
|
||||
((uint64)fgetc(s) << 8) | ((uint64)fgetc(s) << 0);
|
||||
}
|
||||
|
||||
inline void fputlb(file &s, uint8 data) { fputc(data, s); }
|
||||
inline void fputmb(file &s, uint8 data) { fputc(data, s); }
|
||||
|
||||
inline void fputlw(file &s, uint16 data) {
|
||||
fputc(data >> 0, s);
|
||||
fputc(data >> 8, s);
|
||||
}
|
||||
|
||||
inline void fputmw(file &s, uint16 data) {
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 0, s);
|
||||
}
|
||||
|
||||
inline void fputld(file &s, uint32 data) {
|
||||
fputc(data >> 0, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 24, s);
|
||||
}
|
||||
|
||||
inline void fputmd(file &s, uint32 data) {
|
||||
fputc(data >> 24, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 0, s);
|
||||
}
|
||||
|
||||
inline void fputlq(file &s, uint64 data) {
|
||||
fputc(data >> 0, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 24, s);
|
||||
fputc(data >> 32, s);
|
||||
fputc(data >> 40, s);
|
||||
fputc(data >> 48, s);
|
||||
fputc(data >> 56, s);
|
||||
}
|
||||
|
||||
inline void fputmq(file &s, uint64 data) {
|
||||
fputc(data >> 56, s);
|
||||
fputc(data >> 48, s);
|
||||
fputc(data >> 40, s);
|
||||
fputc(data >> 32, s);
|
||||
fputc(data >> 24, s);
|
||||
fputc(data >> 16, s);
|
||||
fputc(data >> 8, s);
|
||||
fputc(data >> 0, s);
|
||||
}
|
||||
|
||||
/*****
|
||||
* ramfile
|
||||
*****/
|
||||
|
||||
class ramfile : public file {
|
||||
private:
|
||||
FILE *fp;
|
||||
array<uint8> filedata;
|
||||
char filename[1024];
|
||||
uint filepos;
|
||||
uint filesize;
|
||||
uint filemode;
|
||||
bool fileopen;
|
||||
bool filevirtual;
|
||||
|
||||
public:
|
||||
void read(uint8 *data, uint length) {
|
||||
if(!fileopen || filemode == mode_write) { return; }
|
||||
|
||||
memcpy(data, filedata.get(filepos + length) + filepos, length);
|
||||
filepos += length;
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
}
|
||||
|
||||
uint8 read() {
|
||||
if(!fileopen || filemode == mode_write) { return 0; }
|
||||
|
||||
if(eof() == true) { return 0xff; }
|
||||
return filedata[filepos++];
|
||||
}
|
||||
|
||||
void write(uint8 *data, uint length) {
|
||||
if(!fileopen || filemode == mode_read) { return; }
|
||||
|
||||
memcpy(filedata.get(filepos + length) + filepos, data, length);
|
||||
filepos += length;
|
||||
if(filepos > filesize)filesize = filepos;
|
||||
}
|
||||
|
||||
void write(uint8 data) {
|
||||
if(!fileopen || filemode == mode_read) { return; }
|
||||
|
||||
filedata[filepos++] = data;
|
||||
if(filepos > filesize)filesize = filepos;
|
||||
}
|
||||
|
||||
void seek(uint offset, uint mode = seek_start) {
|
||||
if(!fileopen) { return; }
|
||||
|
||||
switch(mode) {
|
||||
case seek_start: filepos = offset; break;
|
||||
case seek_end: filepos = filesize + offset; break;
|
||||
case seek_back: filepos -= offset; break;
|
||||
case seek_forward: filepos += offset; break;
|
||||
}
|
||||
|
||||
if(filemode == mode_read) {
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
} else {
|
||||
if(filepos > filesize)filesize = filepos;
|
||||
}
|
||||
}
|
||||
|
||||
void resize(uint size) {
|
||||
filesize = size;
|
||||
if(filepos > filesize)filepos = filesize;
|
||||
}
|
||||
|
||||
uint offset() {
|
||||
if(!fileopen) { return 0; }
|
||||
|
||||
return filepos;
|
||||
}
|
||||
|
||||
uint size() {
|
||||
if(!fileopen) { return 0; }
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
bool eof() {
|
||||
if(!fileopen) { return true; }
|
||||
|
||||
return (filepos >= filesize);
|
||||
}
|
||||
|
||||
bool open(const char *fn, uint mode) {
|
||||
if(fileopen) { return false; }
|
||||
|
||||
strcpy(filename, fn ? fn : "");
|
||||
filevirtual = (*filename == 0);
|
||||
filemode = mode;
|
||||
switch(filemode) {
|
||||
case mode_read:
|
||||
case mode_readwrite:
|
||||
if(filevirtual == true) {
|
||||
filesize = 0;
|
||||
} else {
|
||||
fp = fopen(filename, "rb");
|
||||
if(!fp) { return false; }
|
||||
filesize = fsize(fp);
|
||||
fread(filedata.get(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
filesize = 0;
|
||||
break;
|
||||
}
|
||||
filepos = 0;
|
||||
fileopen = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool open() {
|
||||
return fileopen;
|
||||
}
|
||||
|
||||
bool flush() {
|
||||
if(!fileopen) { return false; }
|
||||
|
||||
switch(filemode) {
|
||||
case mode_readwrite:
|
||||
case mode_write:
|
||||
case mode_writeread:
|
||||
if(filevirtual == false) {
|
||||
fp = fopen(filename, "wb");
|
||||
if(!fp) { return false; }
|
||||
fwrite(filedata.get(filesize), 1, filesize, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool close() {
|
||||
if(!fileopen) { return false; }
|
||||
|
||||
bool result = flush();
|
||||
fileopen = false;
|
||||
filedata.reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
ramfile() {
|
||||
fileopen = false;
|
||||
}
|
||||
|
||||
~ramfile() {
|
||||
if(fileopen) { close(); }
|
||||
}
|
||||
};
|
||||
|
||||
/*****
|
||||
* diskfile
|
||||
*****/
|
||||
|
||||
class diskfile : public file {
|
||||
private:
|
||||
FILE *fp;
|
||||
uint filemode;
|
||||
|
||||
public:
|
||||
void read(uint8 *data, uint length) {
|
||||
if(!fp || filemode == mode_write) { return; }
|
||||
|
||||
fread(data, 1, length, fp);
|
||||
}
|
||||
|
||||
uint8 read() {
|
||||
if(!fp || filemode == mode_write) { return 0; }
|
||||
|
||||
if(eof() == true) { return 0xff; }
|
||||
return fgetc(fp);
|
||||
}
|
||||
|
||||
void write(uint8 *data, uint length) {
|
||||
if(!fp || filemode == mode_read) { return; }
|
||||
|
||||
fwrite(data, 1, length, fp);
|
||||
}
|
||||
|
||||
void write(uint8 data) {
|
||||
if(!fp || filemode == mode_read) { return; }
|
||||
|
||||
fputc(data, fp);
|
||||
}
|
||||
|
||||
void seek(uint offset, uint mode = seek_start) {
|
||||
if(!fp) { return; }
|
||||
|
||||
switch(mode) {
|
||||
default:
|
||||
case seek_start: fseek(fp, offset, SEEK_SET); break;
|
||||
case seek_end: fseek(fp, offset, SEEK_END); break;
|
||||
case seek_back: fseek(fp, offset, SEEK_CUR); break;
|
||||
case seek_forward: fseek(fp, offset, SEEK_CUR); break;
|
||||
}
|
||||
}
|
||||
|
||||
void resize(uint size) {
|
||||
if(!fp) { return; }
|
||||
|
||||
fresize(fp, size);
|
||||
}
|
||||
|
||||
uint offset() {
|
||||
if(!fp) { return 0; }
|
||||
|
||||
return ftell(fp);
|
||||
}
|
||||
|
||||
uint size() {
|
||||
if(!fp) { return 0; }
|
||||
|
||||
uint pos = ftell(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint filesize = ftell(fp);
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
return filesize;
|
||||
}
|
||||
|
||||
bool eof() {
|
||||
if(!fp) { return true; }
|
||||
|
||||
if(feof(fp)) {
|
||||
seek(size(), seek_start);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool open(const char *filename, uint mode) {
|
||||
if(fp) { return false; }
|
||||
|
||||
filemode = mode;
|
||||
char m[8];
|
||||
switch(filemode) {
|
||||
default:
|
||||
case mode_read: strcpy(m, "rb"); break;
|
||||
case mode_write: strcpy(m, "wb"); break;
|
||||
case mode_readwrite: strcpy(m, "rb+"); break;
|
||||
case mode_writeread: strcpy(m, "wb+"); break;
|
||||
}
|
||||
fp = fopen(filename, m);
|
||||
if(!fp) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool open() {
|
||||
return (fp != 0);
|
||||
}
|
||||
|
||||
bool flush() {
|
||||
if(!fp) { return false; }
|
||||
|
||||
fflush(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool close() {
|
||||
if(!fp) { return false; }
|
||||
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
diskfile() {
|
||||
fp = 0;
|
||||
}
|
||||
|
||||
~diskfile() {
|
||||
if(fp) { fclose(fp); }
|
||||
}
|
||||
};
|
||||
|
||||
/*****
|
||||
* directory object
|
||||
*****/
|
||||
|
||||
class directory {
|
||||
public:
|
||||
void open(const char *path) {}
|
||||
void close() {}
|
||||
uint read(char *filename, uint maxlength) { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,341 +1,100 @@
|
||||
/*
|
||||
libfunctor : version 0.01 ~byuu (2007-01-04)
|
||||
libfunctor : version 0.05 ~byuu (2007-09-08)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef __LIBFUNCTOR
|
||||
#define __LIBFUNCTOR
|
||||
#ifndef LIBFUNCTOR_H
|
||||
#define LIBFUNCTOR_H
|
||||
|
||||
template<typename T> struct functor;
|
||||
template<typename T> struct functor_t;
|
||||
//prologue
|
||||
|
||||
/*****
|
||||
* macros
|
||||
*****/
|
||||
#define TN typename
|
||||
|
||||
#define base_functor \
|
||||
functor *f; \
|
||||
virtual operator bool() const { return f && (bool)(*f); } \
|
||||
virtual functor *copy() const { return f->copy(); } \
|
||||
functor &operator=(const functor *source) { if(f) { delete f; } f = (source->f) ? source->copy() : 0; return *this; } \
|
||||
functor &operator=(const functor &source) { if(f) { delete f; } f = (source.f) ? source.copy() : 0; return *this; } \
|
||||
functor(const functor &source) { /* ........................ */ f = (source.f) ? source.copy() : 0; } \
|
||||
functor() : f(0) {} \
|
||||
~functor() { if(f && f != this) { delete f; } }
|
||||
template<typename T> class functor;
|
||||
|
||||
#define base_global_functor \
|
||||
operator bool() const { return proc; } \
|
||||
functor_t *copy() const { return new functor_t(*this); } \
|
||||
functor_t(const functor_t &source) { proc = source.proc; }
|
||||
//parameters = 0
|
||||
|
||||
#define base_member_functor \
|
||||
operator bool() const { return obj && proc; } \
|
||||
functor_t *copy() const { return new functor_t(*this); } \
|
||||
functor_t(const functor_t &source) { obj = source.obj; proc = source.proc; } \
|
||||
C *obj;
|
||||
#define cat(n) n
|
||||
#define TL typename R
|
||||
#define PL
|
||||
#define CL
|
||||
|
||||
/*****
|
||||
* parameters = 0
|
||||
*****/
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R>
|
||||
struct functor<R (*)()> { base_functor
|
||||
virtual R operator()() const { return (*f)(); }
|
||||
};
|
||||
//parameters = 1
|
||||
|
||||
template<typename R>
|
||||
struct functor_t<R (*)()> : public functor<R (*)()> { base_global_functor
|
||||
R (*proc)();
|
||||
R operator()() const { return (*proc)(); }
|
||||
functor_t(R (*_proc)()) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1
|
||||
#define PL P1 p1
|
||||
#define CL p1
|
||||
|
||||
template<typename C, typename R>
|
||||
struct functor_t<R (C::*)()> : public functor<R (*)()> { base_member_functor
|
||||
R (C::*proc)();
|
||||
R operator()() const { return (obj->*proc)(); }
|
||||
functor_t(C *_obj, R (C::*_proc)()) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R>
|
||||
functor_t<R (*)()> make_functor(R (*proc)()) {
|
||||
return functor_t<R (*)()>(proc);
|
||||
}
|
||||
//parameters = 2
|
||||
|
||||
template<typename C, typename R>
|
||||
functor_t<R (C::*)()> make_functor(C *obj, R (C::*proc)()) {
|
||||
return functor_t<R (C::*)()>(obj, proc);
|
||||
}
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2
|
||||
#define PL P1 p1, P2 p2
|
||||
#define CL p1, p2
|
||||
|
||||
/*****
|
||||
* parameters = 1
|
||||
*****/
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R, typename P1>
|
||||
struct functor<R (*)(P1)> { base_functor
|
||||
virtual R operator()(P1 p1) const { return (*f)(p1); }
|
||||
};
|
||||
//parameters = 3
|
||||
|
||||
template<typename R, typename P1>
|
||||
struct functor_t<R (*)(P1)> : public functor<R (*)(P1)> { base_global_functor
|
||||
R (*proc)(P1);
|
||||
R operator()(P1 p1) const { return (*proc)(p1); }
|
||||
functor_t(R (*_proc)(P1)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3
|
||||
#define PL P1 p1, P2 p2, P3 p3
|
||||
#define CL p1, p2, p3
|
||||
|
||||
template<typename C, typename R, typename P1>
|
||||
struct functor_t<R (C::*)(P1)> : public functor<R (*)(P1)> { base_member_functor
|
||||
R (C::*proc)(P1);
|
||||
R operator()(P1 p1) const { return (obj->*proc)(p1); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R, typename P1>
|
||||
functor_t<R (*)(P1)> make_functor(R (*proc)(P1)) {
|
||||
return functor_t<R (*)(P1)>(proc);
|
||||
}
|
||||
//parameters = 4
|
||||
|
||||
template<typename C, typename R, typename P1>
|
||||
functor_t<R (C::*)(P1)> make_functor(C *obj, R (C::*proc)(P1)) {
|
||||
return functor_t<R (C::*)(P1)>(obj, proc);
|
||||
}
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4
|
||||
#define CL p1, p2, p3, p4
|
||||
|
||||
/*****
|
||||
* parameters = 2
|
||||
*****/
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R, typename P1, typename P2>
|
||||
struct functor<R (*)(P1, P2)> { base_functor
|
||||
virtual R operator()(P1 p1, P2 p2) const { return (*f)(p1, p2); }
|
||||
};
|
||||
//parameters = 5
|
||||
|
||||
template<typename R, typename P1, typename P2>
|
||||
struct functor_t<R (*)(P1, P2)> : public functor<R (*)(P1, P2)> { base_global_functor
|
||||
R (*proc)(P1, P2);
|
||||
R operator()(P1 p1, P2 p2) const { return (*proc)(p1, p2); }
|
||||
functor_t(R (*_proc)(P1, P2)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5
|
||||
#define CL p1, p2, p3, p4, p5
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2>
|
||||
struct functor_t<R (C::*)(P1, P2)> : public functor<R (*)(P1, P2)> { base_member_functor
|
||||
R (C::*proc)(P1, P2);
|
||||
R operator()(P1 p1, P2 p2) const { return (obj->*proc)(p1, p2); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1, P2)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R, typename P1, typename P2>
|
||||
functor_t<R (*)(P1, P2)> make_functor(R (*proc)(P1, P2)) {
|
||||
return functor_t<R (*)(P1, P2)>(proc);
|
||||
}
|
||||
//parameters = 6
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2>
|
||||
functor_t<R (C::*)(P1, P2)> make_functor(C *obj, R (C::*proc)(P1, P2)) {
|
||||
return functor_t<R (C::*)(P1, P2)>(obj, proc);
|
||||
}
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6
|
||||
#define CL p1, p2, p3, p4, p5, p6
|
||||
|
||||
/*****
|
||||
* parameters = 3
|
||||
*****/
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3>
|
||||
struct functor<R (*)(P1, P2, P3)> { base_functor
|
||||
virtual R operator()(P1 p1, P2 p2, P3 p3) const { return (*f)(p1, p2, p3); }
|
||||
};
|
||||
//parameters = 7
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3>
|
||||
struct functor_t<R (*)(P1, P2, P3)> : public functor<R (*)(P1, P2, P3)> { base_global_functor
|
||||
R (*proc)(P1, P2, P3);
|
||||
R operator()(P1 p1, P2 p2, P3 p3) const { return (*proc)(p1, p2, p3); }
|
||||
functor_t(R (*_proc)(P1, P2, P3)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7
|
||||
#define CL p1, p2, p3, p4, p5, p6, p7
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3>
|
||||
struct functor_t<R (C::*)(P1, P2, P3)> : public functor<R (*)(P1, P2, P3)> { base_member_functor
|
||||
R (C::*proc)(P1, P2, P3);
|
||||
R operator()(P1 p1, P2 p2, P3 p3) const { return (obj->*proc)(p1, p2, p3); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1, P2, P3)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3>
|
||||
functor_t<R (*)(P1, P2, P3)> make_functor(R (*proc)(P1, P2, P3)) {
|
||||
return functor_t<R (*)(P1, P2, P3)>(proc);
|
||||
}
|
||||
//parameters = 8
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3>
|
||||
functor_t<R (C::*)(P1, P2, P3)> make_functor(C *obj, R (C::*proc)(P1, P2, P3)) {
|
||||
return functor_t<R (C::*)(P1, P2, P3)>(obj, proc);
|
||||
}
|
||||
#define cat(n) , n
|
||||
#define TL TN R, TN P1, TN P2, TN P3, TN P4, TN P5, TN P6, TN P7, TN P8
|
||||
#define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8
|
||||
#define CL p1, p2, p3, p4, p5, p6, p7, p8
|
||||
|
||||
/*****
|
||||
* parameters = 4
|
||||
*****/
|
||||
#include "libfunctor_impl.h"
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4>
|
||||
struct functor<R (*)(P1, P2, P3, P4)> { base_functor
|
||||
virtual R operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { return (*f)(p1, p2, p3, p4); }
|
||||
};
|
||||
//epilogue
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4>
|
||||
struct functor_t<R (*)(P1, P2, P3, P4)> : public functor<R (*)(P1, P2, P3, P4)> { base_global_functor
|
||||
R (*proc)(P1, P2, P3, P4);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { return (*proc)(p1, p2, p3, p4); }
|
||||
functor_t(R (*_proc)(P1, P2, P3, P4)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4>
|
||||
struct functor_t<R (C::*)(P1, P2, P3, P4)> : public functor<R (*)(P1, P2, P3, P4)> { base_member_functor
|
||||
R (C::*proc)(P1, P2, P3, P4);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { return (obj->*proc)(p1, p2, p3, p4); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1, P2, P3, P4)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4>
|
||||
functor_t<R (*)(P1, P2, P3, P4)> make_functor(R (*proc)(P1, P2, P3, P4)) {
|
||||
return functor_t<R (*)(P1, P2, P3, P4)>(proc);
|
||||
}
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4>
|
||||
functor_t<R (C::*)(P1, P2, P3, P4)> make_functor(C *obj, R (C::*proc)(P1, P2, P3, P4)) {
|
||||
return functor_t<R (C::*)(P1, P2, P3, P4)>(obj, proc);
|
||||
}
|
||||
|
||||
/*****
|
||||
* parameters = 5
|
||||
*****/
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||
struct functor<R (*)(P1, P2, P3, P4, P5)> { base_functor
|
||||
virtual R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const { return (*f)(p1, p2, p3, p4, p5); }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||
struct functor_t<R (*)(P1, P2, P3, P4, P5)> : public functor<R (*)(P1, P2, P3, P4, P5)> { base_global_functor
|
||||
R (*proc)(P1, P2, P3, P4, P5);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const { return (*proc)(p1, p2, p3, p4, p5); }
|
||||
functor_t(R (*_proc)(P1, P2, P3, P4, P5)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||
struct functor_t<R (C::*)(P1, P2, P3, P4, P5)> : public functor<R (*)(P1, P2, P3, P4, P5)> { base_member_functor
|
||||
R (C::*proc)(P1, P2, P3, P4, P5);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const { return (obj->*proc)(p1, p2, p3, p4, p5); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1, P2, P3, P4, P5)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||
functor_t<R (*)(P1, P2, P3, P4, P5)> make_functor(R (*proc)(P1, P2, P3, P4, P5)) {
|
||||
return functor_t<R (*)(P1, P2, P3, P4, P5)>(proc);
|
||||
}
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||
functor_t<R (C::*)(P1, P2, P3, P4, P5)> make_functor(C *obj, R (C::*proc)(P1, P2, P3, P4, P5)) {
|
||||
return functor_t<R (C::*)(P1, P2, P3, P4, P5)>(obj, proc);
|
||||
}
|
||||
|
||||
/*****
|
||||
* parameters = 6
|
||||
*****/
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||
struct functor<R (*)(P1, P2, P3, P4, P5, P6)> { base_functor
|
||||
virtual R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) const { return (*f)(p1, p2, p3, p4, p5, p6); }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||
struct functor_t<R (*)(P1, P2, P3, P4, P5, P6)> : public functor<R (*)(P1, P2, P3, P4, P5, P6)> { base_global_functor
|
||||
R (*proc)(P1, P2, P3, P4, P5, P6);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) const { return (*proc)(p1, p2, p3, p4, p5, p6); }
|
||||
functor_t(R (*_proc)(P1, P2, P3, P4, P5, P6)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||
struct functor_t<R (C::*)(P1, P2, P3, P4, P5, P6)> : public functor<R (*)(P1, P2, P3, P4, P5, P6)> { base_member_functor
|
||||
R (C::*proc)(P1, P2, P3, P4, P5, P6);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) const { return (obj->*proc)(p1, p2, p3, p4, p5, p6); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1, P2, P3, P4, P5, P6)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||
functor_t<R (*)(P1, P2, P3, P4, P5, P6)> make_functor(R (*proc)(P1, P2, P3, P4, P5, P6)) {
|
||||
return functor_t<R (*)(P1, P2, P3, P4, P5, P6)>(proc);
|
||||
}
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||
functor_t<R (C::*)(P1, P2, P3, P4, P5, P6)> make_functor(C *obj, R (C::*proc)(P1, P2, P3, P4, P5, P6)) {
|
||||
return functor_t<R (C::*)(P1, P2, P3, P4, P5, P6)>(obj, proc);
|
||||
}
|
||||
|
||||
/*****
|
||||
* parameters = 7
|
||||
*****/
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
|
||||
struct functor<R (*)(P1, P2, P3, P4, P5, P6, P7)> { base_functor
|
||||
virtual R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) const { return (*f)(p1, p2, p3, p4, p5, p6, p7); }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
|
||||
struct functor_t<R (*)(P1, P2, P3, P4, P5, P6, P7)> : public functor<R (*)(P1, P2, P3, P4, P5, P6, P7)> { base_global_functor
|
||||
R (*proc)(P1, P2, P3, P4, P5, P6, P7);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) const { return (*proc)(p1, p2, p3, p4, p5, p6, p7); }
|
||||
functor_t(R (*_proc)(P1, P2, P3, P4, P5, P6, P7)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
|
||||
struct functor_t<R (C::*)(P1, P2, P3, P4, P5, P6, P7)> : public functor<R (*)(P1, P2, P3, P4, P5, P6, P7)> { base_member_functor
|
||||
R (C::*proc)(P1, P2, P3, P4, P5, P6, P7);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) const { return (obj->*proc)(p1, p2, p3, p4, p5, p6, p7); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1, P2, P3, P4, P5, P6, P7)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
|
||||
functor_t<R (*)(P1, P2, P3, P4, P5, P6, P7)> make_functor(R (*proc)(P1, P2, P3, P4, P5, P6, P7)) {
|
||||
return functor_t<R (*)(P1, P2, P3, P4, P5, P6, P7)>(proc);
|
||||
}
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
|
||||
functor_t<R (C::*)(P1, P2, P3, P4, P5, P6, P7)> make_functor(C *obj, R (C::*proc)(P1, P2, P3, P4, P5, P6, P7)) {
|
||||
return functor_t<R (C::*)(P1, P2, P3, P4, P5, P6, P7)>(obj, proc);
|
||||
}
|
||||
|
||||
/*****
|
||||
* parameters = 8
|
||||
*****/
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
|
||||
struct functor<R (*)(P1, P2, P3, P4, P5, P6, P7, P8)> { base_functor
|
||||
virtual R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) const { return (*f)(p1, p2, p3, p4, p5, p6, p7, p8); }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
|
||||
struct functor_t<R (*)(P1, P2, P3, P4, P5, P6, P7, P8)> : public functor<R (*)(P1, P2, P3, P4, P5, P6, P7, P8)> { base_global_functor
|
||||
R (*proc)(P1, P2, P3, P4, P5, P6, P7, P8);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) const { return (*proc)(p1, p2, p3, p4, p5, p6, p7, p8); }
|
||||
functor_t(R (*_proc)(P1, P2, P3, P4, P5, P6, P7, P8)) : proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
|
||||
struct functor_t<R (C::*)(P1, P2, P3, P4, P5, P6, P7, P8)> : public functor<R (*)(P1, P2, P3, P4, P5, P6, P7, P8)> { base_member_functor
|
||||
R (C::*proc)(P1, P2, P3, P4, P5, P6, P7, P8);
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) const { return (obj->*proc)(p1, p2, p3, p4, p5, p6, p7, p8); }
|
||||
functor_t(C *_obj, R (C::*_proc)(P1, P2, P3, P4, P5, P6, P7, P8)) : obj(_obj), proc(_proc) { this->f = this; }
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
|
||||
functor_t<R (*)(P1, P2, P3, P4, P5, P6, P7, P8)> make_functor(R (*proc)(P1, P2, P3, P4, P5, P6, P7, P8)) {
|
||||
return functor_t<R (*)(P1, P2, P3, P4, P5, P6, P7, P8)>(proc);
|
||||
}
|
||||
|
||||
template<typename C, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
|
||||
functor_t<R (C::*)(P1, P2, P3, P4, P5, P6, P7, P8)> make_functor(C *obj, R (C::*proc)(P1, P2, P3, P4, P5, P6, P7, P8)) {
|
||||
return functor_t<R (C::*)(P1, P2, P3, P4, P5, P6, P7, P8)>(obj, proc);
|
||||
}
|
||||
|
||||
/*****
|
||||
* epilogue
|
||||
*****/
|
||||
|
||||
#undef base_functor
|
||||
#undef base_global_functor
|
||||
#undef base_member_functor
|
||||
#undef TN
|
||||
|
||||
#endif
|
||||
|
81
src/lib/libfunctor_impl.h
Normal file
81
src/lib/libfunctor_impl.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifdef LIBFUNCTOR_H
|
||||
|
||||
template<TL>
|
||||
class functor<R (PL)> {
|
||||
private:
|
||||
struct base1 { virtual void func1(PL) {} };
|
||||
struct base2 { virtual void func2(PL) {} };
|
||||
struct derived : base1, virtual base2 {};
|
||||
|
||||
struct data_t {
|
||||
R (*fn_call)(const data_t& cat(PL));
|
||||
union {
|
||||
R (*fn_global)(PL);
|
||||
struct {
|
||||
R (derived::*fn_member)(PL);
|
||||
void *object;
|
||||
};
|
||||
};
|
||||
} data;
|
||||
|
||||
static R fn_call_global(const data_t &d cat(PL)) {
|
||||
return d.fn_global(CL);
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
static R fn_call_member(const data_t &d cat(PL)) {
|
||||
return (((C*)d.object)->*((R (C::*&)(PL))d.fn_member))(CL);
|
||||
}
|
||||
|
||||
public:
|
||||
R operator()(PL) const { return data.fn_call(data cat(CL)); }
|
||||
operator bool() const { return data.fn_call; }
|
||||
|
||||
functor() { data.fn_call = 0; }
|
||||
|
||||
functor(R (*fn)(PL)) {
|
||||
data.fn_call = &fn_call_global;
|
||||
data.fn_global = fn;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
functor(R (C::*fn)(PL), C *obj) {
|
||||
data.fn_call = &fn_call_member<C>;
|
||||
(R (C::*&)(PL))data.fn_member = fn;
|
||||
assert(sizeof data.fn_member >= sizeof fn);
|
||||
data.object = obj;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
functor(R (C::*fn)(PL) const, C *obj) {
|
||||
data.fn_call = &fn_call_member<C>;
|
||||
(R (C::*&)(PL))data.fn_member = (R (C::*&)(PL))fn;
|
||||
assert(sizeof data.fn_member >= sizeof fn);
|
||||
data.object = obj;
|
||||
}
|
||||
|
||||
functor &operator=(const functor &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
|
||||
functor(const functor &source) { memcpy(&data, &source.data, sizeof(data_t)); }
|
||||
};
|
||||
|
||||
template<TL>
|
||||
functor<R (PL)> bind(R (*fn)(PL)) {
|
||||
return functor<R (PL)>(fn);
|
||||
}
|
||||
|
||||
template<typename C, TL>
|
||||
functor<R (PL)> bind(R (C::*fn)(PL), C *obj) {
|
||||
return functor<R (PL)>(fn, obj);
|
||||
}
|
||||
|
||||
template<typename C, TL>
|
||||
functor<R (PL)> bind(R (C::*fn)(PL) const, C *obj) {
|
||||
return functor<R (PL)>(fn, obj);
|
||||
}
|
||||
|
||||
#undef cat
|
||||
#undef TL
|
||||
#undef PL
|
||||
#undef CL
|
||||
|
||||
#endif
|
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
libinterp : version 0.01 ~byuu (2007-02-03)
|
||||
*/
|
||||
|
||||
#ifndef __LIBINTERP
|
||||
#define __LIBINTERP
|
||||
|
||||
static inline
|
||||
double interpolate_point(
|
||||
double mu,
|
||||
double y0, double y1
|
||||
) {
|
||||
return mu < 0.5 ? y0 : y1;
|
||||
}
|
||||
|
||||
static inline
|
||||
double interpolate_linear(
|
||||
double mu,
|
||||
double y0, double y1
|
||||
) {
|
||||
return y0 + mu * (y1 - y0);
|
||||
}
|
||||
|
||||
static inline
|
||||
double interpolate_cosine(
|
||||
double mu,
|
||||
double y0, double y1
|
||||
) {
|
||||
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
|
||||
return y0 + mu * (y1 - y0);
|
||||
}
|
||||
|
||||
static inline
|
||||
double interpolate_cubic(
|
||||
double mu,
|
||||
double y0, double y1, double y2, double y3
|
||||
) {
|
||||
double a0 = y3 - y2 - y0 + y1;
|
||||
double a1 = y0 - y1 - a0;
|
||||
double a2 = y2 - y0;
|
||||
double a3 = y1;
|
||||
return a0 * mu * mu * mu +
|
||||
a1 * mu * mu +
|
||||
a2 * mu +
|
||||
a3;
|
||||
}
|
||||
|
||||
/*
|
||||
tension: (0 = normal, -1 = low, +1 = high)
|
||||
bias: (0 = even, -n = left, +n = right)
|
||||
*/
|
||||
static inline
|
||||
double interpolate_hermite(
|
||||
double mu, double tension, double bias,
|
||||
double y0, double y1, double y2, double y3
|
||||
) {
|
||||
double mu0 = ( (y1 - y0) * (1.0 + bias) * (1.0 - tension) / 2.0 ) +
|
||||
( (y2 - y1) * (1.0 - bias) * (1.0 - tension) / 2.0 );
|
||||
double mu1 = ( (y2 - y1) * (1.0 + bias) * (1.0 - tension) / 2.0 ) +
|
||||
( (y3 - y2) * (1.0 - bias) * (1.0 - tension) / 2.0 );
|
||||
double mu2 = mu * mu;
|
||||
double mu3 = mu * mu * mu;
|
||||
double a0 = 2.0 * mu3 - 3.0 * mu2 + 1.0;
|
||||
double a1 = mu3 - 2.0 * mu2 + mu;
|
||||
double a2 = mu3 - mu2;
|
||||
double a3 = -2.0 * mu3 + 3.0 * mu2;
|
||||
return a0 * y1 +
|
||||
a1 * mu0 +
|
||||
a2 * mu1 +
|
||||
a3 * y2;
|
||||
}
|
||||
|
||||
#endif
|
@@ -7,6 +7,28 @@
|
||||
|
||||
namespace keymap {
|
||||
|
||||
//TODO: use lookup table for find() functions
|
||||
static char keytable[][64] = {
|
||||
"none",
|
||||
"esc",
|
||||
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12",
|
||||
"print_screen", "sys_req", "scroll_lock", "pause", "brk",
|
||||
"grave", "tilde",
|
||||
"num_1", "exclamation",
|
||||
"num_2", "at",
|
||||
"num_3", "pound",
|
||||
"num_4", "dollar",
|
||||
"num_5", "percent",
|
||||
"num_6", "power",
|
||||
"num_7", "ampersand",
|
||||
"num_8", "asterisk",
|
||||
"num_9", "lparenthesis",
|
||||
"num_0", "rparenthesis",
|
||||
"minus", "underscore",
|
||||
"equal", "plus",
|
||||
"backspace",
|
||||
};
|
||||
|
||||
enum {
|
||||
none = 0x0000,
|
||||
|
||||
@@ -108,6 +130,8 @@ enum {
|
||||
rsuper,
|
||||
menu,
|
||||
|
||||
limit, //not an actual key -- marks the end of linear key entries
|
||||
|
||||
joypad_flag = 0x8000,
|
||||
joypad_nummask = 0x7f00,
|
||||
joypad_keymask = 0x00ff,
|
||||
|
@@ -2,8 +2,8 @@
|
||||
libsort : version 0.01 ~byuu (2006-11-15)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSORT
|
||||
#define __LIBSORT
|
||||
#ifndef LIBSORT_H
|
||||
#define LIBSORT_H
|
||||
|
||||
template<typename T>
|
||||
void sort(T list[], uint length) {
|
||||
|
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
libstring : version 0.17 ~byuu (2007-05-20)
|
||||
libstring : version 0.18 ~byuu (2007-06-06)
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTRING
|
||||
#define __LIBSTRING
|
||||
#ifndef LIBSTRING_H
|
||||
#define LIBSTRING_H
|
||||
|
||||
#include "libbase.h"
|
||||
#include "libvector.h"
|
||||
@@ -189,35 +189,32 @@ uint size;
|
||||
|
||||
~string() { safe_free(s); }
|
||||
|
||||
const char *operator()();
|
||||
char &operator[](const uint);
|
||||
string &operator= (const int);
|
||||
string &operator= (const char *);
|
||||
string &operator= (const string &);
|
||||
string &operator+=(const int);
|
||||
string &operator+=(const char *);
|
||||
string &operator+=(const string &);
|
||||
bool operator==(const char *);
|
||||
bool operator==(const string &);
|
||||
bool operator!=(const char *);
|
||||
bool operator!=(const string &);
|
||||
bool operator< (const char *);
|
||||
bool operator< (const string &);
|
||||
bool operator<=(const char *);
|
||||
bool operator<=(const string &);
|
||||
bool operator> (const char *);
|
||||
bool operator> (const string &);
|
||||
bool operator>=(const char *);
|
||||
bool operator>=(const string &);
|
||||
operator const char*() const { return s; }
|
||||
const char* operator()() const { return s; }
|
||||
char& operator[](const uint);
|
||||
|
||||
string operator+(const int);
|
||||
string operator+(const char *);
|
||||
string operator+(const string &);
|
||||
string& operator=(const int);
|
||||
string& operator=(const char*);
|
||||
string& operator=(const string&);
|
||||
|
||||
string& operator<<(const int);
|
||||
string& operator<<(const char*);
|
||||
string& operator<<(const string&);
|
||||
|
||||
bool operator==(const char*);
|
||||
bool operator==(const string&);
|
||||
bool operator!=(const char*);
|
||||
bool operator!=(const string&);
|
||||
bool operator< (const char*);
|
||||
bool operator< (const string&);
|
||||
bool operator<=(const char*);
|
||||
bool operator<=(const string&);
|
||||
bool operator> (const char*);
|
||||
bool operator> (const string&);
|
||||
bool operator>=(const char*);
|
||||
bool operator>=(const string&);
|
||||
};
|
||||
|
||||
string operator+(const int, const string &);
|
||||
string operator+(const char *, const string &);
|
||||
|
||||
inline void swap(string &x, string &y) { x.swap(y); }
|
||||
|
||||
#endif //__LIBSTRING
|
||||
#endif //LIBSTRING_H
|
||||
|
@@ -1,7 +1,3 @@
|
||||
const char *string::operator()() {
|
||||
return s;
|
||||
}
|
||||
|
||||
char &string::operator[](const uint index) {
|
||||
reserve(index);
|
||||
return s[index];
|
||||
@@ -22,17 +18,17 @@ string &string::operator=(const string &str) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
string &string::operator+=(const int num) {
|
||||
string& string::operator<<(const int num) {
|
||||
strcat(*this, strfmt("%d", num));
|
||||
return *this;
|
||||
}
|
||||
|
||||
string &string::operator+=(const char *str) {
|
||||
string& string::operator<<(const char* str) {
|
||||
strcat(*this, str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string &string::operator+=(const string &str) {
|
||||
string& string::operator<<(const string& str) {
|
||||
strcat(*this, str);
|
||||
return *this;
|
||||
}
|
||||
@@ -49,35 +45,3 @@ bool string::operator> (const char *str) { return strcmp(strptr(*this), str)
|
||||
bool string::operator> (const string &str) { return strcmp(strptr(*this), strptr(str)) > 0; }
|
||||
bool string::operator>=(const char *str) { return strcmp(strptr(*this), str) >= 0; }
|
||||
bool string::operator>=(const string &str) { return strcmp(strptr(*this), strptr(str)) >= 0; }
|
||||
|
||||
string string::operator+(const int num) {
|
||||
string temp(*this);
|
||||
strcat(temp, strfmt("%d", num));
|
||||
return temp;
|
||||
}
|
||||
|
||||
string string::operator+(const char *str) {
|
||||
string temp(*this);
|
||||
strcat(temp, str);
|
||||
return temp;
|
||||
}
|
||||
|
||||
string string::operator+(const string &str) {
|
||||
string temp(*this);
|
||||
strcat(temp, str);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
string operator+(const int x, const string &y) {
|
||||
string temp(strfmt("%d", x));
|
||||
strcat(temp, y);
|
||||
return temp;
|
||||
}
|
||||
|
||||
string operator+(const char *x, const string &y) {
|
||||
string temp(x);
|
||||
strcat(temp, y);
|
||||
return temp;
|
||||
}
|
||||
|
@@ -40,13 +40,14 @@ uint get_screen_height() { return gdk_screen_height(); }
|
||||
|
||||
//
|
||||
|
||||
noinline bool gtk_file_load(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File",
|
||||
GTK_WINDOW(owner.info.window), GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
owner ? GTK_WINDOW(owner->info.window) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, 0);
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, (const gchar*)0);
|
||||
|
||||
if(path && strcmp(path, "")) {
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
@@ -62,13 +63,14 @@ GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File",
|
||||
return strcmp(filename, ""); //return true if filename != ""
|
||||
}
|
||||
|
||||
noinline bool gtk_file_save(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File",
|
||||
GTK_WINDOW(owner.info.window), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
owner ? GTK_WINDOW(owner->info.window) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, 0);
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, (const gchar*)0);
|
||||
|
||||
if(path && strcmp(path, "")) {
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
@@ -85,19 +87,6 @@ GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File",
|
||||
return strcmp(filename, ""); //return true if filename != ""
|
||||
}
|
||||
|
||||
//FreeBSD 6.2-amd64 bug workaround for file_load() + file_save()
|
||||
//gdb reveals stack corruption when calling gtk_file_chooset_dialog_new() from inside
|
||||
//a member function. however, calling function with nesting sidesteps the bug ...
|
||||
//gdb shows that the corruption occurs inside a GTK+ internal library function ...
|
||||
|
||||
bool file_load(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
return gtk_file_load(owner, filename, filter, path);
|
||||
}
|
||||
|
||||
bool file_save(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
return gtk_file_save(owner, filename, filter, path);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint16 translate_key(uint key) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libui_gtk ~byuu (2007-05-27)
|
||||
libui_gtk ~byuu (2007-06-06)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
@@ -28,8 +28,8 @@ bool events_pending();
|
||||
uint get_screen_width();
|
||||
uint get_screen_height();
|
||||
|
||||
bool file_load(Window &owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(Window &owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
|
||||
uint16 translate_key(uint key);
|
||||
|
||||
@@ -53,20 +53,22 @@ enum Style {
|
||||
|
||||
MenuBar menu;
|
||||
void create(uint style, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
void set_text(const char *str);
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
void focus();
|
||||
bool focused();
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
virtual bool close() { return true; }
|
||||
virtual void keydown(uint16 key) {}
|
||||
virtual void keyup(uint16 key) {}
|
||||
void show(bool state);
|
||||
bool visible();
|
||||
void fullscreen();
|
||||
void unfullscreen();
|
||||
void fullscreen(bool state);
|
||||
bool is_fullscreen();
|
||||
|
||||
virtual int message(uint id, void *param = 0) {}
|
||||
virtual void clicked(Control&) {}
|
||||
virtual void changed(Control&) {}
|
||||
virtual bool message(uint id, uintptr_t param = 0) { return true; }
|
||||
|
||||
//private:
|
||||
struct {
|
||||
|
@@ -321,13 +321,8 @@ void Label::create(Window &r_owner, uint style, uint x, uint y, uint width, uint
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Label::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string temp;
|
||||
vsprintf(temp, str, args);
|
||||
va_end(args);
|
||||
gtk_label_set_label(GTK_LABEL(widget), strptr(temp));
|
||||
void Label::set_text(const char *str) {
|
||||
gtk_label_set_label(GTK_LABEL(widget), str);
|
||||
}
|
||||
|
||||
/*****
|
||||
@@ -345,13 +340,8 @@ void Button::create(Window &r_owner, uint style, uint x, uint y, uint width, uin
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this);
|
||||
}
|
||||
|
||||
void Button::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string temp;
|
||||
vsprintf(temp, str, args);
|
||||
va_end(args);
|
||||
gtk_button_set_label(GTK_BUTTON(widget), strptr(temp));
|
||||
void Button::set_text(const char *str) {
|
||||
gtk_button_set_label(GTK_BUTTON(widget), str);
|
||||
}
|
||||
|
||||
/*****
|
||||
@@ -447,17 +437,11 @@ void Editbox::create(Window &r_owner, uint style, uint x, uint y, uint width, ui
|
||||
gtk_widget_show(widget);
|
||||
}
|
||||
|
||||
void Editbox::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string temp;
|
||||
vsprintf(temp, str, args);
|
||||
va_end(args);
|
||||
|
||||
void Editbox::set_text(const char *str) {
|
||||
if(multiline == false) {
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), strptr(temp));
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), str);
|
||||
} else {
|
||||
gtk_text_buffer_set_text(buffer, strptr(temp), -1);
|
||||
gtk_text_buffer_set_text(buffer, str, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,28 +523,16 @@ void Listbox::set_column_width(uint column, uint width) {
|
||||
gtk_tree_view_column_set_max_width(column_list[column], width);
|
||||
}
|
||||
|
||||
void Listbox::add_item(const char *data, ...) {
|
||||
va_list args;
|
||||
va_start(args, data);
|
||||
string temp;
|
||||
vsprintf(temp, data, args);
|
||||
va_end(args);
|
||||
|
||||
void Listbox::add_item(const char *data) {
|
||||
stringarray part;
|
||||
split(part, "|", temp);
|
||||
split(part, "|", data);
|
||||
gtk_list_store_append(store, &iter);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
gtk_list_store_set(store, &iter, i, strptr(part[i]), -1);
|
||||
}
|
||||
}
|
||||
|
||||
void Listbox::set_item(uint index, const char *data, ...) {
|
||||
va_list args;
|
||||
va_start(args, data);
|
||||
string temp;
|
||||
vsprintf(temp, data, args);
|
||||
va_end(args);
|
||||
|
||||
void Listbox::set_item(uint index, const char *data) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
for(uint i = 0; i <= index; i++) {
|
||||
(i == 0) ?
|
||||
@@ -569,14 +541,14 @@ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
}
|
||||
|
||||
stringarray part;
|
||||
split(part, "|", temp);
|
||||
split(part, "|", data);
|
||||
for(uint i = 0; i < count(part); i++) {
|
||||
gtk_list_store_set(store, &iter, i, strptr(part[i]), -1);
|
||||
}
|
||||
}
|
||||
|
||||
int Listbox::get_selection() {
|
||||
//... because gtk_tree_view_get_selected_row(GTK_TREE_VIEW(subwidget)) would be too easy ...
|
||||
int Listbox::get_selection() {
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subwidget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) { return -1; }
|
||||
@@ -588,18 +560,21 @@ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Listbox::set_selection(int index) {
|
||||
//... because gtk_tree_view_set_selected_row(GTK_TREE_VIEW(subwidget), index) would be too easy ...
|
||||
void Listbox::set_selection(int index) {
|
||||
int current = get_selection();
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subwidget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget));
|
||||
gtk_tree_selection_unselect_all(selection);
|
||||
if(index < 0) { return; }
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) { return; }
|
||||
if(index == 0) { gtk_tree_selection_select_iter(selection, &iter); return; }
|
||||
if(index < 0) { goto end; }
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) { goto end; }
|
||||
if(index == 0) { gtk_tree_selection_select_iter(selection, &iter); goto end; }
|
||||
for(uint i = 1; i < 100000; i++) {
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) { return; }
|
||||
if(index == i) { gtk_tree_selection_select_iter(selection, &iter); return; }
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) { goto end; }
|
||||
if(index == i) { gtk_tree_selection_select_iter(selection, &iter); goto end; }
|
||||
}
|
||||
end:
|
||||
if(current != index) { owner->message(Message::Changed, (uintptr_t)this); }
|
||||
}
|
||||
|
||||
void Listbox::reset() {
|
||||
|
@@ -147,16 +147,19 @@ class Frame : public Control { public:
|
||||
};
|
||||
|
||||
class Label : public Control { public:
|
||||
enum { ideal_height = 18 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
void set_text(const char *str);
|
||||
};
|
||||
|
||||
class Button : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
void set_text(const char *str);
|
||||
};
|
||||
|
||||
class Checkbox : public Control { public:
|
||||
enum { ideal_height = 18 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
void uncheck();
|
||||
@@ -165,12 +168,14 @@ class Checkbox : public Control { public:
|
||||
};
|
||||
|
||||
class Radiobox : public Control { public:
|
||||
enum { ideal_height = 18 };
|
||||
void create(Window &owner, ControlGroup &group, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
bool checked();
|
||||
};
|
||||
|
||||
class Editbox : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
enum {
|
||||
Multiline = (1 << 1),
|
||||
Readonly = (1 << 2),
|
||||
@@ -185,7 +190,7 @@ enum {
|
||||
};
|
||||
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
void set_text(const char *str);
|
||||
uint get_text(char *str, uint length);
|
||||
|
||||
private:
|
||||
@@ -210,8 +215,8 @@ enum {
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *columns = "");
|
||||
void autosize_columns();
|
||||
void set_column_width(uint column, uint width);
|
||||
void add_item(const char *data, ...);
|
||||
void set_item(uint index, const char *data, ...);
|
||||
void add_item(const char *data);
|
||||
void set_item(uint index, const char *data);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
@@ -226,6 +231,7 @@ GtkTreeIter iter;
|
||||
};
|
||||
|
||||
class Combobox : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void add_item(const char *data);
|
||||
int get_selection();
|
||||
@@ -237,12 +243,14 @@ uint counter;
|
||||
};
|
||||
|
||||
class Progressbar : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void set_progress(uint progress);
|
||||
uint get_progress();
|
||||
};
|
||||
|
||||
class Slider : public Control { public:
|
||||
enum { ideal_height = 25 };
|
||||
enum {
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
|
@@ -6,25 +6,25 @@ gint libui_window_close(GtkWidget *w, GdkEventAny *any, Window *window) {
|
||||
}
|
||||
|
||||
gint libui_window_keydown(GtkWidget *w, GdkEventKey *key, Window *window) {
|
||||
if(window) { window->message(Message::KeyDown, (void*)libui::translate_key(key->keyval)); }
|
||||
if(window) { window->message(Message::KeyDown, libui::translate_key(key->keyval)); }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gint libui_window_keyup(GtkWidget *w, GdkEventKey *key, Window *window) {
|
||||
if(window) { window->message(Message::KeyUp, (void*)libui::translate_key(key->keyval)); }
|
||||
if(window) { window->message(Message::KeyUp, libui::translate_key(key->keyval)); }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void libui_control_clicked(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::Clicked, control); }
|
||||
if(control && control->owner) { control->owner->message(Message::Clicked, (uintptr_t)control); }
|
||||
}
|
||||
|
||||
void libui_control_changed(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::Changed, control); }
|
||||
if(control && control->owner) { control->owner->message(Message::Changed, (uintptr_t)control); }
|
||||
}
|
||||
|
||||
void libui_control_double_clicked(Control *control) {
|
||||
if(control && control->owner) { control->owner->message(Message::DoubleClicked, control); }
|
||||
if(control && control->owner) { control->owner->message(Message::DoubleClicked, (uintptr_t)control); }
|
||||
}
|
||||
|
||||
void Window::create(uint style, uint width, uint height, const char *caption) {
|
||||
@@ -56,6 +56,10 @@ void Window::focus() {
|
||||
gtk_window_present(GTK_WINDOW(info.window));
|
||||
}
|
||||
|
||||
bool Window::focused() {
|
||||
return GTK_WIDGET_HAS_FOCUS(info.window);
|
||||
}
|
||||
|
||||
void Window::move(uint x, uint y) {
|
||||
//if window was centered before, GTK+ will ignore move requests,
|
||||
//therfore we must turn off auto-centering.
|
||||
@@ -75,13 +79,32 @@ void Window::hide() {
|
||||
gtk_widget_hide(info.window);
|
||||
}
|
||||
|
||||
void Window::set_text(const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
string temp;
|
||||
vsprintf(temp, str, args);
|
||||
va_end(args);
|
||||
gtk_window_set_title(GTK_WINDOW(info.window), strptr(temp));
|
||||
void Window::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
bool Window::visible() {
|
||||
return GTK_WIDGET_VISIBLE(info.window);
|
||||
}
|
||||
|
||||
void Window::fullscreen() {
|
||||
gtk_window_fullscreen(GTK_WINDOW(info.window));
|
||||
}
|
||||
|
||||
void Window::unfullscreen() {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(info.window));
|
||||
}
|
||||
|
||||
void Window::fullscreen(bool state) {
|
||||
(state == true) ? fullscreen() : unfullscreen();
|
||||
}
|
||||
|
||||
bool Window::is_fullscreen() {
|
||||
return false;
|
||||
};
|
||||
|
||||
void Window::set_text(const char *str) {
|
||||
gtk_window_set_title(GTK_WINDOW(info.window), str);
|
||||
}
|
||||
|
||||
void Window::set_background_color(uint8 r, uint8 g, uint8 b) {
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#define _WIN32_IE 0x0600
|
||||
|
||||
#include "libui_win.h"
|
||||
#include "libui_win_window.cpp"
|
||||
#include "libui_win_control.cpp"
|
||||
@@ -81,7 +83,7 @@ uint get_screen_height() { return GetSystemMetrics(SM_CYSCREEN); }
|
||||
|
||||
//
|
||||
|
||||
bool file_load(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
string dir, f;
|
||||
strcpy(dir, path ? path : "");
|
||||
replace(dir, "/", "\\");
|
||||
@@ -111,7 +113,7 @@ OPENFILENAME ofn;
|
||||
strcpy(filename, "");
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner.info.hwnd;
|
||||
ofn.hwndOwner = owner ? owner->info.hwnd : 0;
|
||||
ofn.lpstrFilter = pf;
|
||||
ofn.lpstrInitialDir = strptr(dir);
|
||||
ofn.lpstrFile = filename;
|
||||
@@ -122,7 +124,7 @@ OPENFILENAME ofn;
|
||||
return GetOpenFileName(&ofn);
|
||||
}
|
||||
|
||||
bool file_save(Window &owner, char *filename, const char *filter, const char *path) {
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path) {
|
||||
string dir, f;
|
||||
strcpy(dir, path ? path : "");
|
||||
replace(dir, "/", "\\");
|
||||
@@ -152,7 +154,7 @@ OPENFILENAME ofn;
|
||||
strcpy(filename, "");
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner.info.hwnd;
|
||||
ofn.hwndOwner = owner ? owner->info.hwnd : 0;
|
||||
ofn.lpstrFilter = pf;
|
||||
ofn.lpstrInitialDir = strptr(dir);
|
||||
ofn.lpstrFile = filename;
|
||||
@@ -170,6 +172,19 @@ uint16 translate_key(uint key) {
|
||||
|
||||
case VK_ESCAPE: return keymap::esc;
|
||||
|
||||
case VK_F1: return keymap::f1;
|
||||
case VK_F2: return keymap::f2;
|
||||
case VK_F3: return keymap::f3;
|
||||
case VK_F4: return keymap::f4;
|
||||
case VK_F5: return keymap::f5;
|
||||
case VK_F6: return keymap::f6;
|
||||
case VK_F7: return keymap::f7;
|
||||
case VK_F8: return keymap::f8;
|
||||
case VK_F9: return keymap::f9;
|
||||
case VK_F10: return keymap::f10;
|
||||
case VK_F11: return keymap::f11;
|
||||
case VK_F12: return keymap::f12;
|
||||
|
||||
case VK_TAB: return keymap::tab;
|
||||
case VK_RETURN: return keymap::enter;
|
||||
case VK_SPACE: return keymap::space;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
libui_win ~byuu (2007-05-28)
|
||||
libui_win ~byuu (2007-06-10)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
@@ -32,8 +32,8 @@ bool events_pending();
|
||||
uint get_screen_width();
|
||||
uint get_screen_height();
|
||||
|
||||
bool file_load(Window &owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(Window &owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_load(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
bool file_save(Window *owner, char *filename, const char *filter, const char *path = "");
|
||||
|
||||
uint16 translate_key(uint key);
|
||||
|
||||
@@ -60,12 +60,19 @@ MenuBar menu;
|
||||
void set_text(const char *str, ...);
|
||||
void set_background_color(uint8 r, uint8 g, uint8 b);
|
||||
void focus();
|
||||
bool focused();
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
void show(bool state);
|
||||
bool visible();
|
||||
void fullscreen();
|
||||
void unfullscreen();
|
||||
void fullscreen(bool state);
|
||||
bool is_fullscreen();
|
||||
|
||||
virtual int message(uint id, void *param = 0) { return 0; }
|
||||
virtual bool message(uint id, uintptr_t param = 0) { return true; }
|
||||
|
||||
void move(Control &control, uint x, uint y);
|
||||
void attach(Control &control);
|
||||
@@ -78,6 +85,7 @@ MenuBar menu;
|
||||
//private:
|
||||
struct {
|
||||
uint width, height;
|
||||
bool fullscreen;
|
||||
|
||||
HWND hwnd;
|
||||
HWND hwnd_resize;
|
||||
|
@@ -4,6 +4,10 @@ namespace libui {
|
||||
* Control
|
||||
*****/
|
||||
|
||||
void Control::move(uint x, uint y) {
|
||||
SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
void Control::resize(uint width, uint height) {
|
||||
SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
|
||||
}
|
||||
@@ -137,13 +141,13 @@ void MenuCheckItem::create(MenuGroup &r_owner, const char *caption) {
|
||||
void MenuCheckItem::check() {
|
||||
if(checked() == true)return;
|
||||
CheckMenuItem(parent, id, MF_CHECKED);
|
||||
owner->message(Message::Clicked, this);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::uncheck() {
|
||||
if(checked() == false)return;
|
||||
CheckMenuItem(parent, id, MF_UNCHECKED);
|
||||
owner->message(Message::Clicked, this);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::check(bool state) {
|
||||
@@ -180,7 +184,7 @@ void MenuRadioItem::check() {
|
||||
for(uint i = 0; i < group.count(); i++) {
|
||||
CheckMenuItem(parent, group[i].id, (id == group[i].id) ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
owner->message(Message::Clicked, this);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::checked() {
|
||||
@@ -355,11 +359,20 @@ long __stdcall label_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
BeginPaint(hwnd, &ps);
|
||||
RECT rc;
|
||||
char t[4096];
|
||||
GetWindowText(hwnd, t, 4095);
|
||||
GetWindowText(hwnd, t, 4095); //TODO: use internal buffer, so length is not limited ...
|
||||
GetClientRect(hwnd, &rc);
|
||||
SetTextColor(ps.hdc, RGB(0, 0, 0));
|
||||
SetBkMode(ps.hdc, TRANSPARENT);
|
||||
SelectObject(ps.hdc, (HGDIOBJ)libui::font.variable);
|
||||
//center text if text height < control height, otherwise draw from top left corner
|
||||
RECT trc;
|
||||
GetClientRect(hwnd, &trc);
|
||||
DrawText(ps.hdc, t, strlen(t), &trc, DT_CALCRECT);
|
||||
if(trc.bottom < rc.bottom) {
|
||||
rc.top = (rc.bottom - trc.bottom) / 2;
|
||||
rc.bottom = rc.top + trc.bottom;
|
||||
}
|
||||
//
|
||||
DrawText(ps.hdc, t, strlen(t), &rc, DT_END_ELLIPSIS | DT_NOPREFIX);
|
||||
EndPaint(hwnd, &ps);
|
||||
} break;
|
||||
@@ -419,13 +432,13 @@ void Checkbox::create(Window &r_owner, uint style, uint x, uint y, uint width, u
|
||||
void Checkbox::check() {
|
||||
if(checked() == true)return;
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)TRUE, 0);
|
||||
owner->message(Message::Clicked, this);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void Checkbox::uncheck() {
|
||||
if(checked() == false)return;
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)FALSE, 0);
|
||||
owner->message(Message::Clicked, this);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
void Checkbox::check(bool state) {
|
||||
@@ -456,7 +469,7 @@ void Radiobox::check() {
|
||||
for(uint i = 0; i < group.count(); i++) {
|
||||
SendMessage(group[i].hwnd, BM_SETCHECK, (group[i].hwnd == hwnd) ? (WPARAM)TRUE : (WPARAM)FALSE, 0);
|
||||
}
|
||||
owner->message(Message::Clicked, this);
|
||||
owner->message(Message::Clicked, (uintptr_t)this);
|
||||
}
|
||||
|
||||
bool Radiobox::checked() {
|
||||
|
@@ -25,6 +25,7 @@ namespace ControlType {
|
||||
|
||||
class Control { public:
|
||||
uint type;
|
||||
void move(uint x, uint y);
|
||||
void resize(uint width, uint height);
|
||||
|
||||
void focus();
|
||||
@@ -156,15 +157,18 @@ class Frame : public Control { public:
|
||||
};
|
||||
|
||||
class Label : public Control { public:
|
||||
enum { ideal_height = 16 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void set_text(const char *str, ...);
|
||||
};
|
||||
|
||||
class Button : public Control { public:
|
||||
enum { ideal_height = 21 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
};
|
||||
|
||||
class Checkbox : public Control { public:
|
||||
enum { ideal_height = 15 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
void uncheck();
|
||||
@@ -173,6 +177,7 @@ class Checkbox : public Control { public:
|
||||
};
|
||||
|
||||
class Radiobox : public Control { public:
|
||||
enum { ideal_height = 15 };
|
||||
void create(Window &owner, ControlGroup &list, uint style, uint x, uint y, uint width, uint height, const char *caption = "");
|
||||
void check();
|
||||
bool checked();
|
||||
@@ -182,6 +187,7 @@ ControlGroup group;
|
||||
};
|
||||
|
||||
class Editbox : public Control { public:
|
||||
enum { ideal_height = 21 };
|
||||
enum {
|
||||
Multiline = (1 << 1),
|
||||
Readonly = (1 << 2),
|
||||
@@ -234,6 +240,7 @@ uint column_count;
|
||||
};
|
||||
|
||||
class Combobox : public Control { public:
|
||||
enum { ideal_height = 21 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void add_item(const char *data);
|
||||
void set_selection(int index);
|
||||
@@ -242,12 +249,14 @@ class Combobox : public Control { public:
|
||||
};
|
||||
|
||||
class Progressbar : public Control { public:
|
||||
enum { ideal_height = 30 };
|
||||
void create(Window &owner, uint style, uint x, uint y, uint width, uint height);
|
||||
void set_progress(uint progress);
|
||||
uint get_progress();
|
||||
};
|
||||
|
||||
class Slider : public Control { public:
|
||||
enum { ideal_height = 25 };
|
||||
enum Style {
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
|
@@ -33,11 +33,11 @@ long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
||||
} break;
|
||||
|
||||
case WM_KEYDOWN: {
|
||||
message(Message::KeyDown, (void*)libui::translate_key(wparam));
|
||||
message(Message::KeyDown, libui::translate_key(wparam));
|
||||
} break;
|
||||
|
||||
case WM_KEYUP: {
|
||||
message(Message::KeyUp, (void*)libui::translate_key(wparam));
|
||||
message(Message::KeyUp, libui::translate_key(wparam));
|
||||
} break;
|
||||
|
||||
case WM_COMMAND: {
|
||||
@@ -68,7 +68,7 @@ long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
||||
//emit Message::Clicked message directly
|
||||
case ControlType::MenuItem:
|
||||
case ControlType::Button: {
|
||||
message(Message::Clicked, &control);
|
||||
message(Message::Clicked, (uintptr_t)&control);
|
||||
} break;
|
||||
|
||||
}
|
||||
@@ -84,7 +84,7 @@ long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
||||
switch(control.type) {
|
||||
|
||||
case ControlType::Slider: {
|
||||
message(Message::Changed, &control);
|
||||
message(Message::Changed, (uintptr_t)&control);
|
||||
} break;
|
||||
|
||||
}
|
||||
@@ -104,12 +104,12 @@ long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
|
||||
if(((LPNMLISTVIEW)lparam)->uChanged & LVIF_STATE) {
|
||||
if(ListView_GetItemState(listbox.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_FOCUSED)) {
|
||||
if(ListView_GetItemState(listbox.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_SELECTED)) {
|
||||
message(Message::Changed, &control);
|
||||
message(Message::Changed, (uintptr_t)&control);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(((LPNMHDR)lparam)->code == LVN_ITEMACTIVATE) {
|
||||
message(Message::DoubleClicked, &control);
|
||||
message(Message::DoubleClicked, (uintptr_t)&control);
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -131,10 +131,14 @@ void Window::attach(Control &control) {
|
||||
}
|
||||
|
||||
void Window::focus() {
|
||||
show();
|
||||
if(!visible()) { show(); }
|
||||
SetFocus(info.hwnd);
|
||||
}
|
||||
|
||||
bool Window::focused() {
|
||||
return (GetForegroundWindow() == info.hwnd);
|
||||
}
|
||||
|
||||
void Window::move(Control &control, uint x, uint y) {
|
||||
SetWindowPos(control.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
@@ -180,6 +184,13 @@ RECT rc;
|
||||
}
|
||||
|
||||
void Window::resize(uint width, uint height) {
|
||||
if(info.fullscreen == true) {
|
||||
info.width = GetSystemMetrics(SM_CXSCREEN);
|
||||
info.height = GetSystemMetrics(SM_CYSCREEN);
|
||||
SetWindowPos(info.hwnd, 0, 0, 0, info.width, info.height, SWP_NOZORDER);
|
||||
return;
|
||||
}
|
||||
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
|
||||
@@ -212,6 +223,36 @@ void Window::hide() {
|
||||
ShowWindow(info.hwnd, SW_HIDE);
|
||||
}
|
||||
|
||||
void Window::show(bool state) {
|
||||
(state == true) ? show() : hide();
|
||||
}
|
||||
|
||||
bool Window::visible() {
|
||||
return GetWindowLong(info.hwnd, GWL_STYLE) & WS_VISIBLE;
|
||||
}
|
||||
|
||||
void Window::fullscreen() {
|
||||
if(info.fullscreen)return;
|
||||
info.fullscreen = true;
|
||||
SetWindowLong(info.hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
resize(get_screen_width(), get_screen_height());
|
||||
}
|
||||
|
||||
void Window::unfullscreen() {
|
||||
if(!info.fullscreen)return;
|
||||
info.fullscreen = false;
|
||||
SetWindowLong(info.hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE);
|
||||
resize(info.width, info.height);
|
||||
}
|
||||
|
||||
void Window::fullscreen(bool state) {
|
||||
(state == true) ? fullscreen() : unfullscreen();
|
||||
}
|
||||
|
||||
bool Window::is_fullscreen() {
|
||||
return info.fullscreen;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void Window::set_text(const char *str, ...) {
|
||||
@@ -234,6 +275,7 @@ HBRUSH old_brush = info.background;
|
||||
//
|
||||
|
||||
Window::Window() {
|
||||
info.fullscreen = false;
|
||||
info.background = 0;
|
||||
info.center = false;
|
||||
info.control_index = 1;
|
||||
|
@@ -64,10 +64,8 @@
|
||||
* and speed is less critical.
|
||||
*****/
|
||||
|
||||
#ifndef __LIBVECTOR
|
||||
#define __LIBVECTOR
|
||||
|
||||
#include <new>
|
||||
#ifndef LIBVECTOR_H
|
||||
#define LIBVECTOR_H
|
||||
|
||||
template<typename T> class linear_vector {
|
||||
protected:
|
||||
|
@@ -27,11 +27,12 @@ void bMemBus::load_cart() {
|
||||
return;
|
||||
}
|
||||
|
||||
if(cartridge.info.sdd1)cart_map_sdd1();
|
||||
if(cartridge.info.c4) cart_map_c4();
|
||||
if(cartridge.info.dsp1)cart_map_dsp1();
|
||||
if(cartridge.info.dsp2)cart_map_dsp2();
|
||||
if(cartridge.info.obc1)cart_map_obc1();
|
||||
if(cartridge.info.sdd1) cart_map_sdd1();
|
||||
if(cartridge.info.c4) cart_map_c4();
|
||||
if(cartridge.info.dsp1) cart_map_dsp1();
|
||||
if(cartridge.info.dsp2) cart_map_dsp2();
|
||||
if(cartridge.info.obc1) cart_map_obc1();
|
||||
if(cartridge.info.st010)cart_map_st010();
|
||||
|
||||
cart_map_system();
|
||||
|
||||
@@ -57,12 +58,13 @@ char t[256];
|
||||
dprintf("* Region : %s", (cartridge.info.region == Cartridge::NTSC) ? "NTSC" : "PAL");
|
||||
|
||||
strcpy(t, "");
|
||||
if(cartridge.info.srtc)strcat(t, "S-RTC, ");
|
||||
if(cartridge.info.sdd1)strcat(t, "S-DD1, ");
|
||||
if(cartridge.info.c4) strcat(t, "Cx4, ");
|
||||
if(cartridge.info.dsp1)strcat(t, "DSP-1, ");
|
||||
if(cartridge.info.dsp2)strcat(t, "DSP-2, ");
|
||||
if(cartridge.info.obc1)strcat(t, "OBC-1, ");
|
||||
if(cartridge.info.srtc) strcat(t, "S-RTC, ");
|
||||
if(cartridge.info.sdd1) strcat(t, "S-DD1, ");
|
||||
if(cartridge.info.c4) strcat(t, "Cx4, ");
|
||||
if(cartridge.info.dsp1) strcat(t, "DSP-1, ");
|
||||
if(cartridge.info.dsp2) strcat(t, "DSP-2, ");
|
||||
if(cartridge.info.obc1) strcat(t, "OBC-1, ");
|
||||
if(cartridge.info.st010)strcat(t, "ST010, ");
|
||||
strrtrim(t, ", ");
|
||||
dprintf("* Coprocessor(s) : %s", (strlen(t) == 0) ? "None" : t);
|
||||
dprintf("* Reset:%0.4x NMI[n]:%0.4x IRQ[n]:%0.4x BRK[n]:%0.4x COP[n]:%0.4x",
|
||||
|
@@ -41,6 +41,8 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART };
|
||||
void write_dsp2 (uint32 addr, uint8 data);
|
||||
uint8 read_obc1 (uint32 addr);
|
||||
void write_obc1 (uint32 addr, uint8 data);
|
||||
uint8 read_st010 (uint32 addr);
|
||||
void write_st010 (uint32 addr, uint8 data);
|
||||
|
||||
void cart_map_reset();
|
||||
void cart_map_system();
|
||||
@@ -51,6 +53,7 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART };
|
||||
void cart_map_dsp1();
|
||||
void cart_map_dsp2();
|
||||
void cart_map_obc1();
|
||||
void cart_map_st010();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
@@ -178,3 +178,15 @@ void bMemBus::cart_map_obc1() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bMemBus::cart_map_st010() {
|
||||
//$[68-6f|e8-ef]:[0000-0fff]
|
||||
for(uint bank = 0x68; bank <= 0x6f; bank++) {
|
||||
for(uint page = 0x00; page <= 0x0f; page++) {
|
||||
page_read [0x0000 + (bank << 8) + page] = &bMemBus::read_st010;
|
||||
page_read [0x8000 + (bank << 8) + page] = &bMemBus::read_st010;
|
||||
page_write[0x0000 + (bank << 8) + page] = &bMemBus::write_st010;
|
||||
page_write[0x8000 + (bank << 8) + page] = &bMemBus::write_st010;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,3 +62,6 @@ void bMemBus::write_dsp2(uint32 addr, uint8 data) { dsp2->write(addr, data); }
|
||||
|
||||
uint8 bMemBus::read_obc1 (uint32 addr) { return obc1->read(addr); }
|
||||
void bMemBus::write_obc1(uint32 addr, uint8 data) { obc1->write(addr, data); }
|
||||
|
||||
uint8 bMemBus::read_st010 (uint32 addr) { return st010->read(addr); }
|
||||
void bMemBus::write_st010(uint32 addr, uint8 data) { st010->write(addr, data); }
|
||||
|
@@ -148,8 +148,12 @@ struct {
|
||||
void cgram_write(uint16 addr, uint8 value);
|
||||
|
||||
uint16 get_vram_address();
|
||||
uint8 vram_mmio_read (uint16 addr);
|
||||
void vram_mmio_write(uint16 addr, uint8 data);
|
||||
uint8 vram_mmio_read (uint16 addr);
|
||||
void vram_mmio_write (uint16 addr, uint8 data);
|
||||
uint8 oam_mmio_read (uint16 addr);
|
||||
void oam_mmio_write (uint16 addr, uint8 data);
|
||||
uint8 cgram_mmio_read (uint16 addr);
|
||||
void cgram_mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void mmio_w2100(uint8 value); //INIDISP
|
||||
void mmio_w2101(uint8 value); //OBSEL
|
||||
|
@@ -8,7 +8,7 @@ uint16 bPPU::get_vram_address() {
|
||||
uint16 addr;
|
||||
addr = regs.vram_addr;
|
||||
switch(regs.vram_mapping) {
|
||||
case 0: break;
|
||||
case 0: break; //direct
|
||||
case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break;
|
||||
case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break;
|
||||
case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break;
|
||||
@@ -16,6 +16,11 @@ uint16 addr;
|
||||
return (addr << 1);
|
||||
}
|
||||
|
||||
//NOTE: all VRAM writes during active display are invalid. Unlike OAM and CGRAM, they will
|
||||
//not be written anywhere at all. The below address ranges for where writes are invalid have
|
||||
//been validated on hardware, as has the edge case where the S-CPU MDR can be written if the
|
||||
//write occurs during the very last clock cycle of vblank.
|
||||
|
||||
uint8 bPPU::vram_mmio_read(uint16 addr) {
|
||||
if(regs.display_disabled == true) {
|
||||
return vram_read(addr);
|
||||
@@ -46,20 +51,17 @@ uint16 ls = (r_cpu->region_scanlines() >> 1) - 1;
|
||||
|
||||
void bPPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(regs.display_disabled == true) {
|
||||
vram_write(addr, data);
|
||||
return;
|
||||
return vram_write(addr, data);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
if(v == 0) {
|
||||
if(hc <= 4) {
|
||||
vram_write(addr, data);
|
||||
return;
|
||||
return vram_write(addr, data);
|
||||
}
|
||||
if(hc == 6) {
|
||||
vram_write(addr, r_cpu->regs.mdr);
|
||||
return;
|
||||
return vram_write(addr, r_cpu->regs.mdr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -72,13 +74,87 @@ uint16 hc = r_cpu->hclock();
|
||||
if(hc <= 4) {
|
||||
return;
|
||||
}
|
||||
vram_write(addr, data);
|
||||
return;
|
||||
return vram_write(addr, data);
|
||||
}
|
||||
|
||||
vram_write(addr, data);
|
||||
}
|
||||
|
||||
//NOTE: OAM accesses during active display are rerouted to 0x0218 ... this can be considered
|
||||
//a hack. The actual address varies during rendering, as the S-PPU reads in data itself for
|
||||
//processing. Unfortunately, we have yet to determine how this works. The algorithm cannot be
|
||||
//reverse engineered using a scanline renderer such as this, and at this time, there does not
|
||||
//exist a more accurate SNES PPU emulator to work from. The only known game to actually access
|
||||
//OAM during active display is Uniracers. It expects accesses to map to offset 0x0218.
|
||||
//It was decided by public consensus to map writes to this address to match Uniracers, primarily
|
||||
//because it is the only game observed to do this, but also because mapping to this address does
|
||||
//not contradict any of our findings, because we have no findings whatsoever on this behavior.
|
||||
//Think of this what you will, I openly admit that this is a hack. But it is more accurate than
|
||||
//writing to the 'expected' address set by $2102,$2103, and will catch problems in software that
|
||||
//accidentally accesses OAM during active display by virtue of not returning the expected data.
|
||||
//You may disable this behavior by setting config::ppu.hack.oam_address_invalidation to false,
|
||||
//or by changing the address from 0x0218 to 0x0000 below if it bothers you that greatly.
|
||||
|
||||
uint8 bPPU::oam_mmio_read(uint16 addr) {
|
||||
if(config::ppu.hack.oam_address_invalidation == false || regs.display_disabled == true) {
|
||||
return oam_read(addr);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240)) {
|
||||
return oam_read(0x0218);
|
||||
}
|
||||
|
||||
return oam_read(addr);
|
||||
}
|
||||
|
||||
void bPPU::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
if(config::ppu.hack.oam_address_invalidation == false || regs.display_disabled == true) {
|
||||
return oam_write(addr, data);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240)) {
|
||||
return oam_write(0x0218, data);
|
||||
}
|
||||
|
||||
oam_write(addr, data);
|
||||
}
|
||||
|
||||
//NOTE: CGRAM writes during hblank are valid. During active display, the actual address the
|
||||
//data is written to varies, as the S-PPU itself changes the address. Like OAM, we do not know
|
||||
//the exact algorithm used, but we have zero known examples of any commercial software that
|
||||
//attempts to do this. Therefore, the addresses are mapped to 0x01ff. There is nothing special
|
||||
//about this address, it is simply more accurate to invalidate the 'expected' address than not.
|
||||
|
||||
uint8 bPPU::cgram_mmio_read(uint16 addr) {
|
||||
if(config::ppu.hack.cgram_address_invalidation == false || regs.display_disabled == true) {
|
||||
return cgram_read(addr);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240) && hc >= 72 && hc < 1096) {
|
||||
return cgram_read(0x01ff);
|
||||
}
|
||||
|
||||
return cgram_read(addr);
|
||||
}
|
||||
|
||||
void bPPU::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(config::ppu.hack.cgram_address_invalidation == false || regs.display_disabled == true) {
|
||||
return cgram_write(addr, data);
|
||||
}
|
||||
|
||||
uint16 v = r_cpu->vcounter();
|
||||
uint16 hc = r_cpu->hclock();
|
||||
if(v < (!r_cpu->overscan() ? 225 : 240) && hc >= 72 && hc < 1096) {
|
||||
return cgram_write(0x01ff, data);
|
||||
}
|
||||
|
||||
cgram_write(addr, data);
|
||||
}
|
||||
|
||||
//INIDISP
|
||||
void bPPU::mmio_w2100(uint8 value) {
|
||||
if(regs.display_disabled == true && r_cpu->vcounter() == (!r_cpu->overscan() ? 225 : 240)) {
|
||||
@@ -117,12 +193,12 @@ void bPPU::mmio_w2103(uint8 data) {
|
||||
//OAMDATA
|
||||
void bPPU::mmio_w2104(uint8 data) {
|
||||
if(regs.oam_addr & 0x0200) {
|
||||
oam_write(regs.oam_addr, data);
|
||||
oam_mmio_write(regs.oam_addr, data);
|
||||
} else if((regs.oam_addr & 1) == 0) {
|
||||
regs.oam_latchdata = data;
|
||||
} else {
|
||||
oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
|
||||
oam_write((regs.oam_addr & ~1) + 1, data);
|
||||
oam_mmio_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
|
||||
oam_mmio_write((regs.oam_addr & ~1) + 1, data);
|
||||
}
|
||||
|
||||
regs.oam_addr++;
|
||||
@@ -353,8 +429,8 @@ void bPPU::mmio_w2122(uint8 value) {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.cgram_latchdata = value;
|
||||
} else {
|
||||
cgram_write((regs.cgram_addr & 0x01fe), regs.cgram_latchdata);
|
||||
cgram_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f);
|
||||
cgram_mmio_write((regs.cgram_addr & 0x01fe), regs.cgram_latchdata);
|
||||
cgram_mmio_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f);
|
||||
}
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
@@ -540,7 +616,7 @@ uint8 bPPU::mmio_r2137() {
|
||||
|
||||
//OAMDATAREAD
|
||||
uint8 bPPU::mmio_r2138() {
|
||||
regs.ppu1_mdr = oam_read(regs.oam_addr);
|
||||
regs.ppu1_mdr = oam_mmio_read(regs.oam_addr);
|
||||
|
||||
regs.oam_addr++;
|
||||
regs.oam_addr &= 0x03ff;
|
||||
@@ -581,10 +657,10 @@ uint16 addr = get_vram_address() + 1;
|
||||
//update bit 7 of the PPU2 MDR.
|
||||
uint8 bPPU::mmio_r213b() {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.ppu2_mdr = cgram_read(regs.cgram_addr) & 0xff;
|
||||
regs.ppu2_mdr = cgram_mmio_read(regs.cgram_addr) & 0xff;
|
||||
} else {
|
||||
regs.ppu2_mdr &= 0x80;
|
||||
regs.ppu2_mdr |= cgram_read(regs.cgram_addr) & 0x7f;
|
||||
regs.ppu2_mdr |= cgram_mmio_read(regs.cgram_addr) & 0x7f;
|
||||
}
|
||||
regs.cgram_addr++;
|
||||
regs.cgram_addr &= 0x01ff;
|
||||
|
@@ -27,7 +27,9 @@ uint16 bPPU::bg_get_tile(uint8 bg, uint16 x, uint16 y) {
|
||||
uint16 pos = ((y & 0x1f) << 5) + (x & 0x1f);
|
||||
if(y & 0x20)pos += bg_info[bg].scy;
|
||||
if(x & 0x20)pos += bg_info[bg].scx;
|
||||
return read16(vram, regs.bg_scaddr[bg] + (pos << 1));
|
||||
|
||||
uint16 addr = regs.bg_scaddr[bg] + (pos << 1);
|
||||
return (vram_read(addr + 0) << 0) | (vram_read(addr + 1) << 8);
|
||||
}
|
||||
|
||||
#define setpixel_main(x) \
|
||||
|
@@ -61,14 +61,14 @@ tclr_addr_a(0x4e, &~) {
|
||||
5:op_writeaddr(dp, rd $1 regs.a);
|
||||
}
|
||||
|
||||
incw_dp(0x3a, rd++),
|
||||
decw_dp(0x1a, rd--) {
|
||||
incw_dp(0x3a, ++),
|
||||
decw_dp(0x1a, --) {
|
||||
1:dp = op_readpc();
|
||||
2:rd = op_readdp(dp);
|
||||
$1;
|
||||
rd$1;
|
||||
3:op_writedp(dp++, rd);
|
||||
4:rd += op_readdp(dp) << 8;
|
||||
5:op_write(dp, rd >> 8);
|
||||
5:op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
@@ -212,7 +212,7 @@ void sSMP::op_incw_dp() {
|
||||
rd++;
|
||||
op_writedp(dp++, rd);
|
||||
rd += op_readdp(dp) << 8;
|
||||
op_write(dp, rd >> 8);
|
||||
op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
@@ -223,7 +223,7 @@ void sSMP::op_decw_dp() {
|
||||
rd--;
|
||||
op_writedp(dp++, rd);
|
||||
rd += op_readdp(dp) << 8;
|
||||
op_write(dp, rd >> 8);
|
||||
op_writedp(dp, rd >> 8);
|
||||
regs.p.n = !!(rd & 0x8000);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ class SNESInterface { public:
|
||||
|
||||
void audio_sample(uint16 l_sample, uint16 r_sample);
|
||||
|
||||
functor<bool ()> input_ready;
|
||||
void input_poll();
|
||||
bool input_poll(uint deviceid, uint button);
|
||||
|
||||
|
@@ -2,10 +2,10 @@ Scheduler scheduler;
|
||||
|
||||
//
|
||||
|
||||
void cocall threadentry_cpu(void*) { r_cpu->enter(); }
|
||||
void cocall threadentry_smp(void*) { r_smp->enter(); }
|
||||
void cocall threadentry_ppu(void*) {} //currently unused
|
||||
void cocall threadentry_dsp(void*) { r_dsp->enter(); }
|
||||
void threadentry_cpu() { r_cpu->enter(); }
|
||||
void threadentry_smp() { r_smp->enter(); }
|
||||
void threadentry_ppu() { } //currently unused
|
||||
void threadentry_dsp() { r_dsp->enter(); }
|
||||
|
||||
//
|
||||
|
||||
@@ -41,10 +41,10 @@ void Scheduler::init() {
|
||||
if(thread_dsp)co_delete(thread_dsp);
|
||||
|
||||
thread_snes = co_active();
|
||||
thread_cpu = co_create(sizeof(void*) * 64 * 1024, threadentry_cpu, 0);
|
||||
thread_smp = co_create(sizeof(void*) * 64 * 1024, threadentry_smp, 0);
|
||||
thread_ppu = co_create(sizeof(void*) * 64 * 1024, threadentry_ppu, 0);
|
||||
thread_dsp = co_create(sizeof(void*) * 64 * 1024, threadentry_dsp, 0);
|
||||
thread_cpu = co_create(sizeof(void*) * 64 * 1024, threadentry_cpu);
|
||||
thread_smp = co_create(sizeof(void*) * 64 * 1024, threadentry_smp);
|
||||
thread_ppu = co_create(sizeof(void*) * 64 * 1024, threadentry_ppu);
|
||||
thread_dsp = co_create(sizeof(void*) * 64 * 1024, threadentry_dsp);
|
||||
}
|
||||
|
||||
//
|
||||
|
@@ -16,12 +16,13 @@ void SNES::runtoframe() {
|
||||
}
|
||||
|
||||
void SNES::init() {
|
||||
srtc = new SRTC();
|
||||
sdd1 = new SDD1();
|
||||
c4 = new C4();
|
||||
dsp1 = new DSP1();
|
||||
dsp2 = new DSP2();
|
||||
obc1 = new OBC1();
|
||||
srtc = new SRTC();
|
||||
sdd1 = new SDD1();
|
||||
c4 = new C4();
|
||||
dsp1 = new DSP1();
|
||||
dsp2 = new DSP2();
|
||||
obc1 = new OBC1();
|
||||
st010 = new ST010();
|
||||
|
||||
srtc->init();
|
||||
sdd1->init();
|
||||
@@ -29,6 +30,7 @@ void SNES::init() {
|
||||
dsp1->init();
|
||||
dsp2->init();
|
||||
obc1->init();
|
||||
st010->init();
|
||||
|
||||
video_init();
|
||||
audio_init();
|
||||
@@ -50,12 +52,13 @@ void SNES::power() {
|
||||
r_ppu->power();
|
||||
r_mem->power();
|
||||
|
||||
if(cartridge.info.srtc)srtc->power();
|
||||
if(cartridge.info.sdd1)sdd1->power();
|
||||
if(cartridge.info.c4) c4->power();
|
||||
if(cartridge.info.dsp1)dsp1->power();
|
||||
if(cartridge.info.dsp2)dsp2->power();
|
||||
if(cartridge.info.obc1)obc1->power();
|
||||
if(cartridge.info.srtc) srtc->power();
|
||||
if(cartridge.info.sdd1) sdd1->power();
|
||||
if(cartridge.info.c4) c4->power();
|
||||
if(cartridge.info.dsp1) dsp1->power();
|
||||
if(cartridge.info.dsp2) dsp2->power();
|
||||
if(cartridge.info.obc1) obc1->power();
|
||||
if(cartridge.info.st010)st010->power();
|
||||
|
||||
r_mem->flush_mmio_mappers();
|
||||
for(int i = 0x2100; i <= 0x213f; i++)r_mem->set_mmio_mapper(i, r_ppu);
|
||||
@@ -65,12 +68,13 @@ void SNES::power() {
|
||||
for(int i = 0x4200; i <= 0x421f; i++)r_mem->set_mmio_mapper(i, r_cpu);
|
||||
for(int i = 0x4300; i <= 0x437f; i++)r_mem->set_mmio_mapper(i, r_cpu);
|
||||
|
||||
if(cartridge.info.srtc)srtc->enable();
|
||||
if(cartridge.info.sdd1)sdd1->enable();
|
||||
if(cartridge.info.c4) c4->enable();
|
||||
if(cartridge.info.dsp1)dsp1->enable();
|
||||
if(cartridge.info.dsp2)dsp2->enable();
|
||||
if(cartridge.info.obc1)obc1->enable();
|
||||
if(cartridge.info.srtc) srtc->enable();
|
||||
if(cartridge.info.sdd1) sdd1->enable();
|
||||
if(cartridge.info.c4) c4->enable();
|
||||
if(cartridge.info.dsp1) dsp1->enable();
|
||||
if(cartridge.info.dsp2) dsp2->enable();
|
||||
if(cartridge.info.obc1) obc1->enable();
|
||||
if(cartridge.info.st010)st010->enable();
|
||||
|
||||
video_update();
|
||||
}
|
||||
@@ -84,12 +88,13 @@ void SNES::reset() {
|
||||
r_ppu->reset();
|
||||
r_mem->reset();
|
||||
|
||||
if(cartridge.info.srtc)srtc->reset();
|
||||
if(cartridge.info.sdd1)sdd1->reset();
|
||||
if(cartridge.info.c4) c4->reset();
|
||||
if(cartridge.info.dsp1)dsp1->reset();
|
||||
if(cartridge.info.dsp2)dsp2->reset();
|
||||
if(cartridge.info.obc1)obc1->reset();
|
||||
if(cartridge.info.srtc) srtc->reset();
|
||||
if(cartridge.info.sdd1) sdd1->reset();
|
||||
if(cartridge.info.c4) c4->reset();
|
||||
if(cartridge.info.dsp1) dsp1->reset();
|
||||
if(cartridge.info.dsp2) dsp2->reset();
|
||||
if(cartridge.info.obc1) obc1->reset();
|
||||
if(cartridge.info.st010)st010->reset();
|
||||
|
||||
video_update();
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
Tracer tracer;
|
||||
|
||||
void tprintf(char *s, ...) {
|
||||
void tprintf(const char *s, ...) {
|
||||
if(tracer.enabled() == false) { return; }
|
||||
|
||||
char str[4096];
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void tprintf(char *s, ...);
|
||||
void tprintf(const char *s, ...);
|
||||
|
||||
class Tracer {
|
||||
private:
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
Tracer();
|
||||
~Tracer();
|
||||
|
||||
friend void tprintf(char *s, ...);
|
||||
friend void tprintf(const char *s, ...);
|
||||
};
|
||||
|
||||
extern Tracer tracer;
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
|
||||
#include "filter_ntsc_core.cpp"
|
||||
#include "ntsc/snes_ntsc.c"
|
||||
|
||||
NtscVideoFilter::NtscVideoFilter() {
|
||||
ntsc = 0;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#include "filter_ntsc_core.h"
|
||||
#include "ntsc/snes_ntsc.h"
|
||||
|
||||
class NtscVideoFilter : public VideoFilter {
|
||||
private:
|
||||
|
@@ -1,598 +0,0 @@
|
||||
/* snes_ntsc 0.2.1. http://www.slack.net/~ant/ */
|
||||
|
||||
/* compilable in C or C++; just change the file extension */
|
||||
|
||||
//#include "snes_ntsc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Based on algorithm by NewRisingSun */
|
||||
/* Copyright (C) 2006 Shay Green. This module 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
|
||||
module 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 module; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
enum { disable_correction = 0 }; /* for debugging */
|
||||
|
||||
/* macro constants are used instead of enum in some places to work around compiler bug */
|
||||
|
||||
/* half normal range to allow for doubled hires pixels */
|
||||
#define rgb_unit 0x80
|
||||
|
||||
/* begin mostly common NES/SNES/SMS code */
|
||||
|
||||
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 0, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 0, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 0, 1, 0, 0 };
|
||||
|
||||
enum { alignment_count = 3 }; /* different pixel alignments with respect to yiq quads */
|
||||
|
||||
enum { kernel_half = 16 };
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
#define rescale_in 8
|
||||
enum { rescale_out = 7 };
|
||||
|
||||
struct ntsc_impl_t
|
||||
{
|
||||
float to_rgb [snes_ntsc_burst_count] [6];
|
||||
float brightness;
|
||||
float contrast;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float hue_warping;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
};
|
||||
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
static void init_ntsc_impl( struct ntsc_impl_t* impl, snes_ntsc_setup_t const* setup )
|
||||
{
|
||||
float kernels [kernel_size * 2];
|
||||
|
||||
impl->brightness = (float) setup->brightness * (0.4f * rgb_unit);
|
||||
impl->contrast = (float) setup->contrast * 0.4f + 1.0f;
|
||||
impl->hue_warping = (float) setup->hue_warping;
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts *= 0.5f;
|
||||
impl->artifacts += 1.0f;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing *= 0.5f;
|
||||
impl->fringing += 1.0f;
|
||||
|
||||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
/* double precision avoids instability */
|
||||
double const rolloff = 1 + setup->sharpness * 0.004;
|
||||
double const maxh = 256;
|
||||
double const pow_a_n = pow( rolloff, maxh );
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
double to_angle = setup->resolution + 1;
|
||||
to_angle = PI / maxh * 0.20 * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = (float) maxh;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
double angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > 1.01 || pow_a_n < 0.99 )
|
||||
{
|
||||
double rolloff_cos_a = rolloff * cos( angle );
|
||||
double num = 1 - rolloff_cos_a -
|
||||
pow_a_n * cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * cos( (maxh - 1) * angle );
|
||||
double den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
double dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = (float) dsf;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= -30.0f / 0.65f;
|
||||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < rescale_out; i++ )
|
||||
{
|
||||
float* out = &impl->kernel [i * kernel_size * 2];
|
||||
float second = 1.0f / rescale_in * (i + 1);
|
||||
float first = 1.0f - second;
|
||||
int x;
|
||||
*out++ = kernels [0] * first;
|
||||
for ( x = 1; x < kernel_size * 2; x++ )
|
||||
*out++ = kernels [x] * first + kernels [x - 1] * second;
|
||||
}
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
float hue = (float) setup->hue * PI;
|
||||
float sat = (float) setup->saturation + 1.0f;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
int i;
|
||||
if ( !decoder )
|
||||
decoder = default_decoder;
|
||||
else
|
||||
hue += PI / 180 * 15;
|
||||
|
||||
for ( i = 0; i < snes_ntsc_burst_count; i++ )
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float const* in = decoder;
|
||||
float* out = impl->to_rgb [i];
|
||||
int n;
|
||||
for ( n = 3; n; --n )
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
hue -= PI / 180 * 120;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* kernel generation */
|
||||
|
||||
enum { rgb_kernel_size = snes_ntsc_burst_size / alignment_count };
|
||||
|
||||
static float const rgb_offset = rgb_unit * 2 + 0.5f;
|
||||
static ntsc_rgb_t const ntsc_rgb_bias = rgb_unit * 2 * ntsc_rgb_builder;
|
||||
|
||||
#define TO_RGB( y, i, q, to_rgb ) ( \
|
||||
((int) (y + to_rgb [0] * i + to_rgb [1] * q) << 21) +\
|
||||
((int) (y + to_rgb [2] * i + to_rgb [3] * q) << 11) +\
|
||||
((int) (y + to_rgb [4] * i + to_rgb [5] * q) << 1)\
|
||||
)
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
} pixel_info_t;
|
||||
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( struct ntsc_impl_t* impl, float y, float i, float q, ntsc_rgb_t* out )
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb [0];
|
||||
do
|
||||
{
|
||||
static pixel_info_t const pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 1.0000f, 1.0000f, .6667f, .0000f } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1.0000f, 1.0000f, .3333f } },
|
||||
{ PIXEL_OFFSET( 0, -5 ), { .0000f, .6667f, 1.0000f, 1.0000f } },
|
||||
};
|
||||
|
||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
||||
Convolve these with kernels which: filter respective components, apply
|
||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
||||
into integer. */
|
||||
pixel_info_t const* pixel = pixels;
|
||||
do
|
||||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
int n;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( k >= &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
else
|
||||
k += kernel_size * 2 - 1;
|
||||
*out++ = TO_RGB( y, i, q, to_rgb ) - ntsc_rgb_bias;
|
||||
}
|
||||
}
|
||||
while ( pixel++ < &pixels [alignment_count - 1] );
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
/* rotate -120 degrees */
|
||||
{
|
||||
float const sin_b = -0.866025f;
|
||||
float const cos_b = -0.5f;
|
||||
float t;
|
||||
t = i * cos_b - q * sin_b;
|
||||
q = i * sin_b + q * cos_b;
|
||||
i = t;
|
||||
}
|
||||
}
|
||||
while ( to_rgb < impl->to_rgb [snes_ntsc_burst_count] );
|
||||
}
|
||||
|
||||
static void merge_fields( ntsc_rgb_t* io )
|
||||
{
|
||||
int n;
|
||||
for ( n = snes_ntsc_burst_size; n; --n )
|
||||
{
|
||||
ntsc_rgb_t p0 = io [snes_ntsc_burst_size * 0] + ntsc_rgb_bias;
|
||||
ntsc_rgb_t p1 = io [snes_ntsc_burst_size * 1] + ntsc_rgb_bias;
|
||||
ntsc_rgb_t p2 = io [snes_ntsc_burst_size * 2] + ntsc_rgb_bias;
|
||||
/* merge fields without losing precision */
|
||||
io [snes_ntsc_burst_size * 0] =
|
||||
((p0 + p1 - ((p0 ^ p1) & ntsc_rgb_builder)) >> 1) - ntsc_rgb_bias;
|
||||
io [snes_ntsc_burst_size * 1] =
|
||||
((p1 + p2 - ((p1 ^ p2) & ntsc_rgb_builder)) >> 1) - ntsc_rgb_bias;
|
||||
io [snes_ntsc_burst_size * 2] =
|
||||
((p2 + p0 - ((p2 ^ p0) & ntsc_rgb_builder)) >> 1) - ntsc_rgb_bias;
|
||||
++io;
|
||||
}
|
||||
}
|
||||
|
||||
static void correct_errors( ntsc_rgb_t color, ntsc_rgb_t* out )
|
||||
{
|
||||
int burst;
|
||||
for ( burst = 0; burst < snes_ntsc_burst_count; burst++ )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
{
|
||||
ntsc_rgb_t error = color -
|
||||
out [i ] -
|
||||
out [i + 3 +28] -
|
||||
out [i + 5 +14] -
|
||||
out [i + 7 ] -
|
||||
out [(i+10)%14+28] -
|
||||
out [(i+12)%14+14];
|
||||
|
||||
/* distribute error among four kernels */
|
||||
ntsc_rgb_t fourth = (error + 2 * ntsc_rgb_builder) >> 2;
|
||||
fourth &= (ntsc_rgb_bias >> 1) - ntsc_rgb_builder;
|
||||
fourth -= ntsc_rgb_bias >> 2;
|
||||
if ( disable_correction ) { out [i] += ntsc_rgb_bias; continue; }
|
||||
out [i + 3 +28] += fourth;
|
||||
out [i + 5 +14] += fourth;
|
||||
out [i + 7 ] += fourth;
|
||||
out [i ] += error - (fourth * 3);
|
||||
}
|
||||
out += alignment_count * rgb_kernel_size;
|
||||
}
|
||||
}
|
||||
/* end common code */
|
||||
|
||||
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
|
||||
{
|
||||
float to_float [32];
|
||||
int entry;
|
||||
struct ntsc_impl_t impl;
|
||||
if ( !setup )
|
||||
setup = &snes_ntsc_composite;
|
||||
init_ntsc_impl( &impl, setup );
|
||||
|
||||
{
|
||||
double gamma = 1 - setup->gamma * (setup->gamma > 0 ? 0.5f : 1.5f);
|
||||
int i;
|
||||
for ( i = 0; i < 32; i++ )
|
||||
to_float [i] = (float) pow( (1 / 31.0) * i, gamma ) * rgb_unit;
|
||||
}
|
||||
|
||||
for ( entry = 0; entry < snes_ntsc_color_count; entry++ )
|
||||
{
|
||||
/* Reduce number of significant bits of source color. Clearing the
|
||||
low bits of R and B were least notictable. Modifying green was too
|
||||
noticeable. */
|
||||
int ir = entry >> 8 & 0x1E;
|
||||
int ig = entry >> 4 & 0x1F;
|
||||
int ib = entry << 1 & 0x1E;
|
||||
|
||||
if ( setup->bsnes_colortbl )
|
||||
{
|
||||
int bgr15 = (ib << 10) | (ig << 5) | ir;
|
||||
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
|
||||
ir = rgb16 >> 11 & 0x1E;
|
||||
ig = rgb16 >> 6 & 0x1F;
|
||||
ib = rgb16 & 0x1E;
|
||||
}
|
||||
|
||||
{
|
||||
float r = to_float [ir];
|
||||
float g = to_float [ig];
|
||||
float b = to_float [ib];
|
||||
|
||||
float y = r * 0.299f + g * 0.587f + b * 0.114f;
|
||||
float i = r * 0.596f - g * 0.275f - b * 0.321f;
|
||||
float q = r * 0.212f - g * 0.523f + b * 0.311f;
|
||||
|
||||
float iq = i * q;
|
||||
if ( impl.hue_warping && q && iq <= 0 )
|
||||
{
|
||||
float factor = (iq * impl.hue_warping) / (i * i + q * q);
|
||||
i -= i * factor;
|
||||
q += q * factor;
|
||||
}
|
||||
|
||||
y = y * impl.contrast + impl.brightness;
|
||||
|
||||
{
|
||||
float yy = y + rgb_offset;
|
||||
ntsc_rgb_t rgb = TO_RGB( yy, i, q, impl.to_rgb [0] );
|
||||
ntsc_rgb_t* out = ntsc->table [entry];
|
||||
|
||||
gen_kernel( &impl, y, i, q, out );
|
||||
|
||||
if ( setup->merge_fields )
|
||||
merge_fields( out );
|
||||
|
||||
correct_errors( rgb, out );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable 'restrict' keyword by default. If your compiler supports it, put
|
||||
|
||||
#define restrict restrict
|
||||
|
||||
somewhere in a config header, or the equivalent in the command-line:
|
||||
|
||||
-Drestrict=restrict
|
||||
|
||||
If your compiler supports a non-standard version, like __restrict, do this:
|
||||
|
||||
#define restrict __restrict
|
||||
|
||||
Enabling this if your compiler supports it will allow better optimization. */
|
||||
#ifndef restrict
|
||||
#define restrict
|
||||
#endif
|
||||
|
||||
/* Default to 16-bit RGB input and output */
|
||||
#ifndef SNES_NTSC_IN_FORMAT
|
||||
#define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16
|
||||
#endif
|
||||
|
||||
#ifndef SNES_NTSC_OUT_DEPTH
|
||||
#define SNES_NTSC_OUT_DEPTH 16
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if SNES_NTSC_OUT_DEPTH > 16
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int snes_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long snes_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
#else
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short snes_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* useful if you have a linker which doesn't remove unused code from executable */
|
||||
#ifndef SNES_NTSC_NO_BLITTERS
|
||||
|
||||
/* Use this as a starting point for writing your own blitter. To allow easy upgrades
|
||||
to new versions of this library, put your blitter in a separate source file rather
|
||||
than modifying this one directly. */
|
||||
|
||||
void snes_ntsc_blit( snes_ntsc_t const* ntsc, unsigned short const* snes_in,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch )
|
||||
{
|
||||
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
|
||||
for ( ; in_height; --in_height )
|
||||
{
|
||||
/* begin row and read first input pixel */
|
||||
unsigned short const* line_in = snes_in;
|
||||
SNES_NTSC_LORES_ROW( ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, *line_in++ );
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
||||
int n;
|
||||
|
||||
/* blit main chunks, each using 3 input pixels to generate 7 output pixels */
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
SNES_NTSC_PIXEL_IN( 0, line_in [0] );
|
||||
SNES_NTSC_LORES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 1, line_in [1] );
|
||||
SNES_NTSC_LORES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 2, line_in [2] );
|
||||
SNES_NTSC_LORES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
line_in += 3;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
/* you can eliminate the need for the final chunk below by padding
|
||||
input with three extra black pixels at the end of each row */
|
||||
|
||||
/* finish final pixels without starting any new ones */
|
||||
SNES_NTSC_PIXEL_IN( 0, snes_ntsc_black );
|
||||
SNES_NTSC_LORES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 1, snes_ntsc_black );
|
||||
SNES_NTSC_LORES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 2, snes_ntsc_black );
|
||||
SNES_NTSC_LORES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_LORES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
/* advance burst phase and line pointers */
|
||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
||||
snes_in += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, unsigned short const* snes_in,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch )
|
||||
{
|
||||
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
|
||||
for ( ; in_height; --in_height )
|
||||
{
|
||||
unsigned short const* line_in = snes_in;
|
||||
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, line_in [0], line_in [1] );
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
||||
int n;
|
||||
line_in += 2;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
SNES_NTSC_PIXEL_IN( 0, line_in [0] );
|
||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 1, line_in [1] );
|
||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 2, line_in [2] );
|
||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 3, line_in [3] );
|
||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 4, line_in [4] );
|
||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 5, line_in [5] );
|
||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
line_in += 6;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 0, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 1, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 2, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 3, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 4, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_PIXEL_IN( 5, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
||||
snes_in += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,192 +0,0 @@
|
||||
/* SNES NTSC composite video to RGB emulator/blitter */
|
||||
|
||||
/* snes_ntsc 0.2.1 */
|
||||
|
||||
#ifndef SNES_NTSC_H
|
||||
#define SNES_NTSC_H
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0 */
|
||||
typedef struct snes_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees, +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale, +1 = oversaturated colors */
|
||||
double contrast;
|
||||
double brightness;
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma;
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
double hue_warping;/* -1 = expand purple & green, +1 = expand orange & cyan */
|
||||
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned long const* bsnes_colortbl; /* temporary feature for bsnes only; set to 0 */
|
||||
} snes_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
|
||||
|
||||
/* Initialize and adjust parameters. Can be called multiple times on the same
|
||||
snes_ntsc_t object. Caller must allocate memory for snes_ntsc_t. Can pass 0
|
||||
for either parameter. */
|
||||
typedef struct snes_ntsc_t snes_ntsc_t;
|
||||
void snes_ntsc_init( snes_ntsc_t*, snes_ntsc_setup_t const* setup );
|
||||
|
||||
/* Blit one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
|
||||
and output RGB depth is set by NES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void snes_ntsc_blit( snes_ntsc_t const*, unsigned short const* snes_in,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
|
||||
void snes_ntsc_blit_hires( snes_ntsc_t const*, unsigned short const* snes_in,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
|
||||
/* Number of output pixels written by low-res blitter for given input width. Width
|
||||
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
|
||||
value. Guaranteed not to round 256 down at all. */
|
||||
#define SNES_NTSC_OUT_WIDTH( in_width ) \
|
||||
(((in_width) - 1) / snes_ntsc_in_chunk * snes_ntsc_out_chunk + snes_ntsc_out_chunk)
|
||||
|
||||
/* Number of low-res input pixels that will fit within given output width. Might be
|
||||
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
|
||||
value. */
|
||||
#define SNES_NTSC_IN_WIDTH( out_width ) \
|
||||
((out_width) / snes_ntsc_out_chunk * snes_ntsc_in_chunk - snes_ntsc_in_chunk + 1)
|
||||
|
||||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { snes_ntsc_in_chunk = 3 }; /* number of snes pixels read per chunk */
|
||||
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { snes_ntsc_black = 0 }; /* palette index for black */
|
||||
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
|
||||
|
||||
/* Begin outputting row and start three pixels. First pixel will be cut off a bit.
|
||||
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
statement in a block (unless you're using C++). */
|
||||
#define SNES_NTSC_LORES_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
|
||||
char const* ktable = (char*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (ntsc_rgb_t));\
|
||||
int const snes_pixel0_ = (pixel0);\
|
||||
ntsc_rgb_t const* kernel0 = SNES_NTSC_IN_FORMAT( snes_pixel0_ );\
|
||||
int const snes_pixel1_ = (pixel1);\
|
||||
ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( snes_pixel1_ );\
|
||||
int const snes_pixel2_ = (pixel2);\
|
||||
ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( snes_pixel2_ );\
|
||||
ntsc_rgb_t const* kernelx0;\
|
||||
ntsc_rgb_t const* kernelx1 = kernel0;\
|
||||
ntsc_rgb_t const* kernelx2 = kernel0
|
||||
|
||||
/* Begin input pixel */
|
||||
#define SNES_NTSC_PIXEL_IN( in_index, color_in ) {\
|
||||
unsigned n;\
|
||||
kernelx##in_index = kernel##in_index;\
|
||||
kernel##in_index = (n = (color_in), SNES_NTSC_IN_FORMAT( n ));\
|
||||
}
|
||||
|
||||
/* Generate output pixel. Bits can be 24, 16, 15, or 32 (treated as 24):
|
||||
24: RRRRRRRR GGGGGGGG BBBBBBBB
|
||||
16: RRRRRGGG GGGBBBBB
|
||||
15: RRRRRGG GGGBBBBB
|
||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (raw format; x = junk bits) */
|
||||
#define SNES_NTSC_LORES_OUT( x, rgb_out, bits ) {\
|
||||
ntsc_rgb_t raw =\
|
||||
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
|
||||
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
|
||||
SNES_NTSC_CLAMP_( raw, 1 );\
|
||||
SNES_NTSC_OUT_( rgb_out, (bits), raw, 1 );\
|
||||
}
|
||||
|
||||
/* Hires equivalents */
|
||||
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
|
||||
char const* ktable = (char*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (ntsc_rgb_t));\
|
||||
int const snes_pixel1_ = (pixel1);\
|
||||
ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( snes_pixel1_ );\
|
||||
int const snes_pixel2_ = (pixel2);\
|
||||
ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( snes_pixel2_ );\
|
||||
int const snes_pixel3_ = (pixel3);\
|
||||
ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( snes_pixel3_ );\
|
||||
int const snes_pixel4_ = (pixel4);\
|
||||
ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( snes_pixel4_ );\
|
||||
int const snes_pixel5_ = (pixel5);\
|
||||
ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( snes_pixel5_ );\
|
||||
ntsc_rgb_t const* kernel0 = kernel1;\
|
||||
ntsc_rgb_t const* kernelx0;\
|
||||
ntsc_rgb_t const* kernelx1 = kernel1;\
|
||||
ntsc_rgb_t const* kernelx2 = kernel1;\
|
||||
ntsc_rgb_t const* kernelx3 = kernel1;\
|
||||
ntsc_rgb_t const* kernelx4 = kernel1;\
|
||||
ntsc_rgb_t const* kernelx5 = kernel1
|
||||
|
||||
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
|
||||
ntsc_rgb_t raw =\
|
||||
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
|
||||
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
|
||||
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
|
||||
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
|
||||
SNES_NTSC_CLAMP_( raw, 0 );\
|
||||
SNES_NTSC_OUT_( rgb_out, (bits), raw, 0 );\
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
|
||||
enum { snes_ntsc_entry_size = 128 };
|
||||
enum { snes_ntsc_color_count = 0x2000 };
|
||||
typedef unsigned long ntsc_rgb_t;
|
||||
struct snes_ntsc_t
|
||||
{
|
||||
ntsc_rgb_t table [snes_ntsc_color_count] [snes_ntsc_entry_size];
|
||||
};
|
||||
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
|
||||
|
||||
enum { ntsc_rgb_builder = (1L << 21) | (1 << 11) | (1 << 1) };
|
||||
enum { snes_ntsc_clamp_mask = ntsc_rgb_builder * 3 / 2 };
|
||||
enum { snes_ntsc_clamp_add = ntsc_rgb_builder * 0x101 };
|
||||
|
||||
#define SNES_NTSC_RGB16( n ) \
|
||||
(ntsc_rgb_t*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
|
||||
(snes_ntsc_entry_size / 2 * sizeof (ntsc_rgb_t)))
|
||||
|
||||
#define SNES_NTSC_BGR15( n ) \
|
||||
(ntsc_rgb_t*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
|
||||
(snes_ntsc_entry_size / 2 * sizeof (ntsc_rgb_t)))
|
||||
|
||||
#define SNES_NTSC_CLAMP_( io, shift ) {\
|
||||
ntsc_rgb_t sub = io >> (9-shift) & snes_ntsc_clamp_mask;\
|
||||
ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
|
||||
io |= clamp;\
|
||||
clamp -= sub;\
|
||||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define SNES_NTSC_OUT_( rgb_out, bits, raw, x ) {\
|
||||
if ( bits == 16 ) {\
|
||||
rgb_out = (raw>>(13-x)& 0xF800)|(raw>>(8-x)&0x07E0)|(raw>>(4-x)&0x001F);\
|
||||
rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\
|
||||
rgb_out = snes.color_lookup_table[rgb_out];\
|
||||
} else if ( bits == 24 || bits == 32 ) {\
|
||||
rgb_out = (raw>>(5-x)&0xFF0000)|(raw>>(3-x)&0xFF00)|(raw>>(1-x)&0xFF);\
|
||||
rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\
|
||||
rgb_out = snes.color_lookup_table[rgb_out];\
|
||||
} else if ( bits == 15 ) {\
|
||||
rgb_out = (raw>>(14-x)& 0x7C00)|(raw>>(9-x)&0x03E0)|(raw>>(4-x)&0x001F);\
|
||||
rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\
|
||||
rgb_out = snes.color_lookup_table[rgb_out];\
|
||||
} else {\
|
||||
rgb_out = raw;\
|
||||
}\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
251
src/snes/video/ntsc/snes_ntsc.c
Normal file
251
src/snes/video/ntsc/snes_ntsc.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "snes_ntsc.h"
|
||||
|
||||
/* Copyright (C) 2006-2007 Shay Green. This module 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
|
||||
module 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 module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
|
||||
|
||||
#define alignment_count 3
|
||||
#define burst_count 3
|
||||
#define rescale_in 8
|
||||
#define rescale_out 7
|
||||
|
||||
#define artifacts_mid 1.0f
|
||||
#define fringing_mid 1.0f
|
||||
#define std_decoder_hue 0
|
||||
|
||||
#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */
|
||||
#define gamma_size 32
|
||||
|
||||
#include "snes_ntsc_impl.h"
|
||||
|
||||
/* 3 input pixels -> 8 composite samples */
|
||||
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
|
||||
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
|
||||
};
|
||||
|
||||
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
|
||||
{
|
||||
int n;
|
||||
for ( n = burst_size; n; --n )
|
||||
{
|
||||
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
|
||||
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
|
||||
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
|
||||
/* merge colors without losing precision */
|
||||
io [burst_size * 0] =
|
||||
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io [burst_size * 1] =
|
||||
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io [burst_size * 2] =
|
||||
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
++io;
|
||||
}
|
||||
}
|
||||
|
||||
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
|
||||
{
|
||||
int n;
|
||||
for ( n = burst_count; n; --n )
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
{
|
||||
snes_ntsc_rgb_t error = color -
|
||||
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
|
||||
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
|
||||
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
|
||||
}
|
||||
out += alignment_count * rgb_kernel_size;
|
||||
}
|
||||
}
|
||||
|
||||
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
|
||||
{
|
||||
int merge_fields;
|
||||
int entry;
|
||||
init_t impl;
|
||||
if ( !setup )
|
||||
setup = &snes_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
|
||||
merge_fields = setup->merge_fields;
|
||||
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
|
||||
merge_fields = 1;
|
||||
|
||||
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
|
||||
{
|
||||
/* Reduce number of significant bits of source color. Clearing the
|
||||
low bits of R and B were least notictable. Modifying green was too
|
||||
noticeable. */
|
||||
int ir = entry >> 8 & 0x1E;
|
||||
int ig = entry >> 4 & 0x1F;
|
||||
int ib = entry << 1 & 0x1E;
|
||||
|
||||
#if SNES_NTSC_BSNES_COLORTBL
|
||||
if ( setup->bsnes_colortbl )
|
||||
{
|
||||
int bgr15 = (ib << 10) | (ig << 5) | ir;
|
||||
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
|
||||
ir = rgb16 >> 11 & 0x1E;
|
||||
ig = rgb16 >> 6 & 0x1F;
|
||||
ib = rgb16 & 0x1E;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
float rr = impl.to_float [ir];
|
||||
float gg = impl.to_float [ig];
|
||||
float bb = impl.to_float [ib];
|
||||
|
||||
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
|
||||
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
|
||||
|
||||
snes_ntsc_rgb_t* out = ntsc->table [entry];
|
||||
gen_kernel( &impl, y, i, q, out );
|
||||
if ( merge_fields )
|
||||
merge_kernel_fields( out );
|
||||
correct_errors( rgb, out );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SNES_NTSC_NO_BLITTERS
|
||||
|
||||
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
|
||||
{
|
||||
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
|
||||
for ( ; in_height; --in_height )
|
||||
{
|
||||
SNES_NTSC_IN_T const* line_in = input;
|
||||
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
||||
int n;
|
||||
++line_in;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
|
||||
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
|
||||
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
|
||||
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
line_in += 3;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
|
||||
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
|
||||
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
|
||||
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
||||
input += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
|
||||
{
|
||||
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
|
||||
for ( ; in_height; --in_height )
|
||||
{
|
||||
SNES_NTSC_IN_T const* line_in = input;
|
||||
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
|
||||
SNES_NTSC_ADJ_IN( line_in [0] ),
|
||||
SNES_NTSC_ADJ_IN( line_in [1] ) );
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
||||
int n;
|
||||
line_in += 2;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* twice as many input pixels per chunk */
|
||||
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
|
||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
|
||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
|
||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
|
||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
|
||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
|
||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
line_in += 6;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
|
||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
||||
input += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
228
src/snes/video/ntsc/snes_ntsc.h
Normal file
228
src/snes/video/ntsc/snes_ntsc.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/* SNES NTSC video filter */
|
||||
|
||||
/* snes_ntsc 0.2.2 */
|
||||
#ifndef SNES_NTSC_H
|
||||
#define SNES_NTSC_H
|
||||
|
||||
#include "snes_ntsc_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
in parenthesis and should remain fairly stable in future versions. */
|
||||
typedef struct snes_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
|
||||
} snes_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
|
||||
|
||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
||||
snes_ntsc_t object. Can pass NULL for either parameter. */
|
||||
typedef struct snes_ntsc_t snes_ntsc_t;
|
||||
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
|
||||
|
||||
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
|
||||
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
|
||||
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
|
||||
/* Number of output pixels written by low-res blitter for given input width. Width
|
||||
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
|
||||
value. Guaranteed not to round 256 down at all. */
|
||||
#define SNES_NTSC_OUT_WIDTH( in_width ) \
|
||||
((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk)
|
||||
|
||||
/* Number of low-res input pixels that will fit within given output width. Might be
|
||||
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
|
||||
value. */
|
||||
#define SNES_NTSC_IN_WIDTH( out_width ) \
|
||||
(((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1)
|
||||
|
||||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
|
||||
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { snes_ntsc_black = 0 }; /* palette index for black */
|
||||
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
|
||||
|
||||
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
|
||||
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
statement in a block (unless you're using C++). */
|
||||
#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
|
||||
char const* ktable = \
|
||||
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
|
||||
SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable )
|
||||
|
||||
/* Begins input pixel */
|
||||
#define SNES_NTSC_COLOR_IN( index, color ) \
|
||||
SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable )
|
||||
|
||||
/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0:
|
||||
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
|
||||
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
|
||||
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
|
||||
14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format)
|
||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
|
||||
#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \
|
||||
SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 )
|
||||
|
||||
/* Hires equivalents */
|
||||
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
|
||||
char const* ktable = \
|
||||
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
|
||||
unsigned const snes_ntsc_pixel1_ = (pixel1);\
|
||||
snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\
|
||||
unsigned const snes_ntsc_pixel2_ = (pixel2);\
|
||||
snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\
|
||||
unsigned const snes_ntsc_pixel3_ = (pixel3);\
|
||||
snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\
|
||||
unsigned const snes_ntsc_pixel4_ = (pixel4);\
|
||||
snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\
|
||||
unsigned const snes_ntsc_pixel5_ = (pixel5);\
|
||||
snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\
|
||||
snes_ntsc_rgb_t const* kernel0 = kernel1;\
|
||||
snes_ntsc_rgb_t const* kernelx0;\
|
||||
snes_ntsc_rgb_t const* kernelx1 = kernel1;\
|
||||
snes_ntsc_rgb_t const* kernelx2 = kernel1;\
|
||||
snes_ntsc_rgb_t const* kernelx3 = kernel1;\
|
||||
snes_ntsc_rgb_t const* kernelx4 = kernel1;\
|
||||
snes_ntsc_rgb_t const* kernelx5 = kernel1
|
||||
|
||||
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
|
||||
snes_ntsc_rgb_t raw_ =\
|
||||
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
|
||||
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
|
||||
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
|
||||
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
|
||||
SNES_NTSC_CLAMP_( raw_, 0 );\
|
||||
SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
enum { snes_ntsc_entry_size = 128 };
|
||||
enum { snes_ntsc_palette_size = 0x2000 };
|
||||
typedef unsigned long snes_ntsc_rgb_t;
|
||||
struct snes_ntsc_t {
|
||||
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
|
||||
};
|
||||
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
|
||||
|
||||
#define SNES_NTSC_RGB16( ktable, n ) \
|
||||
(snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
|
||||
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
|
||||
|
||||
#define SNES_NTSC_BGR15( ktable, n ) \
|
||||
(snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
|
||||
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
|
||||
|
||||
/* common 3->7 ntsc macros */
|
||||
#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
|
||||
unsigned const snes_ntsc_pixel0_ = (pixel0);\
|
||||
snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\
|
||||
unsigned const snes_ntsc_pixel1_ = (pixel1);\
|
||||
snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\
|
||||
unsigned const snes_ntsc_pixel2_ = (pixel2);\
|
||||
snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\
|
||||
snes_ntsc_rgb_t const* kernelx0;\
|
||||
snes_ntsc_rgb_t const* kernelx1 = kernel0;\
|
||||
snes_ntsc_rgb_t const* kernelx2 = kernel0
|
||||
|
||||
#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
|
||||
snes_ntsc_rgb_t raw_ =\
|
||||
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
|
||||
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
|
||||
SNES_NTSC_CLAMP_( raw_, shift );\
|
||||
SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
|
||||
}
|
||||
|
||||
/* common ntsc macros */
|
||||
#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
|
||||
#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2)
|
||||
#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101)
|
||||
#define SNES_NTSC_CLAMP_( io, shift ) {\
|
||||
snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\
|
||||
snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
|
||||
io |= clamp;\
|
||||
clamp -= sub;\
|
||||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
||||
}
|
||||
|
||||
/* x is always zero except in snes_ntsc library */
|
||||
/* original routine */
|
||||
/*
|
||||
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
||||
if ( bits == 16 )\
|
||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
||||
if ( bits == 24 || bits == 32 )\
|
||||
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
|
||||
if ( bits == 15 )\
|
||||
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
|
||||
if ( bits == 14 )\
|
||||
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\
|
||||
if ( bits == 0 )\
|
||||
rgb_out = raw_ << x;\
|
||||
}
|
||||
*/
|
||||
|
||||
/* custom bsnes routine -- hooks into bsnes colortable */
|
||||
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
||||
if ( bits == 16 ) {\
|
||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
||||
rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\
|
||||
rgb_out = snes.color_lookup_table[rgb_out];\
|
||||
} else if ( bits == 24 || bits == 32 ) {\
|
||||
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
|
||||
rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\
|
||||
rgb_out = snes.color_lookup_table[rgb_out];\
|
||||
} else if ( bits == 15 ) {\
|
||||
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
|
||||
rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\
|
||||
rgb_out = snes.color_lookup_table[rgb_out];\
|
||||
} else {\
|
||||
rgb_out = raw_ << x;\
|
||||
}\
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
26
src/snes/video/ntsc/snes_ntsc_config.h
Normal file
26
src/snes/video/ntsc/snes_ntsc_config.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Configure library by modifying this file */
|
||||
|
||||
#ifndef SNES_NTSC_CONFIG_H
|
||||
#define SNES_NTSC_CONFIG_H
|
||||
|
||||
/* Format of source pixels */
|
||||
/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */
|
||||
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
|
||||
|
||||
/* The following affect the built-in blitter only; a custom blitter can
|
||||
handle things however it wants. */
|
||||
|
||||
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
|
||||
#define SNES_NTSC_OUT_DEPTH 16
|
||||
|
||||
/* Type of input pixel values */
|
||||
#define SNES_NTSC_IN_T unsigned short
|
||||
|
||||
/* Each raw pixel input value is passed through this. You might want to mask
|
||||
the pixel index if you use the high bits as flags, etc. */
|
||||
#define SNES_NTSC_ADJ_IN( in ) in
|
||||
|
||||
/* For each pixel, this is the basic operation:
|
||||
output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */
|
||||
|
||||
#endif
|
439
src/snes/video/ntsc/snes_ntsc_impl.h
Normal file
439
src/snes/video/ntsc/snes_ntsc_impl.h
Normal file
@@ -0,0 +1,439 @@
|
||||
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Common implementation of NTSC filters */
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2006 Shay Green. This module 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
|
||||
module 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 module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#define DISABLE_CORRECTION 0
|
||||
|
||||
#undef PI
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
#ifndef LUMA_CUTOFF
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#endif
|
||||
#ifndef gamma_size
|
||||
#define gamma_size 1
|
||||
#endif
|
||||
#ifndef rgb_bits
|
||||
#define rgb_bits 8
|
||||
#endif
|
||||
#ifndef artifacts_max
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#endif
|
||||
#ifndef fringing_max
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#endif
|
||||
#ifndef STD_HUE_CONDITION
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#endif
|
||||
|
||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
||||
#define rgb_unit (1 << rgb_bits)
|
||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
||||
|
||||
enum { burst_size = snes_ntsc_entry_size / burst_count };
|
||||
enum { kernel_half = 16 };
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
|
||||
typedef struct init_t
|
||||
{
|
||||
float to_rgb [burst_count * 6];
|
||||
float to_float [gamma_size];
|
||||
float contrast;
|
||||
float brightness;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
} init_t;
|
||||
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
float t;\
|
||||
t = i * cos_b - q * sin_b;\
|
||||
q = i * sin_b + q * cos_b;\
|
||||
i = t;\
|
||||
}
|
||||
|
||||
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
|
||||
{
|
||||
#if rescale_out > 1
|
||||
float kernels [kernel_size * 2];
|
||||
#else
|
||||
float* const kernels = impl->kernel;
|
||||
#endif
|
||||
|
||||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
float to_angle = (float) setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
float angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
||||
{
|
||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
||||
float num = 1 - rolloff_cos_a -
|
||||
pow_a_n * (float) cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= -30.0f / 0.65f;
|
||||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
printf( "luma:\n" );
|
||||
for ( i = kernel_size; i < kernel_size * 2; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
printf( "chroma:\n" );
|
||||
for ( i = 0; i < kernel_size; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
*/
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
#if rescale_out > 1
|
||||
{
|
||||
float weight = 1.0f;
|
||||
float* out = impl->kernel;
|
||||
int n = rescale_out;
|
||||
do
|
||||
{
|
||||
float remain = 0;
|
||||
int i;
|
||||
weight -= 1.0f / rescale_in;
|
||||
for ( i = 0; i < kernel_size * 2; i++ )
|
||||
{
|
||||
float cur = kernels [i];
|
||||
float m = cur * weight;
|
||||
*out++ = m + remain;
|
||||
remain = cur - m;
|
||||
}
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
|
||||
static void init( init_t* impl, snes_ntsc_setup_t const* setup )
|
||||
{
|
||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
if ( !setup->palette )
|
||||
impl->contrast *= default_palette_contrast;
|
||||
#endif
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing *= fringing_max - fringing_mid;
|
||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
||||
|
||||
init_filters( impl, setup );
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
for ( i = 0; i < gamma_size; i++ )
|
||||
impl->to_float [i] =
|
||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
{
|
||||
decoder = default_decoder;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
||||
}
|
||||
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float* out = impl->to_rgb;
|
||||
int n;
|
||||
|
||||
n = burst_count;
|
||||
do
|
||||
{
|
||||
float const* in = decoder;
|
||||
int n = 3;
|
||||
do
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n );
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* kernel generation */
|
||||
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
|
||||
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
|
||||
)
|
||||
|
||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
||||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
||||
)
|
||||
|
||||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
||||
|
||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
||||
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
} pixel_info_t;
|
||||
|
||||
#if rescale_in > 1
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#else
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
(kernel_size / 2 + (ntsc) - (scaled)),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#endif
|
||||
|
||||
extern pixel_info_t const snes_ntsc_pixels [alignment_count];
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
int burst_remain = burst_count;
|
||||
y -= rgb_offset;
|
||||
do
|
||||
{
|
||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
||||
Convolve these with kernels which: filter respective components, apply
|
||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
||||
into integer. Based on algorithm by NewRisingSun. */
|
||||
pixel_info_t const* pixel = snes_ntsc_pixels;
|
||||
int alignment_remain = alignment_count;
|
||||
do
|
||||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
int n;
|
||||
++pixel;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( rescale_out <= 1 )
|
||||
k--;
|
||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
k += kernel_size * 2 - 1;
|
||||
else
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
||||
}
|
||||
while ( --burst_remain );
|
||||
}
|
||||
|
||||
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
|
||||
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
out [a] += fourth;\
|
||||
out [b] += fourth;\
|
||||
out [c] += fourth;\
|
||||
out [i] += error - (fourth * 3);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define RGB_PALETTE_OUT( rgb, out_ )\
|
||||
{\
|
||||
unsigned char* out = (out_);\
|
||||
snes_ntsc_rgb_t clamped = (rgb);\
|
||||
SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
|
||||
out [0] = (unsigned char) (clamped >> 21);\
|
||||
out [1] = (unsigned char) (clamped >> 11);\
|
||||
out [2] = (unsigned char) (clamped >> 1);\
|
||||
}
|
||||
|
||||
/* blitter related */
|
||||
|
||||
#ifndef restrict
|
||||
#if defined (__GNUC__)
|
||||
#define restrict __restrict__
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict __restrict
|
||||
#else
|
||||
/* no support for restricted pointers */
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if SNES_NTSC_OUT_DEPTH <= 16
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short snes_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int snes_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long snes_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -1,100 +1,4 @@
|
||||
/*
|
||||
* interpolation routines are located in: /src/lib/libinterp.h
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
inline uint Audio::bind_range(uint min, uint max, uint index) {
|
||||
return index < min ? min : index > max ? max : index;
|
||||
}
|
||||
|
||||
void Audio::resample_point(
|
||||
uint32 *output, uint32 *input, uint output_samples, uint input_samples
|
||||
) {
|
||||
double scalar = double(input_samples--) / double(output_samples--); //convert lengths to upper bounds
|
||||
double sindex = 0.0;
|
||||
for(uint x = 0; x <= output_samples; x++) {
|
||||
uint32 y0 = input[bind_range(0, input_samples, uint32(sindex) + 0)];
|
||||
uint32 y1 = input[bind_range(0, input_samples, uint32(sindex) + 1)];
|
||||
double mu = sindex - uint(sindex); //calculate fractional portion of step
|
||||
uint16 yl = interpolate_point(mu, int16(y0 >> 0), int16(y1 >> 0));
|
||||
uint16 yr = interpolate_point(mu, int16(y0 >> 16), int16(y1 >> 16));
|
||||
output[x] = (yl << 0) + (yr << 16);
|
||||
sindex += scalar;
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::resample_linear(
|
||||
uint32 *output, uint32 *input, uint output_samples, uint input_samples
|
||||
) {
|
||||
double scalar = double(input_samples--) / double(output_samples--); //convert lengths to upper bounds
|
||||
double sindex = 0.0;
|
||||
for(uint x = 0; x <= output_samples; x++) {
|
||||
uint32 y0 = input[bind_range(0, input_samples, uint32(sindex) + 0)];
|
||||
uint32 y1 = input[bind_range(0, input_samples, uint32(sindex) + 1)];
|
||||
double mu = sindex - uint(sindex); //calculate fractional portion of step
|
||||
uint16 yl = interpolate_linear(mu, int16(y0 >> 0), int16(y1 >> 0));
|
||||
uint16 yr = interpolate_linear(mu, int16(y0 >> 16), int16(y1 >> 16));
|
||||
output[x] = (yl << 0) + (yr << 16);
|
||||
sindex += scalar;
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::resample_cosine(
|
||||
uint32 *output, uint32 *input, uint output_samples, uint input_samples
|
||||
) {
|
||||
double scalar = double(input_samples--) / double(output_samples--); //convert lengths to upper bounds
|
||||
double sindex = 0.0;
|
||||
for(uint x = 0; x <= output_samples; x++) {
|
||||
uint32 y0 = input[bind_range(0, input_samples, uint32(sindex) + 0)];
|
||||
uint32 y1 = input[bind_range(0, input_samples, uint32(sindex) + 1)];
|
||||
double mu = sindex - uint(sindex); //calculate fractional portion of step
|
||||
uint16 yl = interpolate_cosine(mu, int16(y0 >> 0), int16(y1 >> 0));
|
||||
uint16 yr = interpolate_cosine(mu, int16(y0 >> 16), int16(y1 >> 16));
|
||||
output[x] = (yl << 0) + (yr << 16);
|
||||
sindex += scalar;
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::resample_cubic(
|
||||
uint32 *output, uint32 *input, uint output_samples, uint input_samples
|
||||
) {
|
||||
double scalar = double(input_samples--) / double(output_samples--); //convert lengths to upper bounds
|
||||
double sindex = 0.0;
|
||||
for(uint x = 0; x <= output_samples; x++) {
|
||||
uint32 y0 = input[bind_range(0, input_samples, uint32(sindex) - 1)];
|
||||
uint32 y1 = input[bind_range(0, input_samples, uint32(sindex) + 0)];
|
||||
uint32 y2 = input[bind_range(0, input_samples, uint32(sindex) + 1)];
|
||||
uint32 y3 = input[bind_range(0, input_samples, uint32(sindex) + 2)];
|
||||
double mu = sindex - uint(sindex); //calculate fractional portion of step
|
||||
uint16 yl = sclamp<16>( interpolate_cubic(mu, int16(y0 >> 0), int16(y1 >> 0), int16(y2 >> 0), int16(y3 >> 0)) );
|
||||
uint16 yr = sclamp<16>( interpolate_cubic(mu, int16(y0 >> 16), int16(y1 >> 16), int16(y2 >> 16), int16(y3 >> 16)) );
|
||||
output[x] = (yl << 0) + (yr << 16);
|
||||
sindex += scalar;
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::resample_hermite(
|
||||
uint32 *output, uint32 *input, uint output_samples, uint input_samples
|
||||
) {
|
||||
double scalar = double(input_samples--) / double(output_samples--); //convert lengths to upper bounds
|
||||
double sindex = 0.0;
|
||||
for(uint x = 0; x <= output_samples; x++) {
|
||||
uint32 y0 = input[bind_range(0, input_samples, uint32(sindex) - 1)];
|
||||
uint32 y1 = input[bind_range(0, input_samples, uint32(sindex) + 0)];
|
||||
uint32 y2 = input[bind_range(0, input_samples, uint32(sindex) + 1)];
|
||||
uint32 y3 = input[bind_range(0, input_samples, uint32(sindex) + 2)];
|
||||
double mu = sindex - uint(sindex); //calculate fractional portion of step
|
||||
uint16 yl = sclamp<16>( interpolate_hermite(mu, 0.0, 0.0, int16(y0 >> 0), int16(y1 >> 0), int16(y2 >> 0), int16(y3 >> 0)) );
|
||||
uint16 yr = sclamp<16>( interpolate_hermite(mu, 0.0, 0.0, int16(y0 >> 16), int16(y1 >> 16), int16(y2 >> 16), int16(y3 >> 16)) );
|
||||
output[x] = (yl << 0) + (yr << 16);
|
||||
sindex += scalar;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
#include "audio.h"
|
||||
|
||||
void Audio::update_frequency() {
|
||||
uint freq = config::audio.frequency;
|
||||
|
@@ -1,3 +1,6 @@
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
class Audio {
|
||||
public:
|
||||
uint frequency, latency;
|
||||
@@ -7,14 +10,7 @@ uint frequency, latency;
|
||||
virtual void init() {}
|
||||
virtual void term() {}
|
||||
|
||||
/*
|
||||
uint bind_range(uint min, uint max, uint index);
|
||||
void resample_point (uint32 *output, uint32 *input, uint output_samples, uint input_samples);
|
||||
void resample_linear (uint32 *output, uint32 *input, uint output_samples, uint input_samples);
|
||||
void resample_cosine (uint32 *output, uint32 *input, uint output_samples, uint input_samples);
|
||||
void resample_cubic (uint32 *output, uint32 *input, uint output_samples, uint input_samples);
|
||||
void resample_hermite(uint32 *output, uint32 *input, uint output_samples, uint input_samples);
|
||||
*/
|
||||
|
||||
Audio();
|
||||
} *uiAudio;
|
||||
|
||||
#endif
|
||||
|
@@ -2,7 +2,7 @@ void AudioDS::sample(uint16 l_sample, uint16 r_sample) {
|
||||
data.buffer[data.buffer_pos++] = (l_sample << 0) + (r_sample << 16);
|
||||
if(data.buffer_pos < latency)return;
|
||||
|
||||
uint32 ring_pos, pos, size;
|
||||
DWORD ring_pos, pos, size;
|
||||
for(;;) {
|
||||
dsb_b->GetCurrentPosition(&pos, 0);
|
||||
ring_pos = pos / data.ring_size;
|
||||
@@ -30,7 +30,7 @@ void *output;
|
||||
data.buffer[data.buffer_pos++] = (l_sample << 0) + (r_sample << 16);
|
||||
//if(data.buffer_pos & 15)return;
|
||||
|
||||
uint32 ring_pos, pos, size;
|
||||
DWORD ring_pos, pos, size;
|
||||
dsb_b->GetCurrentPosition(&pos, 0);
|
||||
ring_pos = pos / data.ring_size;
|
||||
if(ring_pos == data.ring_pos)return;
|
||||
@@ -66,7 +66,7 @@ void AudioDS::clear_audio() {
|
||||
dsb_b->Stop();
|
||||
dsb_b->SetCurrentPosition(0);
|
||||
|
||||
uint32 size;
|
||||
DWORD size;
|
||||
void *output;
|
||||
dsb_b->Lock(0, data.ring_size * 3, &output, &size, 0, 0, 0);
|
||||
memset(output, 0, size);
|
||||
|
@@ -9,60 +9,72 @@ struct System {
|
||||
static IntegerSetting regulate_speed, speed;
|
||||
static IntegerSetting speed_slowest, speed_slow, speed_normal, speed_fast, speed_fastest;
|
||||
} system;
|
||||
StringSetting System::video(&config_file, "system.video", "Video hardware interface", "");
|
||||
StringSetting System::audio(&config_file, "system.audio", "Audio hardware interface", "");
|
||||
StringSetting System::input(&config_file, "system.input", "Input hardware interface", "");
|
||||
StringSetting System::video(&config(), "system.video", "Video hardware interface", "");
|
||||
StringSetting System::audio(&config(), "system.audio", "Audio hardware interface", "");
|
||||
StringSetting System::input(&config(), "system.input", "Input hardware interface", "");
|
||||
|
||||
StringSetting System::video_flags(&config_file, "system.video_flags", "Video hardware interface flags", "");
|
||||
StringSetting System::audio_flags(&config_file, "system.audio_flags", "Audio hardware interface flags", "");
|
||||
StringSetting System::input_flags(&config_file, "system.input_flags", "Input hardware interface flags", "");
|
||||
StringSetting System::video_flags(&config(), "system.video_flags", "Video hardware interface flags", "");
|
||||
StringSetting System::audio_flags(&config(), "system.audio_flags", "Audio hardware interface flags", "");
|
||||
StringSetting System::input_flags(&config(), "system.input_flags", "Input hardware interface flags", "");
|
||||
|
||||
IntegerSetting System::regulate_speed(&config_file, "system.regulate_speed", "Regulate speed to 60hz (NTSC) / 50hz (PAL)", IntegerSetting::Boolean, true);
|
||||
IntegerSetting System::regulate_speed(&config(), "system.regulate_speed", "Regulate speed to 60hz (NTSC) / 50hz (PAL)", IntegerSetting::Boolean, true);
|
||||
IntegerSetting System::speed (0, "system.speed", "Current speed regulation setting (1-5)", IntegerSetting::Decimal, 3);
|
||||
IntegerSetting System::speed_slowest (&config_file, "system.speed_slowest", "Slowest speed setting", IntegerSetting::Decimal, 50);
|
||||
IntegerSetting System::speed_slow (&config_file, "system.speed_slow", "Slow speed setting", IntegerSetting::Decimal, 75);
|
||||
IntegerSetting System::speed_normal (&config_file, "system.speed_normal", "Normal speed setting", IntegerSetting::Decimal, 100);
|
||||
IntegerSetting System::speed_fast (&config_file, "system.speed_fast", "Fast speed setting", IntegerSetting::Decimal, 150);
|
||||
IntegerSetting System::speed_fastest (&config_file, "system.speed_fastest", "Fastest speed setting", IntegerSetting::Decimal, 200);
|
||||
IntegerSetting System::speed_slowest (&config(), "system.speed_slowest", "Slowest speed setting", IntegerSetting::Decimal, 50);
|
||||
IntegerSetting System::speed_slow (&config(), "system.speed_slow", "Slow speed setting", IntegerSetting::Decimal, 75);
|
||||
IntegerSetting System::speed_normal (&config(), "system.speed_normal", "Normal speed setting", IntegerSetting::Decimal, 100);
|
||||
IntegerSetting System::speed_fast (&config(), "system.speed_fast", "Fast speed setting", IntegerSetting::Decimal, 150);
|
||||
IntegerSetting System::speed_fastest (&config(), "system.speed_fastest", "Fastest speed setting", IntegerSetting::Decimal, 200);
|
||||
|
||||
struct Video {
|
||||
static IntegerSetting synchronize;
|
||||
static IntegerSetting fullscreen;
|
||||
static IntegerSetting multiplier, aspect_correction, region;
|
||||
static IntegerSetting aspect_ntsc_x, aspect_ntsc_y, aspect_pal_x, aspect_pal_y;
|
||||
static IntegerSetting hardware_filter, software_filter;
|
||||
static IntegerSetting frameskip;
|
||||
static IntegerSetting use_vram;
|
||||
} video;
|
||||
IntegerSetting Video::synchronize(&config_file, "video.synchronize", "Synchronize to video refresh rate.", IntegerSetting::Boolean, false);
|
||||
IntegerSetting Video::multiplier(&config_file, "video.multiplier", "Video output size multiplier (1-5x)\n"
|
||||
IntegerSetting Video::synchronize(&config(), "video.synchronize", "Synchronize to video refresh rate.", IntegerSetting::Boolean, false);
|
||||
IntegerSetting Video::fullscreen(0, "video.fullscreen", "", IntegerSetting::Boolean, false);
|
||||
IntegerSetting Video::multiplier(&config(), "video.multiplier", "Video output size multiplier (1-5x)\n"
|
||||
"1 = 1x (~256x224)\n"
|
||||
"2 = 2x (~512x448)\n"
|
||||
"etc.",
|
||||
IntegerSetting::Decimal, 2);
|
||||
IntegerSetting Video::aspect_correction(&config_file, "video.aspect_correction", "Correct video aspect ratio", IntegerSetting::Boolean, true);
|
||||
IntegerSetting Video::region(&config_file, "video.region", "Video output region\n"
|
||||
IntegerSetting Video::aspect_correction(&config(), "video.aspect_correction",
|
||||
"Correct video aspect ratio\n"
|
||||
"Formula: width = width * video.aspect_<region>_x / video.aspect_<region>_y",
|
||||
IntegerSetting::Boolean, true);
|
||||
IntegerSetting Video::region(&config(), "video.region", "Video output region\n"
|
||||
"0 = NTSC, 1 = PAL",
|
||||
IntegerSetting::Decimal, 0);
|
||||
IntegerSetting Video::hardware_filter(&config_file, "video.hardware_filter", "Video hardware filter\n"
|
||||
|
||||
IntegerSetting Video::aspect_ntsc_x(&config(), "video.aspect_ntsc_x", "", IntegerSetting::Decimal, 54);
|
||||
IntegerSetting Video::aspect_ntsc_y(&config(), "video.aspect_ntsc_y", "", IntegerSetting::Decimal, 47);
|
||||
IntegerSetting Video::aspect_pal_x (&config(), "video.aspect_pal_x", "", IntegerSetting::Decimal, 32);
|
||||
IntegerSetting Video::aspect_pal_y (&config(), "video.aspect_pal_y", "", IntegerSetting::Decimal, 23);
|
||||
|
||||
IntegerSetting Video::hardware_filter(&config(), "video.hardware_filter", "Video hardware filter\n"
|
||||
"0 = Point\n"
|
||||
"1 = Linear\n",
|
||||
IntegerSetting::Decimal, 1);
|
||||
IntegerSetting Video::software_filter(&config_file, "video.software_filter", "Video software filter\n"
|
||||
IntegerSetting Video::software_filter(&config(), "video.software_filter", "Video software filter\n"
|
||||
"0 = None\n"
|
||||
"1 = NTSC\n"
|
||||
"2 = HQ2x\n"
|
||||
"3 = Scale2x\n",
|
||||
IntegerSetting::Decimal, 0);
|
||||
IntegerSetting Video::frameskip(0, "video.frameskip", "Video frameskip", IntegerSetting::Decimal, 0);
|
||||
IntegerSetting Video::use_vram(&config_file, "video.use_vram", "Use Video RAM instead of System RAM", IntegerSetting::Boolean, true);
|
||||
IntegerSetting Video::use_vram(&config(), "video.use_vram", "Use Video RAM instead of System RAM", IntegerSetting::Boolean, true);
|
||||
|
||||
struct Audio {
|
||||
static IntegerSetting synchronize;
|
||||
static IntegerSetting frequency;
|
||||
static IntegerSetting latency;
|
||||
} audio;
|
||||
IntegerSetting Audio::synchronize(&config_file, "audio.synchronize", "Synchronize to audio sample rate.", IntegerSetting::Boolean, true);
|
||||
IntegerSetting Audio::frequency(&config_file, "audio.frequency", "Default audio playback frequency.", IntegerSetting::Decimal, 32000);
|
||||
IntegerSetting Audio::latency(&config_file, "audio.latency", "Audio playback latency in milliseconds.\n"
|
||||
IntegerSetting Audio::synchronize(&config(), "audio.synchronize", "Synchronize to audio sample rate.", IntegerSetting::Boolean, true);
|
||||
IntegerSetting Audio::frequency(&config(), "audio.frequency", "Default audio playback frequency.", IntegerSetting::Decimal, 32000);
|
||||
IntegerSetting Audio::latency(&config(), "audio.latency", "Audio playback latency in milliseconds.\n"
|
||||
"Specifies how long audio playback is delayed compared to a real SNES.\n"
|
||||
"A delay is necessary to allow smooth audio playback via buffering.\n"
|
||||
"Raising this value may help with audio playback problems, but will decrease\n"
|
||||
@@ -82,7 +94,7 @@ struct Input {
|
||||
} joypad2;
|
||||
} input;
|
||||
|
||||
IntegerSetting Input::axis_resistance(&config_file, "input.axis_resistance",
|
||||
IntegerSetting Input::axis_resistance(&config(), "input.axis_resistance",
|
||||
"Axis resistance for all analog joypads\n"
|
||||
"Affects responsiveness of analog stick movement by specifying what percentage\n"
|
||||
"in any given direction the axis must be pressed to trigger a button press.\n"
|
||||
@@ -94,34 +106,40 @@ IntegerSetting Input::axis_resistance(&config_file, "input.axis_resistance",
|
||||
"Note: Values below 10 or above 90 are not recommended and may not work at all.",
|
||||
IntegerSetting::Decimal, 75);
|
||||
|
||||
IntegerSetting Input::allow_invalid_input(&config_file, "input.allow_invalid_input",
|
||||
IntegerSetting Input::allow_invalid_input(&config(), "input.allow_invalid_input",
|
||||
"Allow up+down and left+right combinations (not recommended)",
|
||||
IntegerSetting::Boolean, false);
|
||||
|
||||
StringSetting Input::Joypad1::up (&config_file, "input.joypad1.up", "", "up");
|
||||
StringSetting Input::Joypad1::down (&config_file, "input.joypad1.down", "", "down");
|
||||
StringSetting Input::Joypad1::left (&config_file, "input.joypad1.left", "", "left");
|
||||
StringSetting Input::Joypad1::right (&config_file, "input.joypad1.right", "", "right");
|
||||
StringSetting Input::Joypad1::a (&config_file, "input.joypad1.a", "", "x");
|
||||
StringSetting Input::Joypad1::b (&config_file, "input.joypad1.b", "", "z");
|
||||
StringSetting Input::Joypad1::x (&config_file, "input.joypad1.x", "", "s");
|
||||
StringSetting Input::Joypad1::y (&config_file, "input.joypad1.y", "", "a");
|
||||
StringSetting Input::Joypad1::l (&config_file, "input.joypad1.l", "", "d");
|
||||
StringSetting Input::Joypad1::r (&config_file, "input.joypad1.r", "", "c");
|
||||
StringSetting Input::Joypad1::select(&config_file, "input.joypad1.select", "", "rshift");
|
||||
StringSetting Input::Joypad1::start (&config_file, "input.joypad1.start", "", "enter");
|
||||
StringSetting Input::Joypad1::up (&config(), "input.joypad1.up", "", "up");
|
||||
StringSetting Input::Joypad1::down (&config(), "input.joypad1.down", "", "down");
|
||||
StringSetting Input::Joypad1::left (&config(), "input.joypad1.left", "", "left");
|
||||
StringSetting Input::Joypad1::right (&config(), "input.joypad1.right", "", "right");
|
||||
StringSetting Input::Joypad1::a (&config(), "input.joypad1.a", "", "x");
|
||||
StringSetting Input::Joypad1::b (&config(), "input.joypad1.b", "", "z");
|
||||
StringSetting Input::Joypad1::x (&config(), "input.joypad1.x", "", "s");
|
||||
StringSetting Input::Joypad1::y (&config(), "input.joypad1.y", "", "a");
|
||||
StringSetting Input::Joypad1::l (&config(), "input.joypad1.l", "", "d");
|
||||
StringSetting Input::Joypad1::r (&config(), "input.joypad1.r", "", "c");
|
||||
StringSetting Input::Joypad1::select(&config(), "input.joypad1.select", "", "rshift");
|
||||
StringSetting Input::Joypad1::start (&config(), "input.joypad1.start", "", "enter");
|
||||
|
||||
StringSetting Input::Joypad2::up (&config_file, "input.joypad2.up", "", "t");
|
||||
StringSetting Input::Joypad2::down (&config_file, "input.joypad2.down", "", "g");
|
||||
StringSetting Input::Joypad2::left (&config_file, "input.joypad2.left", "", "f");
|
||||
StringSetting Input::Joypad2::right (&config_file, "input.joypad2.right", "", "h");
|
||||
StringSetting Input::Joypad2::a (&config_file, "input.joypad2.a", "", "k");
|
||||
StringSetting Input::Joypad2::b (&config_file, "input.joypad2.b", "", "j");
|
||||
StringSetting Input::Joypad2::x (&config_file, "input.joypad2.x", "", "i");
|
||||
StringSetting Input::Joypad2::y (&config_file, "input.joypad2.y", "", "u");
|
||||
StringSetting Input::Joypad2::l (&config_file, "input.joypad2.l", "", "o");
|
||||
StringSetting Input::Joypad2::r (&config_file, "input.joypad2.r", "", "l");
|
||||
StringSetting Input::Joypad2::select(&config_file, "input.joypad2.select", "", "lbracket");
|
||||
StringSetting Input::Joypad2::start (&config_file, "input.joypad2.start", "", "rbracket");
|
||||
StringSetting Input::Joypad2::up (&config(), "input.joypad2.up", "", "t");
|
||||
StringSetting Input::Joypad2::down (&config(), "input.joypad2.down", "", "g");
|
||||
StringSetting Input::Joypad2::left (&config(), "input.joypad2.left", "", "f");
|
||||
StringSetting Input::Joypad2::right (&config(), "input.joypad2.right", "", "h");
|
||||
StringSetting Input::Joypad2::a (&config(), "input.joypad2.a", "", "k");
|
||||
StringSetting Input::Joypad2::b (&config(), "input.joypad2.b", "", "j");
|
||||
StringSetting Input::Joypad2::x (&config(), "input.joypad2.x", "", "i");
|
||||
StringSetting Input::Joypad2::y (&config(), "input.joypad2.y", "", "u");
|
||||
StringSetting Input::Joypad2::l (&config(), "input.joypad2.l", "", "o");
|
||||
StringSetting Input::Joypad2::r (&config(), "input.joypad2.r", "", "l");
|
||||
StringSetting Input::Joypad2::select(&config(), "input.joypad2.select", "", "lbracket");
|
||||
StringSetting Input::Joypad2::start (&config(), "input.joypad2.start", "", "rbracket");
|
||||
|
||||
struct Misc {
|
||||
static IntegerSetting show_frame_counter;
|
||||
} misc;
|
||||
|
||||
IntegerSetting Misc::show_frame_counter(&config(), "misc.show_frame_counter", "Display frame counter", IntegerSetting::Boolean, true);
|
||||
|
||||
};
|
||||
|
@@ -1,10 +1,14 @@
|
||||
#include "dinput.h"
|
||||
|
||||
void InputDI::clear_input() {
|
||||
memset(keystate, 0, sizeof keystate);
|
||||
}
|
||||
|
||||
void InputDI::poll() {
|
||||
clear_input();
|
||||
|
||||
HRESULT hr;
|
||||
DIJOYSTATE2 js;
|
||||
memset(keystate, 0, sizeof(keystate));
|
||||
|
||||
if(di_key) {
|
||||
hr = di_key->GetDeviceState(256, keystate);
|
||||
if(FAILED(hr)) {
|
||||
|
@@ -15,6 +15,7 @@ LPDIRECTINPUT8 di;
|
||||
LPDIRECTINPUTDEVICE8 di_key, di_joy[DIRECTINPUT_JOYMAX];
|
||||
uint32 di_joy_count;
|
||||
|
||||
void clear_input();
|
||||
void poll();
|
||||
void init();
|
||||
void term();
|
||||
|
@@ -0,0 +1 @@
|
||||
#include "input.h"
|
||||
|
@@ -5,9 +5,7 @@ class Input { public:
|
||||
virtual bool key_down(uint16 key) { return false; }
|
||||
virtual bool key_up (uint16 key) { return !key_down(key); }
|
||||
|
||||
virtual void signal_key_down(uint16 key) {}
|
||||
virtual void signal_key_up (uint16 key) {}
|
||||
|
||||
virtual void clear_input() {}
|
||||
virtual void poll() {}
|
||||
virtual void init() {}
|
||||
virtual void term() {}
|
||||
|
@@ -1 +0,0 @@
|
||||
#include "inputui.h"
|
@@ -1,26 +0,0 @@
|
||||
/*****
|
||||
* InputUI
|
||||
*
|
||||
* Input wrapper to capture UI key presses. Useful for when OS does not
|
||||
* support direct input polling methods (eg Xorg, etc)
|
||||
*****/
|
||||
|
||||
#ifndef INPUTUI_H
|
||||
#define INPUTUI_H
|
||||
|
||||
class InputUI : public Input {
|
||||
private:
|
||||
bool keystate[65536];
|
||||
|
||||
public:
|
||||
void init() {
|
||||
Input::init();
|
||||
memset(keystate, 0, sizeof(keystate));
|
||||
}
|
||||
|
||||
bool key_down(uint16 key) { return keystate[key]; }
|
||||
void signal_key_down(uint16 key) { keystate[key] = true; }
|
||||
void signal_key_up (uint16 key) { keystate[key] = false; }
|
||||
};
|
||||
|
||||
#endif
|
143
src/ui/input/xinput.cpp
Normal file
143
src/ui/input/xinput.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "xinput.h"
|
||||
|
||||
bool InputX::key_down(uint16 key) {
|
||||
#define map(i) (keymap[i >> 3] & (1 << (i & 7)))
|
||||
switch(key) {
|
||||
case keymap::esc: return map(0x09);
|
||||
|
||||
case keymap::f1: return map(0x43);
|
||||
case keymap::f2: return map(0x44);
|
||||
case keymap::f3: return map(0x45);
|
||||
case keymap::f4: return map(0x46);
|
||||
case keymap::f5: return map(0x47);
|
||||
case keymap::f6: return map(0x48);
|
||||
case keymap::f7: return map(0x49);
|
||||
case keymap::f8: return map(0x4a);
|
||||
case keymap::f9: return map(0x4b);
|
||||
case keymap::f10: return map(0x4c);
|
||||
case keymap::f11: return map(0x5f);
|
||||
case keymap::f12: return map(0x60);
|
||||
|
||||
case keymap::print_screen: return map(0x6f);
|
||||
case keymap::scroll_lock: return map(0x4e);
|
||||
case keymap::pause: return map(0x6e);
|
||||
|
||||
case keymap::grave: return map(0x31);
|
||||
|
||||
case keymap::num_1: return map(0x0a);
|
||||
case keymap::num_2: return map(0x0b);
|
||||
case keymap::num_3: return map(0x0c);
|
||||
case keymap::num_4: return map(0x0d);
|
||||
case keymap::num_5: return map(0x0e);
|
||||
case keymap::num_6: return map(0x0f);
|
||||
case keymap::num_7: return map(0x10);
|
||||
case keymap::num_8: return map(0x11);
|
||||
case keymap::num_9: return map(0x12);
|
||||
case keymap::num_0: return map(0x13);
|
||||
|
||||
case keymap::minus: return map(0x14);
|
||||
case keymap::equal: return map(0x15);
|
||||
case keymap::backspace: return map(0x16);
|
||||
|
||||
case keymap::ins: return map(0x6a);
|
||||
case keymap::del: return map(0x6b);
|
||||
case keymap::home: return map(0x61);
|
||||
case keymap::end: return map(0x67);
|
||||
case keymap::page_up: return map(0x63);
|
||||
case keymap::page_down: return map(0x69);
|
||||
|
||||
case keymap::a: return map(0x26);
|
||||
case keymap::b: return map(0x38);
|
||||
case keymap::c: return map(0x36);
|
||||
case keymap::d: return map(0x28);
|
||||
case keymap::e: return map(0x1a);
|
||||
case keymap::f: return map(0x29);
|
||||
case keymap::g: return map(0x2a);
|
||||
case keymap::h: return map(0x2b);
|
||||
case keymap::i: return map(0x1f);
|
||||
case keymap::j: return map(0x2c);
|
||||
case keymap::k: return map(0x2d);
|
||||
case keymap::l: return map(0x2e);
|
||||
case keymap::m: return map(0x3a);
|
||||
case keymap::n: return map(0x39);
|
||||
case keymap::o: return map(0x20);
|
||||
case keymap::p: return map(0x21);
|
||||
case keymap::q: return map(0x18);
|
||||
case keymap::r: return map(0x1b);
|
||||
case keymap::s: return map(0x27);
|
||||
case keymap::t: return map(0x1c);
|
||||
case keymap::u: return map(0x1e);
|
||||
case keymap::v: return map(0x37);
|
||||
case keymap::w: return map(0x19);
|
||||
case keymap::x: return map(0x35);
|
||||
case keymap::y: return map(0x1d);
|
||||
case keymap::z: return map(0x34);
|
||||
|
||||
case keymap::lbracket: return map(0x22);
|
||||
case keymap::rbracket: return map(0x23);
|
||||
case keymap::backslash: return map(0x33);
|
||||
case keymap::semicolon: return map(0x2f);
|
||||
case keymap::apostrophe: return map(0x30);
|
||||
case keymap::comma: return map(0x3b);
|
||||
case keymap::period: return map(0x3c);
|
||||
case keymap::slash: return map(0x3d);
|
||||
|
||||
case keymap::kp_1: return map(0x57);
|
||||
case keymap::kp_2: return map(0x58);
|
||||
case keymap::kp_3: return map(0x59);
|
||||
case keymap::kp_4: return map(0x53);
|
||||
case keymap::kp_5: return map(0x54);
|
||||
case keymap::kp_6: return map(0x55);
|
||||
case keymap::kp_7: return map(0x4f);
|
||||
case keymap::kp_8: return map(0x50);
|
||||
case keymap::kp_9: return map(0x51);
|
||||
|
||||
case keymap::kp_plus: return map(0x56);
|
||||
case keymap::kp_minus: return map(0x52);
|
||||
case keymap::kp_mul: return map(0x3f);
|
||||
case keymap::kp_div: return map(0x70);
|
||||
case keymap::kp_enter: return map(0x6c);
|
||||
|
||||
case keymap::num_lock: return map(0x4d);
|
||||
case keymap::caps_lock: return map(0x42);
|
||||
|
||||
case keymap::up: return map(0x62);
|
||||
case keymap::down: return map(0x68);
|
||||
case keymap::left: return map(0x64);
|
||||
case keymap::right: return map(0x66);
|
||||
|
||||
case keymap::tab: return map(0x17);
|
||||
case keymap::enter: return map(0x24);
|
||||
case keymap::space: return map(0x41);
|
||||
|
||||
case keymap::lctrl: return map(0x25);
|
||||
case keymap::rctrl: return map(0x6d);
|
||||
case keymap::lalt: return map(0x40);
|
||||
case keymap::ralt: return map(0x71);
|
||||
case keymap::lshift: return map(0x32);
|
||||
case keymap::rshift: return map(0x3e);
|
||||
case keymap::lsuper: return map(0x73);
|
||||
case keymap::rsuper: return map(0x74);
|
||||
case keymap::menu: return map(0x75);
|
||||
}
|
||||
#undef map
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InputX::clear_input() {
|
||||
memset(keymap, 0, sizeof keymap);
|
||||
}
|
||||
|
||||
void InputX::poll() {
|
||||
XQueryKeymap(display, keymap);
|
||||
}
|
||||
|
||||
void InputX::init() {
|
||||
Input::init();
|
||||
display = XOpenDisplay(0);
|
||||
}
|
||||
|
||||
void InputX::term() {
|
||||
Input::term();
|
||||
}
|
26
src/ui/input/xinput.h
Normal file
26
src/ui/input/xinput.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef XINPUT_H
|
||||
#define XINPUT_H
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/Xv.h>
|
||||
#include <X11/extensions/Xvlib.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
|
||||
class InputX : public Input { public:
|
||||
bool key_down(uint16 key);
|
||||
|
||||
void clear_input();
|
||||
void poll();
|
||||
void init();
|
||||
void term();
|
||||
|
||||
private:
|
||||
Display *display;
|
||||
char keymap[32];
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,115 +1,144 @@
|
||||
class InputManager { public:
|
||||
struct Joypad {
|
||||
uint16 up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joypad1, joypad2;
|
||||
struct Joystat {
|
||||
bool up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joystat1, joystat2;
|
||||
|
||||
void bind();
|
||||
void poll();
|
||||
bool get_status(uint device, uint button);
|
||||
} input_manager;
|
||||
|
||||
void InputManager::bind() {
|
||||
joypad1.up = keymap::find(config::input.joypad1.up);
|
||||
joypad1.down = keymap::find(config::input.joypad1.down);
|
||||
joypad1.left = keymap::find(config::input.joypad1.left);
|
||||
joypad1.right = keymap::find(config::input.joypad1.right);
|
||||
joypad1.a = keymap::find(config::input.joypad1.a);
|
||||
joypad1.b = keymap::find(config::input.joypad1.b);
|
||||
joypad1.x = keymap::find(config::input.joypad1.x);
|
||||
joypad1.y = keymap::find(config::input.joypad1.y);
|
||||
joypad1.l = keymap::find(config::input.joypad1.l);
|
||||
joypad1.r = keymap::find(config::input.joypad1.r);
|
||||
joypad1.select = keymap::find(config::input.joypad1.select);
|
||||
joypad1.start = keymap::find(config::input.joypad1.start);
|
||||
|
||||
joystat1.up = joystat1.down = joystat1.left = joystat1.right =
|
||||
joystat1.a = joystat1.b = joystat1.x = joystat1.y =
|
||||
joystat1.l = joystat1.r = joystat1.select = joystat1.start = false;
|
||||
|
||||
joypad2.up = keymap::find(config::input.joypad2.up);
|
||||
joypad2.down = keymap::find(config::input.joypad2.down);
|
||||
joypad2.left = keymap::find(config::input.joypad2.left);
|
||||
joypad2.right = keymap::find(config::input.joypad2.right);
|
||||
joypad2.a = keymap::find(config::input.joypad2.a);
|
||||
joypad2.b = keymap::find(config::input.joypad2.b);
|
||||
joypad2.x = keymap::find(config::input.joypad2.x);
|
||||
joypad2.y = keymap::find(config::input.joypad2.y);
|
||||
joypad2.l = keymap::find(config::input.joypad2.l);
|
||||
joypad2.r = keymap::find(config::input.joypad2.r);
|
||||
joypad2.select = keymap::find(config::input.joypad2.select);
|
||||
joypad2.start = keymap::find(config::input.joypad2.start);
|
||||
|
||||
joystat2.up = joystat2.down = joystat2.left = joystat2.right =
|
||||
joystat2.a = joystat2.b = joystat2.x = joystat2.y =
|
||||
joystat2.l = joystat2.r = joystat2.select = joystat2.start = false;
|
||||
}
|
||||
|
||||
void InputManager::poll() {
|
||||
joystat1.up = uiInput->key_down(joypad1.up);
|
||||
joystat1.down = uiInput->key_down(joypad1.down);
|
||||
joystat1.left = uiInput->key_down(joypad1.left);
|
||||
joystat1.right = uiInput->key_down(joypad1.right);
|
||||
joystat1.a = uiInput->key_down(joypad1.a);
|
||||
joystat1.b = uiInput->key_down(joypad1.b);
|
||||
joystat1.x = uiInput->key_down(joypad1.x);
|
||||
joystat1.y = uiInput->key_down(joypad1.y);
|
||||
joystat1.l = uiInput->key_down(joypad1.l);
|
||||
joystat1.r = uiInput->key_down(joypad1.r);
|
||||
joystat1.select = uiInput->key_down(joypad1.select);
|
||||
joystat1.start = uiInput->key_down(joypad1.start);
|
||||
|
||||
joystat2.up = uiInput->key_down(joypad2.up);
|
||||
joystat2.down = uiInput->key_down(joypad2.down);
|
||||
joystat2.left = uiInput->key_down(joypad2.left);
|
||||
joystat2.right = uiInput->key_down(joypad2.right);
|
||||
joystat2.a = uiInput->key_down(joypad2.a);
|
||||
joystat2.b = uiInput->key_down(joypad2.b);
|
||||
joystat2.x = uiInput->key_down(joypad2.x);
|
||||
joystat2.y = uiInput->key_down(joypad2.y);
|
||||
joystat2.l = uiInput->key_down(joypad2.l);
|
||||
joystat2.r = uiInput->key_down(joypad2.r);
|
||||
joystat2.select = uiInput->key_down(joypad2.select);
|
||||
joystat2.start = uiInput->key_down(joypad2.start);
|
||||
}
|
||||
|
||||
bool InputManager::get_status(uint device, uint button) {
|
||||
switch(device) {
|
||||
case SNES::DEVICEID_JOYPAD1:
|
||||
switch(button) {
|
||||
case SNES::JOYPAD_UP: return joystat1.up;
|
||||
case SNES::JOYPAD_DOWN: return joystat1.down;
|
||||
case SNES::JOYPAD_LEFT: return joystat1.left;
|
||||
case SNES::JOYPAD_RIGHT: return joystat1.right;
|
||||
case SNES::JOYPAD_A: return joystat1.a;
|
||||
case SNES::JOYPAD_B: return joystat1.b;
|
||||
case SNES::JOYPAD_X: return joystat1.x;
|
||||
case SNES::JOYPAD_Y: return joystat1.y;
|
||||
case SNES::JOYPAD_L: return joystat1.l;
|
||||
case SNES::JOYPAD_R: return joystat1.r;
|
||||
case SNES::JOYPAD_SELECT: return joystat1.select;
|
||||
case SNES::JOYPAD_START: return joystat1.start;
|
||||
}
|
||||
break;
|
||||
case SNES::DEVICEID_JOYPAD2:
|
||||
switch(button) {
|
||||
case SNES::JOYPAD_UP: return joystat2.up;
|
||||
case SNES::JOYPAD_DOWN: return joystat2.down;
|
||||
case SNES::JOYPAD_LEFT: return joystat2.left;
|
||||
case SNES::JOYPAD_RIGHT: return joystat2.right;
|
||||
case SNES::JOYPAD_A: return joystat2.a;
|
||||
case SNES::JOYPAD_B: return joystat2.b;
|
||||
case SNES::JOYPAD_X: return joystat2.x;
|
||||
case SNES::JOYPAD_Y: return joystat2.y;
|
||||
case SNES::JOYPAD_L: return joystat2.l;
|
||||
case SNES::JOYPAD_R: return joystat2.r;
|
||||
case SNES::JOYPAD_SELECT: return joystat2.select;
|
||||
case SNES::JOYPAD_START: return joystat2.start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
class InputManager { public:
|
||||
struct Joypad {
|
||||
uint16 up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joypad1, joypad2;
|
||||
struct Joystat {
|
||||
bool up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joystat1, joystat2;
|
||||
|
||||
uint16 scan();
|
||||
void bind();
|
||||
void poll();
|
||||
bool get_status(uint device, uint button);
|
||||
} input_manager;
|
||||
|
||||
//search all key bindings, return keymap::none if no keys are active
|
||||
uint16 InputManager::scan() {
|
||||
uiInput->poll();
|
||||
for(uint i = 0; i < keymap::limit; i++) {
|
||||
if(uiInput->key_down(i)) { return i; }
|
||||
}
|
||||
for(uint j = 0; j < 16; j++) {
|
||||
if(uiInput->key_down(keymap::joypad_flag | (j << 16) | keymap::joypad_up)) {
|
||||
return (keymap::joypad_flag | (j << 16) | keymap::joypad_up);
|
||||
}
|
||||
if(uiInput->key_down(keymap::joypad_flag | (j << 16) | keymap::joypad_down)) {
|
||||
return (keymap::joypad_flag | (j << 16) | keymap::joypad_down);
|
||||
}
|
||||
if(uiInput->key_down(keymap::joypad_flag | (j << 16) | keymap::joypad_left)) {
|
||||
return (keymap::joypad_flag | (j << 16) | keymap::joypad_left);
|
||||
}
|
||||
if(uiInput->key_down(keymap::joypad_flag | (j << 16) | keymap::joypad_right)) {
|
||||
return (keymap::joypad_flag | (j << 16) | keymap::joypad_right);
|
||||
}
|
||||
for(uint i = 0; i < 128; i++) {
|
||||
if(uiInput->key_down(keymap::joypad_flag | (j << 16) | i)) {
|
||||
return (keymap::joypad_flag | (j << 16) | i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return keymap::none;
|
||||
}
|
||||
|
||||
void InputManager::bind() {
|
||||
joypad1.up = keymap::find(config::input.joypad1.up);
|
||||
joypad1.down = keymap::find(config::input.joypad1.down);
|
||||
joypad1.left = keymap::find(config::input.joypad1.left);
|
||||
joypad1.right = keymap::find(config::input.joypad1.right);
|
||||
joypad1.a = keymap::find(config::input.joypad1.a);
|
||||
joypad1.b = keymap::find(config::input.joypad1.b);
|
||||
joypad1.x = keymap::find(config::input.joypad1.x);
|
||||
joypad1.y = keymap::find(config::input.joypad1.y);
|
||||
joypad1.l = keymap::find(config::input.joypad1.l);
|
||||
joypad1.r = keymap::find(config::input.joypad1.r);
|
||||
joypad1.select = keymap::find(config::input.joypad1.select);
|
||||
joypad1.start = keymap::find(config::input.joypad1.start);
|
||||
|
||||
joystat1.up = joystat1.down = joystat1.left = joystat1.right =
|
||||
joystat1.a = joystat1.b = joystat1.x = joystat1.y =
|
||||
joystat1.l = joystat1.r = joystat1.select = joystat1.start = false;
|
||||
|
||||
joypad2.up = keymap::find(config::input.joypad2.up);
|
||||
joypad2.down = keymap::find(config::input.joypad2.down);
|
||||
joypad2.left = keymap::find(config::input.joypad2.left);
|
||||
joypad2.right = keymap::find(config::input.joypad2.right);
|
||||
joypad2.a = keymap::find(config::input.joypad2.a);
|
||||
joypad2.b = keymap::find(config::input.joypad2.b);
|
||||
joypad2.x = keymap::find(config::input.joypad2.x);
|
||||
joypad2.y = keymap::find(config::input.joypad2.y);
|
||||
joypad2.l = keymap::find(config::input.joypad2.l);
|
||||
joypad2.r = keymap::find(config::input.joypad2.r);
|
||||
joypad2.select = keymap::find(config::input.joypad2.select);
|
||||
joypad2.start = keymap::find(config::input.joypad2.start);
|
||||
|
||||
joystat2.up = joystat2.down = joystat2.left = joystat2.right =
|
||||
joystat2.a = joystat2.b = joystat2.x = joystat2.y =
|
||||
joystat2.l = joystat2.r = joystat2.select = joystat2.start = false;
|
||||
}
|
||||
|
||||
void InputManager::poll() {
|
||||
joystat1.up = uiInput->key_down(joypad1.up);
|
||||
joystat1.down = uiInput->key_down(joypad1.down);
|
||||
joystat1.left = uiInput->key_down(joypad1.left);
|
||||
joystat1.right = uiInput->key_down(joypad1.right);
|
||||
joystat1.a = uiInput->key_down(joypad1.a);
|
||||
joystat1.b = uiInput->key_down(joypad1.b);
|
||||
joystat1.x = uiInput->key_down(joypad1.x);
|
||||
joystat1.y = uiInput->key_down(joypad1.y);
|
||||
joystat1.l = uiInput->key_down(joypad1.l);
|
||||
joystat1.r = uiInput->key_down(joypad1.r);
|
||||
joystat1.select = uiInput->key_down(joypad1.select);
|
||||
joystat1.start = uiInput->key_down(joypad1.start);
|
||||
|
||||
joystat2.up = uiInput->key_down(joypad2.up);
|
||||
joystat2.down = uiInput->key_down(joypad2.down);
|
||||
joystat2.left = uiInput->key_down(joypad2.left);
|
||||
joystat2.right = uiInput->key_down(joypad2.right);
|
||||
joystat2.a = uiInput->key_down(joypad2.a);
|
||||
joystat2.b = uiInput->key_down(joypad2.b);
|
||||
joystat2.x = uiInput->key_down(joypad2.x);
|
||||
joystat2.y = uiInput->key_down(joypad2.y);
|
||||
joystat2.l = uiInput->key_down(joypad2.l);
|
||||
joystat2.r = uiInput->key_down(joypad2.r);
|
||||
joystat2.select = uiInput->key_down(joypad2.select);
|
||||
joystat2.start = uiInput->key_down(joypad2.start);
|
||||
}
|
||||
|
||||
bool InputManager::get_status(uint device, uint button) {
|
||||
switch(device) {
|
||||
case SNES::DEVICEID_JOYPAD1:
|
||||
switch(button) {
|
||||
case SNES::JOYPAD_UP: return joystat1.up;
|
||||
case SNES::JOYPAD_DOWN: return joystat1.down;
|
||||
case SNES::JOYPAD_LEFT: return joystat1.left;
|
||||
case SNES::JOYPAD_RIGHT: return joystat1.right;
|
||||
case SNES::JOYPAD_A: return joystat1.a;
|
||||
case SNES::JOYPAD_B: return joystat1.b;
|
||||
case SNES::JOYPAD_X: return joystat1.x;
|
||||
case SNES::JOYPAD_Y: return joystat1.y;
|
||||
case SNES::JOYPAD_L: return joystat1.l;
|
||||
case SNES::JOYPAD_R: return joystat1.r;
|
||||
case SNES::JOYPAD_SELECT: return joystat1.select;
|
||||
case SNES::JOYPAD_START: return joystat1.start;
|
||||
}
|
||||
break;
|
||||
case SNES::DEVICEID_JOYPAD2:
|
||||
switch(button) {
|
||||
case SNES::JOYPAD_UP: return joystat2.up;
|
||||
case SNES::JOYPAD_DOWN: return joystat2.down;
|
||||
case SNES::JOYPAD_LEFT: return joystat2.left;
|
||||
case SNES::JOYPAD_RIGHT: return joystat2.right;
|
||||
case SNES::JOYPAD_A: return joystat2.a;
|
||||
case SNES::JOYPAD_B: return joystat2.b;
|
||||
case SNES::JOYPAD_X: return joystat2.x;
|
||||
case SNES::JOYPAD_Y: return joystat2.y;
|
||||
case SNES::JOYPAD_L: return joystat2.l;
|
||||
case SNES::JOYPAD_R: return joystat2.r;
|
||||
case SNES::JOYPAD_SELECT: return joystat2.select;
|
||||
case SNES::JOYPAD_START: return joystat2.start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -40,7 +40,11 @@ void SNESInterface::audio_sample(uint16 l_sample, uint16 r_sample) {
|
||||
//input
|
||||
|
||||
void SNESInterface::input_poll() {
|
||||
uiInput->poll();
|
||||
if(input_ready && input_ready() == false) {
|
||||
uiInput->clear_input();
|
||||
} else {
|
||||
uiInput->poll();
|
||||
}
|
||||
input_manager.poll();
|
||||
}
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
namespace event {
|
||||
|
||||
void update_frame_counter() {
|
||||
if(r_ppu->status.frames_updated) {
|
||||
r_ppu->status.frames_updated = false;
|
||||
if(bool(true) == true) { //TODO: add config file variable to toggle fps counter
|
||||
window_main.set_text("%s [%d]", BSNES_TITLE, r_ppu->status.frames_executed);
|
||||
}
|
||||
}
|
||||
namespace event {
|
||||
|
||||
void update_frame_counter() {
|
||||
if(r_ppu->status.frames_updated) {
|
||||
r_ppu->status.frames_updated = false;
|
||||
if(config::misc.show_frame_counter == true) {
|
||||
window_main.set_text(string() << BSNES_TITLE << " [" << r_ppu->status.frames_executed << "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_video_settings() {
|
||||
@@ -16,10 +16,25 @@ uint multiplier = minmax<1, 5>(uint(config::video.multiplier));
|
||||
width *= multiplier;
|
||||
height *= multiplier;
|
||||
if(config::video.aspect_correction == true) {
|
||||
width = uint( double(width) * 8.0 / 7.0 );
|
||||
if(config::video.region == 0) { //NTSC
|
||||
width = uint( double(width) * double(config::video.aspect_ntsc_x) / double(config::video.aspect_ntsc_y) );
|
||||
} else { //PAL
|
||||
width = uint( double(width) * double(config::video.aspect_pal_x) / double(config::video.aspect_pal_y) );
|
||||
}
|
||||
}
|
||||
|
||||
if(config::video.fullscreen) {
|
||||
//window_main.menu.hide();
|
||||
window_main.fullscreen();
|
||||
window_main.view.move((ui::get_screen_width() - width) / 2, (ui::get_screen_height() - height) / 2);
|
||||
window_main.view.resize(width, height);
|
||||
} else {
|
||||
//window_main.menu.show();
|
||||
window_main.unfullscreen();
|
||||
window_main.resize(width, height);
|
||||
window_main.view.move(0, 0);
|
||||
window_main.view.resize(width, height);
|
||||
}
|
||||
window_main.resize(width, height);
|
||||
window_main.view.resize(width, height);
|
||||
}
|
||||
|
||||
void update_raster_settings() {
|
||||
@@ -40,6 +55,16 @@ uint filter, standard;
|
||||
snes.set_video_standard(standard);
|
||||
}
|
||||
|
||||
void toggle_menu() {
|
||||
window_main.menu.show(!window_main.menu.visible());
|
||||
update_video_settings();
|
||||
}
|
||||
|
||||
void toggle_fullscreen() {
|
||||
config::video.fullscreen = !config::video.fullscreen;
|
||||
update_video_settings();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
bool load_rom(char *fn) {
|
||||
@@ -57,7 +82,7 @@ stringarray dir;
|
||||
strcat(dir[0], dir[1]);
|
||||
}
|
||||
|
||||
return ui::file_load(window_main, fn,
|
||||
return ui::file_load(&window_main, fn,
|
||||
"SNES images;*.smc,*.sfc,*.swc,*.fig,*.ufo,*.gd3,*.078,*.st"
|
||||
#if defined(GZIP_SUPPORT)
|
||||
",*.gz,*.z,*.zip"
|
||||
@@ -70,7 +95,7 @@ stringarray dir;
|
||||
}
|
||||
|
||||
void load_rom() {
|
||||
char fn[4096];
|
||||
char fn[PATH_MAX];
|
||||
if(load_rom(fn) == false)return;
|
||||
|
||||
if(cartridge.loaded() == true)cartridge.unload();
|
||||
@@ -78,11 +103,43 @@ char fn[4096];
|
||||
cartridge.load(fn);
|
||||
cartridge.load_end();
|
||||
snes.power();
|
||||
window_cheat_editor.refresh();
|
||||
}
|
||||
|
||||
void load_rom_st() {
|
||||
char fn[PATH_MAX];
|
||||
if(load_rom(fn) == false)return;
|
||||
|
||||
if(cartridge.loaded() == true)cartridge.unload();
|
||||
cartridge.load_begin(Cartridge::CART_ST);
|
||||
cartridge.load(fn);
|
||||
cartridge.load_end();
|
||||
snes.power();
|
||||
window_cheat_editor.refresh();
|
||||
}
|
||||
|
||||
void load_rom_stdual() {
|
||||
char fn_a[PATH_MAX], fn_b[PATH_MAX];
|
||||
if(load_rom(fn_a) == false)return;
|
||||
if(load_rom(fn_b) == false)return;
|
||||
|
||||
if(cartridge.loaded() == true)cartridge.unload();
|
||||
cartridge.load_begin(Cartridge::CART_STDUAL);
|
||||
cartridge.load(fn_a);
|
||||
cartridge.load(fn_b);
|
||||
cartridge.load_end();
|
||||
snes.power();
|
||||
window_cheat_editor.refresh();
|
||||
}
|
||||
|
||||
void unload_rom() {
|
||||
cartridge.unload();
|
||||
uiAudio->clear_audio();
|
||||
if(cartridge.loaded() == true) {
|
||||
cartridge.unload();
|
||||
uiVideo->clear_video();
|
||||
uiAudio->clear_audio();
|
||||
}
|
||||
window_main.set_text(BSNES_TITLE);
|
||||
window_cheat_editor.refresh();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
@@ -1,11 +1,15 @@
|
||||
namespace event {
|
||||
|
||||
|
||||
void update_frame_counter();
|
||||
void update_video_settings();
|
||||
void update_raster_settings();
|
||||
void toggle_menu();
|
||||
void toggle_fullscreen();
|
||||
|
||||
bool load_rom(char *fn);
|
||||
void load_rom();
|
||||
void load_rom_st();
|
||||
void load_rom_stdual();
|
||||
void unload_rom();
|
||||
void reset();
|
||||
void power();
|
||||
|
@@ -1,3 +1,5 @@
|
||||
void run();
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
#include "../../lib/libui_win.h"
|
||||
#elif defined(PLATFORM_X)
|
||||
@@ -16,7 +18,7 @@ bool _term_ = false;
|
||||
#include "ui.cpp"
|
||||
#include "event.cpp"
|
||||
|
||||
void alert(char *s, ...) {
|
||||
void alert(const char *s, ...) {
|
||||
char str[4096];
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
@@ -25,7 +27,7 @@ va_list args;
|
||||
fprintf(stdout, "%s\r\n", str);
|
||||
}
|
||||
|
||||
void dprintf(char *s, ...) {
|
||||
void dprintf(const char *s, ...) {
|
||||
char str[4096];
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
@@ -34,7 +36,7 @@ va_list args;
|
||||
fprintf(stdout, "%s\r\n", str);
|
||||
}
|
||||
|
||||
void dprintf(uint source, char *s, ...) {
|
||||
void dprintf(uint source, const char *s, ...) {
|
||||
char str[4096];
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
@@ -43,31 +45,6 @@ va_list args;
|
||||
fprintf(stdout, "[%d]: %s\r\n", source, str);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void set_config_filename(const char *filename) {
|
||||
realpath(filename, config::filename);
|
||||
|
||||
//if argv[0] does not contain path information, obtain from getcwd()
|
||||
//otherwise, it was retrieved from argv[0] + realpath()
|
||||
if(strchr(config::filename, '/') == 0 && strchr(config::filename, '\\') == 0) {
|
||||
getcwd(config::filename, PATH_MAX);
|
||||
strcat(config::filename, "/");
|
||||
}
|
||||
|
||||
//convert all path delimiters to '/'
|
||||
for(int i = 0; i < strlen(config::filename); i++) {
|
||||
if(config::filename[i] == '\\') { config::filename[i] = '/'; }
|
||||
}
|
||||
|
||||
//remove program name from filename
|
||||
char *p = strrchr(config::filename, '/');
|
||||
if(p) { *p = 0; }
|
||||
|
||||
//finally, append config file name
|
||||
strcat(config::filename, "/bsnes.cfg");
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_config_filename() {
|
||||
userpath(config::filename);
|
||||
strcat(config::filename, "/.bsnes");
|
||||
@@ -75,8 +52,46 @@ void set_config_filename() {
|
||||
strcat(config::filename, "/bsnes.cfg");
|
||||
}
|
||||
|
||||
void get_base_path() {
|
||||
#if defined(PLATFORM_WIN)
|
||||
int __stdcall WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) {
|
||||
char full_name[PATH_MAX];
|
||||
GetFullPathName(__argv[0], PATH_MAX, full_name, 0);
|
||||
|
||||
string t;
|
||||
strcpy(t, full_name);
|
||||
|
||||
if(strlen(t) != 0) {
|
||||
//remove program name
|
||||
replace(t, "\\", "/");
|
||||
for(int i = strlen(t) - 1; i >= 0; i--) {
|
||||
if(strptr(t)[i] == '/' || strptr(t)[i] == '\\') {
|
||||
strptr(t)[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(strend(t, "/") == false) { strcat(t, "/"); }
|
||||
config::path.base = strptr(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
void run() {
|
||||
while(ui::events_pending() == true) { ui::run(); }
|
||||
if(cartridge.loaded() == true) {
|
||||
snes.runtoframe();
|
||||
event::update_frame_counter();
|
||||
} else { //prevent bsnes from consuming 100% CPU resources when idle
|
||||
#if defined(PLATFORM_WIN)
|
||||
Sleep(1);
|
||||
#elif defined(PLATFORM_X)
|
||||
usleep(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
int argc = __argc;
|
||||
char **argv = __argv;
|
||||
#else
|
||||
@@ -85,24 +100,28 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
//int main(int argc, char *argv[]) {
|
||||
set_config_filename();
|
||||
get_base_path();
|
||||
|
||||
ui::init();
|
||||
config_file.load(config::filename);
|
||||
config_file.save(config::filename); //in case program crashes on first run, config file settings can be modified
|
||||
config::config().load(config::filename);
|
||||
config::config().save(config::filename); //in case program crashes on first run, config file settings can be modified
|
||||
init_snes();
|
||||
ui_init();
|
||||
|
||||
while(_term_ == false) {
|
||||
while(ui::events_pending() == true) { ui::run(); }
|
||||
if(cartridge.loaded() == true) {
|
||||
snes.runtoframe();
|
||||
event::update_frame_counter();
|
||||
}
|
||||
if(argc >= 2) {
|
||||
cartridge.load_begin(Cartridge::CART_NORMAL);
|
||||
cartridge.load(argv[1]);
|
||||
cartridge.load_end();
|
||||
snes.power();
|
||||
}
|
||||
|
||||
if(cartridge.loaded() == true) { cartridge.unload(); }
|
||||
while(_term_ == false) {
|
||||
run();
|
||||
}
|
||||
|
||||
config_file.save(config::filename);
|
||||
event::unload_rom();
|
||||
|
||||
config::config().save(config::filename);
|
||||
term_snes();
|
||||
ui_term();
|
||||
ui::term();
|
||||
|
@@ -1,45 +1,46 @@
|
||||
int AdvancedWindow::message(uint id, void *param) {
|
||||
if(id == ui::Message::Changed && param == &list) {
|
||||
bool AdvancedWindow::message(uint id, uintptr_t param) {
|
||||
ui::Control *control = (ui::Control*)param;
|
||||
if(id == ui::Message::Changed && control == &list) {
|
||||
int pos = list.get_selection();
|
||||
set_val.enable(pos >= 0);
|
||||
set_def.enable(pos >= 0);
|
||||
if(pos >= 0 && pos < config_file.list_count) {
|
||||
desc.set_text("(default = %s)\n%s", config_file.list[pos]->def, config_file.list[pos]->desc);
|
||||
if(pos >= 0 && pos < config::config().list_count) {
|
||||
desc.set_text(string() << "(default = " << config::config().list[pos]->def << ")\n" << config::config().list[pos]->desc);
|
||||
string val;
|
||||
config_file.list[pos]->get(val);
|
||||
edit_val.set_text("%s", strptr(val));
|
||||
config::config().list[pos]->get(val);
|
||||
edit_val.set_text(strptr(val));
|
||||
}
|
||||
} else if(id == ui::Message::Clicked && param == &set_val) {
|
||||
} else if(id == ui::Message::Clicked && control == &set_val) {
|
||||
char t[4096];
|
||||
edit_val.get_text(t, sizeof(t));
|
||||
update(list.get_selection(), t);
|
||||
} else if(id == ui::Message::Clicked && param == &set_def) {
|
||||
} else if(id == ui::Message::Clicked && control == &set_def) {
|
||||
update(list.get_selection(), 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdvancedWindow::read_config(uint pos, string &data) {
|
||||
strcpy(data, "?|?|?");
|
||||
if(pos >= config_file.list_count)return;
|
||||
if(pos >= config::config().list_count)return;
|
||||
string name, val;
|
||||
name = config_file.list[pos]->name;
|
||||
config_file.list[pos]->get(val);
|
||||
if(val != config_file.list[pos]->def) { strcat(name, " (*)"); }
|
||||
name = config::config().list[pos]->name;
|
||||
config::config().list[pos]->get(val);
|
||||
if(val != config::config().list[pos]->def) { strcat(name, " (*)"); }
|
||||
sprintf(data, "%s|%s|%s",
|
||||
strptr(name),
|
||||
config_file.list[pos]->type == Setting::String ? "String" : "Integer",
|
||||
config::config().list[pos]->type == Setting::String ? "String" : "Integer",
|
||||
strptr(val)
|
||||
);
|
||||
}
|
||||
|
||||
void AdvancedWindow::update(uint pos, const char *data) {
|
||||
if(pos >= config_file.list_count)return;
|
||||
config_file.list[pos]->set(data ? data : config_file.list[pos]->def);
|
||||
if(pos >= config::config().list_count)return;
|
||||
config::config().list[pos]->set(data ? data : config::config().list[pos]->def);
|
||||
string val;
|
||||
config_file.list[pos]->get(val);
|
||||
edit_val.set_text("%s", strptr(val));
|
||||
config::config().list[pos]->get(val);
|
||||
edit_val.set_text(strptr(val));
|
||||
read_config(pos, val);
|
||||
list.set_item(pos, strptr(val));
|
||||
list.autosize_columns();
|
||||
@@ -49,20 +50,27 @@ void AdvancedWindow::setup() {
|
||||
create(0, 475, 355);
|
||||
|
||||
int x = 0, y = 0;
|
||||
list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, 235, "Name|Type|Value");
|
||||
y += 240;
|
||||
desc.create(*this, ui::Editbox::Multiline | ui::Editbox::Readonly, x, y, 475, 80,
|
||||
int bh = ui::Button::ideal_height;
|
||||
int eh = ui::Editbox::ideal_height;
|
||||
bh = max(bh, eh); //set both editbox and button to same size, as they are on the same line
|
||||
int th = 80;
|
||||
int lh = 355 - th - bh - 10;
|
||||
list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, lh, "Name|Type|Value");
|
||||
y += lh + 5;
|
||||
|
||||
desc.create(*this, ui::Editbox::Multiline | ui::Editbox::Readonly, x, y, 475, th,
|
||||
"<description>\n"
|
||||
"Warning: modifification of certain variables will not take effect until\n"
|
||||
"bsnes is restarted, and corresponding UI elements will not be updated\n"
|
||||
"to reflect changes here. (*) = modified"
|
||||
);
|
||||
y += 85;
|
||||
edit_val.create(*this, 0, x, y, 265, 30, "<current value>");
|
||||
set_val.create(*this, 0, x + 270, y, 100, 30, "Set");
|
||||
set_def.create(*this, 0, x + 375, y, 100, 30, "Default");
|
||||
y += th + 5;
|
||||
|
||||
for(int i = 0; i < config_file.list_count; i++) {
|
||||
edit_val.create(*this, 0, x, y, 265, bh, "<current value>");
|
||||
set_val.create(*this, 0, x + 270, y, 100, bh, "Set");
|
||||
set_def.create(*this, 0, x + 375, y, 100, bh, "Default");
|
||||
|
||||
for(int i = 0; i < config::config().list_count; i++) {
|
||||
string val;
|
||||
read_config(i, val);
|
||||
list.add_item(strptr(val));
|
||||
|
@@ -1,11 +1,11 @@
|
||||
class AdvancedWindow : public ui::Window { public:
|
||||
ui::Listbox list;
|
||||
ui::Editbox desc;
|
||||
ui::Editbox edit_val;
|
||||
ui::Button set_val;
|
||||
ui::Button set_def;
|
||||
int message(uint id, void *param);
|
||||
void read_config(uint pos, string &data);
|
||||
void update(uint pos, const char *data);
|
||||
void setup();
|
||||
} window_advanced;
|
||||
class AdvancedWindow : public ui::Window { public:
|
||||
ui::Listbox list;
|
||||
ui::Editbox desc;
|
||||
ui::Editbox edit_val;
|
||||
ui::Button set_val;
|
||||
ui::Button set_def;
|
||||
bool message(uint id, uintptr_t param);
|
||||
void read_config(uint pos, string &data);
|
||||
void update(uint pos, const char *data);
|
||||
void setup();
|
||||
} window_advanced;
|
||||
|
@@ -1,26 +1,82 @@
|
||||
int CheatEditorWindow::message(uint id, void *param) {
|
||||
return 0;
|
||||
void CheatEditorWindow::refresh() {
|
||||
list.reset();
|
||||
|
||||
for(uint i = 0; i < cheat.count(); i++) {
|
||||
bool enabled;
|
||||
uint32 addr;
|
||||
uint8 data;
|
||||
char s_code[256], s_desc[256], s_result[1024];
|
||||
cheat.get(i, enabled, addr, data, s_code, s_desc);
|
||||
sprintf(s_result, "%s|%s|%s", enabled ? "Enabled" : "Disabled", s_code, s_desc);
|
||||
list.add_item(s_result);
|
||||
}
|
||||
|
||||
list.autosize_columns();
|
||||
|
||||
//enable controls only if cartridge is loaded
|
||||
bool loaded = cartridge.loaded();
|
||||
add_code.enable(loaded);
|
||||
toggle_code.enable(loaded);
|
||||
delete_code.enable(loaded);
|
||||
}
|
||||
|
||||
bool CheatEditorWindow::message(uint id, uintptr_t param) {
|
||||
ui::Control *control = (ui::Control*)param;
|
||||
|
||||
if(id == ui::Message::Clicked && control == &add_code) {
|
||||
char s_code[256], s_desc[256];
|
||||
code.get_text(s_code, sizeof s_code);
|
||||
desc.get_text(s_desc, sizeof s_desc);
|
||||
cheat.add(false, s_code, s_desc); //param 0 = new codes disabled by default
|
||||
refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
if((id == ui::Message::Clicked && control == &toggle_code) ||
|
||||
(id == ui::Message::DoubleClicked && control == &list)) {
|
||||
int index = list.get_selection();
|
||||
if(index >= 0 && index < cheat.count()) {
|
||||
cheat.enabled(index) ? cheat.disable(index) : cheat.enable(index);
|
||||
bool enabled;
|
||||
uint32 addr;
|
||||
uint8 data;
|
||||
char s_code[256], s_desc[256], s_result[1024];
|
||||
cheat.get(index, enabled, addr, data, s_code, s_desc);
|
||||
sprintf(s_result, "%s|%s|%s", enabled ? "Enabled" : "Disabled", s_code, s_desc);
|
||||
list.set_item(index, s_result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == ui::Message::Clicked && control == &delete_code) {
|
||||
int index = list.get_selection();
|
||||
if(index >= 0 && index < cheat.count()) {
|
||||
cheat.remove(index);
|
||||
refresh();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheatEditorWindow::setup() {
|
||||
create(0, 475, 355);
|
||||
|
||||
int x = 0, y = 0;
|
||||
list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, 285, "Status|Code|Description");
|
||||
list.add_item("Enabled|0123-4567|Infinite Energy");
|
||||
list.add_item("Disabled|89ab-cdef|Infinite Lives");
|
||||
list.autosize_columns();
|
||||
y += 290;
|
||||
int bh = ui::Button::ideal_height;
|
||||
int eh = ui::Editbox::ideal_height;
|
||||
int lh = 355 - bh - eh - 10;
|
||||
list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, lh, "Status|Code|Description");
|
||||
y += lh + 5;
|
||||
|
||||
add_code.create (*this, 0, x, y, 155, 30, "Add Code");
|
||||
toggle_code.create(*this, 0, x + 160, y, 155, 30, "Toggle Status");
|
||||
delete_code.create(*this, 0, x + 320, y, 155, 30, "Delete Code");
|
||||
y += 35;
|
||||
add_code.create (*this, 0, x, y, 155, bh, "Add Code");
|
||||
toggle_code.create(*this, 0, x + 160, y, 155, bh, "Toggle Status");
|
||||
delete_code.create(*this, 0, x + 320, y, 155, bh, "Delete Code");
|
||||
y += bh + 5;
|
||||
|
||||
code.create(*this, 0, x, y, 155, 30, "<code>");
|
||||
desc.create(*this, 0, x + 160, y, 315, 30, "<description>");
|
||||
code.create(*this, 0, x, y, 155, eh, "<code>");
|
||||
desc.create(*this, 0, x + 160, y, 315, eh, "<description>");
|
||||
|
||||
add_code.disable();
|
||||
toggle_code.disable();
|
||||
delete_code.disable();
|
||||
refresh();
|
||||
}
|
||||
|
@@ -1,10 +1,12 @@
|
||||
class CheatEditorWindow : public ui::Window { public:
|
||||
ui::Listbox list;
|
||||
ui::Button add_code;
|
||||
ui::Button toggle_code;
|
||||
ui::Button delete_code;
|
||||
ui::Editbox code;
|
||||
ui::Editbox desc;
|
||||
int message(uint id, void *param);
|
||||
void setup();
|
||||
} window_cheat_editor;
|
||||
class CheatEditorWindow : public ui::Window { public:
|
||||
ui::Listbox list;
|
||||
ui::Button add_code;
|
||||
ui::Button toggle_code;
|
||||
ui::Button delete_code;
|
||||
ui::Editbox code;
|
||||
ui::Editbox desc;
|
||||
bool message(uint id, uintptr_t param);
|
||||
void setup();
|
||||
|
||||
void refresh();
|
||||
} window_cheat_editor;
|
||||
|
@@ -58,7 +58,7 @@ uint InputConfigWindow::get_value(uint index) {
|
||||
return keymap::none;
|
||||
}
|
||||
|
||||
void InputConfigWindow::set_value(uint index, uint value) {
|
||||
void InputConfigWindow::set_value(uint index, uint16 value) {
|
||||
switch(index) {
|
||||
case 0: config::input.joypad1.up = keymap::find(value); break;
|
||||
case 1: config::input.joypad1.down = keymap::find(value); break;
|
||||
@@ -92,60 +92,74 @@ void InputConfigWindow::set_value(uint index, uint value) {
|
||||
|
||||
void InputConfigWindow::refresh_list() {
|
||||
for(uint i = 0; i < 24; i++) {
|
||||
list.set_item(i, "%s|%s", list_index[i], keymap::find(get_value(i)));
|
||||
list.set_item(i, string() << list_index[i] << "|" << keymap::find(get_value(i)));
|
||||
}
|
||||
list.autosize_columns();
|
||||
}
|
||||
|
||||
int InputConfigWindow::message(uint id, void *param) {
|
||||
if(id == ui::Message::Changed && param == &list) {
|
||||
bool InputConfigWindow::message(uint id, uintptr_t param) {
|
||||
ui::Control *control = (ui::Control*)param;
|
||||
if(id == ui::Message::Changed && control == &list) {
|
||||
int pos = list.get_selection();
|
||||
setkey.enable(pos >= 0);
|
||||
clrkey.enable(pos >= 0);
|
||||
} else if((id == ui::Message::DoubleClicked && param == &list) ||
|
||||
(id == ui::Message::Clicked && param == &setkey)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if((id == ui::Message::DoubleClicked && control == &list) ||
|
||||
(id == ui::Message::Clicked && control == &setkey)) {
|
||||
int pos = list.get_selection();
|
||||
if(pos < 0) { return 0; }
|
||||
if(pos < 0) { return true; }
|
||||
window_input_capture.index = pos;
|
||||
window_input_capture.label.set_text("Please press a key to assign to '%s' ...", list_index[pos]);
|
||||
window_input_capture.label.set_text(string() << "Please press a key to assign to " << list_index[pos] << " ...");
|
||||
window_input_capture.show();
|
||||
window_input_capture.focus();
|
||||
} else if(id == ui::Message::Clicked && param == &clrkey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == ui::Message::Clicked && control == &clrkey) {
|
||||
int pos = list.get_selection();
|
||||
if(pos < 0) { return 0; }
|
||||
if(pos < 0) { return true; }
|
||||
set_value(pos, keymap::none);
|
||||
refresh_list();
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputConfigWindow::setup() {
|
||||
create(0, 475, 355);
|
||||
|
||||
int x = 0, y = 0;
|
||||
lportA.create(*this, 0, x, y + 7, 105, 15, "Controller Port A:");
|
||||
portA.create(*this, 0, x + 110, y, 125, 30);
|
||||
int lh = ui::Label::ideal_height;
|
||||
int ch = ui::Combobox::ideal_height;
|
||||
int bh = ui::Button::ideal_height;
|
||||
int lbh = 355 - lh - ch - bh - 10;
|
||||
lportA.create(*this, 0, x, y, 235, lh, "Controller Port A:");
|
||||
lportB.create(*this, 0, x + 240, y, 235, lh, "Controller Port B:");
|
||||
y += lh;
|
||||
|
||||
portA.create (*this, 0, x, y, 235, ch);
|
||||
portA.add_item("None");
|
||||
portA.add_item("Joypad 1");
|
||||
portA.add_item("Joypad 2");
|
||||
portA.set_selection(1);
|
||||
portA.disable();
|
||||
|
||||
lportB.create(*this, 0, x + 240, y + 7, 105, 15, "Controller Port B:");
|
||||
portB.create(*this, 0, x + 350, y, 125, 30);
|
||||
portB.create (*this, 0, x + 240, y, 235, ch);
|
||||
portB.add_item("None");
|
||||
portB.add_item("Joypad 1");
|
||||
portB.add_item("Joypad 2");
|
||||
portB.set_selection(2);
|
||||
portB.disable();
|
||||
y += 35;
|
||||
y += ch + 5;
|
||||
|
||||
list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, 285, "Name|Value");
|
||||
list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, lbh, "Name|Value");
|
||||
for(uint i = 0; i < 24; i++) { list.add_item("???|???"); }
|
||||
y += 290;
|
||||
y += lbh + 5;
|
||||
|
||||
setkey.create(*this, 0, x, y, 235, 30, "Assign Key");
|
||||
clrkey.create(*this, 0, x + 240, y, 235, 30, "Unassign Key");
|
||||
setkey.create(*this, 0, x, y, 235, bh, "Assign Key");
|
||||
clrkey.create(*this, 0, x + 240, y, 235, bh, "Unassign Key");
|
||||
|
||||
refresh_list();
|
||||
window_input_capture.setup();
|
||||
@@ -156,19 +170,42 @@ int x = 0, y = 0;
|
||||
|
||||
//
|
||||
|
||||
int InputCaptureWindow::message(uint id, void *param) {
|
||||
bool InputCaptureWindow::message(uint id, uintptr_t param) {
|
||||
if(id == ui::Message::Close) {
|
||||
hide();
|
||||
return false;
|
||||
} else if(id == ui::Message::KeyUp) {
|
||||
hide();
|
||||
window_input_config.set_value(index, uint(param));
|
||||
window_input_config.refresh_list();
|
||||
}
|
||||
return 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputCaptureWindow::show() {
|
||||
uiInput->clear_input();
|
||||
|
||||
//enter and spacebar can be used to activate key capture,
|
||||
//set lock on these keys if they are held down to prevent
|
||||
//them from being instantly assigned to selected entry ...
|
||||
uiInput->poll();
|
||||
key_lock = (uiInput->key_down(keymap::enter) || uiInput->key_down(keymap::space));
|
||||
Window::show();
|
||||
Window::focus();
|
||||
|
||||
while(_term_ == false && visible() == true) {
|
||||
run();
|
||||
uint16 key = input_manager.scan();
|
||||
if(key == keymap::none) { key_lock = false; continue; }
|
||||
if(key_lock && (key == keymap::enter || key == keymap::space)) { continue; }
|
||||
hide();
|
||||
window_input_config.set_value(index, key);
|
||||
window_input_config.refresh_list();
|
||||
break;
|
||||
}
|
||||
|
||||
uiInput->clear_input();
|
||||
}
|
||||
|
||||
void InputCaptureWindow::setup() {
|
||||
create(ui::Window::Center, 350, 100, "bsnes Key Capture");
|
||||
label.create(*this, 0, 5, 5, 340, 90);
|
||||
int lh = ui::Label::ideal_height;
|
||||
create(ui::Window::Center, 350, lh * 3, "bsnes Key Capture");
|
||||
label.create(*this, 0, 5, lh, 340, lh);
|
||||
}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
class InputCaptureWindow : public ui::Window { public:
|
||||
ui::Label label;
|
||||
uint index;
|
||||
int message(uint id, void *param = 0);
|
||||
bool key_lock;
|
||||
bool message(uint id, uintptr_t param = 0);
|
||||
void show();
|
||||
void setup();
|
||||
InputCaptureWindow() : index(0) {}
|
||||
} window_input_capture;
|
||||
@@ -17,9 +19,9 @@ ui::Button clrkey;
|
||||
|
||||
static const char list_index[][64];
|
||||
|
||||
int message(uint id, void *param = 0);
|
||||
bool message(uint id, uintptr_t param = 0);
|
||||
uint get_value(uint index);
|
||||
void set_value(uint index, uint value);
|
||||
void set_value(uint index, uint16 value);
|
||||
void refresh_list();
|
||||
void setup();
|
||||
} window_input_config;
|
||||
|
@@ -1,49 +1,50 @@
|
||||
int RasterSettingsWindow::message(uint id, void *param) {
|
||||
bool RasterSettingsWindow::message(uint id, uintptr_t param) {
|
||||
ui::Control *control = (ui::Control*)param;
|
||||
if(id == ui::Message::Changed) {
|
||||
if(param == &contrast) {
|
||||
if(control == &contrast) {
|
||||
if(config::snes.contrast != contrast.get_position() - 96) {
|
||||
config::snes.contrast = contrast.get_position() - 96;
|
||||
lcontrast.set_text("Contrast: %d", int(config::snes.contrast));
|
||||
lcontrast.set_text(string() << "Contrast: " << config::snes.contrast);
|
||||
snes.update_color_lookup_table();
|
||||
}
|
||||
} else if(param == &brightness) {
|
||||
} else if(control == &brightness) {
|
||||
if(config::snes.brightness != brightness.get_position() - 96) {
|
||||
config::snes.brightness = brightness.get_position() - 96;
|
||||
lbrightness.set_text("Brightness: %d", int(config::snes.brightness));
|
||||
lbrightness.set_text(string() << "Brightness: " << config::snes.brightness);
|
||||
snes.update_color_lookup_table();
|
||||
}
|
||||
} else if(param == &gamma) {
|
||||
} else if(control == &gamma) {
|
||||
if(config::snes.gamma != gamma.get_position() + 10) {
|
||||
config::snes.gamma = gamma.get_position() + 10;
|
||||
lgamma.set_text("Gamma: %0.2f", double(config::snes.gamma) / 100.0);
|
||||
lgamma.set_text(string() << "Gamma: " << config::snes.gamma); //TODO: print gamma as "%0.2f" / 100.0
|
||||
snes.update_color_lookup_table();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == ui::Message::Clicked) {
|
||||
if(param == &gamma_ramp) {
|
||||
if(control == &gamma_ramp) {
|
||||
if(config::snes.gamma_ramp != gamma_ramp.checked()) {
|
||||
config::snes.gamma_ramp = gamma_ramp.checked();
|
||||
snes.update_color_lookup_table();
|
||||
}
|
||||
} else if(param == &sepia) {
|
||||
} else if(control == &sepia) {
|
||||
if(config::snes.sepia != sepia.checked()) {
|
||||
config::snes.sepia = sepia.checked();
|
||||
snes.update_color_lookup_table();
|
||||
}
|
||||
} else if(param == &grayscale) {
|
||||
} else if(control == &grayscale) {
|
||||
if(config::snes.grayscale != grayscale.checked()) {
|
||||
config::snes.grayscale = grayscale.checked();
|
||||
snes.update_color_lookup_table();
|
||||
}
|
||||
} else if(param == &invert) {
|
||||
} else if(control == &invert) {
|
||||
if(config::snes.invert != invert.checked()) {
|
||||
config::snes.invert = invert.checked();
|
||||
snes.update_color_lookup_table();
|
||||
}
|
||||
} else if(param == &preset_optimal) {
|
||||
} else if(control == &preset_optimal) {
|
||||
config::snes.contrast = 0;
|
||||
config::snes.brightness = 0;
|
||||
config::snes.gamma = 80;
|
||||
@@ -52,7 +53,7 @@ int RasterSettingsWindow::message(uint id, void *param) {
|
||||
config::snes.grayscale = false;
|
||||
config::snes.invert = false;
|
||||
sync_ui();
|
||||
} else if(param == &preset_standard) {
|
||||
} else if(control == &preset_standard) {
|
||||
config::snes.contrast = 0;
|
||||
config::snes.brightness = 0;
|
||||
config::snes.gamma = 100;
|
||||
@@ -62,20 +63,20 @@ int RasterSettingsWindow::message(uint id, void *param) {
|
||||
config::snes.invert = false;
|
||||
sync_ui();
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//update all UI controls to match config file values ...
|
||||
void RasterSettingsWindow::sync_ui() {
|
||||
contrast.set_position(config::snes.contrast + 96);
|
||||
lcontrast.set_text("Contrast: %d", int(config::snes.contrast));
|
||||
lcontrast.set_text(string() << "Contrast: " << config::snes.contrast);
|
||||
brightness.set_position(config::snes.brightness + 96);
|
||||
lbrightness.set_text("Brightness: %d", int(config::snes.brightness));
|
||||
lbrightness.set_text(string() << "Brightness: " << config::snes.brightness);
|
||||
gamma.set_position(config::snes.gamma - 10);
|
||||
lgamma.set_text("Gamma: %0.2f", double(config::snes.gamma) / 100.0);
|
||||
lgamma.set_text(string() << "Gamma: " << config::snes.gamma); //TODO: print gamma as "%0.2f" / 100.0
|
||||
gamma_ramp.check(config::snes.gamma_ramp);
|
||||
sepia.check(config::snes.sepia);
|
||||
grayscale.check(config::snes.grayscale);
|
||||
@@ -87,29 +88,32 @@ void RasterSettingsWindow::setup() {
|
||||
create(0, 475, 355);
|
||||
|
||||
int x = 0, y = 0;
|
||||
lcontrast.create(*this, 0, x, y + 5, 100, 15);
|
||||
contrast.create(*this, 0, x + 100, y, 375, 25, 192);
|
||||
y += 25;
|
||||
int sh = ui::Slider::ideal_height;
|
||||
int kh = ui::Checkbox::ideal_height;
|
||||
int bh = ui::Button::ideal_height;
|
||||
lcontrast.create(*this, 0, x, y, 100, sh);
|
||||
contrast.create (*this, 0, x + 100, y, 375, sh, 192);
|
||||
y += sh;
|
||||
|
||||
lbrightness.create(*this, 0, x, y + 5, 100, 15);
|
||||
brightness.create(*this, 0, x + 100, y, 375, 25, 192);
|
||||
y += 25;
|
||||
lbrightness.create(*this, 0, x, y, 100, sh);
|
||||
brightness.create (*this, 0, x + 100, y, 375, sh, 192);
|
||||
y += sh;
|
||||
|
||||
lgamma.create(*this, 0, x, y + 5, 100, 15);
|
||||
gamma.create(*this, 0, x + 100, y, 375, 25, 191);
|
||||
y += 25;
|
||||
lgamma.create(*this, 0, x, y, 100, sh);
|
||||
gamma.create (*this, 0, x + 100, y, 375, sh, 191);
|
||||
y += sh;
|
||||
|
||||
gamma_ramp.create(*this, 0, x, y, 235, 20, "Gamma ramp");
|
||||
sepia.create(*this, 0, x + 240, y, 235, 20, "Sepia");
|
||||
y += 20;
|
||||
gamma_ramp.create(*this, 0, x, y, 235, kh, "Gamma ramp");
|
||||
sepia.create(*this, 0, x + 240, y, 235, kh, "Sepia");
|
||||
y += kh;
|
||||
|
||||
grayscale.create(*this, 0, x, y, 235, 20, "Grayscale");
|
||||
invert.create(*this, 0, x + 240, y, 235, 20, "Invert colors");
|
||||
y += 20;
|
||||
grayscale.create(*this, 0, x, y, 235, kh, "Grayscale");
|
||||
invert.create(*this, 0, x + 240, y, 235, kh, "Invert colors");
|
||||
y += kh + 5;
|
||||
|
||||
y += 5;
|
||||
preset_optimal.create (*this, 0, x, y, 235, 30, "Optimal Preset");
|
||||
preset_standard.create(*this, 0, x + 240, y, 235, 30, "Standard Preset");
|
||||
preset_optimal.create (*this, 0, x, y, 235, bh, "Optimal Preset");
|
||||
preset_standard.create(*this, 0, x + 240, y, 235, bh, "Standard Preset");
|
||||
y += bh;
|
||||
|
||||
sync_ui();
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ ui::Checkbox invert;
|
||||
ui::Button preset_optimal;
|
||||
ui::Button preset_standard;
|
||||
|
||||
int message(uint id, void *param);
|
||||
bool message(uint id, uintptr_t param);
|
||||
void setup();
|
||||
void sync_ui();
|
||||
} window_raster_settings;
|
||||
|
@@ -1,9 +1,10 @@
|
||||
void SettingsWindow::setup() {
|
||||
create(ui::Window::Center, 640, 365, "bsnes Configuration Settings");
|
||||
panel_list.create(*this, 0, 5, 5, 150, 355);
|
||||
//panel_list.add_item("Video Settings");
|
||||
panel_list.add_item("Raster Settings");
|
||||
panel_list.add_item("Input Configuration");
|
||||
//panel_list.add_item("Cheat Code Editor");
|
||||
panel_list.add_item("Cheat Code Editor");
|
||||
panel_list.add_item("Advanced");
|
||||
panel.create(*this, 0, 160, 5, 475, 355);
|
||||
|
||||
@@ -15,22 +16,23 @@ void SettingsWindow::show() {
|
||||
panel_list.focus();
|
||||
}
|
||||
|
||||
int SettingsWindow::message(uint id, void *param) {
|
||||
bool SettingsWindow::message(uint id, uintptr_t param) {
|
||||
if(id == ui::Message::Close) {
|
||||
hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(id == ui::Message::Changed && param == &panel_list) {
|
||||
if(id == ui::Message::Changed && (ui::Control*)param == &panel_list) {
|
||||
switch(panel_list.get_selection()) {
|
||||
//case 0: panel.attach(window_video_settings); break;
|
||||
case 0: panel.attach(window_raster_settings); break;
|
||||
case 1: panel.attach(window_input_config); break;
|
||||
//case 2: panel.attach(window_cheat_editor); break;
|
||||
case 2: panel.attach(window_advanced); break;
|
||||
case 2: panel.attach(window_cheat_editor); break;
|
||||
case 3: panel.attach(window_advanced); break;
|
||||
}
|
||||
panel_list.focus();
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
class SettingsWindow : public ui::Window { public:
|
||||
ui::Listbox panel_list;
|
||||
ui::Panel panel;
|
||||
int message(uint id, void *param);
|
||||
bool message(uint id, uintptr_t param = 0);
|
||||
void show();
|
||||
void setup();
|
||||
} window_settings;
|
||||
|
59
src/ui/lui/settings/ui_videosettings.cpp
Normal file
59
src/ui/lui/settings/ui_videosettings.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
bool VideoSettingsWindow::message(uint id, uintptr_t param) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoSettingsWindow::setup() {
|
||||
create(0, 475, 355);
|
||||
|
||||
int x = 0, y = 0;
|
||||
int lh = ui::Label::ideal_height;
|
||||
int ch = ui::Combobox::ideal_height;
|
||||
int kh = ui::Checkbox::ideal_height;
|
||||
int eh = ui::Editbox::ideal_height;
|
||||
label_select.create(*this, 0, x, y, 475, lh, "Select video mode to configure:");
|
||||
y += lh;
|
||||
mode_select.create(*this, 0, x, y, 475, ch);
|
||||
mode_select.add_item("Windowed mode");
|
||||
mode_select.add_item("Pseudo-fullscreen mode");
|
||||
mode_select.add_item("Fullscreen mode");
|
||||
y += ch + 5;
|
||||
|
||||
label_region.create(*this, 0, x, y, 235, lh, "Region:");
|
||||
label_scalar.create(*this, 0, x + 240, y, 235, lh, "Scale:");
|
||||
y += lh;
|
||||
region.create(*this, 0, x, y, 235, ch);
|
||||
region.add_item("NTSC");
|
||||
region.add_item("PAL");
|
||||
scalar.create(*this, 0, x + 240, y, 235, ch);
|
||||
scalar.add_item("100%");
|
||||
scalar.add_item("200%");
|
||||
scalar.add_item("300%");
|
||||
scalar.add_item("400%");
|
||||
scalar.add_item("500%");
|
||||
y += ch;
|
||||
|
||||
label_hwfilter.create(*this, 0, x, y, 235, lh, "Hardware filter:");
|
||||
label_swfilter.create(*this, 0, x + 240, y, 235, lh, "Software filter:");
|
||||
y += lh;
|
||||
hwfilter.create(*this, 0, x, y, 235, ch);
|
||||
hwfilter.add_item("Point");
|
||||
hwfilter.add_item("Linear");
|
||||
swfilter.create(*this, 0, x + 240, y, 235, ch);
|
||||
swfilter.add_item("None");
|
||||
swfilter.add_item("NTSC");
|
||||
swfilter.add_item("HQ2x");
|
||||
swfilter.add_item("Scale2x");
|
||||
y += ch + 5;
|
||||
|
||||
aspect.create(*this, 0, x, y, 235, kh, "Correct aspect ratio");
|
||||
vsync.create(*this, 0, x + 240, y, 235, kh, "Sync to vertical retrace");
|
||||
y += kh + 5;
|
||||
|
||||
label_fsmode.create(*this, 0, x, y, 475, lh, "Fullscreen mode (width x height x refresh rate):");
|
||||
y += lh;
|
||||
|
||||
fs_width.create(*this, 0, x, y, 155, eh, "<width>");
|
||||
fs_height.create(*this, 0, x + 160, y, 155, eh, "<height>");
|
||||
fs_refresh.create(*this, 0, x + 320, y, 155, eh, "<refresh_rate>");
|
||||
y += eh + 5;
|
||||
}
|
14
src/ui/lui/settings/ui_videosettings.h
Normal file
14
src/ui/lui/settings/ui_videosettings.h
Normal file
@@ -0,0 +1,14 @@
|
||||
class VideoSettingsWindow : public ui::Window { public:
|
||||
ui::Label label_select;
|
||||
ui::Combobox mode_select;
|
||||
|
||||
ui::Label label_region, label_scalar, label_hwfilter, label_swfilter;
|
||||
ui::Combobox region, scalar, hwfilter, swfilter;
|
||||
|
||||
ui::Checkbox aspect, vsync;
|
||||
|
||||
ui::Label label_fsmode;
|
||||
ui::Editbox fs_width, fs_height, fs_refresh;
|
||||
bool message(uint, uintptr_t);
|
||||
void setup();
|
||||
} window_video_settings;
|
@@ -2,6 +2,7 @@
|
||||
#include "ui_about.cpp"
|
||||
|
||||
#include "settings/ui_settings.cpp"
|
||||
#include "settings/ui_videosettings.cpp"
|
||||
#include "settings/ui_rastersettings.cpp"
|
||||
#include "settings/ui_inputconfig.cpp"
|
||||
#include "settings/ui_cheateditor.cpp"
|
||||
@@ -20,14 +21,14 @@
|
||||
#include "../video/xv.cpp"
|
||||
#include "../video/gtk.cpp"
|
||||
#include "../audio/ao.cpp"
|
||||
#include "../input/xinput.cpp"
|
||||
#endif
|
||||
|
||||
#include "../input/inputui.cpp"
|
||||
|
||||
void ui_init() {
|
||||
window_main.setup();
|
||||
window_about.setup();
|
||||
|
||||
window_video_settings.setup();
|
||||
window_raster_settings.setup();
|
||||
window_input_config.setup();
|
||||
window_cheat_editor.setup();
|
||||
@@ -49,7 +50,6 @@ void ui_init() {
|
||||
(Audio*)new AudioDS(window_main.handle());
|
||||
uiInput =
|
||||
config::system.input == "none" ? (Input*)new Input() :
|
||||
config::system.input == "ui" ? (Input*)new InputUI() :
|
||||
(Input*)new InputDI(window_main.handle());
|
||||
#elif defined(PLATFORM_X)
|
||||
uiVideo =
|
||||
@@ -61,7 +61,7 @@ void ui_init() {
|
||||
(Audio*)new AudioAO(config::system.audio_flags);
|
||||
uiInput =
|
||||
config::system.input == "none" ? (Input*)new Input() :
|
||||
(Input*)new InputUI();
|
||||
(Input*)new InputX();
|
||||
#endif
|
||||
|
||||
uiVideo->init();
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include "ui_about.h"
|
||||
|
||||
#include "settings/ui_settings.h"
|
||||
#include "settings/ui_videosettings.h"
|
||||
#include "settings/ui_rastersettings.h"
|
||||
#include "settings/ui_inputconfig.h"
|
||||
#include "settings/ui_cheateditor.h"
|
||||
|
@@ -13,11 +13,11 @@ void AboutWindow::setup() {
|
||||
about.create(*this, 0, 5, 5, 290, 120, about_text);
|
||||
}
|
||||
|
||||
int AboutWindow::message(uint id, void *param) {
|
||||
bool AboutWindow::message(uint id, uintptr_t param) {
|
||||
if(id == ui::Message::Close) {
|
||||
hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
class AboutWindow : public ui::Window { public:
|
||||
ui::Label about;
|
||||
static const char about_text[4096];
|
||||
int message(uint id, void *param);
|
||||
bool message(uint id, uintptr_t param);
|
||||
void setup();
|
||||
} window_about;
|
||||
|
@@ -1,4 +1,15 @@
|
||||
int MainWindow::message(uint id, void *param) {
|
||||
bool MainWindow::input_ready() {
|
||||
#if defined(PLATFORM_X)
|
||||
//FIXME: focused() is broken in X port
|
||||
return true;
|
||||
#endif
|
||||
|
||||
//only allow input when main window is focused
|
||||
return focused() == true;
|
||||
}
|
||||
|
||||
bool MainWindow::message(uint id, uintptr_t param) {
|
||||
ui::Control *control = (ui::Control*)param;
|
||||
if(id == ui::Message::Close) {
|
||||
_term_ = true;
|
||||
hide();
|
||||
@@ -7,114 +18,125 @@ int MainWindow::message(uint id, void *param) {
|
||||
|
||||
if(id == ui::Message::Block) {
|
||||
if(uiAudio) { uiAudio->clear_audio(); }
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == ui::Message::KeyDown) {
|
||||
if(uiInput) { uiInput->signal_key_down((int)param); }
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(id == ui::Message::KeyUp) {
|
||||
if(uiInput) { uiInput->signal_key_up((int)param); }
|
||||
return 0;
|
||||
if(param == keymap::esc) { event::toggle_menu(); }
|
||||
if(param == keymap::f11) { event::toggle_fullscreen(); }
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == ui::Message::Clicked) {
|
||||
if(param == &menu_file_load) {
|
||||
if(control == &menu_file_load) {
|
||||
event::load_rom();
|
||||
}
|
||||
|
||||
if(param == &menu_file_unload) {
|
||||
if(control == &menu_file_load_st) {
|
||||
event::load_rom_st();
|
||||
}
|
||||
|
||||
if(control == &menu_file_load_stdual) {
|
||||
event::load_rom_stdual();
|
||||
}
|
||||
|
||||
if(control == &menu_file_unload) {
|
||||
event::unload_rom();
|
||||
}
|
||||
|
||||
if(param == &menu_file_reset) {
|
||||
if(control == &menu_file_reset) {
|
||||
event::reset();
|
||||
}
|
||||
|
||||
if(param == &menu_file_power) {
|
||||
if(control == &menu_file_power) {
|
||||
event::power();
|
||||
}
|
||||
|
||||
if(param == &menu_file_exit) {
|
||||
if(control == &menu_file_exit) {
|
||||
message(ui::Message::Close);
|
||||
}
|
||||
|
||||
if(param == &menu_settings_videomode_1x) { config::video.multiplier = 1; event::update_video_settings(); }
|
||||
if(param == &menu_settings_videomode_2x) { config::video.multiplier = 2; event::update_video_settings(); }
|
||||
if(param == &menu_settings_videomode_3x) { config::video.multiplier = 3; event::update_video_settings(); }
|
||||
if(param == &menu_settings_videomode_4x) { config::video.multiplier = 4; event::update_video_settings(); }
|
||||
if(param == &menu_settings_videomode_5x) { config::video.multiplier = 5; event::update_video_settings(); }
|
||||
if(control == &menu_settings_videomode_1x) { config::video.multiplier = 1; event::update_video_settings(); }
|
||||
if(control == &menu_settings_videomode_2x) { config::video.multiplier = 2; event::update_video_settings(); }
|
||||
if(control == &menu_settings_videomode_3x) { config::video.multiplier = 3; event::update_video_settings(); }
|
||||
if(control == &menu_settings_videomode_4x) { config::video.multiplier = 4; event::update_video_settings(); }
|
||||
if(control == &menu_settings_videomode_5x) { config::video.multiplier = 5; event::update_video_settings(); }
|
||||
|
||||
if(param == &menu_settings_videomode_aspect_correction) {
|
||||
if(control == &menu_settings_videomode_aspect_correction) {
|
||||
config::video.aspect_correction = menu_settings_videomode_aspect_correction.checked();
|
||||
event::update_video_settings();
|
||||
}
|
||||
|
||||
if(param == &menu_settings_videomode_ntsc) { config::video.region = 0; event::update_raster_settings(); event::update_video_settings(); }
|
||||
if(param == &menu_settings_videomode_pal) { config::video.region = 1; event::update_raster_settings(); event::update_video_settings(); }
|
||||
if(control == &menu_settings_videomode_ntsc) { config::video.region = 0; event::update_raster_settings(); event::update_video_settings(); }
|
||||
if(control == &menu_settings_videomode_pal) { config::video.region = 1; event::update_raster_settings(); event::update_video_settings(); }
|
||||
|
||||
if(param == &menu_settings_videofilter_hwpoint) { config::video.hardware_filter = 0; uiVideo->update_hardware_filter(); }
|
||||
if(param == &menu_settings_videofilter_hwlinear) { config::video.hardware_filter = 1; uiVideo->update_hardware_filter(); }
|
||||
if(control == &menu_settings_videofilter_hwpoint) { config::video.hardware_filter = 0; uiVideo->update_hardware_filter(); }
|
||||
if(control == &menu_settings_videofilter_hwlinear) { config::video.hardware_filter = 1; uiVideo->update_hardware_filter(); }
|
||||
|
||||
if(param == &menu_settings_videofilter_swnone) { config::video.software_filter = 0; event::update_raster_settings(); }
|
||||
if(param == &menu_settings_videofilter_swntsc) { config::video.software_filter = 1; event::update_raster_settings(); }
|
||||
if(param == &menu_settings_videofilter_swhq2x) { config::video.software_filter = 2; event::update_raster_settings(); }
|
||||
if(param == &menu_settings_videofilter_swscale2x) { config::video.software_filter = 3; event::update_raster_settings(); }
|
||||
if(control == &menu_settings_videofilter_swnone) { config::video.software_filter = 0; event::update_raster_settings(); }
|
||||
if(control == &menu_settings_videofilter_swntsc) { config::video.software_filter = 1; event::update_raster_settings(); }
|
||||
if(control == &menu_settings_videofilter_swhq2x) { config::video.software_filter = 2; event::update_raster_settings(); }
|
||||
if(control == &menu_settings_videofilter_swscale2x) { config::video.software_filter = 3; event::update_raster_settings(); }
|
||||
|
||||
if(param == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; }
|
||||
if(param == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; }
|
||||
if(param == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; }
|
||||
if(param == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; }
|
||||
if(param == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; }
|
||||
if(param == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; }
|
||||
if(param == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; }
|
||||
if(param == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; }
|
||||
if(param == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; }
|
||||
if(param == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; }
|
||||
if(control == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; }
|
||||
if(control == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; }
|
||||
if(control == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; }
|
||||
if(control == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; }
|
||||
if(control == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; }
|
||||
if(control == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; }
|
||||
if(control == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; }
|
||||
if(control == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; }
|
||||
if(control == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; }
|
||||
if(control == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; }
|
||||
|
||||
if(param == &menu_settings_mute) {
|
||||
if(control == &menu_settings_mute) {
|
||||
config::snes.mute = menu_settings_mute.checked();
|
||||
}
|
||||
|
||||
if(param == &menu_settings_speedreg_enable) {
|
||||
if(control == &menu_settings_speedreg_enable) {
|
||||
config::system.regulate_speed = menu_settings_speedreg_enable.checked();
|
||||
}
|
||||
|
||||
if(param == &menu_settings_speedreg_slowest) { config::system.speed = 1; uiAudio->update_frequency(); }
|
||||
if(param == &menu_settings_speedreg_slow) { config::system.speed = 2; uiAudio->update_frequency(); }
|
||||
if(param == &menu_settings_speedreg_normal) { config::system.speed = 3; uiAudio->update_frequency(); }
|
||||
if(param == &menu_settings_speedreg_fast) { config::system.speed = 4; uiAudio->update_frequency(); }
|
||||
if(param == &menu_settings_speedreg_fastest) { config::system.speed = 5; uiAudio->update_frequency(); }
|
||||
if(control == &menu_settings_speedreg_slowest) { config::system.speed = 1; uiAudio->update_frequency(); }
|
||||
if(control == &menu_settings_speedreg_slow) { config::system.speed = 2; uiAudio->update_frequency(); }
|
||||
if(control == &menu_settings_speedreg_normal) { config::system.speed = 3; uiAudio->update_frequency(); }
|
||||
if(control == &menu_settings_speedreg_fast) { config::system.speed = 4; uiAudio->update_frequency(); }
|
||||
if(control == &menu_settings_speedreg_fastest) { config::system.speed = 5; uiAudio->update_frequency(); }
|
||||
|
||||
if(param == &menu_settings_config) { window_settings.show(); }
|
||||
if(control == &menu_settings_config) { window_settings.show(); }
|
||||
|
||||
if(param == &menu_misc_logaudio) {
|
||||
if(control == &menu_misc_logaudio) {
|
||||
(menu_misc_logaudio.checked() == true) ? snes.log_audio_enable() : snes.log_audio_disable();
|
||||
}
|
||||
|
||||
if(param == &menu_misc_about) {
|
||||
if(control == &menu_misc_about) {
|
||||
window_about.focus();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::setup() {
|
||||
snesinterface.input_ready = bind(&MainWindow::input_ready, this);
|
||||
|
||||
ui::ControlGroup group;
|
||||
create(ui::Window::Center, 256, 224, BSNES_TITLE);
|
||||
set_background_color(0, 0, 0);
|
||||
|
||||
menu.create(*this);
|
||||
menu_file.create(menu, "File");
|
||||
menu_file_load.create(menu_file, "Load Cartridge");
|
||||
menu_file_unload.create(menu_file, "Unload");
|
||||
menu_file_load.create(menu_file, "Load Cartridge ...");
|
||||
menu_file_load_special.create(menu_file, "Load Special");
|
||||
menu_file_load_st.create(menu_file_load_special, "Load ST Cartridge ...");
|
||||
menu_file_load_stdual.create(menu_file_load_special, "Load ST Dual Cartridge ...");
|
||||
menu_file_load_special.finish();
|
||||
menu_file_unload.create(menu_file, "Unload Cartridge");
|
||||
menu_file_sep1.create(menu_file);
|
||||
menu_file_reset.create(menu_file, "Reset");
|
||||
menu_file_power.create(menu_file, "Power");
|
||||
menu_file_reset.create(menu_file, "Reset System");
|
||||
menu_file_power.create(menu_file, "Power Cycle System");
|
||||
menu_file_sep2.create(menu_file);
|
||||
menu_file_exit.create(menu_file, "Exit");
|
||||
menu_file.finish();
|
||||
@@ -171,7 +193,7 @@ ui::ControlGroup group;
|
||||
group.add(menu_settings_videoframeskip_7);
|
||||
group.add(menu_settings_videoframeskip_8);
|
||||
group.add(menu_settings_videoframeskip_9);
|
||||
menu_settings_videoframeskip_0.create(menu_settings_videoframeskip, group, "0 (off)");
|
||||
menu_settings_videoframeskip_0.create(menu_settings_videoframeskip, group, "0");
|
||||
menu_settings_videoframeskip_sep1.create(menu_settings_videoframeskip);
|
||||
menu_settings_videoframeskip_1.create(menu_settings_videoframeskip, group, "1");
|
||||
menu_settings_videoframeskip_2.create(menu_settings_videoframeskip, group, "2");
|
||||
@@ -206,7 +228,7 @@ ui::ControlGroup group;
|
||||
menu_settings_speedreg.finish();
|
||||
|
||||
menu_settings_sep3.create(menu_settings);
|
||||
menu_settings_config.create(menu_settings, "Configuration");
|
||||
menu_settings_config.create(menu_settings, "Configuration ...");
|
||||
menu_settings.finish();
|
||||
|
||||
menu_misc.create(menu, "Misc");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user