diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..07f245cea --- /dev/null +++ b/Makefile @@ -0,0 +1,285 @@ + +SRC = src/ + +CORE_OBJS = \ + $(SRC)cart.o $(SRC)cheat.o $(SRC)config.o $(SRC)movie.o $(SRC)oldmovie.o \ + $(SRC)drawing.o $(SRC)fceu.o $(SRC)fds.o $(SRC)file.o $(SRC)conddebug.o \ + $(SRC)filter.o $(SRC)ines.o $(SRC)input.o $(SRC)debug.o $(SRC)wave.o \ + $(SRC)nsf.o $(SRC)palette.o $(SRC)ppu.o $(SRC)sound.o $(SRC)state.o $(SRC)unif.o \ + $(SRC)video.o $(SRC)vsuni.o $(SRC)x6502.o $(SRC)netplay.o $(SRC)emufile.o + +BOARDS_OBJS = \ + $(SRC)boards/01-222.o \ + $(SRC)boards/3d-block.o \ + $(SRC)boards/09-034a.o \ + $(SRC)boards/12in1.o \ + $(SRC)boards/15.o \ + $(SRC)boards/158B.o \ + $(SRC)boards/18.o \ + $(SRC)boards/190.o \ + $(SRC)boards/28.o \ + $(SRC)boards/32.o \ + $(SRC)boards/33.o \ + $(SRC)boards/34.o \ + $(SRC)boards/36.o \ + $(SRC)boards/40.o \ + $(SRC)boards/41.o \ + $(SRC)boards/42.o \ + $(SRC)boards/43.o \ + $(SRC)boards/46.o \ + $(SRC)boards/50.o \ + $(SRC)boards/51.o \ + $(SRC)boards/57.o \ + $(SRC)boards/62.o \ + $(SRC)boards/65.o \ + $(SRC)boards/67.o \ + $(SRC)boards/68.o \ + $(SRC)boards/69.o \ + $(SRC)boards/71.o \ + $(SRC)boards/72.o \ + $(SRC)boards/77.o \ + $(SRC)boards/79.o \ + $(SRC)boards/80.o \ + $(SRC)boards/82.o \ + $(SRC)boards/88.o \ + $(SRC)boards/90.o \ + $(SRC)boards/91.o \ + $(SRC)boards/96.o \ + $(SRC)boards/99.o \ + $(SRC)boards/103.o \ + $(SRC)boards/106.o \ + $(SRC)boards/108.o \ + $(SRC)boards/112.o \ + $(SRC)boards/116.o \ + $(SRC)boards/117.o \ + $(SRC)boards/120.o \ + $(SRC)boards/121.o \ + $(SRC)boards/151.o \ + $(SRC)boards/156.o \ + $(SRC)boards/164.o \ + $(SRC)boards/168.o \ + $(SRC)boards/170.o \ + $(SRC)boards/175.o \ + $(SRC)boards/176.o \ + $(SRC)boards/177.o \ + $(SRC)boards/178.o \ + $(SRC)boards/183.o \ + $(SRC)boards/185.o \ + $(SRC)boards/186.o \ + $(SRC)boards/187.o \ + $(SRC)boards/189.o \ + $(SRC)boards/193.o \ + $(SRC)boards/199.o \ + $(SRC)boards/206.o \ + $(SRC)boards/208.o \ + $(SRC)boards/222.o \ + $(SRC)boards/225.o \ + $(SRC)boards/228.o \ + $(SRC)boards/230.o \ + $(SRC)boards/232.o \ + $(SRC)boards/234.o \ + $(SRC)boards/235.o \ + $(SRC)boards/244.o \ + $(SRC)boards/246.o \ + $(SRC)boards/252.o \ + $(SRC)boards/253.o \ + $(SRC)boards/411120-c.o \ + $(SRC)boards/603-5052.o \ + $(SRC)boards/8157.o \ + $(SRC)boards/8237.o \ + $(SRC)boards/80013-B.o \ + $(SRC)boards/830118C.o \ + $(SRC)boards/8in1.o \ + $(SRC)boards/__dummy_mapper.o \ + $(SRC)boards/a9746.o \ + $(SRC)boards/ac-08.o \ + $(SRC)boards/addrlatch.o \ + $(SRC)boards/ax5705.o \ + $(SRC)boards/bandai.o \ + $(SRC)boards/bb.o \ + $(SRC)boards/bmc13in1jy110.o \ + $(SRC)boards/bmc42in1r.o \ + $(SRC)boards/bmc64in1nr.o \ + $(SRC)boards/bmc70in1.o \ + $(SRC)boards/BMW8544.o \ + $(SRC)boards/bonza.o \ + $(SRC)boards/bs-5.o \ + $(SRC)boards/cheapocabra.o \ + $(SRC)boards/cityfighter.o \ + $(SRC)boards/coolboy.o \ + $(SRC)boards/dance2000.o \ + $(SRC)boards/datalatch.o \ + $(SRC)boards/dream.o \ + $(SRC)boards/edu2000.o \ + $(SRC)boards/eh8813a.o \ + $(SRC)boards/emu2413.o \ + $(SRC)boards/et-100.o \ + $(SRC)boards/et-4320.o \ + $(SRC)boards/F-15.o \ + $(SRC)boards/famicombox.o \ + $(SRC)boards/ffe.o \ + $(SRC)boards/fk23c.o \ + $(SRC)boards/ghostbusters63in1.o \ + $(SRC)boards/gs-2004.o \ + $(SRC)boards/gs-2013.o \ + $(SRC)boards/h2288.o \ + $(SRC)boards/hp898f.o \ + $(SRC)boards/hp10xx_hp20xx.o \ + $(SRC)boards/inlnsf.o \ + $(SRC)boards/karaoke.o \ + $(SRC)boards/kof97.o \ + $(SRC)boards/ks7010.o \ + $(SRC)boards/ks7012.o \ + $(SRC)boards/ks7013.o \ + $(SRC)boards/ks7016.o \ + $(SRC)boards/ks7017.o \ + $(SRC)boards/ks7030.o \ + $(SRC)boards/ks7031.o \ + $(SRC)boards/ks7032.o \ + $(SRC)boards/ks7037.o \ + $(SRC)boards/ks7057.o \ + $(SRC)boards/le05.o \ + $(SRC)boards/lh32.o \ + $(SRC)boards/lh53.o \ + $(SRC)boards/malee.o \ + $(SRC)boards/mihunche.o \ + $(SRC)boards/mmc1.o \ + $(SRC)boards/mmc2and4.o \ + $(SRC)boards/mmc3.o \ + $(SRC)boards/mmc5.o \ + $(SRC)boards/n106.o \ + $(SRC)boards/n625092.o \ + $(SRC)boards/novel.o \ + $(SRC)boards/onebus.o \ + $(SRC)boards/pec-586.o \ + $(SRC)boards/rt-01.o \ + $(SRC)boards/sa-9602b.o \ + $(SRC)boards/sachen.o \ + $(SRC)boards/sb-2000.o \ + $(SRC)boards/sc-127.o \ + $(SRC)boards/sheroes.o \ + $(SRC)boards/sl1632.o \ + $(SRC)boards/subor.o \ + $(SRC)boards/super24.o \ + $(SRC)boards/supervision.o \ + $(SRC)boards/t-227-1.o \ + $(SRC)boards/t-262.o \ + $(SRC)boards/tengen.o \ + $(SRC)boards/tf-1201.o \ + $(SRC)boards/transformer.o \ + $(SRC)boards/unrom512.o \ + $(SRC)boards/vrc1.o \ + $(SRC)boards/vrc2and4.o \ + $(SRC)boards/vrc3.o \ + $(SRC)boards/vrc5.o \ + $(SRC)boards/vrc6.o \ + $(SRC)boards/vrc7.o \ + $(SRC)boards/vrc7p.o \ + $(SRC)boards/yoko.o + +INPUT_OBJS = $(SRC)input/arkanoid.o $(SRC)input/bworld.o $(SRC)input/cursor.o \ + $(SRC)input/fkb.o $(SRC)input/ftrainer.o $(SRC)input/hypershot.o $(SRC)input/mahjong.o \ + $(SRC)input/mouse.o $(SRC)input/oekakids.o $(SRC)input/pec586kb.o \ + $(SRC)input/powerpad.o $(SRC)input/quiz.o $(SRC)input/shadow.o $(SRC)input/snesmouse.o \ + $(SRC)input/suborkb.o $(SRC)input/toprider.o $(SRC)input/zapper.o + +MAPPERS_OBJS = + +UTILS_OBJS = $(SRC)utils/crc32.o $(SRC)utils/endian.o $(SRC)utils/general.o \ + $(SRC)utils/guid.o $(SRC)utils/md5.o $(SRC)utils/memory.o $(SRC)utils/unzip.o \ + $(SRC)utils/xstring.o $(SRC)utils/ioapi.o $(SRC)utils/ConvertUTF.o + +COMMON_DRIVER_OBJS = $(SRC)drivers/common/args.o $(SRC)drivers/common/cheat.o \ + $(SRC)drivers/common/config.o $(SRC)drivers/common/configSys.o $(SRC)drivers/common/nes_ntsc.o + +GUI_OBJS = \ + $(SRC)drivers/dingux-sdl/gui/gui.o \ + $(SRC)drivers/dingux-sdl/gui/file_list.o \ + $(SRC)drivers/dingux-sdl/gui/font.o + +DRIVER_OBJS = $(SRC)drivers/dingux-sdl/config.o $(SRC)drivers/dingux-sdl/input.o \ + $(SRC)drivers/dingux-sdl/dingoo.o $(SRC)drivers/dingux-sdl/dingoo-joystick.o \ + $(SRC)drivers/dingux-sdl/dingoo-throttle.o $(SRC)drivers/dingux-sdl/dingoo-sound.o \ + $(SRC)drivers/dingux-sdl/dingoo-video.o $(SRC)drivers/dingux-sdl/dummy-netplay.o \ + $(SRC)drivers/dingux-sdl/2xSaI.o \ + $(SRC)drivers/dingux-sdl/scaler.o \ + $(SRC)drivers/dingux-sdl/dma.o \ + $(MINIMAL_OBJS) $(GUI_OBJS) + +OBJS = $(CORE_OBJS) $(BOARDS_OBJS) $(INPUT_OBJS) $(MAPPERS_OBJS) $(UTILS_OBJS) \ + $(COMMON_DRIVER_OBJS) $(DRIVER_OBJS) + +TOOLCHAIN= +BINDIR= +CC = mipsel-linux-gcc +CXX = mipsel-linux-g++ +LD = mipsel-linux-g++ +AS = mipsel-linux-as + +SYSROOT := $(shell $(CC) --print-sysroot) +SDL_CONFIG := $(SYSROOT)/usr/bin/sdl-config +SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags) +SDL_LIBS := $(shell $(SDL_CONFIG) --libs) + +INCLUDEDIR=$(TOOLCHAIN)/include +CFLAGS = -I$(INCLUDEDIR) -I$(SRC) +CXXFLAGS = -I$(INCLUDEDIR) -std=gnu++0x + +LDFLAGS = -s + +W_OPTS= -Wno-write-strings -Wno-sign-compare + +F_OPTS = -fomit-frame-pointer -fno-builtin -fno-common -fpermissive + +OPTIMIZE = -O4 -fexpensive-optimizations -mips32r2 -fomit-frame-pointer -fno-builtin \ + -fno-common -Wno-write-strings -Wno-sign-compare -ffast-math -ftree-vectorize \ + -funswitch-loops -fno-strict-aliasing -flto + + +CC_OPTS = $(F_OPTS) $(W_OPTS) $(OPTIMIZE) + +CFLAGS += $(CC_OPTS) +CFLAGS += -DDINGUX \ + -DLSB_FIRST \ + -DPSS_STYLE=1 \ + -DHAVE_ASPRINTF \ + -DFRAMESKIP \ + -D_REENTRANT \ + $(SDL_CFLAGS) -D_GNU_SOURCE=1 -D_REENTRANT +CXXFLAGS += $(CFLAGS) +LDFLAGS += $(CC_OPTS) +ifdef STATIC +LDFLAGS += -static-libgcc -static-libstdc++ +endif +LIBS = $(SDL_LIBS) -lz -lm + +TARGET = fceux + +all: $(TARGET) + mipsel-linux-strip bin/$(TARGET) + +$(TARGET): $(OBJS) + @mkdir -p bin/ + @cp src/drivers/dingux-sdl/gui/*.bmp bin/ + @echo Linking $@... + @echo $(LD) $(LDFLAGS) $(OBJS) -o bin/$@ + $(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o bin/$@ + +%.o: %.c + @echo Compiling $<... + $(CC) $(CDEFS) $(CFLAGS) -c $< -o $@ + +%.o: %.o \ + @echo Compiling $<... + $(CXX) $(CDEFS) $(CXXFLAGS) -c $< -o $@ + +%.o: %.s + @echo Assembling $<... + $(CXX) $(CDEFS) $(CXXFLAGS) -c $< -o $@ + +%.o: %.S + @echo Assembling $<... + $(CXX) $(CDEFS) $(CXXFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) bin/$(TARGET) diff --git a/make_opk.sh b/make_opk.sh new file mode 100755 index 000000000..35435c212 --- /dev/null +++ b/make_opk.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +OPK_NAME=fceux.opk +echo ${OPK_NAME} + +# create default.gcw0.desktop +cat > default.gcw0.desktop <::iterator int_i; + std::map::iterator dbl_i; + std::map::iterator str_i; + std::string line, name, value; + char buf[1024]; + + // set the exception handling to catch i/o errors + config.exceptions(std::fstream::badbit); + + try { + // open the file for reading (create if it doesn't exist) + config.open(cfgname.c_str(), std::ios::in | std::ios::out); + if(!config.is_open()) { + // XXX file couldn't be opened? + return _load(); + } + + while(!config.eof()) { + // read a line + config.getline(buf, 1024); + line = buf; + + // check line validity + eqPos = line.find("="); + if(line[0] == '#') { + // skip this line + continue; + } + + // get the name and value for the option + pos = line.find(" "); + name = line.substr(0, (pos > eqPos) ? eqPos : pos); + pos = line.find_first_not_of(" ", eqPos + 1); + if (pos == std::string::npos) value = ""; + else value = line.substr(pos); + + // check if the option exists, and if so, set it appropriately + str_i = _strOptMap.find(name); + dbl_i = _dblOptMap.find(name); + int_i = _intOptMap.find(name); + if(str_i != _strOptMap.end()) { + str_i->second = value; + } else if(int_i != _intOptMap.end()) { + int_i->second = atol(value.c_str()); + } else if(dbl_i != _dblOptMap.end()) { + dbl_i->second = atof(value.c_str()); + } + } + + // close the file + config.close(); + } catch(std::fstream::failure e) { + std::cerr << e.what() << std::endl; + return -1; + } + + return 0; +} + // load and parse the default configuration file int Config::_load() @@ -745,3 +809,50 @@ Config::save() return 0; } + +int +Config::save(const std::string &name) +{ + std::fstream config; + std::map::iterator int_i; + std::map::iterator dbl_i; + std::map::iterator str_i; + char buf[1024]; + + // set the exception handling to catch i/o errors + config.exceptions(std::ios::failbit | std::ios::badbit); + + try { + // open the file, truncate and for write + config.open(name.c_str(), std::ios::out | std::ios::trunc); + + // write a warning + strcpy(buf, "# Auto-generated\n"); + config.write(buf, strlen(buf)); + + // write each configuration setting + for(int_i = _intOptMap.begin(); int_i != _intOptMap.end(); int_i++) { + snprintf(buf, 1024, "%s = %d\n", + int_i->first.c_str(), int_i->second); + config.write(buf, strlen(buf)); + } + for(dbl_i = _dblOptMap.begin(); dbl_i != _dblOptMap.end(); dbl_i++) { + snprintf(buf, 1024, "%s = %f\n", + dbl_i->first.c_str(), dbl_i->second); + config.write(buf, strlen(buf)); + } + for(str_i = _strOptMap.begin(); str_i != _strOptMap.end(); str_i++) { + snprintf(buf, 1024, "%s = %s\n", + str_i->first.c_str(), str_i->second.c_str()); + config.write(buf, strlen(buf)); + } + + // close the file + config.close(); + } catch(std::fstream::failure e) { + std::cerr << e.what() << std::endl; + return -1; + } + + return 0; +} diff --git a/src/drivers/common/configSys.h b/src/drivers/common/configSys.h index d0756eb84..23bf773e8 100644 --- a/src/drivers/common/configSys.h +++ b/src/drivers/common/configSys.h @@ -33,6 +33,11 @@ class Config { Config(std::string d) : _dir(d) { } ~Config() { } + /** + * Reloads configuration file with given filename + */ + int reload(const std::string &); + /** * Adds a configuration option. All options must be added before * parse(). @@ -89,6 +94,11 @@ class Config { * configuration file. */ int save(); + + /** + * Like save with given filename + */ + int save(const std::string &); }; #endif // !__CONFIGSYS_H diff --git a/src/drivers/dingux-sdl/2xSaI.cpp b/src/drivers/dingux-sdl/2xSaI.cpp new file mode 100644 index 000000000..17fa0b9cc --- /dev/null +++ b/src/drivers/dingux-sdl/2xSaI.cpp @@ -0,0 +1,1059 @@ +/* + * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + * + * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and + * Jerremy Koot (jkoot@snes9x.com) + * + * Super FX C emulator code + * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and + * Gary Henderson. + * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. + * + * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. + * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. + * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). + * + * DOS port code contains the works of other authors. See headers in + * individual files. + * + * Snes9x homepage: www.snes9x.com + * + * Permission to use, copy, modify and distribute Snes9x in both binary and + * source form, for non-commercial purposes, is hereby granted without fee, + * providing that this license information and copyright notice appear with + * all copies and any derived work. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event shall the authors be held liable for any damages + * arising from the use of this software. + * + * Snes9x is freeware for PERSONAL USE only. Commercial users should + * seek permission of the copyright holders first. Commercial use includes + * charging money for Snes9x or software derived from Snes9x. + * + * The copyright holders request that bug fixes and improvements to the code + * should be forwarded to them so everyone can benefit from the modifications + * in future versions. + * + * Super NES and Super Nintendo Entertainment System are trademarks of + * Nintendo Co., Limited and its subsidiary companies. + */ +#include "types.h" +#include "2xSaI.h" + +#define USE_COLOR_MODE 1 //0:var, 1:RGB565, 2:RGB555 + +#if USE_COLOR_MODE == 1 +#define colorMask 0xF7DEF7DE +#define lowPixelMask 0x08210821 +#define qcolorMask 0xE79CE79C +#define qlowpixelMask 0x18631863 +#define redblueMask 0xF81F +#define greenMask 0x7E0 +int Init_2xSaI(u32 BitFormat) +{ + return BitFormat == 565 ? 1 : 0; +} +#elif USE_COLOR_MODE == 2 +#define colorMask 0x7BDE7BDE +#define lowPixelMask 0x04210421 +#define qcolorMask 0x739C739C +#define qlowpixelMask 0x0C630C63 +#define redblueMask 0x7C1F +#define greenMask 0x3E0 +int Init_2xSaI(u32 BitFormat) +{ + return BitFormat == 555 ? 1 : 0; +} +#else +static u32 colorMask = 0xF7DEF7DE; +static u32 lowPixelMask = 0x08210821; +static u32 qcolorMask = 0xE79CE79C; +static u32 qlowpixelMask = 0x18631863; +static u32 redblueMask = 0xF81F; +static u32 greenMask = 0x7E0; + +int Init_2xSaI(u32 BitFormat) +{ + if (BitFormat == 565) { + colorMask = 0xF7DEF7DE; + lowPixelMask = 0x08210821; + qcolorMask = 0xE79CE79C; + qlowpixelMask = 0x18631863; + redblueMask = 0xF81F; + greenMask = 0x7E0; + } else if (BitFormat == 555) { + colorMask = 0x7BDE7BDE; + lowPixelMask = 0x04210421; + qcolorMask = 0x739C739C; + qlowpixelMask = 0x0C630C63; + redblueMask = 0x7C1F; + greenMask = 0x3E0; + } else { + return 0; + } + + return 1; +} +#endif + + +static inline int GetResult1 (u32 A, u32 B, u32 C, u32 D, + u32 /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +static inline int GetResult2 (u32 A, u32 B, u32 C, u32 D, + u32 /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r -= 1; + if (y <= 1) + r += 1; + return r; +} + +static inline int GetResult (u32 A, u32 B, u32 C, u32 D) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +static inline u32 INTERPOLATE (u32 A, u32 B) +{ + if (A != B) { + return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + + (A & B & lowPixelMask)); + } else + return A; +} + +static inline u32 Q_INTERPOLATE (u32 A, u32 B, u32 C, u32 D) +{ + register u32 x = ((A & qcolorMask) >> 2) + + ((B & qcolorMask) >> 2) + + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2); + register u32 y = (A & qlowpixelMask) + + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask); + + y = (y >> 2) & qlowpixelMask; + return x + y; +} + +#define BLUE_MASK565 0x001F001F +#define RED_MASK565 0xF800F800 +#define GREEN_MASK565 0x07E007E0 + +#define BLUE_MASK555 0x001F001F +#define RED_MASK555 0x7C007C00 +#define GREEN_MASK555 0x03E003E0 + +void Super2xSaI (u8 *srcPtr, u32 srcPitch, + u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, + int width, int height) +{ + u16 *bP; + u8 *dP; + u32 inc_bP; + u32 Nextline = srcPitch >> 1; + + { + inc_bP = 1; + + for (; height; height--) { + bP = (u16 *) srcPtr; + dP = (u8 *) dstPtr; + + for (u32 finish = width; finish; finish -= inc_bP) { + u32 color4, color5, color6; + u32 color1, color2, color3; + u32 colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, colorS1, colorS2; + u32 product1a, product1b, product2a, product2b; + + //--------------------------------------- B1 B2 + // 4 5 6 S2 + // 1 2 3 S1 + // A1 A2 + + colorB0 = *(bP - Nextline - 1); + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + colorB3 = *(bP - Nextline + 2); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA0 = *(bP + Nextline + Nextline - 1); + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + colorA3 = *(bP + Nextline + Nextline + 2); + + //-------------------------------------- + if (color2 == color6 && color5 != color3) { + product2b = product1b = color2; + } else if (color5 == color3 && color2 != color6) { + product2b = product1b = color5; + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else if (r < 0) + product2b = product1b = color5; + else { + product2b = product1b = INTERPOLATE (color5, color6); + } + } else { + if (color6 == color3 && color3 == colorA1 + && color2 != colorA2 && color3 != colorA0) + product2b = + Q_INTERPOLATE (color3, color3, color3, color2); + else if (color5 == color2 && color2 == colorA2 + && colorA1 != color3 && color2 != colorA3) + product2b = + Q_INTERPOLATE (color2, color2, color2, color3); + else + product2b = INTERPOLATE (color2, color3); + + if (color6 == color3 && color6 == colorB1 + && color5 != colorB2 && color6 != colorB0) + product1b = + Q_INTERPOLATE (color6, color6, color6, color5); + else if (color5 == color2 && color5 == colorB2 + && colorB1 != color6 && color5 != colorB3) + product1b = + Q_INTERPOLATE (color6, color5, color5, color5); + else + product1b = INTERPOLATE (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 + && color5 != colorA2) + product2a = INTERPOLATE (color2, color5); + else + if (color5 == color1 && color6 == color5 + && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE (color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 + && color2 != colorB2) + product1a = INTERPOLATE (color2, color5); + else + if (color4 == color2 && color3 == color2 + && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE (color2, color5); + else + product1a = color5; + + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + + *((u32 *) dP) = product1a; + *((u32 *) (dP + dstPitch)) = product2a; + + bP += inc_bP; + dP += sizeof (u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; +// deltaPtr += srcPitch; + } // endof: for (; height; height--) + } +} + +void SuperEagle (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u8 *dP; + u16 *bP; + u16 *xP; + u32 inc_bP; + + { + inc_bP = 1; + + u32 Nextline = srcPitch >> 1; + + for (; height; height--) { + bP = (u16 *) srcPtr; +// xP = (u16 *) deltaPtr; + dP = dstPtr; + for (u32 finish = width; finish; finish -= inc_bP) { + u32 color4, color5, color6; + u32 color1, color2, color3; + u32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + u32 product1a, product1b, product2a, product2b; + + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + + // -------------------------------------- + if (color2 == color6 && color5 != color3) { + product1b = product2a = color2; + if ((color1 == color2) || (color6 == colorB2)) { + product1a = INTERPOLATE (color2, color5); + product1a = INTERPOLATE (color2, product1a); + // product1a = color2; + } else { + product1a = INTERPOLATE (color5, color6); + } + + if ((color6 == colorS2) || (color2 == colorA1)) { + product2b = INTERPOLATE (color2, color3); + product2b = INTERPOLATE (color2, product2b); + // product2b = color2; + } else { + product2b = INTERPOLATE (color2, color3); + } + } else if (color5 == color3 && color2 != color6) { + product2b = product1a = color5; + + if ((colorB1 == color5) || (color3 == colorS1)) { + product1b = INTERPOLATE (color5, color6); + product1b = INTERPOLATE (color5, product1b); + // product1b = color5; + } else { + product1b = INTERPOLATE (color5, color6); + } + + if ((color3 == colorA2) || (color4 == color5)) { + product2a = INTERPOLATE (color5, color2); + product2a = INTERPOLATE (color5, product2a); + // product2a = color5; + } else { + product2a = INTERPOLATE (color2, color3); + } + + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE (color5, color6); + } else if (r < 0) { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE (color5, color6); + } else { + product2b = product1a = color5; + product1b = product2a = color2; + } + } else { + product2b = product1a = INTERPOLATE (color2, color6); + product2b = + Q_INTERPOLATE (color3, color3, color3, product2b); + product1a = + Q_INTERPOLATE (color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE (color5, color3); + product2a = + Q_INTERPOLATE (color2, color2, color2, product2a); + product1b = + Q_INTERPOLATE (color6, color6, color6, product1b); + + // product1a = color5; + // product1b = color6; + // product2a = color2; + // product2b = color3; + } + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + + *((u32 *) dP) = product1a; + *((u32 *) (dP + dstPitch)) = product2a; +// *xP = color5; + + bP += inc_bP; +// xP += inc_bP; + dP += sizeof (u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; +// deltaPtr += srcPitch; + } // endof: for (height; height; height--) + } +} + +void _2xSaI (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u8 *dP; + u16 *bP; + u32 inc_bP; + + { + inc_bP = 1; + + u32 Nextline = srcPitch >> 1; + + for (; height; height--) { + bP = (u16 *) srcPtr; + dP = dstPtr; + + for (u32 finish = width; finish; finish -= inc_bP) { + + register u32 colorA, colorB; + u32 colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + + colorM, colorN, colorO, colorP; + u32 product, product1, product2; + + //--------------------------------------- + // Map of the pixels: I|E F|J + // G|A B|K + // H|C D|L + // M|N O|P + colorI = *(bP - Nextline - 1); + colorE = *(bP - Nextline); + colorF = *(bP - Nextline + 1); + colorJ = *(bP - Nextline + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + Nextline - 1); + colorC = *(bP + Nextline); + colorD = *(bP + Nextline + 1); + colorL = *(bP + Nextline + 2); + + colorM = *(bP + Nextline + Nextline - 1); + colorN = *(bP + Nextline + Nextline); + colorO = *(bP + Nextline + Nextline + 1); + colorP = *(bP + Nextline + Nextline + 2); + + if ((colorA == colorD) && (colorB != colorC)) { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ))) { + product = colorA; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM))) { + product1 = colorA; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorA; + } else if ((colorB == colorC) && (colorA != colorD)) { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI))) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI))) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorB; + } else if ((colorA == colorD) && (colorB == colorC)) { + if (colorA == colorB) { + product = colorA; + product1 = colorA; + product2 = colorA; + } else { + register int r = 0; + + product1 = INTERPOLATE (colorA, colorC); + product = INTERPOLATE (colorA, colorB); + + r += + GetResult1 (colorA, colorB, colorG, colorE, + colorI); + r += + GetResult2 (colorB, colorA, colorK, colorF, + colorJ); + r += + GetResult2 (colorB, colorA, colorH, colorN, + colorM); + r += + GetResult1 (colorA, colorB, colorL, colorO, + colorP); + + if (r > 0) + product2 = colorA; + else if (r < 0) + product2 = colorB; + else { + product2 = + Q_INTERPOLATE (colorA, colorB, colorC, + colorD); + } + } + } else { + product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) { + product = colorA; + } else if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM)) { + product1 = colorA; + } else if ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI)) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + } + + product = colorA | (product << 16); + product1 = product1 | (product2 << 16); + *((s32 *) dP) = product; + *((u32 *) (dP + dstPitch)) = product1; + + bP += inc_bP; + dP += sizeof (u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; +// deltaPtr += srcPitch; + } // endof: for (height; height; height--) + } +} + +static u32 Bilinear (u32 A, u32 B, u32 x) +{ + unsigned long areaA, areaB; + unsigned long result; + + if (A == B) + return A; + + areaB = (x >> 11) & 0x1f; // reduce 16 bit fraction to 5 bits + areaA = 0x20 - areaB; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + + result = ((areaA * A) + (areaB * B)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); +} + +static u32 Bilinear4 (u32 A, u32 B, u32 C, u32 D, u32 x, + u32 y) +{ + unsigned long areaA, areaB, areaC, areaD; + unsigned long result, xy; + + x = (x >> 11) & 0x1f; + y = (y >> 11) & 0x1f; + xy = (x * y) >> 5; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + C = (C & redblueMask) | ((C & greenMask) << 16); + D = (D & redblueMask) | ((D & greenMask) << 16); + + areaA = 0x20 + xy - x - y; + areaB = x - xy; + areaC = y - xy; + areaD = xy; + + result = ((areaA * A) + (areaB * B) + (areaC * C) + (areaD * D)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); +} + +void Scale_2xSaI (u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, + u8 *dstPtr, u32 dstPitch, + u32 dstWidth, u32 dstHeight, int width, int height) +{ + u8 *dP; + u16 *bP; + + u32 w; + u32 h; + u32 dw; + u32 dh; + u32 hfinish; + u32 wfinish; + + u32 Nextline = srcPitch >> 1; + + wfinish = (width - 1) << 16; // convert to fixed point + dw = wfinish / (dstWidth - 1); + hfinish = (height - 1) << 16; // convert to fixed point + dh = hfinish / (dstHeight - 1); + + for (h = 0; h < hfinish; h += dh) { + u32 y1, y2; + + y1 = h & 0xffff; // fraction part of fixed point + bP = (u16 *) (srcPtr + ((h >> 16) * srcPitch)); + dP = dstPtr; + y2 = 0x10000 - y1; + + w = 0; + + for (; w < wfinish;) { + u32 A, B, C, D; + u32 E, F, G, H; + u32 I, J, K, L; + u32 x1, x2, a1, f1, f2; + u32 position, product1; + + position = w >> 16; + A = bP[position]; // current pixel + B = bP[position + 1]; // next pixel + C = bP[position + Nextline]; + D = bP[position + Nextline + 1]; + E = bP[position - Nextline]; + F = bP[position - Nextline + 1]; + G = bP[position - 1]; + H = bP[position + Nextline - 1]; + I = bP[position + 2]; + J = bP[position + Nextline + 2]; + K = bP[position + Nextline + Nextline]; + L = bP[position + Nextline + Nextline + 1]; + + x1 = w & 0xffff; // fraction part of fixed point + x2 = 0x10000 - x1; + + /*0*/ + if (A == B && C == D && A == C) + product1 = A; + else /*1*/ if (A == D && B != C) { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y1 <= f1 && A == J && A != E) // close to B + { + a1 = f1 - y1; + product1 = Bilinear (A, B, a1); + } else if (y1 >= f1 && A == G && A != L) // close to C + { + a1 = y1 - f1; + product1 = Bilinear (A, C, a1); + } + else if (x1 >= f2 && A == E && A != J) // close to B + { + a1 = x1 - f2; + product1 = Bilinear (A, B, a1); + } + else if (x1 <= f2 && A == L && A != G) // close to C + { + a1 = f2 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 >= x1) // close to C + { + a1 = y1 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 <= x1) // close to B + { + a1 = x1 - y1; + product1 = Bilinear (A, B, a1); + } + } + else + /*2*/ + if (B == C && A != D) + { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y2 >= f1 && B == H && B != F) // close to A + { + a1 = y2 - f1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= f1 && B == I && B != K) // close to D + { + a1 = f1 - y2; + product1 = Bilinear (B, D, a1); + } + else if (x2 >= f2 && B == F && B != H) // close to A + { + a1 = x2 - f2; + product1 = Bilinear (B, A, a1); + } + else if (x2 <= f2 && B == K && B != I) // close to D + { + a1 = f2 - x2; + product1 = Bilinear (B, D, a1); + } + else if (y2 >= x1) // close to A + { + a1 = y2 - x1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= x1) // close to D + { + a1 = x1 - y2; + product1 = Bilinear (B, D, a1); + } + } + /*3*/ + else + { + product1 = Bilinear4 (A, B, C, D, x1, y1); + } + + //end First Pixel + *(u32 *) dP = product1; + dP += 2; + w += dw; + } + dstPtr += dstPitch; + } +} + +void palette_2xSaI(u8* srcPtr, u32 srcPitch, u8* deltaPtr, u8* dstPtr, u32 dstPitch, int width, int height, u16 palette[]) +{ + for (; height; height--) + { + u8* bP = (u8*)srcPtr; + u8* dP = (u8*)dstPtr; + + for (u32 finish = width; finish; finish--) + { + register u32 colorA, colorB; + u32 colorC, colorD, colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO, colorP; + u32 product, product1, product2; + + //--------------------------------------- + // Map of the pixels: I|E F|J + // G|A B|K + // H|C D|L + // M|N O|P + colorI = palette[*(bP - srcPitch - 1)]; + colorE = palette[*(bP - srcPitch)]; + colorF = palette[*(bP - srcPitch + 1)]; + colorJ = palette[*(bP - srcPitch + 2)]; + + colorG = palette[*(bP - 1)]; + colorA = palette[*(bP)]; + colorB = palette[*(bP + 1)]; + colorK = palette[*(bP + 2)]; + + colorH = palette[*(bP + srcPitch - 1)]; + colorC = palette[*(bP + srcPitch)]; + colorD = palette[*(bP + srcPitch + 1)]; + colorL = palette[*(bP + srcPitch + 2)]; + + colorM = palette[*(bP + srcPitch + srcPitch - 1)]; + colorN = palette[*(bP + srcPitch + srcPitch)]; + colorO = palette[*(bP + srcPitch + srcPitch + 1)]; + colorP = palette[*(bP + srcPitch + srcPitch + 2)]; + + if ((colorA == colorD) && (colorB != colorC)) + { + if (((colorA == colorE) && (colorB == colorL)) || ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) + { + product = colorA; + } + else + { + product = INTERPOLATE(colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || ((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM))) + { + product1 = colorA; + } + else + { + product1 = INTERPOLATE(colorA, colorC); + } + product2 = colorA; + } + else if ((colorB == colorC) && (colorA != colorD)) + { + if (((colorB == colorF) && (colorA == colorH)) || ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) + { + product = colorB; + } + else + { + product = INTERPOLATE(colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) + { + product1 = colorC; + } + else + { + product1 = INTERPOLATE(colorA, colorC); + } + product2 = colorB; + } + else if ((colorA == colorD) && (colorB == colorC)) + { + if (colorA == colorB) + { + product = colorA; + product1 = colorA; + product2 = colorA; + } + else + { + register int r = 0; + + product1 = INTERPOLATE(colorA, colorC); + product = INTERPOLATE(colorA, colorB); + + r += GetResult1(colorA, colorB, colorG, colorE, colorI); + r += GetResult2(colorB, colorA, colorK, colorF, colorJ); + r += GetResult2(colorB, colorA, colorH, colorN, colorM); + r += GetResult1(colorA, colorB, colorL, colorO, colorP); + + if (r > 0) + { + product2 = colorA; + } + else if (r < 0) + { + product2 = colorB; + } + else + { + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + } + } + } + else + { + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ)) + { + product = colorA; + } + else if ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI)) + { + product = colorB; + } + else + { + product = INTERPOLATE(colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM)) + { + product1 = colorA; + } + else if ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI)) + { + product1 = colorC; + } + else + { + product1 = INTERPOLATE(colorA, colorC); + } + } + + product = colorA | (product << 16); + product1 = product1 | (product2 << 16); + *((s32*)dP) = product; + *((u32*)(dP + dstPitch)) = product1; + + bP++; + dP += sizeof(u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + //deltaPtr += srcPitch; + } // endof: for (height; height; height--) +} + + +void half_2xSaI (u8* srcPtr, u32 srcPitch, u8* deltaPtr, + u8* dstPtr, u32 dstPitch, int width, int height) +{ + u8 *dP; + u16 *bP; + u32 Nextline = srcPitch >> 1; + + for (; height; height--) + { + bP = (u16*)srcPtr; + dP = dstPtr; + int finish = width; + while (--finish >= 0) + { + register u32 colorA, colorB; + u32 colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL; + u32 colorM, colorN, colorO, colorP; + u32 product; + + //--------------------------------------- + // Map of the pixels: I|E F|J + // G|A B|K + // H|C D|L + // M|N O|P + colorI = *(bP - Nextline - 1); + colorE = *(bP - Nextline); + colorF = *(bP - Nextline + 1); + colorJ = *(bP - Nextline + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + Nextline - 1); + colorC = *(bP + Nextline); + colorD = *(bP + Nextline + 1); + colorL = *(bP + Nextline + 2); + + if (finish == 0) + { + colorB = colorA; + } + + //colorM = *(bP + Nextline + Nextline - 1); + //colorN = *(bP + Nextline + Nextline); + //colorO = *(bP + Nextline + Nextline + 1); + //colorP = *(bP + Nextline + Nextline + 2); + + if ((colorA == colorD) && (colorB != colorC)) { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ))) { + product = colorA; + } else { + product = INTERPOLATE (colorA, colorB); + } + } else if ((colorB == colorC) && (colorA != colorD)) { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI))) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + } else if ((colorA == colorD) && (colorB == colorC)) { + if (colorA == colorB) { + product = colorA; + } else { + product = INTERPOLATE (colorA, colorB); + } + } else { + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) { + product = colorA; + } else if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + } + + product = colorA | (product << 16); + *((s32 *) dP) = product; + + bP++; + dP += sizeof (u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch; + //dstPtr += dstPitch * 2; +// deltaPtr += srcPitch; + } // endof: for (height; height; height--) +} \ No newline at end of file diff --git a/src/drivers/dingux-sdl/2xSaI.h b/src/drivers/dingux-sdl/2xSaI.h new file mode 100644 index 000000000..48baa66ac --- /dev/null +++ b/src/drivers/dingux-sdl/2xSaI.h @@ -0,0 +1,21 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __2XSAI_H__ +#define __2XSAI_H__ + +int Init_2xSaI(u32 BitFormat); +void Super2xSaI (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, int width, int height); +void SuperEagle (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, int width, int height); +void _2xSaI (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, int width, int height); +void Scale_2xSaI (u8 *srcPtr, u32 srcPitch, u8 * /*deltaPtr */, u8 *dstPtr, u32 dstPitch, u32 dstWidth, u32 dstHeight, int width, int height); + +#endif \ No newline at end of file diff --git a/src/drivers/dingux-sdl/config.cpp b/src/drivers/dingux-sdl/config.cpp new file mode 100644 index 000000000..44f7c98de --- /dev/null +++ b/src/drivers/dingux-sdl/config.cpp @@ -0,0 +1,434 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "throttle.h" +#include "config.h" + +#include "../common/cheat.h" + +#include "input.h" +#include "dface.h" + +#include "dingoo.h" +#include "dingoo-video.h" +#include "dummy-netplay.h" + +#ifdef WIN32 +#include +#endif + +/** + * Read a custom pallete from a file and load it into the core. + */ +int LoadCPalette(const std::string &file) { + uint8 tmpp[192]; + FILE *fp; + + if (!(fp = FCEUD_UTF8fopen(file.c_str(), "rb"))) { + printf(" Error loading custom palette from file: %s\n", file.c_str()); + return 0; + } + size_t result = fread(tmpp, 1, 192, fp); + if (result != 192) { + printf(" Error reading custom palette from file: %s\n", file.c_str()); + return 0; + } + FCEUI_SetUserPalette(tmpp, 192); + fclose(fp); + return 1; +} + +/** + * Creates the subdirectories used for saving snapshots, movies, game + * saves, etc. Hopefully obsolete with new configuration system. + */ +static void CreateDirs(const std::string &dir) { + char *subs[7] = { "fcs", "snaps", "gameinfo", "sav", "cheats", "movie", + "cfg" }; + std::string subdir; + int x; + +#if defined(WIN32) || defined(NEED_MINGW_HACKS) + mkdir(dir.c_str()); + for(x = 0; x < 7; x++) { + subdir = dir + PSS + subs[x]; + mkdir(subdir.c_str()); + } +#else + mkdir(dir.c_str(), S_IRWXU); + for (x = 0; x < 7; x++) { + subdir = dir + PSS + subs[x]; + mkdir(subdir.c_str(), S_IRWXU); + } +#endif +} + +/** + * Attempts to locate FCEU's application directory. This will + * hopefully become obsolete once the new configuration system is in + * place. + */ +static void GetBaseDirectory(std::string &dir) +{ +#ifdef WIN32 + dir = ".fceux"; + mkdir(dir.c_str()); +#else + char *home = getenv("HOME"); + if (home) { + dir = std::string(home) + "/.fceux"; + } else { +#ifdef WIN32 + home = new char[MAX_PATH + 1]; + GetModuleFileName(NULL, home, MAX_PATH + 1); + + char *lastBS = strrchr(home,'\\'); + if(lastBS) { + *lastBS = 0; + } + + dir = std::string(home); + delete[] home; +#else + dir = ""; +#endif + } +#endif +} + +Config * InitConfig() { + std::string dir, prefix; + Config *config; + + GetBaseDirectory(dir); + + FCEUI_SetBaseDirectory(dir.c_str()); + CreateDirs(dir); + + config = new Config(dir); + + // sound options + config->addOption('s', "sound", "SDL.Sound", 1); + config->addOption("volume", "SDL.Sound.Volume", 256); + config->addOption("trianglevol", "SDL.Sound.TriangleVolume", 256); + config->addOption("square1vol", "SDL.Sound.Square1Volume", 256); + config->addOption("square2vol", "SDL.Sound.Square2Volume", 256); + config->addOption("noisevol", "SDL.Sound.NoiseVolume", 256); + config->addOption("pcmvol", "SDL.Sound.PCMVolume", 256); + config->addOption("soundrate", "SDL.Sound.Rate", 32000); + config->addOption("soundq", "SDL.Sound.Quality", 0); + config->addOption("soundrecord", "SDL.Sound.RecordFile", ""); + config->addOption("soundbufsize", "SDL.Sound.BufSize", 30); + config->addOption("lowpass", "SDL.Sound.LowPass", 0); + + config->addOption('g', "gamegenie", "SDL.GameGenie", 0); + config->addOption("pal", "SDL.PAL", 0); + config->addOption("frameskip", "SDL.Frameskip", 0); + config->addOption("clipsides", "SDL.ClipSides", 0); + config->addOption("nospritelim", "SDL.DisableSpriteLimit", 1); + + // color control + config->addOption('p', "palette", "SDL.Palette", ""); + config->addOption("tint", "SDL.Tint", 56); + config->addOption("hue", "SDL.Hue", 72); + config->addOption("ntsccolor", "SDL.NTSCpalette", 0); + + // scanline settings + config->addOption("slstart", "SDL.ScanLineStart", 0); + config->addOption("slend", "SDL.ScanLineEnd", 239); + + // video controls + config->addOption('x', "xres", "SDL.XResolution", 320); + config->addOption('y', "yres", "SDL.YResolution", 240); + config->addOption('f', "fullscreen", "SDL.Fullscreen", 0); + config->addOption('b', "bpp", "SDL.BitsPerPixel", 8); + config->addOption("doublebuf", "SDL.DoubleBuffering", 0); + config->addOption("autoscale", "SDL.AutoScale", 1); + config->addOption("keepratio", "SDL.KeepRatio", 1); + config->addOption("xscale", "SDL.XScale", 1.0); + config->addOption("yscale", "SDL.YScale", 1.0); + config->addOption("xstretch", "SDL.XStretch", 0); + config->addOption("ystretch", "SDL.YStretch", 0); + config->addOption("noframe", "SDL.NoFrame", 0); + config->addOption("special", "SDL.SpecialFilter", 0); + + // NOT SUPPORTED + // OpenGL options + //config->addOption("opengl", "SDL.OpenGL", 0); + //config->addOption("openglip", "SDL.OpenGLip", 0); + //config->addOption("SDL.SpecialFilter", 0); + //config->addOption("SDL.SpecialFX", 0); + + // network play options - netplay is broken + //config->addOption("server", "SDL.NetworkIsServer", 0); + //config->addOption('n', "net", "SDL.NetworkIP", ""); + //config->addOption('u', "user", "SDL.NetworkUsername", ""); + //config->addOption('w', "pass", "SDL.NetworkPassword", ""); + //config->addOption('k', "netkey", "SDL.NetworkGameKey", ""); + //config->addOption("port", "SDL.NetworkPort", 4046); + //config->addOption("players", "SDL.NetworkPlayers", 1); + + config->addOption("mousespeed", "SDL.MouseSpeed", 3); + config->addOption("showmouse", "SDL.ShowMouseCursor", 0); + + config->addOption("fpsthottle", "SDL.FPSThrottle", 0); + config->addOption("showfps", "SDL.ShowFPS", 0); + + // input configuration options + config->addOption("input1", "SDL.Input.0", "GamePad.0"); + config->addOption("input2", "SDL.Input.1", "GamePad.1"); + config->addOption("input3", "SDL.Input.2", "Gamepad.2"); + config->addOption("input4", "SDL.Input.3", "Gamepad.3"); + config->addOption("mergecontrols", "SDL.MergeControls", 0); + + // allow for input configuration + // NOT SUPPORTED + // config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg); + + // display input + config->addOption("inputdisplay", "SDL.InputDisplay", 0); + + // pause movie playback at frame x + config->addOption("pauseframe", "SDL.PauseFrame", 0); + config->addOption("moviemsg", "SDL.MovieMsg", 1); + + // overwrite the config file? + config->addOption("no-config", "SDL.NoConfig", 0); + + // video playback + config->addOption("playmov", "SDL.Movie", ""); + config->addOption("subtitles", "SDL.SubtitleDisplay", 1); + + config->addOption("fourscore", "SDL.FourScore", 0); + +#ifdef _S9XLUA_H + // load lua script + config->addOption("loadlua", "SDL.LuaScript", ""); +#endif + +#ifdef CREATE_AVI + config->addOption("videolog", "SDL.VideoLog", ""); + config->addOption("mute", "SDL.MuteCapture", 0); +#endif + + // fcm -> fm2 conversion + config->addOption("fcmconvert", "SDL.FCMConvert", ""); + + // fm2 -> srt conversion + config->addOption("ripsubs", "SDL.RipSubs", ""); + + // enable new PPU core + config->addOption("newppu", "SDL.NewPPU", 0); + + // GamePad 0 - 3 + for (unsigned int i = 0; i < GAMEPAD_NUM_DEVICES; i++) { + char buf[64]; + snprintf(buf, 20, "SDL.Input.GamePad.%d.", i); + prefix = buf; + + config->addOption(prefix + "DeviceType", DefaultGamePadDevice[i]); + config->addOption(prefix + "DeviceNum", 0); + for (unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) { + config->addOption(prefix + GamePadNames[j], DefaultGamePad[i][j]); + } + } + +#if 0 + // PowerPad 0 - 1 + for(unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) { + char buf[64]; + snprintf(buf, 20, "SDL.Input.PowerPad.%d.", i); + prefix = buf; + + config->addOption(prefix + "DeviceType", DefaultPowerPadDevice[i]); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < POWERPAD_NUM_BUTTONS; j++) { + config->addOption(prefix +PowerPadNames[j], DefaultPowerPad[i][j]); + } + } +#endif + + // QuizKing + prefix = "SDL.Input.QuizKing."; + config->addOption(prefix + "DeviceType", DefaultQuizKingDevice); + config->addOption(prefix + "DeviceNum", 0); + for (unsigned int j = 0; j < QUIZKING_NUM_BUTTONS; j++) { + config->addOption(prefix + QuizKingNames[j], DefaultQuizKing[j]); + } + + // HyperShot + prefix = "SDL.Input.HyperShot."; + config->addOption(prefix + "DeviceType", DefaultHyperShotDevice); + config->addOption(prefix + "DeviceNum", 0); + for (unsigned int j = 0; j < HYPERSHOT_NUM_BUTTONS; j++) { + config->addOption(prefix + HyperShotNames[j], DefaultHyperShot[j]); + } + +#if 0 + // Mahjong + prefix = "SDL.Input.Mahjong."; + config->addOption(prefix + "DeviceType", DefaultMahjongDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < MAHJONG_NUM_BUTTONS; j++) { + config->addOption(prefix + MahjongNames[j], DefaultMahjong[j]); + } +#endif + + // TopRider + prefix = "SDL.Input.TopRider."; + config->addOption(prefix + "DeviceType", DefaultTopRiderDevice); + config->addOption(prefix + "DeviceNum", 0); + for (unsigned int j = 0; j < TOPRIDER_NUM_BUTTONS; j++) { + config->addOption(prefix + TopRiderNames[j], DefaultTopRider[j]); + } + +#if 0 + // FTrainer + prefix = "SDL.Input.FTrainer."; + config->addOption(prefix + "DeviceType", DefaultFTrainerDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < FTRAINER_NUM_BUTTONS; j++) { + config->addOption(prefix + FTrainerNames[j], DefaultFTrainer[j]); + } + + // FamilyKeyBoard + prefix = "SDL.Input.FamilyKeyBoard."; + config->addOption(prefix + "DeviceType", DefaultFamilyKeyBoardDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < FAMILYKEYBOARD_NUM_BUTTONS; j++) { + config->addOption(prefix + FamilyKeyBoardNames[j], + DefaultFamilyKeyBoard[j]); + } +#endif + + // Will use R + Button combo for hotkeys on dingoo + // So only 11 hotkeys available + // L trigger will be saved for GUI + const int Hotkeys[HK_MAX] = { -1, // cheat menu + -1, // bind state + -1, // load lua + -1, // toggleBG + 0, // save state + 2, // fds flip disk + -1, // fds select + 1, // load state + -1, // fds eject + 5, // VS insert coin + -1, // VS toggle dipswitch + 6, // toggle frame display + 27, // toggle subtitle + -1, // reset + 17, // screenshot + 16, // pause + -1, // speed++ + -1, // speed-- + 18, //frame advance + -1, // turbo + -1, // toggle input display + -1, // toggle movie RW + -1, // toggle mute capture + 29, // quit + -1, // frame advance lag skip + -1, // lag counter display + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + + prefix = "SDL.Hotkeys."; + for (int i = 0; i < HK_MAX; i++) + config->addOption(prefix + HotkeyStrings[i], Hotkeys[i]); + + // TODO - Are these necessary? + /* + config->addOption(prefix + "Pause", SDLK_PAUSE); + config->addOption(prefix + "DecreaseSpeed", SDLK_MINUS); + config->addOption(prefix + "IncreaseSpeed", SDLK_EQUALS); + config->addOption(prefix + "FrameAdvance", SDLK_BACKSLASH); + config->addOption(prefix + "FastForward", SDLK_TAB); + config->addOption(prefix + "InputDisplay", SDLK_i); + config->addOption(prefix + "MovieToggleReadWrite", SDLK_q); + #ifdef CREATE_AVI + config->addOption(prefix + "MuteCapture", SDLK_DELETE); + #endif + config->addOption(prefix + "Quit", SDLK_ESCAPE); + //config->addOption(prefix + "Power", 0); + */ + + /* NOT SUPPORTED + config->addOption(prefix + "SelectState0", SDLK_0); + config->addOption(prefix + "SelectState1", SDLK_1); + config->addOption(prefix + "SelectState2", SDLK_2); + config->addOption(prefix + "SelectState3", SDLK_3); + config->addOption(prefix + "SelectState4", SDLK_4); + config->addOption(prefix + "SelectState5", SDLK_5); + config->addOption(prefix + "SelectState6", SDLK_6); + config->addOption(prefix + "SelectState7", SDLK_7); + config->addOption(prefix + "SelectState8", SDLK_8); + config->addOption(prefix + "SelectState9", SDLK_9); + */ + + // All mouse devices + config->addOption("SDL.OekaKids.0.DeviceType", "Mouse"); + config->addOption("SDL.OekaKids.0.DeviceNum", 0); + + config->addOption("SDL.Arkanoid.0.DeviceType", "Mouse"); + config->addOption("SDL.Arkanoid.0.DeviceNum", 0); + + config->addOption("SDL.Shadow.0.DeviceType", "Mouse"); + config->addOption("SDL.Shadow.0.DeviceNum", 0); + + config->addOption("SDL.Zapper.0.DeviceType", "Mouse"); + config->addOption("SDL.Zapper.0.DeviceNum", 0); + + return config; +} + +void UpdateEMUCore(Config *config) { + int ntsccol, ntsctint, ntschue, flag, start, end; + std::string cpalette; + + config->getOption("SDL.NTSCpalette", &ntsccol); + config->getOption("SDL.Tint", &ntsctint); + config->getOption("SDL.Hue", &ntschue); + FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue); + + config->getOption("SDL.Palette", &cpalette); + if (cpalette.size()) { + LoadCPalette(cpalette); + } + + config->getOption("SDL.PAL", &flag); + FCEUI_SetVidSystem(flag ? 1 : 0); + + config->getOption("SDL.GameGenie", &flag); + FCEUI_SetGameGenie(flag ? 1 : 0); + + config->getOption("SDL.Sound.LowPass", &flag); + FCEUI_SetLowPass(flag ? 1 : 0); + + config->getOption("SDL.DisableSpriteLimit", &flag); + FCEUI_DisableSpriteLimitation(flag ? 1 : 0); + + //Not used anymore. + //config->getOption("SDL.SnapName", &flag); + //FCEUI_SetSnapName(flag ? true : false); + + config->getOption("SDL.ScanLineStart", &start); + config->getOption("SDL.ScanLineEnd", &end); + +#if DOING_SCANLINE_CHECKS + for(int i = 0; i < 2; x++) { + if(srendlinev[x]<0 || srendlinev[x]>239) srendlinev[x]=0; + if(erendlinev[x]239) erendlinev[x]=239; + } +#endif + + FCEUI_SetRenderedLines(start + 8, end - 8, start, end); +} diff --git a/src/drivers/dingux-sdl/config.h b/src/drivers/dingux-sdl/config.h new file mode 100644 index 000000000..4e1fef52d --- /dev/null +++ b/src/drivers/dingux-sdl/config.h @@ -0,0 +1,56 @@ +#ifndef CONFIG_H_HF128 +#define CONFIG_H_HF128 + +#include "../common/configSys.h" + +Config *InitConfig(void); +void UpdateEMUCore(Config *); +int LoadCPalette(const std::string &file); + +// hotkey definitions + + +enum HOTKEY { HK_CHEAT_MENU, HK_BIND_STATE, HK_LOAD_LUA, HK_TOGGLE_BG, + HK_SAVE_STATE, HK_FDS_FLIP, HK_FDS_SELECT, HK_LOAD_STATE, HK_FDS_EJECT , + HK_VS_INSERT_COIN, HK_VS_TOGGLE_DIPSWITCH, + HK_TOGGLE_FRAME_DISPLAY, HK_TOGGLE_SUBTITLE, HK_RESET, HK_SCREENSHOT, + HK_PAUSE, HK_DECREASE_SPEED, HK_INCREASE_SPEED, HK_FRAME_ADVANCE, HK_TURBO, + HK_TOGGLE_INPUT_DISPLAY, HK_MOVIE_TOGGLE_RW, HK_MUTE_CAPTURE, HK_QUIT, HK_FA_LAG_SKIP, HK_LAG_COUNTER_DISPLAY, + HK_SELECT_STATE_0, HK_SELECT_STATE_1, HK_SELECT_STATE_2, HK_SELECT_STATE_3, + HK_SELECT_STATE_4, HK_SELECT_STATE_5, HK_SELECT_STATE_6, HK_SELECT_STATE_7, + HK_SELECT_STATE_8, HK_SELECT_STATE_9}; + +const int HK_MAX = 36; + +static const char* HotkeyStrings[HK_MAX] = { + "CheatMenu", + "BindState", + "LoadLua", + "ToggleBG", + "SaveState", + "FDSFlip", + "FDSSelect", + "LoadState", + "FDSEject", + "VSInsertCoin", + "VSToggleDip", + "MovieToggleFrameDisplay", + "SubtitleDisplay", + "Reset", + "Screenshot", + "Pause", + "DecreaseSpeed", + "IncreaseSpeed", + "FrameAdvance", + "Turbo", + "ToggleInputDisplay", + "ToggleMovieRW", + "MuteCapture", + "Quit", + "FrameAdvanceLagSkip", + "LagCounterDisplay", + "SelectState0", "SelectState1", "SelectState2", "SelectState3", + "SelectState4", "SelectState5", "SelectState6", "SelectState7", + "SelectState8", "SelectState9" }; + +#endif diff --git a/src/drivers/dingux-sdl/dface.h b/src/drivers/dingux-sdl/dface.h new file mode 100644 index 000000000..bd39b5baf --- /dev/null +++ b/src/drivers/dingux-sdl/dface.h @@ -0,0 +1,41 @@ +#include "../common/args.h" +#include "../common/config.h" + +#include "input.h" + +extern CFGSTRUCT DriverConfig[]; +extern ARGPSTRUCT DriverArgs[]; +extern char *DriverUsage; + +void DoDriverArgs(void); + +int InitSound(); +void WriteSound(int32 *Buffer, int Count); +int KillSound(void); +uint32 GetMaxSound(void); +uint32 GetBufferSize(void); +uint32 GetBufferedSound(void); + +void SilenceSound(int s); /* DOS and SDL */ + + +int InitJoysticks(void); +int KillJoysticks(void); +uint32 *GetJSOr(void); + +int InitVideo(FCEUGI *gi); +int KillVideo(void); +void BlitScreen(uint8 *XBuf); +void LockConsole(void); +void UnlockConsole(void); +void ToggleFS(); /* SDL */ + +int LoadGame(const char *path); +//int CloseGame(void); + +void Giggles(int); +void DoFun(void); + +int FCEUD_NetworkConnect(void); + +uint16 *FCEUD_GetPaletteArray16(); diff --git a/src/drivers/dingux-sdl/dingoo-joystick.cpp b/src/drivers/dingux-sdl/dingoo-joystick.cpp new file mode 100644 index 000000000..59aec23a5 --- /dev/null +++ b/src/drivers/dingux-sdl/dingoo-joystick.cpp @@ -0,0 +1,54 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2002 Paul Kuliniewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/// \file +/// \brief Handles joystick input using the SDL. + +#include +#include +#include +#include + +#include "dingoo.h" + +/** + * Tests if the given button is active on the joystick. + */ +int DTestButtonJoy(ButtConfig *bc) +{ + return(0); +} + +/** + * Shutdown the DINGOO joystick subsystem. + */ +int KillJoysticks() +{ + return(0); +} + +/** + * Initialize the DINGOO joystick subsystem. + */ +int InitJoysticks() +{ + return(1); +} diff --git a/src/drivers/dingux-sdl/dingoo-sound.cpp b/src/drivers/dingux-sdl/dingoo-sound.cpp new file mode 100644 index 000000000..3f5d3fbb6 --- /dev/null +++ b/src/drivers/dingux-sdl/dingoo-sound.cpp @@ -0,0 +1,275 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/// \file +/// \brief Handles sound emulation using the SDL. + +#include +#include +#include + +#include "dingoo.h" + +#include "../common/configSys.h" + +extern Config *g_config; + +static int16 *s_Buffer = 0; +static unsigned int s_BufferSize; +static unsigned int s_BufferRead; +static unsigned int s_BufferWrite; +static volatile unsigned int s_BufferIn; + +static int s_mute = 0; + +SDL_AudioSpec spec; + +/** + * Callback to get and play audio data. + */ +static void fillaudio(void *udata, uint8 *stream, int len) // len == spec.samples * 4 +{ + int32 *tmps = (int32 *)stream; + len >>= 2; + + // debug code + //printf("s_BufferIn: %i s_BufferWrite = %i s_BufferRead = %i s_BufferSize = %i\n", + // s_BufferIn, s_BufferWrite, s_BufferRead, s_BufferSize); + + while (len) { + int32 sample = 0; + if (s_BufferIn) { + sample = s_Buffer[s_BufferRead] & 0xFFFF; + s_BufferRead = (s_BufferRead + 1) % s_BufferSize; + s_BufferIn--; + sample |= (sample << 16); + } else { + sample = 0; + } + + *tmps = sample; + tmps++; + len--; + } +} + +/** + * Initialize the audio subsystem. + */ +int InitSound() +{ + int sound, soundrate, soundbufsize, soundvolume, soundtrianglevolume, + soundsquare1volume, soundsquare2volume, soundnoisevolume, + soundpcmvolume, soundq, lowpass, samples; + + + FCEUI_printf("Initializing audio...\n"); + + g_config->getOption("SDL.Sound", &sound); + if (!sound) return 0; + + memset(&spec, 0, sizeof(spec)); + if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + puts(SDL_GetError()); + KillSound(); + return(0); + } + char driverName[8]; + SDL_AudioDriverName(driverName, 8); + + fprintf(stderr, "Loading SDL sound with %s driver...\n", driverName); + + // load configuration variables + g_config->getOption("SDL.Sound.Rate", &soundrate); + g_config->getOption("SDL.Sound.BufSize", &soundbufsize); + g_config->getOption("SDL.Sound.Volume", &soundvolume); + g_config->getOption("SDL.Sound.Quality", &soundq); + g_config->getOption("SDL.Sound.TriangleVolume", &soundtrianglevolume); + g_config->getOption("SDL.Sound.Square1Volume", &soundsquare1volume); + g_config->getOption("SDL.Sound.Square2Volume", &soundsquare2volume); + g_config->getOption("SDL.Sound.NoiseVolume", &soundnoisevolume); + g_config->getOption("SDL.Sound.PCMVolume", &soundpcmvolume); + g_config->getOption("SDL.Sound.LowPass", &lowpass); + + spec.freq = soundrate; + spec.format = AUDIO_S16; + spec.channels = 2; + spec.samples = 512; + spec.callback = fillaudio; + spec.userdata = 0; + + while(spec.samples < (soundrate / 60) * 1) spec.samples <<= 1; + + s_BufferSize = spec.samples * 4; + + s_Buffer = (int16 *) malloc(sizeof(int16) * s_BufferSize); + if (!s_Buffer) return 0; + + s_BufferRead = s_BufferWrite = s_BufferIn = 0; + + printf("SDL Size: %d, Internal size: %d\n", spec.samples, s_BufferSize); + + if(SDL_OpenAudio(&spec, 0) < 0) { + puts(SDL_GetError()); + KillSound(); + return(0); + } + + SDL_PauseAudio(0); + + FCEUI_SetSoundVolume(soundvolume); + FCEUI_SetSoundQuality(soundq); + FCEUI_Sound(soundrate); + FCEUI_SetTriangleVolume(soundtrianglevolume); + FCEUI_SetSquare1Volume(soundsquare1volume); + FCEUI_SetSquare2Volume(soundsquare2volume); + FCEUI_SetNoiseVolume(soundnoisevolume); + FCEUI_SetPCMVolume(soundpcmvolume); + FCEUI_SetLowPass(lowpass); + + return (1); +} + +/** + * Returns the size of the audio buffer. + */ +uint32 GetMaxSound(void) { + return (s_BufferSize); +} + +/** + * Returns the size of the audio buffer used by one SDL callback. + */ +uint32 GetBufferSize(void) { + return spec.samples; +} + +/** + * Returns the amount of used space in the audio buffer. + */ +uint32 GetBufferedSound(void) { + return s_BufferIn; +} + +/** + * Send a sound clip to the audio subsystem. + */ +void WriteSound(int32 *buf, int Count) +{ + //extern int EmulationPaused; + + SDL_LockAudio(); + + /*if (EmulationPaused == 0)*/ { // for some reason EmulationPaused is always 1, ignore it + while(Count) { + if(s_BufferIn == s_BufferSize) goto _exit; + + s_Buffer[s_BufferWrite] = *buf; + Count--; + s_BufferWrite = (s_BufferWrite + 1) % s_BufferSize; + + s_BufferIn++; + + buf++; + } + } +_exit: + SDL_UnlockAudio(); + + // If we have too much audio, wait a bit before accepting more. + // This keeps the lag in check. + while (GetBufferedSound() > 3 * GetBufferSize()) + usleep(1000); +} + +/** + * Pause (1) or unpause (0) the audio output. + */ +void SilenceSound(int n) +{ + // Not needed, the callback will write silence to buffer anyway + // otherwise it causes noticable lag + SDL_PauseAudio(n); +} + +/** + * Shut down the audio subsystem. + */ +int KillSound(void) { + FCEUI_Sound(0); + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + if (s_Buffer) { + free((void *) s_Buffer); + s_Buffer = 0; + } + return (0); +} + +/** + * Adjust the volume either down (-1), up (1), or to the default (0). + * Unmutes if mute was active before. + */ +void FCEUD_SoundVolumeAdjust(int n) { + int soundvolume; + g_config->getOption("SDL.SoundVolume", &soundvolume); + + switch (n) { + case -1: + soundvolume -= 10; + if (soundvolume < 0) { + soundvolume = 0; + } + break; + case 0: + soundvolume = 100; + break; + case 1: + soundvolume += 10; + if (soundvolume > 150) { + soundvolume = 150; + } + break; + } + + s_mute = 0; + FCEUI_SetSoundVolume(soundvolume); + g_config->setOption("SDL.SoundVolume", soundvolume); + + FCEU_DispMessage("Sound volume %d.", soundvolume); +} + +/** + * Toggles the sound on or off. + */ +void FCEUD_SoundToggle(void) { + if (s_mute) { + int soundvolume; + g_config->getOption("SDL.SoundVolume", &soundvolume); + + s_mute = 0; + FCEUI_SetSoundVolume(soundvolume); + FCEU_DispMessage("Sound mute off.", 0); + } else { + s_mute = 1; + FCEUI_SetSoundVolume(0); + FCEU_DispMessage("Sound mute on.", 0); + } +} diff --git a/src/drivers/dingux-sdl/dingoo-throttle.cpp b/src/drivers/dingux-sdl/dingoo-throttle.cpp new file mode 100644 index 000000000..80aa8165e --- /dev/null +++ b/src/drivers/dingux-sdl/dingoo-throttle.cpp @@ -0,0 +1,178 @@ +/// \file +/// \brief Handles emulation speed throttling using the DINGOO timing functions. + +#include +#include + +#include "dingoo.h" +#include "throttle.h" + +static const double Slowest = 0.015625; // 1/64x speed (around 1 fps on NTSC) +static const double Fastest = 32; // 32x speed (around 1920 fps on NTSC) +static const double Normal = 1.0; // 1x speed (around 60 fps on NTSC) + +uint64 Lasttime, Nexttime; +static long double desired_frametime; +static uint64 desired_frametime_us; +static int InFrame; +double g_fpsScale = Normal; // used by dingoo.cpp +bool MaxSpeed = false; + +uint64 get_ticks_us() +{ + struct timeval current_time; + gettimeofday(¤t_time, NULL); + + return (uint64)current_time.tv_sec * 1000000 + current_time.tv_usec; +} + +void delay_us(uint64 us_count) +{ +#if 1 // busy wait + uint64 start; + uint64 current; + + start = get_ticks_us(); + + do { + current = get_ticks_us(); + } while((uint64)(current - start) < us_count); +#else // normal wait, not reliable enough + usleep(us_count); +#endif +} + +/* LOGMUL = exp(log(2) / 3) + * + * This gives us a value such that if we do x*=LOGMUL three times, + * then after that, x is twice the value it was before. + * + * This gives us three speed steps per order of magnitude. + * + */ +#define LOGMUL 1.259921049894873 + +/** + * Refreshes the FPS throttling variables. + */ +void RefreshThrottleFPS() +{ + uint64 fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz + desired_frametime = 16777216.0l / (fps * g_fpsScale); + desired_frametime_us = (uint64)(desired_frametime * 1000000.0l); + + Lasttime=0; + Nexttime=0; + InFrame=0; + printf("desired_frametime: %i\n", desired_frametime_us); +} + +/** + * Perform FPS speed throttling by delaying until the next time slot. + */ +int SpeedThrottle() + +{ + //puts("SpeedThrottle"); + if(g_fpsScale >= 32) + { + return 0; /* Done waiting */ + } + uint64 time_left; + uint64 cur_time; + + if(!Lasttime) Lasttime = get_ticks_us(); + + if(!InFrame) { + InFrame = 1; + Nexttime = Lasttime + desired_frametime_us; + } + + cur_time = get_ticks_us(); + + if(cur_time >= Nexttime) + time_left = 0; + else + time_left = Nexttime - cur_time; + + if(time_left > 50000) { + time_left = 50000; + /* In order to keep input responsive, don't wait too long at once */ + /* 50 ms wait gives us a 20 Hz responsetime which is nice. */ + } else InFrame = 0; + + //printf("attempting to sleep %Ld ms, frame complete=%i\n", time_left, InFrame); + delay_us(time_left); + + if(!InFrame) + { + Lasttime = get_ticks_us(); + return 0; /* Done waiting */ + } + return 1; /* Must still wait some more */ +} + +/** + * Set the emulation speed throttling to the next entry in the speed table. + */ +void IncreaseEmulationSpeed(void) +{ +puts("IncreaseEmulationSpeed"); + g_fpsScale *= LOGMUL; + + if(g_fpsScale > Fastest) g_fpsScale = Fastest; + + RefreshThrottleFPS(); + + FCEU_DispMessage("emulation speed %.1f%%", g_fpsScale*100.0); +} + +/** + * Set the emulation speed throttling to the previous entry in the speed table. + */ +void DecreaseEmulationSpeed(void) +{ +puts("DecreaseEmulationSpeed"); + g_fpsScale /= LOGMUL; + if(g_fpsScale < Slowest) + g_fpsScale = Slowest; + + RefreshThrottleFPS(); + + FCEU_DispMessage("emulation speed %.1f%%", g_fpsScale*100.0); +} + +/** + * Set the emulation speed throttling to a specific value. + */ +void +FCEUD_SetEmulationSpeed(int cmd) +{ +puts("SetEmulationSpeed"); + MaxSpeed = false; + + switch(cmd) { + case EMUSPEED_SLOWEST: + g_fpsScale = Slowest; + break; + case EMUSPEED_SLOWER: + DecreaseEmulationSpeed(); + break; + case EMUSPEED_NORMAL: + g_fpsScale = Normal; + break; + case EMUSPEED_FASTER: + IncreaseEmulationSpeed(); + break; + case EMUSPEED_FASTEST: + g_fpsScale = Fastest; + MaxSpeed = true; + break; + default: + return; + } + + RefreshThrottleFPS(); + + FCEU_DispMessage("emulation speed %.1f%%", g_fpsScale*100.0); +} diff --git a/src/drivers/dingux-sdl/dingoo-video.cpp b/src/drivers/dingux-sdl/dingoo-video.cpp new file mode 100644 index 000000000..7d59c1a22 --- /dev/null +++ b/src/drivers/dingux-sdl/dingoo-video.cpp @@ -0,0 +1,446 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/// \file +/// \brief Handles the graphical game display for the SDL implementation. + +#include +#include +#include +#include +#include + +#include "dingoo.h" +#include "dingoo-video.h" +#include "scaler.h" + +#include "../common/vidblit.h" +#include "../../fceu.h" +#include "../../version.h" + +#include "dface.h" + +#include "../common/configSys.h" + +// GLOBALS +SDL_Surface *screen; +SDL_Surface *nes_screen; // 256x224 + +extern Config *g_config; + +// STATIC GLOBALS +static int s_curbpp; +static int s_srendline, s_erendline; +static int s_tlines; +static int s_inited; +static bool s_VideoModeSet = false; + +static int s_clipSides; +int s_fullscreen; +static int noframe; + +static int FDSTimer = 0; +int FDSSwitchRequested = 0; + +#define NWIDTH (256 - (s_clipSides ? 16 : 0)) +#define NOFFSET (s_clipSides ? 8 : 0) + +/* Blur effect taken from vidblit.cpp */ +uint32 palettetranslate[65536 * 4]; +static uint32 CBM[3] = { 63488, 2016, 31 }; +static uint16 s_psdl[256]; + +struct Color { + uint8 r; + uint8 g; + uint8 b; + uint8 unused; +}; + +static struct Color s_cpsdl[256]; + +#define BLUR_RED 30 +#define BLUR_GREEN 30 +#define BLUR_BLUE 20 + +#ifdef SDL_TRIPLEBUF +# define DINGOO_MULTIBUF SDL_TRIPLEBUF +#else +# define DINGOO_MULTIBUF SDL_DOUBLEBUF +#endif + +/** + * Attempts to destroy the graphical video display. Returns 0 on + * success, -1 on failure. + */ + +//draw input aids if we are fullscreen +bool FCEUD_ShouldDrawInputAids() { + return s_fullscreen != 0; +} + +int KillVideo() { + // return failure if the video system was not initialized + if (s_inited == 0) + return -1; + + SDL_FreeSurface(nes_screen); + s_inited = 0; + return 0; +} + +/** + * These functions determine an appropriate scale factor for fullscreen/ + */ +inline double GetXScale(int xres) { + return ((double) xres) / NWIDTH; +} +inline double GetYScale(int yres) { + return ((double) yres) / s_tlines; +} +void FCEUD_VideoChanged() { + int buf; + g_config->getOption("SDL.PAL", &buf); + if (buf) + PAL = 1; + else + PAL = 0; +} +/** + * Attempts to initialize the graphical video display. Returns 0 on + * success, -1 on failure. + */ +int InitVideo(FCEUGI *gi) { + FCEUI_printf("Initializing video...\n"); + + // load the relevant configuration variables + g_config->getOption("SDL.Fullscreen", &s_fullscreen); + g_config->getOption("SDL.ClipSides", &s_clipSides); + + // check the starting, ending, and total scan lines + FCEUI_GetCurrentVidSystem(&s_srendline, &s_erendline); + s_tlines = s_erendline - s_srendline + 1; + + int brightness; + g_config->getOption("SDL.Brightness", &brightness); + + s_inited = 1; + FDSSwitchRequested = 0; + + //int desbpp; + //g_config->getOption("SDL.SpecialFilter", &s_eefx); + + SetPaletteBlitToHigh((uint8 *) s_cpsdl); + + //Init video subsystem + if (!(SDL_WasInit(SDL_INIT_VIDEO) & SDL_INIT_VIDEO)) + if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) { + fprintf(stderr,"%s",SDL_GetError()); + } + + // initialize dingoo video mode + if (!s_VideoModeSet) { + uint32 vm = 0; // 0 - 320x240, 1 - 400x240, 2 - 480x272 + + #define NUMOFVIDEOMODES 3 + struct { + uint32 x; + uint32 y; + } VModes[NUMOFVIDEOMODES] = { + {320, 240}, + {400, 240}, + {480, 272} + }; + + for(vm = NUMOFVIDEOMODES-1; vm >= 0; vm--) + { + if(SDL_VideoModeOK(VModes[vm].x, VModes[vm].y, 16, SDL_HWSURFACE | DINGOO_MULTIBUF) != 0) + { + screen = SDL_SetVideoMode(VModes[vm].x, VModes[vm].y, 16, SDL_HWSURFACE | DINGOO_MULTIBUF); + s_VideoModeSet = true; + break; + } + } + } + + // a hack to bind inner buffer to nes_screen surface + extern uint8 *XBuf; + + nes_screen = SDL_CreateRGBSurfaceFrom(XBuf, 256, 224, 8, 256, 0, 0, 0, 0); + if(!nes_screen) + printf("Error in SDL_CreateRGBSurfaceFrom\n"); + SDL_SetPalette(nes_screen, SDL_LOGPAL, (SDL_Color *)s_cpsdl, 0, 256); + + SDL_ShowCursor(0); + + /* clear screen */ + dingoo_clear_video(); + + return 0; +} + +/** + * Toggles the full-screen display. + */ +void ToggleFS() { +} + +/* Taken from /src/drivers/common/vidblit.cpp */ +static void CalculateShift(uint32 *CBM, int *cshiftr, int *cshiftl) +{ + int a, x, z, y; + cshiftl[0] = cshiftl[1] = cshiftl[2] = -1; + for (a = 0; a < 3; a++) { + for (x = 0, y = -1, z = 0; x < 32; x++) { + if (CBM[a] & (1 << x)) { + if (cshiftl[a] == -1) + cshiftl[a] = x; + z++; + } + } + cshiftr[a] = (8 - z); + } +} + +void SetPaletteBlitToHigh(uint8 *src) +{ + int cshiftr[3]; + int cshiftl[3]; + int x, y; + + CalculateShift(CBM, cshiftr, cshiftl); + + for (x = 0; x < 65536; x++) { + uint16 lower, upper; + + lower = (src[((x & 255) << 2)] >> cshiftr[0]) << cshiftl[0]; + lower |= (src[((x & 255) << 2) + 1] >> cshiftr[1]) << cshiftl[1]; + lower |= (src[((x & 255) << 2) + 2] >> cshiftr[2]) << cshiftl[2]; + upper = (src[((x >> 8) << 2)] >> cshiftr[0]) << cshiftl[0]; + upper |= (src[((x >> 8) << 2) + 1] >> cshiftr[1]) << cshiftl[1]; + upper |= (src[((x >> 8) << 2) + 2] >> cshiftr[2]) << cshiftl[2]; + + palettetranslate[x] = lower | (upper << 16); + } +} + +/** + * Sets the color for a particular index in the palette. + */ +void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b) +{ + s_cpsdl[index].r = r; + s_cpsdl[index].g = g; + s_cpsdl[index].b = b; + + //uint32 col = (r << 16) | (g << 8) | b; + //s_psdl[index] = (uint16)COL32_TO_16(col); + s_psdl[index] = dingoo_video_color15(r, g, b); + + if (index == 255) + SetPaletteBlitToHigh((uint8 *) s_cpsdl); +} + +/** + * Gets the color for a particular index in the palette. + */ +void FCEUD_GetPalette(uint8 index, uint8 *r, uint8 *g, uint8 *b) +{ + *r = s_cpsdl[index].r; + *g = s_cpsdl[index].g; + *b = s_cpsdl[index].b; +} + +uint16 * FCEUD_GetPaletteArray16() +{ + return s_psdl; +} + +/** + * Pushes the palette structure into the underlying video subsystem. + */ +static void RedoPalette() { +} + +// XXX soules - console lock/unlock unimplemented? + +///Currently unimplemented. +void LockConsole() { +} + +///Currently unimplemented. +void UnlockConsole() { +} + +#define READU16(x) (uint16) ((uint16)(x)[0] | (uint16)(x)[1] << 8) + +/** + * Pushes the given buffer of bits to the screen. + */ +void BlitScreen(uint8 *XBuf) { + int x, x2, y, y2; + + // Taken from fceugc + // FDS switch disk requested - need to eject, select, and insert + // but not all at once! + if (FDSSwitchRequested) { + switch (FDSSwitchRequested) { + case 1: + FDSSwitchRequested++; + FCEUI_FDSInsert(); // eject disk + FDSTimer = 0; + break; + case 2: + if (FDSTimer > 60) { + FDSSwitchRequested++; + FDSTimer = 0; + FCEUI_FDSSelect(); // select other side + FCEUI_FDSInsert(); // insert disk + } + break; + case 3: + if (FDSTimer > 200) { + FDSSwitchRequested = 0; + FDSTimer = 0; + } + break; + } + FDSTimer++; + } + + // TODO - Move these to its own file? + if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); + + register uint8 *pBuf = XBuf; + + if(s_fullscreen == 3) { // fullscreen smooth + if (s_clipSides) { + upscale_320x240_bilinearish_clip((uint32 *)screen->pixels, (uint8 *)XBuf + 256 * 8, 256); + } else { + upscale_320x240_bilinearish_noclip((uint32 *)screen->pixels, (uint8 *)XBuf + 256 * 8, 256); + } + } else if(s_fullscreen == 2) { // fullscreen + switch(screen->w) { + case 480: upscale_480x272((uint32 *)screen->pixels, (uint8 *)XBuf + 256 * 8); break; + case 400: upscale_384x240((uint32 *)screen->pixels, (uint8 *)XBuf + 256 * 8); break; + case 320: upscale_320x240((uint32 *)screen->pixels, (uint8 *)XBuf + 256 * 8); break; + } + } else if(s_fullscreen == 1) { // aspect fullscreen + switch(screen->w) { + case 480: upscale_384x272((uint32 *)screen->pixels, (uint8 *)XBuf + 256 * 8); break; + case 400: + case 320: + pBuf += (s_srendline * 256) + 8; + register uint16 *dest = (uint16 *) screen->pixels; + //dest += (320 * s_srendline) + 20; + dest += (screen->w * s_srendline) + (screen->w - 280) / 2 + ((screen->h - 240) / 2) * screen->w; + + // semi fullscreen no blur + for (y = s_tlines; y; y--) { + for (x = 240; x; x -= 6) { + __builtin_prefetch(dest + 2, 1); + *dest++ = s_psdl[*pBuf]; + *dest++ = s_psdl[*(pBuf + 1)]; + *dest++ = s_psdl[*(pBuf + 2)]; + *dest++ = s_psdl[*(pBuf + 3)]; + *dest++ = s_psdl[*(pBuf + 3)]; + *dest++ = s_psdl[*(pBuf + 4)]; + *dest++ = s_psdl[*(pBuf + 5)]; + pBuf += 6; + } + pBuf += 16; + //dest += 40; + dest += screen->w - 280; + } + } + } else { // native res + //int pinc = (320 - NWIDTH) >> 1; + int32 pinc = (screen->w - NWIDTH) >> 1; + + //SDL_Rect dstrect; + + // center windows + //dstrect.x = (screen->w - 256) / 2; + //dstrect.y = (screen->h - 224) / 2; + + // doesn't work in rzx-50 dingux + //SDL_BlitSurface(nes_screen, 0, screen, &dstrect); + + register uint32 *dest = (uint32 *) screen->pixels; + + // XXX soules - not entirely sure why this is being done yet + pBuf += (s_srendline * 256) + NOFFSET; + //dest += (s_srendline * 320) + pinc >> 1; + dest += (screen->w/2 * s_srendline) + pinc / 2 + ((screen->h - 240) / 4) * screen->w; + + for (y = s_tlines; y; y--, pBuf += 256 - NWIDTH) { + for (x = NWIDTH >> 3; x; x--) { + __builtin_prefetch(dest + 4, 1); + *dest++ = palettetranslate[*(uint16 *) pBuf]; + *dest++ = palettetranslate[*(uint16 *) (pBuf + 2)]; + *dest++ = palettetranslate[*(uint16 *) (pBuf + 4)]; + *dest++ = palettetranslate[*(uint16 *) (pBuf + 6)]; + pBuf += 8; + } + dest += pinc; + } + } + + if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); + SDL_Flip(screen); +} + +/** + * Converts an x-y coordinate in the window manager into an x-y + * coordinate on FCEU's screen. + */ +uint32 PtoV(uint16 x, uint16 y) { + y = (uint16) ((double) y); + x = (uint16) ((double) x); + if (s_clipSides) { + x += 8; + } + y += s_srendline; + return (x | (y << 16)); +} + +bool disableMovieMessages = false; +bool FCEUI_AviDisableMovieMessages() { + if (disableMovieMessages) + return true; + + return false; +} + +void FCEUI_SetAviDisableMovieMessages(bool disable) { + disableMovieMessages = disable; +} + +//clear all screens (for multiple-buffering) +void dingoo_clear_video(void) { + SDL_FillRect(screen,NULL,SDL_MapRGBA(screen->format, 0, 0, 0, 255)); + SDL_Flip(screen); + SDL_FillRect(screen,NULL,SDL_MapRGBA(screen->format, 0, 0, 0, 255)); + SDL_Flip(screen); +#ifdef SDL_TRIPLEBUF + SDL_FillRect(screen,NULL,SDL_MapRGBA(screen->format, 0, 0, 0, 255)); + SDL_Flip(screen); +#endif +} diff --git a/src/drivers/dingux-sdl/dingoo-video.h b/src/drivers/dingux-sdl/dingoo-video.h new file mode 100644 index 000000000..9925ef8f2 --- /dev/null +++ b/src/drivers/dingux-sdl/dingoo-video.h @@ -0,0 +1,8 @@ + +uint32 PtoV(uint16 x, uint16 y); +bool FCEUD_ShouldDrawInputAids(); +unsigned short *FCEUD_GetScreen(); + +#define dingoo_video_color15(R,G,B) ((((R)&0xF8)<<8)|(((G)&0xFC)<<3)|(((B)&0xF8)>>3)) + +extern void dingoo_clear_video(void); diff --git a/src/drivers/dingux-sdl/dingoo.cpp b/src/drivers/dingux-sdl/dingoo.cpp new file mode 100644 index 000000000..e891c5813 --- /dev/null +++ b/src/drivers/dingux-sdl/dingoo.cpp @@ -0,0 +1,927 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "throttle.h" +#include "config.h" + +#include "../common/cheat.h" +#include "../../fceu.h" +#include "../../movie.h" +#include "../../version.h" +#ifdef _S9XLUA_H +#include "../../fceulua.h" +#endif + +#include "input.h" +#include "dface.h" + +#include "gui/gui.h" + +#include "SDL/SDL.h" +#include "dingoo.h" +#include "dingoo-video.h" +#include "dummy-netplay.h" + +#include "../common/configSys.h" +#include "../../oldmovie.h" +#include "../../types.h" + +#ifdef CREATE_AVI +#include "../videolog/nesvideos-piece.h" +#endif + +#ifdef WIN32 +#include +#endif + +extern double g_fpsScale; + +extern bool MaxSpeed; + +static int isloaded; + +int closeFinishedMovie = 0; + +// NOTE: an ugly hack to get +// mouse support +int showmouse = 0; +int mousespeed = 3; + +int showfps = 0; + +int master_volume = 100; + +bool turbo = false; + +int CloseGame(void); + +static int inited = 0; + +int eoptions = 0; + +static int fpsthrottle = 0; +static int frameskip = 0; + +static void DriverKill(void); +static int DriverInitialize(FCEUGI *gi); +int gametype = 0; +#ifdef CREATE_AVI +int mutecapture; +#endif +static int noconfig; + +int pal_emulation; +int dendy; +bool swapDuty; + +// originally in src/drivers/common/vidblit.cpp +bool paldeemphswap = 0; + +char* DriverUsage = "\ + Option Value Description\n\ + --pal {0|1} Use PAL timing.\n\ + --newppu {0|1} Enable the new PPU core. (WARNING: May break savestates)\n\ + --inputcfg d Configures input device d on startup.\n\ + --gamegenie {0|1} Enable emulated Game Genie.\n\ + --frameskip x Set # of frames to skip per emulated frame.\n\ + --xres x Set horizontal resolution for full screen mode.\n\ + --yres x Set vertical resolution for full screen mode.\n\ + --autoscale {0|1} Enable autoscaling in fullscreen. \n\ + --keepratio {0|1} Keep native NES aspect ratio when autoscaling. \n\ + --(x/y)scale x Multiply width/height by x. \n\ + (Real numbers >0 with OpenGL, otherwise integers >0).\n\ + --(x/y)stretch {0|1} Stretch to fill surface on x/y axis (OpenGL only).\n\ + --bpp {8|16|32} Set bits per pixel.\n\ + --opengl {0|1} Enable OpenGL support.\n\ + --fullscreen {0|1} Enable full screen mode.\n\ + --noframe {0|1} Hide title bar and window decorations.\n\ + --special {1-4} Use special video scaling filters\n\ + (1 = hq2x 2 = Scale2x 3 = hq3x 4 = Scale3x)\n\ + --palette f Load custom global palette from file f.\n\ + --sound {0|1} Enable sound.\n\ + --soundrate x Set sound playback rate to x Hz.\n\ + --soundq {0|1|2} Set sound quality. (0=Low;1=High;2=Very High)\n\ + --soundbufsize x Set sound buffer size to x ms.\n\ + --volume {0-256} Set volume to x.\n\ + --soundrecord f Record sound to file f.\n\ + --input(1,2) d Set the input device for input 1 or 2.\n\ + Devices: gamepad zapper powerpad.0 powerpad.1 arkanoid\n\ + --input(3,4) d Set the famicom expansion device for input(3, 4)\n\ + Devices: quizking hypershot mahjong toprider ftrainer\n\ + familykeyboard oekakids arkanoid shadow bworld 4player\n\ + --playmov f Play back a recorded FCM/FM2 movie from filename f.\n\ + --pauseframe x Pause movie playback at frame x.\n\ + --fcmconvert f Convert fcm movie file f to fm2.\n\ + --ripsubs f Convert movie's subtitles to srt\n\ + --subtitles {0,1} Enable subtitle display\n\ + --fourscore {0,1} Enable fourscore emulation\n\ + --no-config {0,1} Use default config file and do not save\n\ + --net s Connect to server 's' for TCP/IP network play.\n\ + --port x Use TCP/IP port x for network play.\n\ + --user x Set the nickname to use in network play.\n\ + --pass x Set password to use for connecting to the server.\n\ + --netkey s Use string 's' to create a unique session for the game loaded.\n\ + --players x Set the number of local players.\n"; + +// these should be moved to the man file +//--nospritelim {0|1} Disables the 8 sprites per scanline limitation.\n +//--trianglevol {0-256} Sets Triangle volume.\n +//--square1vol {0-256} Sets Square 1 volume.\n +//--square2vol {0-256} Sets Square 2 volume.\n +//--noisevol {0-256} Sets Noise volume.\n +//--pcmvol {0-256} Sets PCM volume.\n +//--lowpass {0|1} Enables low-pass filter if x is nonzero.\n +//--doublebuf {0|1} Enables SDL double-buffering if x is nonzero.\n +//--slend {0-239} Sets the last drawn emulated scanline.\n +//--ntsccolor {0|1} Emulates an NTSC TV's colors.\n +//--hue x Sets hue for NTSC color emulation.\n +//--tint x Sets tint for NTSC color emulation.\n +//--slstart {0-239} Sets the first drawn emulated scanline.\n +//--clipsides {0|1} Clips left and rightmost 8 columns of pixels.\n + +// global configuration object +Config *g_config; + +static void ShowUsage(char *prog) { + printf("\nUsage is as follows:\n%s filename\n\n", prog); + puts("Options:"); + puts(DriverUsage); +#ifdef _S9XLUA_H + puts ("--loadlua f Loads lua script from filename f."); +#endif +#ifdef CREATE_AVI + puts ("--videolog c Calls mencoder to grab the video and audio streams to\n encode them. Check the documentation for more on this."); + puts ("--mute {0|1} Mutes FCEUX while still passing the audio stream to\n mencoder."); +#endif + puts(""); +} + +/** + * Prints an error string to STDOUT. + */ +void FCEUD_PrintError(char *s) { + puts(s); +} + +/** + * Prints the given string to STDOUT. + */ +void FCEUD_Message(char *s) { + fputs(s, stdout); +} + +/** + * Loads a game, given a full path/filename. The driver code must be + * initialized after the game is loaded, because the emulator code + * provides data necessary for the driver code(number of scanlines to + * render, what virtual input devices to use, etc.). + */ +int LoadGame(const char *path) { + CloseGame(); + if (!FCEUI_LoadGame(path, 1)) { + return 0; + } + ParseGIInput(GameInfo); + RefreshThrottleFPS(); + + // Reload game config or default config + g_config->reload(FCEU_MakeFName(FCEUMKF_CFG, 0, 0)); + +#ifdef FRAMESKIP + // Update frameskip value + g_config->getOption("SDL.Frameskip", &frameskip); +#endif + + if (!DriverInitialize(GameInfo)) { + return (0); + } + + // set pal/ntsc + int id; + g_config->getOption("SDL.PAL", &id); + if (id) + FCEUI_SetVidSystem(1); + else + FCEUI_SetVidSystem(0); + + std::string filename; + g_config->getOption("SDL.Sound.RecordFile", &filename); + if (filename.size()) { + if (!FCEUI_BeginWaveRecord(filename.c_str())) { + g_config->setOption("SDL.Sound.RecordFile", ""); + } + } + + // Set mouse cursor's movement speed + g_config->getOption("SDL.MouseSpeed", &mousespeed); + g_config->getOption("SDL.ShowMouseCursor", &showmouse); + + // Show or not to show fps, that is the cuestion ... + g_config->getOption("SDL.ShowFPS", &showfps); + g_config->getOption("SDL.FPSThrottle", &fpsthrottle); + + isloaded = 1; + + FCEUD_NetworkConnect(); + return 1; +} + +/** + * Closes a game. Frees memory, and deinitializes the drivers. + */ +int CloseGame() { + std::string filename; + + if (!isloaded) { + return (0); + } + + FCEUI_CloseGame(); + DriverKill(); + isloaded = 0; + GameInfo = 0; + + g_config->getOption("SDL.Sound.RecordFile", &filename); + if (filename.size()) { + FCEUI_EndWaveRecord(); + } + + InputUserActiveFix(); + return (1); +} + +void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count); + +static void DoFun(int fskip) { + uint8 *gfx; + int32 *sound; + int32 ssize; + extern uint8 PAL; + int done = 0, timer = 0, ticks = 0, tick = 0, fps = 0; + unsigned int frame_limit = 60, frametime = 16667; + + while (GameInfo) { + /* Frameskip decision based on the audio buffer */ + if (!fpsthrottle) { + // Fill up the audio buffer with up to 6 frames dropped. + int FramesSkipped = 0; + while (GameInfo + && GetBufferedSound() < GetBufferSize() * 3 / 2 + && ++FramesSkipped < 6) { + FCEUI_Emulate(&gfx, &sound, &ssize, 1); + FCEUD_Update(NULL, sound, ssize); + } + + // Force at least one frame to be displayed. + if (GameInfo) { + FCEUI_Emulate(&gfx, &sound, &ssize, 0); + FCEUD_Update(gfx, sound, ssize); + } + + // Then render all frames while audio is sufficient. + while (GameInfo + && GetBufferedSound() > GetBufferSize() * 3 / 2) { + FCEUI_Emulate(&gfx, &sound, &ssize, 0); + FCEUD_Update(gfx, sound, ssize); + } + } + else { + FCEUI_Emulate(&gfx, &sound, &ssize, 0); + FCEUD_Update(gfx, sound, ssize); + } + } + +} + +/** + * Initialize all of the subsystem drivers: video, audio, and joystick. + */ +static int DriverInitialize(FCEUGI *gi) { + if (InitVideo(gi) < 0) + return 0; + inited |= 4; + + if (InitSound()) + inited |= 1; + + if (InitJoysticks()) + inited |= 2; + + int fourscore = 0; + g_config->getOption("SDL.FourScore", &fourscore); + eoptions &= ~EO_FOURSCORE; + if (fourscore) + eoptions |= EO_FOURSCORE; + + InitInputInterface(); + + FCEUGUI_Reset(gi); + return 1; +} + +/** + * Resets sound and video subsystem drivers. + */ +int FCEUD_DriverReset() { + // Save game config file + g_config->save(FCEU_MakeFName(FCEUMKF_CFG, 0, 0)); + +#ifdef FRAMESKIP + // Update frameskip value + g_config->getOption("SDL.Frameskip", &frameskip); +#endif + + // Kill drivers first + if (inited & 4) + KillVideo(); + if (inited & 1) + KillSound(); + + if (InitVideo(GameInfo) < 0) + return 0; + inited |= 4; + + if (InitSound()) + inited |= 1; + + // Set mouse cursor's movement speed + g_config->getOption("SDL.MouseSpeed", &mousespeed); + g_config->getOption("SDL.ShowMouseCursor", &showmouse); + + // Set showfps variable and throttle + g_config->getOption("SDL.ShowFPS", &showfps); + g_config->getOption("SDL.FPSThrottle", &fpsthrottle); + + return 1; +} + +/** + * Shut down all of the subsystem drivers: video, audio, and joystick. + */ +static void DriverKill() { + // Save only game config file + g_config->save(FCEU_MakeFName(FCEUMKF_CFG, 0, 0)); + + if (inited & 2) + KillJoysticks(); + if (inited & 4) + KillVideo(); + if (inited & 1) + KillSound(); + inited = 0; +} + +/** + * Update the video, audio, and input subsystems with the provided + * video (XBuf) and audio (Buffer) information. + */ +void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count) +{ + // Write the audio before the screen, because writing the screen induces + // a delay after double-buffering. + if (Count) WriteSound(Buffer, Count); + + if (XBuf && (inited & 4)) BlitScreen(XBuf); + + FCEUD_UpdateInput(); +} + +/** + * Opens a file to be read a byte at a time. + */ +EMUFILE_FILE* FCEUD_UTF8_fstream(const char *fn, const char *m) +{ + std::ios_base::openmode mode = std::ios_base::binary; + if(!strcmp(m,"r") || !strcmp(m,"rb")) + mode |= std::ios_base::in; + else if(!strcmp(m,"w") || !strcmp(m,"wb")) + mode |= std::ios_base::out | std::ios_base::trunc; + else if(!strcmp(m,"a") || !strcmp(m,"ab")) + mode |= std::ios_base::out | std::ios_base::app; + else if(!strcmp(m,"r+") || !strcmp(m,"r+b")) + mode |= std::ios_base::in | std::ios_base::out; + else if(!strcmp(m,"w+") || !strcmp(m,"w+b")) + mode |= std::ios_base::in | std::ios_base::out | std::ios_base::trunc; + else if(!strcmp(m,"a+") || !strcmp(m,"a+b")) + mode |= std::ios_base::in | std::ios_base::out | std::ios_base::app; + return new EMUFILE_FILE(fn, m); +} + + +/** + * Opens a file, C++ style, to be read a byte at a time. + */ +FILE *FCEUD_UTF8fopen(const char *fn, const char *mode) { + return (fopen(fn, mode)); +} + +static char *s_linuxCompilerString = "g++ " __VERSION__; +/** + * Returns the compiler string. + */ +const char *FCEUD_GetCompilerString() { + return (const char *) s_linuxCompilerString; +} + +/** + * Unimplemented. + */ +void FCEUD_DebugBreakpoint() { + return; +} + +/** + * Unimplemented. + */ +void FCEUD_TraceInstruction() { + return; +} + +/** + * Convert FCM movie to FM2 . + * Returns 1 on success, otherwise 0. + */ +int FCEUD_ConvertMovie(const char *name, char *outname) { + int okcount = 0; + std::string infname = name; + + // produce output filename + std::string tmp; + size_t dot = infname.find_last_of("."); + if (dot == std::string::npos) + tmp = infname + ".fm2"; + else + tmp = infname.substr(0, dot) + ".fm2"; + + MovieData md; + EFCM_CONVERTRESULT result = convert_fcm(md, infname); + + if (result == FCM_CONVERTRESULT_SUCCESS) { + okcount++; + EMUFILE_FILE* outf = FCEUD_UTF8_fstream(tmp, "wb"); + md.dump(outf, false); + delete outf; + FCEUD_Message("Your file has been converted to FM2.\n"); + + strncpy(outname, tmp.c_str(), 128); + return 1; + } else { + FCEUD_Message("Something went wrong while converting your file...\n"); + return 0; + } + + return 0; +} + +/* + * Loads a movie, if fcm movie will convert first. And will + * ask for rom too, returns 1 on success, 0 otherwise. + */ +int FCEUD_LoadMovie(const char *name, char *romname) { + std::string s = std::string(name); + + // Convert to fm2 if necessary ... + if (s.find(".fcm") != std::string::npos) { + char tmp[128]; + if (!FCEUD_ConvertMovie(name, tmp)) + return 0; + s = std::string(tmp); + } + + if (s.find(".fm2") != std::string::npos) { + // WARNING: Must load rom first + // Launch file browser to search for movies's rom file. + const char *types[] = { ".nes", ".fds", ".zip", NULL }; + if (!RunFileBrowser(NULL, romname, types, "Select movie's rom file")) { + FCEUI_printf("WARNING: Must load a rom to play the movie! %s\n", + s.c_str()); + return 0; + } + + if (LoadGame(romname) != 1) + return -1; + + static int pauseframe; + g_config->getOption("SDL.PauseFrame", &pauseframe); + g_config->setOption("SDL.PauseFrame", 0); + FCEUI_printf("Playing back movie located at %s\n", s.c_str()); + FCEUI_LoadMovie(s.c_str(), false, pauseframe ? pauseframe : false); + } else { + // Must be a rom file ... + return 0; + } + + return 1; +} + +/** + * The main loop for the SDL. + */ +#ifdef WIN32 +#undef main +#endif +int main(int argc, char *argv[]) { + + int error; + + FCEUD_Message("\nStarting " FCEU_NAME_AND_VERSION "...\n"); + +#ifdef WIN32 + /* Taken from win32 sdl_main.c */ + SDL_SetModuleHandle(GetModuleHandle(NULL)); +#endif + + /* SDL_INIT_VIDEO Needed for (joystick config) event processing? */ + if(SDL_Init(SDL_INIT_VIDEO)) { + printf("Could not initialize SDL: %s.\n", SDL_GetError()); + return(-1); + } + + // Initialize the configuration system + g_config = InitConfig(); + + if (!g_config) { + SDL_Quit(); + return -1; + } + + // Initialize the fceu320 gui + FCEUGUI_Init(NULL); + + // initialize the infrastructure + error = FCEUI_Initialize(); + + if (error != 1) { + ShowUsage(argv[0]); + SDL_Quit(); + return -1; + } + + int romIndex = g_config->parse(argc, argv); + + // This is here so that a default fceux.cfg will be created on first + // run, even without a valid ROM to play. + // Unless, of course, there's actually --no-config given + // mbg 8/23/2008 - this is also here so that the inputcfg routines can + // have a chance to dump the new inputcfg to the fceux.cfg + // in case you didnt specify a rom filename + g_config->getOption("SDL.NoConfig", &noconfig); + if (!noconfig) + g_config->save(); + + std::string s; + g_config->getOption("SDL.InputCfg", &s); + + // update the input devices + UpdateInput(g_config); + + // check for a .fcm file to convert to .fm2 + g_config->getOption("SDL.FCMConvert", &s); + g_config->setOption("SDL.FCMConvert", ""); + + if (!s.empty()) { + int okcount = 0; + std::string infname = s.c_str(); + // produce output filename + std::string outname; + size_t dot = infname.find_last_of("."); + if (dot == std::string::npos) + outname = infname + ".fm2"; + else + outname = infname.substr(0, dot) + ".fm2"; + + MovieData md; + EFCM_CONVERTRESULT result = convert_fcm(md, infname); + + if (result == FCM_CONVERTRESULT_SUCCESS) { + okcount++; + EMUFILE_FILE* outf = FCEUD_UTF8_fstream(outname, "wb"); + md.dump(outf, false); + delete outf; + FCEUD_Message("Your file has been converted to FM2.\n"); + } else + FCEUD_Message( + "Something went wrong while converting your file...\n"); + + DriverKill(); + SDL_Quit(); + return 0; + } + + // check to see if movie messages are disabled + int mm; + g_config->getOption("SDL.MovieMsg", &mm); + FCEUI_SetAviDisableMovieMessages(mm == 0); + + // check for a .fm2 file to rip the subtitles + g_config->getOption("SDL.RipSubs", &s); + g_config->setOption("SDL.RipSubs", ""); + if (!s.empty()) { + MovieData md; + std::string infname; + infname = s.c_str(); + FCEUFILE *fp = FCEU_fopen(s.c_str(), 0, "rb", 0); + + // load the movie and and subtitles + extern bool LoadFM2(MovieData&, EMUFILE*, int, bool); + LoadFM2(md, fp->stream, INT_MAX, false); + LoadSubtitles(md); // fill subtitleFrames and subtitleMessages + delete fp; + + // produce .srt file's name and open it for writing + std::string outname; + size_t dot = infname.find_last_of("."); + if (dot == std::string::npos) + outname = infname + ".srt"; + else + outname = infname.substr(0, dot) + ".srt"; + FILE *srtfile; + srtfile = fopen(outname.c_str(), "w"); + + if (srtfile != NULL) { + extern std::vector subtitleFrames; + extern std::vector subtitleMessages; + float fps = (md.palFlag == 0 ? 60.0988 : 50.0069); // NTSC vs PAL + float subduration = 3; // seconds for the subtitles to be displayed + for (int i = 0; i < subtitleFrames.size(); i++) { + fprintf(srtfile, "%i\n", i + 1); // starts with 1, not 0 + double seconds, ms, endseconds, endms; + seconds = subtitleFrames[i] / fps; + if (i + 1 < subtitleFrames.size()) { // there's another subtitle coming after this one + if (subtitleFrames[i + 1] - subtitleFrames[i] < subduration + * fps) { // avoid two subtitles at the same time + endseconds = (subtitleFrames[i + 1] - 1) / fps; // frame x: subtitle1; frame x+1 subtitle2 + } else + endseconds = seconds + subduration; + } else + endseconds = seconds + subduration; + + ms = modf(seconds, &seconds); + endms = modf(endseconds, &endseconds); + // this is just beyond ugly, don't show it to your kids + fprintf( + srtfile, + "%02.0f:%02d:%02d,%03d --> %02.0f:%02d:%02d,%03d\n", // hh:mm:ss,ms --> hh:mm:ss,ms + floor(seconds / 3600), (int) floor(seconds / 60) % 60, + (int) floor(seconds) % 60, (int) (ms * 1000), floor( + endseconds / 3600), + (int) floor(endseconds / 60) % 60, (int) floor( + endseconds) % 60, (int) (endms * 1000)); + fprintf(srtfile, "%s\n\n", subtitleMessages[i].c_str()); // new line for every subtitle + } + fclose(srtfile); + printf("%d subtitles have been ripped.\n", + (int) subtitleFrames.size()); + } else + FCEUD_Message("Couldn't create output srt file...\n"); + + DriverKill(); + SDL_Quit(); + return 0; + } + + // check for --help or -h and display usage + for (int i = 0; i < argc; i++) { + if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { + ShowUsage(argv[0]); + SDL_Quit(); + return 0; + } + } + + /* + // if there is no rom specified launch the file browser + if(romIndex <= 0) { + ShowUsage(argv[0]); + FCEUD_Message("\nError parsing command line arguments\n"); + SDL_Quit(); + return -1; + } + */ + + // update the emu core + UpdateEMUCore(g_config); + +#ifdef CREATE_AVI + g_config->getOption("SDL.VideoLog", &s); + g_config->setOption("SDL.VideoLog", ""); + if(!s.empty()) { + NESVideoSetVideoCmd(s.c_str()); + LoggingEnabled = 1; + g_config->getOption("SDL.MuteCapture", &mutecapture); + } else + mutecapture = 0; +#endif + + { + int id; + g_config->getOption("SDL.InputDisplay", &id); + extern int input_display; + input_display = id; + // not exactly an id as an true/false switch; still better than creating another int for that + g_config->getOption("SDL.SubtitleDisplay", &id); + extern bool movieSubtitles; + movieSubtitles = id != 0; + } + + // load the hotkeys from the config life + setHotKeys(); + + if (romIndex >= 0) { + // load the specified game + error = LoadGame(argv[romIndex]); + if (error != 1) { + DriverKill(); + SDL_Quit(); + return -1; + } + } else { + // Launch file browser + const char *types[] = { ".nes", ".fds", ".zip", ".fcm", ".fm2", ".nsf", + NULL }; + char filename[128], romname[128]; + + InitVideo(0); inited |= 4; // Hack to init video mode before running gui + + #ifdef WIN32 + if (!RunFileBrowser("D:\\", filename, types)) { + #else + if (!RunFileBrowser(NULL, filename, types)) { + #endif + DriverKill(); + SDL_Quit(); + return -1; + } + + // Is this a movie? + if (!(error = FCEUD_LoadMovie(filename, romname))) + error = LoadGame(filename); + + if (error != 1) { + DriverKill(); + SDL_Quit(); + return -1; + } + } + + // movie playback + g_config->getOption("SDL.Movie", &s); + g_config->setOption("SDL.Movie", ""); + if (s != "") { + if (s.find(".fm2") != std::string::npos) { + static int pauseframe; + g_config->getOption("SDL.PauseFrame", &pauseframe); + g_config->setOption("SDL.PauseFrame", 0); + FCEUI_printf("Playing back movie located at %s\n", s.c_str()); + FCEUI_LoadMovie(s.c_str(), false, pauseframe ? pauseframe : false); + } else + FCEUI_printf("Sorry, I don't know how to play back %s\n", s.c_str()); + } + +#ifdef _S9XLUA_H + // load lua script if option passed + g_config->getOption("SDL.LuaScript", &s); + g_config->setOption("SDL.LuaScript", ""); + if (s != "") + FCEU_LoadLuaCode(s.c_str()); +#endif + + { + int id; + g_config->getOption("SDL.NewPPU", &id); + if (id) + newppu = 1; + } + + g_config->getOption("SDL.Frameskip", &frameskip); + + // loop playing the game + DoFun(frameskip); + + CloseGame(); + + // exit the infrastructure + FCEUI_Kill(); + SDL_Quit(); + return 0; +} + +/** + * Get the time in ticks. + */ +uint64 FCEUD_GetTime() { + return SDL_GetTicks(); +} + +/** + * Get the tick frequency in Hz. + */ +uint64 FCEUD_GetTimeFreq(void) +{ + return 1000; +} + +/** + * Prints a textual message without adding a newline at the end. + * + * @param text The text of the message. + * + * TODO: This function should have a better name. + **/ +void FCEUD_Message(const char *text) { + fputs(text, stdout); +#ifdef _GTK + pushOutputToGTK(text); +#endif +} + +/** + * Shows an error message in a message box. + * (For now: prints to stderr.) + * + * @param errormsg Text of the error message. + **/ +void FCEUD_PrintError(const char *errormsg) { + fprintf(stderr, "%s\n", errormsg); +} + +// dummy functions + +#define DUMMY(__f) void __f(void) {printf("%s\n", #__f); FCEU_DispMessage("Not implemented.", 0);} +DUMMY(FCEUD_HideMenuToggle) +DUMMY(FCEUD_MovieReplayFrom) +DUMMY(FCEUD_ToggleStatusIcon) +DUMMY(FCEUD_AviRecordTo) +DUMMY(FCEUD_AviStop) +void FCEUI_AviVideoUpdate(const unsigned char* buffer) { +} +int FCEUD_ShowStatusIcon(void) { + return 0; +} +bool FCEUI_AviIsRecording(void) { + return false; +} +void FCEUI_UseInputPreset(int preset) { +} +bool FCEUD_PauseAfterPlayback() { + return false; +} +// These are actually fine, but will be unused and overriden by the current UI code. +void FCEUD_TurboOn(void) { + NoWaiting |= 1; +} +void FCEUD_TurboOff(void) { + NoWaiting &= ~1; +} +void FCEUD_TurboToggle(void) { + NoWaiting ^= 1; +} +FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string &fname, + int innerIndex) { + return 0; +} +FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, + std::string* innerFilename) { + return 0; +} +FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string &fname, int innerIndex, int* userCancel) { return 0; } +FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel) { return 0; } +ArchiveScanRecord FCEUD_ScanArchive(std::string fname) { + return ArchiveScanRecord(); +} + +extern uint8 SelectDisk, InDisk; +extern int FDSSwitchRequested; + +void FCEUI_FDSFlip(void) +{ + /* Taken from fceugc + the commands shouldn't be issued in parallel so + * we'll delay them so the virtual FDS has a chance + * to process them + */ + if(FDSSwitchRequested == 0) + FDSSwitchRequested = 1; +} + +bool enableHUDrecording = false; +bool FCEUI_AviEnableHUDrecording() +{ + if (enableHUDrecording) + return true; + + return false; +} diff --git a/src/drivers/dingux-sdl/dingoo.h b/src/drivers/dingux-sdl/dingoo.h new file mode 100644 index 000000000..5d976badd --- /dev/null +++ b/src/drivers/dingux-sdl/dingoo.h @@ -0,0 +1,24 @@ +#ifndef __FCEU_DINGOO_H +#define __FCEU_DINGOO_H + +#include +#include "main.h" +#include "dface.h" +#include "input.h" + +void DoFun(int frameskip, int); + +int LoadGame(const char *path); +int CloseGame(void); + +int FCEUD_LoadMovie(const char *name, char *romname); +int FCEUD_DriverReset(); + +void FCEUI_FDSFlip(void); + +extern int dendy; +extern int pal_emulation; +extern bool swapDuty; +extern bool paldeemphswap; + +#endif diff --git a/src/drivers/dingux-sdl/dma.cpp b/src/drivers/dingux-sdl/dma.cpp new file mode 100644 index 000000000..47a4db3f5 --- /dev/null +++ b/src/drivers/dingux-sdl/dma.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include "dma.h" + +int dma_fd; +volatile uint16_t *dma_ptr = NULL; +const int dma_size = 320 * 480 * 2; + +int dma_map_buffer(void) +{ + if (dma_ptr) + return -1; + dma_fd = open("/dev/mem", O_RDWR | O_SYNC); + if (dma_fd < 0) { + //printf("failed to open /dev/mem\n"); + return -1; + } + return dma_ptr = mmap(0, dma_size, PROT_READ | PROT_WRITE, MAP_SHARED, dma_fd, 0x4200000); +} + +void dma_unmap_buffer(void) +{ + if (dma_ptr) { + munmap(dma_ptr, dma_size); + close(dma_fd); + } +} \ No newline at end of file diff --git a/src/drivers/dingux-sdl/dma.h b/src/drivers/dingux-sdl/dma.h new file mode 100644 index 000000000..cbd040208 --- /dev/null +++ b/src/drivers/dingux-sdl/dma.h @@ -0,0 +1,24 @@ +#ifndef _DMA_H_ +#define _DMA_H_ + +#include +#include +#include +#include + + +extern int dma_fd; +extern volatile uint16_t *dma_ptr; + +typedef struct { + uint64_t pfn : 54; + unsigned int soft_dirty : 1; + unsigned int file_page : 1; + unsigned int swapped : 1; + unsigned int present : 1; +} PagemapEntry; + + +int dma_map_buffer(void); +void dma_unmap_buffer(void); +#endif \ No newline at end of file diff --git a/src/drivers/dingux-sdl/dummy-netplay.cpp b/src/drivers/dingux-sdl/dummy-netplay.cpp new file mode 100644 index 000000000..a963d21c3 --- /dev/null +++ b/src/drivers/dingux-sdl/dummy-netplay.cpp @@ -0,0 +1,78 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//todo - ensure that #ifdef WIN32 makes sense +//consider changing this to use sdl net stuff? + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "main.h" +#include "dface.h" +#include "dummy-netplay.h" + +#include "../../fceu.h" +#include "../../utils/md5.h" + +#include +#include "../common/configSys.h" + +extern Config *g_config; + +int FCEUDnetplay=0; + +int +FCEUD_NetworkConnect(void) +{ + return 1; +} + + +int +FCEUD_SendData(void *data, + uint32 len) +{ + return 1; +} + +int +FCEUD_RecvData(void *data, + uint32 len) +{ + return 0; +} + +void +FCEUD_NetworkClose(void) +{ + FCEUDnetplay = 0; +} + + +void +FCEUD_NetplayText(uint8 *text) +{ +} diff --git a/src/drivers/dingux-sdl/dummy-netplay.h b/src/drivers/dingux-sdl/dummy-netplay.h new file mode 100644 index 000000000..27b1de432 --- /dev/null +++ b/src/drivers/dingux-sdl/dummy-netplay.h @@ -0,0 +1,6 @@ +extern char *netplaynick; +extern char *netplayhost; +extern char *netpassword; +extern char *netgamekey; +extern int tport; +extern int netlocalplayers; diff --git a/src/drivers/dingux-sdl/gui/bg.bmp b/src/drivers/dingux-sdl/gui/bg.bmp new file mode 100644 index 000000000..8ec5ce1a3 Binary files /dev/null and b/src/drivers/dingux-sdl/gui/bg.bmp differ diff --git a/src/drivers/dingux-sdl/gui/control_settings.cpp b/src/drivers/dingux-sdl/gui/control_settings.cpp new file mode 100644 index 000000000..7ffba90a5 --- /dev/null +++ b/src/drivers/dingux-sdl/gui/control_settings.cpp @@ -0,0 +1,242 @@ +// Externals +extern Config *g_config; + +#define CONTROL_MENUSIZE 6 + +/* MENU COMMANDS */ + +int keyCheck(unsigned long key) +{ + if (key == DINGOO_B) return DefaultGamePad[0][1]; + if (key == DINGOO_A) return DefaultGamePad[0][0]; + if (key == DINGOO_Y) return DefaultGamePad[0][9]; + if (key == DINGOO_X) return DefaultGamePad[0][8]; + + return -1; +} + +//!!! BUG LOCATED IN SDL LIBRARY GUI.CPP +//!!! << configGamePadButton prefix creation SDL.Input.GamePad.%d missing "." at end >> +//!!! FOLLOWING STRINGS MAY BE DEPRECATED IF FIXED IN FUTURE RELEASE +static void setA(unsigned long key) +{ + g_config->setOption("SDL.Input.GamePad.0A", keyCheck(key)); + UpdateInput(g_config); +} + +static void setB(unsigned long key) +{ + g_config->setOption("SDL.Input.GamePad.0B", keyCheck(key)); + UpdateInput(g_config); +} + +static void setTurboB(unsigned long key) +{ + g_config->setOption("SDL.Input.GamePad.0TurboB", keyCheck(key)); + UpdateInput(g_config); +} + +static void setTurboA(unsigned long key) +{ + g_config->setOption("SDL.Input.GamePad.0TurboA", keyCheck(key)); + UpdateInput(g_config); +} + +static void MergeControls(unsigned long key) +{ + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.MergeControls", val); +} + +static void resetMappings(unsigned long key) +{ + g_config->setOption("SDL.Input.GamePad.0A", DefaultGamePad[0][0]); + g_config->setOption("SDL.Input.GamePad.0B", DefaultGamePad[0][1]); + g_config->setOption("SDL.Input.GamePad.0TurboA", DefaultGamePad[0][8]); + g_config->setOption("SDL.Input.GamePad.0TurboB", DefaultGamePad[0][9]); + g_config->setOption("SDL.MergeControls", 0); + UpdateInput(g_config); +} +/* CONTROL SETTING MENU */ + +static SettingEntry cm_menu[] = +{ + {"Button B", "Map input for B", "SDL.Input.GamePad.0B", setB}, + {"Button A", "Map input for A", "SDL.Input.GamePad.0A", setA}, + {"Turbo B", "Map input for Turbo B", "SDL.Input.GamePad.0TurboB", setTurboB}, + {"Turbo A", "Map input for Turbo A", "SDL.Input.GamePad.0TurboA", setTurboA}, + {"Merge P1/P2", "Control both players at once", "SDL.MergeControls", MergeControls}, + {"Reset defaults", "Reset default control mappings", "", resetMappings}, +}; + +int RunControlSettings() +{ + static int index = 0; + static int spy = 72; + int done = 0, y, i; + int err = 1; + int editMode = 0; + + g_dirty = 1; + while (!done) { + // Parse input + readkey(); + if (parsekey(DINGOO_SELECT)) { + if(index < 4) // Allow edit mode only for button mapping menu items + { + editMode = 1; + DrawText(gui_screen, ">>", 185, spy); + g_dirty = 0; + } + } + + if (!editMode) { + if (parsekey(DINGOO_A)) { + if (index > 3) { + cm_menu[index].update(g_key); + } + } + if (parsekey(DINGOO_B)) { + //ERROR CHECKING + int iBtn1 = -1; + int iBtn2 = -1; + err = 1; + for ( int i = 0; i < 5; i++ ) { + for ( int y = 0; y < 5; y++ ) { + g_config->getOption(cm_menu[i].option, &iBtn1); + if (i != y) { + g_config->getOption(cm_menu[y].option, &iBtn2); + if (iBtn1 == iBtn2) { + err = 0; + g_dirty = 1; + } + + } + } + } + + done= err; + } + } + if ( !editMode ) { + if (parsekey(DINGOO_UP, 1)) { + if (index > 0) { + index--; + spy -= 15; + } else { + index = CONTROL_MENUSIZE - 1; + spy = 72 + 15*index; + } + } + + if (parsekey(DINGOO_DOWN, 1)) { + if (index < CONTROL_MENUSIZE - 1) { + index++; + spy += 15; + } else { + index = 0; + spy = 72; + } + } + + if (parsekey(DINGOO_LEFT, 1)) { + if (index == 4) { + cm_menu[index].update(g_key); + } + } + + if (parsekey(DINGOO_RIGHT, 1)) { + if (index == 4) { + cm_menu[index].update(g_key); + } + } + } + + if ( editMode ) { + if (parsekey(DINGOO_A, 0) || parsekey(DINGOO_B, 0) || parsekey(DINGOO_X, 0) || parsekey(DINGOO_Y, 0)) { + cm_menu[index].update(g_key); + g_dirty = 1; + editMode = 0; + } + } + + // Draw stuff + if( g_dirty ) + { + draw_bg(g_bg); + + //Draw Top and Bottom Bars + DrawChar(gui_screen, SP_SELECTOR, 0, 37); + DrawChar(gui_screen, SP_SELECTOR, 81, 37); + DrawChar(gui_screen, SP_SELECTOR, 0, 225); + DrawChar(gui_screen, SP_SELECTOR, 81, 225); + DrawText(gui_screen, "B - Go Back", 235, 225); + DrawChar(gui_screen, SP_LOGO, 12, 9); + + // Draw selector + DrawChar(gui_screen, SP_SELECTOR, 56, spy); + DrawChar(gui_screen, SP_SELECTOR, 77, spy); + if (err == 0) { + DrawText(gui_screen, "!!!Error - Duplicate Key Mapping!!! ", 8, 37); + } else { + DrawText(gui_screen, "Control Settings - Press select to edit", 8, 37); + } + + // Draw menu + for(i=0,y=72;i < CONTROL_MENUSIZE;i++,y+=15) { + int iBtnVal = -1; + char cBtn[32]; + int mergeValue; + + DrawText(gui_screen, cm_menu[i].name, 60, y); + + g_config->getOption(cm_menu[i].option, &iBtnVal); + + if (i == CONTROL_MENUSIZE-1) + sprintf(cBtn, "%s", ""); + else if (i == CONTROL_MENUSIZE-2) + { + int mergeValue; + g_config->getOption("SDL.MergeControls", &mergeValue); + sprintf(cBtn, "%s", mergeValue ? "on" : "off"); + } + else if (iBtnVal == DefaultGamePad[0][0]) + sprintf(cBtn, "%s", "GCW_A"); + else if (iBtnVal == DefaultGamePad[0][1]) + sprintf(cBtn, "%s", "GCW_B"); + else if (iBtnVal == DefaultGamePad[0][8]) + sprintf(cBtn, "%s", "GCW_Y"); + else if (iBtnVal == DefaultGamePad[0][9]) + sprintf(cBtn, "%s", "GCW_X"); + else + sprintf(cBtn, "%s", ""); + + + DrawText(gui_screen, cBtn, 210, y); + + } + + // Draw info + DrawText(gui_screen, cm_menu[index].info, 8, 225); + + g_dirty = 0; + } + + SDL_Delay(16); + + // Update real screen + FCEUGUI_Flip(); + } + + // Clear screen + dingoo_clear_video(); + + g_dirty = 1; + return 0; +} diff --git a/src/drivers/dingux-sdl/gui/file_browser.cpp b/src/drivers/dingux-sdl/gui/file_browser.cpp new file mode 100644 index 000000000..62758b893 --- /dev/null +++ b/src/drivers/dingux-sdl/gui/file_browser.cpp @@ -0,0 +1,232 @@ +#include +#include +#include + +#include "file_list.h" + +// Externals +extern SDL_Surface* screen; +extern Config *g_config; + +static char s_LastDir[128] = "/"; +int RunFileBrowser(char *source, char *outname, const char *types[], + const char *info) { + + int size = 0; + int index; + int offset_start, offset_end; + static int max_entries = 8; + int scrollModifier = 4; + int justsavedromdir = 0; + int scrollMult; + + static int spy; + int y, i; + + // Try to get a saved romdir from a config file + char* home = getenv("HOME"); + char romcfgfile [128]; + sprintf (romcfgfile, "%s/.fceux/romdir.cfg", home); + FILE * pFile; + pFile = fopen (romcfgfile,"r+"); + if (pFile != NULL) { + fgets (s_LastDir , 128 , pFile); + fclose (pFile); + } + + // Create file list + FileList *list = new FileList(source ? source : s_LastDir, types); + if (list == NULL) + return 0; + + scrollModifier *= max_entries; + +RESTART: + size = list->Size(); + + spy = 72; + index = 0; + offset_start = 0; + offset_end = size > max_entries ? max_entries : size; + + g_dirty = 1; + while (1) { + // Parse input + readkey(); + // TODO - put exit keys + + // Go to previous folder or return ... + if (parsekey(DINGOO_B)) { + list->Enter(-1); + goto RESTART; + } + + // Enter folder or select rom ... + if (parsekey(DINGOO_A)) { + if (list->GetSize(index) == -1) { + list->Enter(index); + goto RESTART; + } else { + strncpy(outname, list->GetPath(index), 128); + break; + } + } + + if (parsekey(DINGOO_X)) { + return 0; + } + + if (parsekey(DINGOO_SELECT)) { + // Save the current romdir in a config file + char* home = getenv("HOME"); + char romcfgfile [128]; + strncpy(s_LastDir, list->GetCurDir(), 128); + sprintf (romcfgfile, "%s/.fceux/romdir.cfg", home); + FILE * pFile; + pFile = fopen (romcfgfile,"w+"); + fputs (s_LastDir,pFile); + fclose (pFile); + justsavedromdir = 1; + } + + if (size > 0) { + // Move through file list + + if (parsekey(DINGOO_R, 0)) { + int iSmartOffsetAdj = ((size <= max_entries) ? size : max_entries); + index = size - 1; + spy = 72 + 15*(iSmartOffsetAdj-1); + offset_end = size; + offset_start = offset_end - iSmartOffsetAdj; + } + + if (parsekey(DINGOO_L, 0)) { + goto RESTART; + } + + if (parsekey(DINGOO_UP, 1)) { + if (index > offset_start){ + index--; + spy -= 15; + } else if (offset_start > 0) { + index--; + offset_start--; + offset_end--; + } else { + index = size - 1; + offset_end = size; + offset_start = size <= max_entries ? 0 : offset_end - max_entries; + spy = 72 + 15*(index - offset_start); + } + } + + if (parsekey(DINGOO_DOWN, 1)) { + if (index < offset_end - 1){ + index++; + spy += 15; + } else if (offset_end < size) { + index++; + offset_start++; + offset_end++; + } else { + index = 0; + offset_start = 0; + offset_end = size <= max_entries ? size : max_entries; + spy = 72; + } + } + + if (parsekey(DINGOO_LEFT, 1)) { + if (index > offset_start) { + index = offset_start; + + spy = 72; + + } else if (index - scrollModifier >= 0){ + index -= scrollModifier; + offset_start -= scrollModifier; + offset_end = offset_start + max_entries; + } else + goto RESTART; + } + + if (parsekey(DINGOO_RIGHT, 1)) { + if (index < offset_end-1) { + index = offset_end-1; + + spy = 72 + 15*(index-offset_start); + + } else if (offset_end + scrollModifier <= size) { + index += scrollModifier; + offset_end += scrollModifier; + offset_start += scrollModifier; + } else { + int iSmartOffsetAdj = ((size <= max_entries) ? size : max_entries); + index = size - 1; + spy = 72 + 15*(iSmartOffsetAdj-1); + offset_end = size; + offset_start = offset_end - iSmartOffsetAdj; + } + } + } + + // Draw stuff + if (g_dirty) { + draw_bg(g_bg); + + //Draw Top and Bottom Bars + DrawChar(gui_screen, SP_SELECTOR, 0, 37); + DrawChar(gui_screen, SP_SELECTOR, 81, 37); + DrawChar(gui_screen, SP_SELECTOR, 0, 225); + DrawChar(gui_screen, SP_SELECTOR, 81, 225); + DrawText(gui_screen, "B - Go Back", 235, 225); + DrawChar(gui_screen, SP_LOGO, 12, 9); + + // Draw selector + DrawChar(gui_screen, SP_SELECTOR, 4, spy); + DrawChar(gui_screen, SP_SELECTOR, 81, spy); + + DrawText(gui_screen, "ROM Browser", 8, 37); + + // Draw file list + for (i = offset_start, y = 72; i < offset_end; i++, y += 15) { + DrawText(gui_screen, list->GetName(i), 8, y); + } + + // Draw info + if (info) + DrawText(gui_screen, info, 8, 225); + else { + if (justsavedromdir == 1){ + DrawText(gui_screen, "ROM dir successfully saved!", 8, 225); + } else { + if (list->GetSize(index) == -1) + DrawText(gui_screen, "SELECT - Save ROM dir", 8, 225); + else + DrawText(gui_screen, "SELECT - Save ROM dir", 8, 225); + } + justsavedromdir = 0; + } + + // Draw offset marks + if (offset_start > 0) + DrawChar(gui_screen, SP_UPARROW, 157, 57); + if (offset_end < list->Size()) + DrawChar(gui_screen, SP_DOWNARROW, 157, 197); + + g_dirty = 0; + } + + SDL_Delay(4); + + // Update real screen + FCEUGUI_Flip(); + + } + + if (source == NULL) + strncpy(s_LastDir, list->GetCurDir(), 128); + delete list; + + return 1; +} diff --git a/src/drivers/dingux-sdl/gui/file_list.cpp b/src/drivers/dingux-sdl/gui/file_list.cpp new file mode 100644 index 000000000..dffc4687b --- /dev/null +++ b/src/drivers/dingux-sdl/gui/file_list.cpp @@ -0,0 +1,150 @@ +/* This file is based on FileList.cpp from Oldplay's soure code written + by Jonas Minnberg. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "file_list.h" + +#define MAX_FILE_NAME 128 + +using namespace std; + +/* Util functions */ +const char *BaseName(const char *fname) { + const char *ptr = &fname[strlen(fname) - 1]; + while (ptr > fname && *ptr != ':' && *ptr != '\\' && *ptr != '/') + ptr--; + if (ptr != fname) + ptr++; + return ptr; +} + +int is_ext(const char *s, const char *ext) { + const char *sext = strrchr(s, '.'); + return sext && strcasecmp(ext, sext) == 0; +} + +int compare(const void* a, const void* b) { + return strcasecmp((const char *) a, (const char *) b); +} + +/* Class functions */ +int FileList::filter_cb(const char *name) { + for (int i = 0; file_types[i] != NULL; i++) + if (is_ext(name, file_types[i])) + return 1; + return 0; +} + +FileList::FileList(char *dirname, const char *types[]) { + file_types = types; + + if (dirname) { + strcpy(curdir, dirname); + Enter(dirname); + } else + *curdir = 0; +} + +void FileList::AddDirectory(char *dirname, bool recursive) { + DIR *dir = opendir(dirname); + if (dir) { + char tmp[MAX_FILE_NAME]; + int count = 0; + int folders = 0, files = 0; + for (struct dirent *de; de = readdir(dir);) { + struct stat ss; + ss.st_mode = 0; + sprintf(tmp, "%s%c%s", dirname, SEPARATOR, de->d_name); + if (stat(tmp, &ss) == 0 && de->d_name[0] != '.') { + if (ss.st_mode & S_IFDIR) + folders++; + else + files++; + } + } + rewinddir(dir); + char sorted[folders + files][MAX_FILE_NAME]; + int k = 0, m = 0, n = 0; + for (struct dirent *de; de = readdir(dir);) { + struct stat ss; + ss.st_mode = 0; + sprintf(tmp, "%s%c%s", dirname, SEPARATOR, de->d_name); + if (stat(tmp, &ss) == 0 && de->d_name[0] != '.') { + if (ss.st_mode & S_IFDIR) + strcpy(sorted[k++], de->d_name); + else + strcpy(sorted[folders + n++], de->d_name); + } + } + + qsort(sorted, folders, MAX_FILE_NAME, &compare); + qsort(&sorted[folders], files, MAX_FILE_NAME, &compare); + + for (k = 0, m = folders + files; k < m; k++) { + char *tmp2 = sorted[k]; + struct stat ss; + ss.st_mode = 0; + sprintf(tmp, "%s%c%s", dirname, SEPARATOR, tmp2); + if (stat(tmp, &ss) == 0) { + if ((ss.st_mode & S_IFDIR) || filter_cb(tmp2)) { + if (recursive && (ss.st_mode & S_IFDIR)) + AddDirectory(tmp, recursive); + else { + FileData fd; + fd.path = string(tmp); + fd.name = string(BaseName(tmp)); + if (ss.st_mode & S_IFDIR) + fd.size = -1; + else + fd.size = ss.st_size; + filerefs.push_back(fd); + } + } + } + } + closedir(dir); + } +} + +void FileList::Enter(char *dirname) { + filerefs.clear(); + AddDirectory(dirname); +} + +int FileList::Enter(int index) { + char old[MAX_FILE_NAME] = ""; + if (index == -1) { + char *end = strrchr(curdir, SEPARATOR); + if (end) { + strcpy(old, curdir); + *end = 0; + if (!strchr(curdir, SEPARATOR)) { + *end = SEPARATOR; + end[1] = 0; + } + } + } else + strcpy(curdir, filerefs[index].path.c_str()); + + Enter(curdir); + + if (strlen(old)) { + for (unsigned int i = 0; i < filerefs.size(); i++) { + if (strcmp(filerefs[i].path.c_str(), old) == 0) { + return i; + } + } + } + + return 0; + +} + diff --git a/src/drivers/dingux-sdl/gui/file_list.h b/src/drivers/dingux-sdl/gui/file_list.h new file mode 100644 index 000000000..4184f9fc6 --- /dev/null +++ b/src/drivers/dingux-sdl/gui/file_list.h @@ -0,0 +1,34 @@ +/* This file is based on FileList.h from Oldplay's soure code written + by Jonas Minnberg. + */ + +#ifndef FILELIST_H +#define FILELIST_H + +#include "files.h" + +class FileList : public IFileList +{ + public: + FileList(char *source, const char *types[]); + virtual ~FileList() {} + + virtual const char *GetName(int index) { return filerefs[index].name.c_str(); } + virtual const char *GetPath(int index) { return filerefs[index].path.c_str(); } + virtual int GetSize(int index) { return filerefs[index].size; } + int Size() { return filerefs.size(); } + virtual int Enter(int index); + char *GetCurDir() { return curdir; } + + protected: + void AddDirectory(char *dirname, bool recursive = false); + void Enter(char *dirname); + int filter_cb(const char *); + // void *cb_data; + // bool dirty; + // int changed; + char curdir[256]; + const char **file_types; +}; + +#endif diff --git a/src/drivers/dingux-sdl/gui/files.h b/src/drivers/dingux-sdl/gui/files.h new file mode 100644 index 000000000..10079f9ee --- /dev/null +++ b/src/drivers/dingux-sdl/gui/files.h @@ -0,0 +1,35 @@ +/* This file is based on Files.h from Oldplay's soure code written + by Jonas Minnberg. + */ + +#ifndef FILES_H +#define FILES_H + +#include +#include + +#define SEPARATOR '/' + +struct FileData +{ + std::string name; + std::string path; + int size; +}; + +class IFileList +{ + public: + IFileList() {} + virtual ~IFileList() {} + + virtual int Size() = 0; + virtual const char *GetName(int index) = 0; + virtual const char *GetPath(int index) = 0; + + virtual int Enter(int index) = 0; + protected: + std::vector filerefs; +}; + +#endif diff --git a/src/drivers/dingux-sdl/gui/font.cpp b/src/drivers/dingux-sdl/gui/font.cpp new file mode 100644 index 000000000..544fa136b --- /dev/null +++ b/src/drivers/dingux-sdl/gui/font.cpp @@ -0,0 +1,187 @@ + +#include +#include +#include +#include + +#include "../dingoo.h" +#include "../dingoo-video.h" + +#include "../dface.h" + +#include "font.h" + +typedef struct _letter +{ + int x, y, w, h; + int pre, pos; +} Letter; + +static int g_max_height = 13; +static SDL_Surface *g_font; +static Letter g_letters[] = +{ + /*" "*/ {80,214,5,13,0,0}, + /*"!"*/ {1,227,5,13,0,0}, + /*"""*/ {6,227,6,13,0,0}, + /*"#"*/ {12,227,8,13,0,0}, + /*"$"*/ {20,227,8,13,0,0}, + /*"%"*/ {28,227,7,13,0,0}, + /*"&"*/ {35,227,8,13,0,0}, + /*"'"*/ {43,227,3,13,0,0}, + /*"("*/ {46,227,5,13,0,0}, + /*")"*/ {51,227,5,13,0,0}, + /*"*"*/ {56,227,8,13,0,0}, + /*"+"*/ {64,227,7,13,0,0}, + /*","*/ {71,227,5,13,0,0}, + /*"-"*/ {76,227,7,13,0,0}, + /*"."*/ {83,227,5,13,0,0}, + /*"/"*/ {88,227,7,13,0,0}, + /*"0"*/ {1,214,8,13,0,0}, + /*"1"*/ {9,214,7,13,0,0}, + /*"2"*/ {16,214,8,13,0,0}, + /*"3"*/ {24,214,8,13,0,0}, + /*"4"*/ {32,214,8,13,0,0}, + /*"5"*/ {40,214,8,13,0,0}, + /*"6"*/ {48,214,8,13,0,0}, + /*"7"*/ {56,214,8,13,0,0}, + /*"8"*/ {64,214,8,13,0,0}, + /*"9"*/ {72,214,8,13,0,0}, + /*":"*/ {95,227,5,13,0,0}, + /*";"*/ {100,227,5,13,0,0}, + /*"<"*/ {105,227,5,13,0,0}, + /*"="*/ {110,227,8,13,0,0}, + /*">"*/ {118,227,5,13,0,0}, + /*"?"*/ {123,227,8,13,0,0}, + /*"@"*/ {131,227,8,13,0,0}, + /*"A"*/ {1,188,8,13,0,0}, + /*"B"*/ {9,188,8,13,0,0}, + /*"C"*/ {17,188,8,13,0,0}, + /*"D"*/ {25,188,8,13,0,0}, + /*"E"*/ {33,188,8,13,0,0}, + /*"F"*/ {41,188,8,13,0,0}, + /*"G"*/ {49,188,8,13,0,0}, + /*"H"*/ {57,188,8,13,0,0}, + /*"I"*/ {65,188,5,13,0,0}, + /*"J"*/ {70,188,8,13,0,0}, + /*"K"*/ {78,188,8,13,0,0}, + /*"L"*/ {86,188,8,13,0,0}, + /*"M"*/ {94,188,8,13,0,0}, + /*"N"*/ {102,188,8,13,0,0}, + /*"O"*/ {110,188,8,13,0,0}, + /*"P"*/ {118,188,8,13,0,0}, + /*"Q"*/ {126,188,8,13,0,0}, + /*"R"*/ {134,188,8,13,0,0}, + /*"S"*/ {142,188,8,13,0,0}, + /*"T"*/ {150,188,7,13,0,0}, + /*"U"*/ {157,188,8,13,0,0}, + /*"V"*/ {165,188,8,13,0,0}, + /*"W"*/ {173,188,8,13,0,0}, + /*"X"*/ {181,188,8,13,0,0}, + /*"Y"*/ {189,188,7,13,0,0}, + /*"Z"*/ {196,188,8,13,0,0}, + /*"["*/ {139,227,5,13,0,0}, + /*"\"*/ {144,227,7,13,0,0}, + /*"]"*/ {151,227,5,13,0,0}, + /*"^"*/ {156,227,8,13,0,0}, + /*"_"*/ {164,227,8,13,0,0}, + /*"`"*/ {172,227,3,13,0,0}, + /*"a"*/ {1,201,8,13,0,0}, + /*"b"*/ {9,201,8,13,0,0}, + /*"c"*/ {17,201,8,13,0,0}, + /*"d"*/ {25,201,8,13,0,0}, + /*"e"*/ {33,201,8,13,0,0}, + /*"f"*/ {41,201,7,13,0,0}, + /*"g"*/ {48,201,8,13,0,0}, + /*"h"*/ {56,201,8,13,0,0}, + /*"i"*/ {64,201,3,13,0,0}, + /*"j"*/ {67,201,6,13,0,0}, + /*"k"*/ {73,201,7,13,0,0}, + /*"l"*/ {80,201,5,13,0,0}, + /*"m"*/ {85,201,9,13,0,0}, + /*"n"*/ {94,201,8,13,0,0}, + /*"o"*/ {102,201,8,13,0,0}, + /*"p"*/ {110,201,8,13,0,0}, + /*"q"*/ {118,201,8,13,0,0}, + /*"r"*/ {126,201,8,13,0,0}, + /*"s"*/ {134,201,8,13,0,0}, + /*"t"*/ {142,201,7,13,0,0}, + /*"u"*/ {149,201,8,13,0,0}, + /*"v"*/ {157,201,8,13,0,0}, + /*"w"*/ {165,201,9,13,0,0}, + /*"x"*/ {174,201,8,13,0,0}, + /*"y"*/ {182,201,8,13,0,0}, + /*"z"*/ {190,201,8,13,0,0}, + /*"{"*/ {175,227,7,13,0,0}, + /*"|"*/ {182,227,3,13,0,0}, + /*"}"*/ {185,227,7,13,0,0}, + /*"~"*/ {192,227,8,13,0,0}, + + /*SELECTOR*/ {0,174,240,14,0,0}, + /*ROM*/ {132,12,36,12,0,0}, + /*SETTINGS*/ {132,0,65,12,0,0}, + /*NOPREVIEW*/ {145,25,54,8,0,0}, + /*LEFTARROW*/ {1,165,9,8,0,0}, + /*RIGHTARROW*/ {11,165,9,8,0,0}, + /*UPARROW*/ {23,164,8,9,0,0}, + /*DOWNARROW*/ {33,164,8,9,0,0}, + /*MAINSETTINGS*/ {132,70,94,12,0,0}, + /*VIDEOSETTINGS*/ {132,58,99,12,0,0}, + /*SOUNDSETTINGS*/ {132,46,103,12,0,0}, + /*BROWSER*/ {132,82,89,12,0,0}, + /*PREVIEWBLOCK*/ {1,55,99,105,0,0}, + /*LOGO*/ {119,155,119,18,0,0} +}; + +int InitFont() +{ + // Load font image + g_font = SDL_LoadBMP("./sp.bmp"); + if(g_font == NULL) return -1; + + int color_key = SDL_MapRGB(g_font->format, 255, 0, 255); + SDL_SetColorKey(g_font, SDL_SRCCOLORKEY, color_key); + + return 0; +} + +void KillFont() +{ + SDL_FreeSurface(g_font); +} + +int DrawChar(SDL_Surface *dest, uint8 c, int x, int y) +{ + Letter *l = &g_letters[c]; + SDL_Rect src, dst; + + dst.x = x; + dst.y = y; + src.x = l->x; + src.y = l->y; + src.w = l->w; + src.h = l->h; + + SDL_BlitSurface(g_font, &src, dest, &dst); + + return l->w + l->pos; +} + +void DrawText(SDL_Surface *dest, const char *textmsg, int x, int y) +{ + if( textmsg == NULL ) return; + + char *str = (char *)textmsg; + int x0 = x, y0 = y; + for(; *str; str++) { + if(*str == '\n') + y0 += g_max_height; + else { + uint8 c = (*str - 32) & 0x7F; + x0 += DrawChar(dest, c, x0, y0); + + if(x0 > 320) break; + } + } +} + diff --git a/src/drivers/dingux-sdl/gui/font.h b/src/drivers/dingux-sdl/gui/font.h new file mode 100644 index 000000000..50efd353a --- /dev/null +++ b/src/drivers/dingux-sdl/gui/font.h @@ -0,0 +1,27 @@ +#ifndef FONT_H +#define FONT_H + +enum { + SP_SELECTOR = 95, + SP_ROM, + SP_SETTINGS, + SP_NOPREVIEW, + SP_LEFTARROW, + SP_RIGHTARROW, + SP_UPARROW, + SP_DOWNARROW, + SP_MAIN_SETTINGS, + SP_VIDEO_SETTINGS, + SP_SOUND_SETTINGS, + SP_BROWSER, + SP_PREVIEWBLOCK, + SP_LOGO +}; + + +int InitFont(); +void KillFont(); +int DrawChar(SDL_Surface *dest, uint8 c, int x, int y); +void DrawText(SDL_Surface *dest, const char *textmsg, int x, int y); + +#endif diff --git a/src/drivers/dingux-sdl/gui/gui.cpp b/src/drivers/dingux-sdl/gui/gui.cpp new file mode 100644 index 000000000..b5f97f06c --- /dev/null +++ b/src/drivers/dingux-sdl/gui/gui.cpp @@ -0,0 +1,453 @@ +#include +#include +#include +#include + +#include "../dingoo.h" +#include "../dingoo-video.h" +#include "../keyscan.h" + +#include "../dface.h" + +#include "font.h" + +// ... +extern SDL_Surface* screen; +extern int RunFileBrowser(char *source, char *romname, const char *types[], + const char *info = NULL); + +typedef struct _menu_entry { + const char *name; + const char *info; + int (*command)(); +} MenuEntry; + +SDL_Surface *gui_screen; +static SDL_Surface *g_bg; +static uint16 *g_psdl; +static uint8 g_preview[256 * 256 + 8]; +static uint8 g_ispreview; +static char g_romname[32] = ""; +static int g_dirty = 1; +int g_slot = 0; // make it accessible from input.cpp +static int g_romtype; +static unsigned long g_key = 0, last_key; +static int counter = 0; + +void FCEUGUI_Flip() +{ + SDL_Rect dstrect; + + dstrect.x = (screen->w - 320) / 2; + dstrect.y = (screen->h - 240) / 2; + + SDL_BlitSurface(gui_screen, 0, screen, &dstrect); + SDL_Flip(screen); +} + +void readkey() +{ + SDL_Event event; + + last_key = g_key; + + // loop, handling all pending events + while(SDL_PollEvent(&event)) + switch(event.type) { + case SDL_KEYUP: + SDL_EnableKeyRepeat(0,0); + g_key = 0; + return; + case SDL_KEYDOWN: + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY + 100, SDL_DEFAULT_REPEAT_INTERVAL); + g_key = event.key.keysym.sym; + return; + } + + if (g_key == 0) + counter = 0; +} + +int parsekey(unsigned long code, int repeat = 0) +{ + if (g_key == code) { + if (g_key != last_key) { + counter = 0; + g_dirty = 1; + return 1; + } + + if (repeat && (counter > 5)) { + counter = 0; + g_dirty = 1; + return 1; + } + + counter++; + return 0; + } + + return 0; +} + +void draw_bg(SDL_Surface *bg) +{ + if(bg) + SDL_BlitSurface(bg, NULL, gui_screen, NULL); + else + SDL_FillRect(gui_screen, NULL, (1<<11) | (8<<5) | 10); +} + +int update_time() +{ + + return 1; // always set g_dirty +} + +// Include additional files +#include "file_browser.cpp" +#include "settings_menu.cpp" + +/* MENU COMMANDS */ + +// Load preview from save state +void load_preview() { + char sname[2048]; + strcpy(sname, FCEU_MakeFName(FCEUMKF_STATE, g_slot, 0).c_str()); + strcat(sname, ".preview"); + + FILE *fp = fopen(sname, "rb"); + if (fp) { + fread(g_preview, 1, 256 * 256 + 8, fp); + fclose(fp); + g_ispreview = 1; + } else { + memset(g_preview, 0, 256 * 256 + 8); + g_ispreview = 0; + } +} + +void save_preview() +{ + char sname[2048]; + strcpy(sname, FCEU_MakeFName(FCEUMKF_STATE, g_slot, 0).c_str()); + strcat(sname, ".preview"); + + FILE *fp = fopen(sname, "wb"); + if (fp) { + extern uint8 *XBuf; + fwrite(XBuf, 1, 256 * 256 + 8, fp); + fclose(fp); + } +} + +#define MASK (0xF7DEF7DE | (0xF7DEF7DE << 16)) +#define LMASK (0x08210821 | (0x08210821 << 16)) +#define INTERPOLATE(A, B) (((A & MASK) >> 1) + ((B & MASK) >> 1) + (A & B & LMASK)) + +void draw_preview(unsigned short *dest, int x, int y) { + uint8 *PBuf = g_preview; + uint16 *dst = (uint16 *) dest; + + PBuf += 256 * 8; + dst += y * 320 + x; + + for (y = 0; y < 76; y++) { + for (x = 0; x < 32; x++) { + *dst++ = INTERPOLATE(g_psdl[*PBuf], g_psdl[*(PBuf+1)]); + *dst++ = INTERPOLATE(g_psdl[*(PBuf+3)], g_psdl[*(PBuf+4)]); + *dst++ = INTERPOLATE(g_psdl[*(PBuf+7)], g_psdl[*(PBuf+6)]); + PBuf += 8; + } + + PBuf += 256 * 2; + dst += 224; + } +} + +void draw_shot_preview(unsigned short *dest, int x, int y) { + extern uint8 *XBuf; + uint8 *PBuf = XBuf; + uint16 *dst = (uint16 *) dest; + + PBuf += 256 * 8; + dst += y * 320 + x; + + for (y = 0; y < 76; y++) { + for (x = 0; x < 32; x++) { + *dst++ = INTERPOLATE(g_psdl[*PBuf], g_psdl[*(PBuf+1)]); + *dst++ = INTERPOLATE(g_psdl[*(PBuf+3)], g_psdl[*(PBuf+4)]); + *dst++ = INTERPOLATE(g_psdl[*(PBuf+7)], g_psdl[*(PBuf+6)]); + PBuf += 8; + } + + PBuf += 256 * 2; + dst += 224; + } +} + +// Main menu commands +static int load_rom() { + const char *types[] = { ".nes", ".fds", ".zip", ".fcm", ".fm2", ".nsf", + NULL }; + char filename[128], romname[128]; + int error; + + #ifdef WIN32 + if (!RunFileBrowser("d:\\", filename, types)) { + #else + if (!RunFileBrowser(NULL, filename, types)) { + #endif + CloseGame(); + SDL_Quit(); + exit(-1); + } + + // TODO - Must close game here? + CloseGame(); + + // Is this a movie? + if (!(error = FCEUD_LoadMovie(filename, romname))) + error = LoadGame(filename); + + if (error != 1) { + CloseGame(); + SDL_Quit(); + exit(-1); + } + + return 1; +} + +static int reset_nes() { + FCEUI_ResetNES(); + return 1; +} + +// Dirty way of flipping disc +extern uint8 SelectDisk, InDisk; +static int flip_disc() { + if (g_romtype != GIT_FDS) + return 0; + FCEUI_FDSFlip(); + return 1; +} + +static int save_state() { + FCEUI_SaveState(NULL); + save_preview(); + return 0; +} + +static int load_state() { + FCEUI_LoadState(NULL); + return 0; +} + +static int save_screenshot() { + FCEUI_SaveSnapshot(); + return 0; +} + +static int cmd_settings_menu() { + return RunSettingsMenu(); +} + +static int cmd_exit() { + FCEUI_CloseGame(); + return 1; +} + +/* MAIN MENU */ + +static MenuEntry main_menu[] = { + { "Load ROM", "Load new rom or movie", load_rom }, + { "Reset", "Reset NES", reset_nes }, + { "Flip disc", "Switch side or disc (FDS)", flip_disc }, + { "Save state", "Save current state", save_state }, + { "Load state", "Load emulation state", load_state }, + { "Screenshot", "Save current frame shot", save_screenshot }, + { "Settings", "Change current settings", cmd_settings_menu }, + { "Exit", "Exit emulator", cmd_exit } +}; + +extern char FileBase[2048]; + +int FCEUGUI_Init(FCEUGI *gi) +{ + + // create 565 RGB surface + gui_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 240, 16, 0xf800, 0x7e0, 0x1f, 0); + if(!gui_screen) printf("Error creating surface gui\n"); + + // Load bg image + g_bg = SDL_LoadBMP("./bg.bmp"); + + if (InitFont() < 0) + return -2; + + if (gi) { + if (strlen(FileBase) > 28) { + strncpy(g_romname, FileBase, 24); + strcat(g_romname, "..."); + } else + strcpy(g_romname, FileBase); + g_romtype = gi->type; + } + + return 0; +} + +void FCEUGUI_Reset(FCEUGI *gi) { + g_psdl = FCEUD_GetPaletteArray16(); + + if (strlen(FileBase) > 28) { + strncpy(g_romname, FileBase, 24); + strcat(g_romname, "..."); + } else + strcpy(g_romname, FileBase); + g_romtype = gi->type; +} + +void FCEUGUI_Kill() { + // free stuff + if (g_bg) + SDL_FreeSurface(g_bg); + if (gui_screen) + SDL_FreeSurface(gui_screen); + KillFont(); +} + +void FCEUGUI_Run() { + static int index = 0; + static int spy = 72; + int done = 0, y, i; + + load_preview(); + + g_dirty = 1; + while (!done) { + + // Parse input + readkey(); + if (parsekey(DINGOO_B)) + done = 1; + + if (parsekey(DINGOO_UP, 0)) { + if (index > 0) { + index--; + spy -= 16; + } else { + index = 7; + spy = 72 + 16*index; + } + } + + if (parsekey(DINGOO_DOWN, 0)) { + if (index < 7) { + index++; + spy += 16; + } else { + index = 0; + spy = 72; + } + } + + if (parsekey(DINGOO_A)) { + done = main_menu[index].command(); + if(index == 3) load_preview(); + } + + if (index == 3 || index == 4) { + if (parsekey(DINGOO_RIGHT, 0)) { + if (g_slot < 9) { + g_slot++; + FCEUI_SelectState(g_slot, 0); + load_preview(); + } + } + + if (parsekey(DINGOO_LEFT, 0)) { + if (g_slot > 0) { + g_slot--; + FCEUI_SelectState(g_slot, 0); + load_preview(); + } + } + } + + // Must draw bg only when needed + // Draw stuff + if (g_dirty) { + draw_bg(g_bg); + + //Draw Top and Bottom Bars + DrawChar(gui_screen, SP_SELECTOR, 0, 37); + DrawChar(gui_screen, SP_SELECTOR, 81, 37); + DrawChar(gui_screen, SP_SELECTOR, 0, 225); + DrawChar(gui_screen, SP_SELECTOR, 81, 225); + DrawText(gui_screen, "B - Go Back", 235, 225); + DrawChar(gui_screen, SP_LOGO, 12, 9); + + // Draw selector + DrawChar(gui_screen, SP_SELECTOR, 56, spy); + DrawChar(gui_screen, SP_SELECTOR, 77, spy); + + if (index == 3 || index == 4) { + // Draw state preview + DrawChar(gui_screen, SP_PREVIEWBLOCK, 184, 73); + draw_preview((unsigned short *)gui_screen->pixels, 185, 100); + if (!g_ispreview) + DrawChar(gui_screen, SP_NOPREVIEW, 207, 135); + } + + if (index == 5) { + DrawChar(gui_screen, SP_PREVIEWBLOCK, 184, 73); + draw_shot_preview((unsigned short *)gui_screen->pixels, 185, 100); + } + + DrawText(gui_screen, "Now Playing:", 8, 37); + DrawText(gui_screen, g_romname, 96, 37); + + // Draw menu + for (i = 0, y = 72; i < 8; i++, y += 16) { + DrawText(gui_screen, main_menu[i].name, 60, y); + } + + // Draw info + DrawText(gui_screen, main_menu[index].info, 8, 225); + + // If save/load state render slot preview and number + if (index == 3 || index == 4) { + char tmp[32]; + sprintf(tmp, "Slot %d", g_slot); + DrawText(gui_screen, tmp, 212, 80); + + if (g_slot > 0) + DrawChar(gui_screen, SP_LEFTARROW, 197, 83); + if (g_slot < 9) + DrawChar(gui_screen, SP_RIGHTARROW, 259, 83); + } + + // If screenshot render current frame preview + if (index == 5) { + DrawText(gui_screen, "Preview", 207, 80); + } + + g_dirty = 0; + } + + SDL_Delay(16); + + // Update real screen + FCEUGUI_Flip(); + } + + g_psdl = FCEUD_GetPaletteArray16(); + + // Clear screen + dingoo_clear_video(); + + g_key = 0; + counter = 0; +} diff --git a/src/drivers/dingux-sdl/gui/gui.h b/src/drivers/dingux-sdl/gui/gui.h new file mode 100644 index 000000000..5e991c30e --- /dev/null +++ b/src/drivers/dingux-sdl/gui/gui.h @@ -0,0 +1,13 @@ +#ifndef _gui_h +#define _gui_h + +int FCEUGUI_Init(FCEUGI *gi); +void FCEUGUI_Reset(FCEUGI *gi); +void FCEUGUI_Close(); +void FCEUGUI_Run(); + +int InitFileBrowser(); +void KillFileBrowser(); +int RunFileBrowser(char *source, char *romname, const char *types[], const char *info = NULL); + +#endif diff --git a/src/drivers/dingux-sdl/gui/main_settings.cpp b/src/drivers/dingux-sdl/gui/main_settings.cpp new file mode 100644 index 000000000..fbc462aa3 --- /dev/null +++ b/src/drivers/dingux-sdl/gui/main_settings.cpp @@ -0,0 +1,269 @@ +// Externals +extern Config *g_config; + +/* MENU COMMANDS */ + +// Use PAL or NTSC rate +static void pal_update(unsigned long key) { + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.PAL", val); +} + +// TODO - Open game genie screen +static void gg_update(unsigned long key) { + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.GameGenie", val); +} + +static void sprite_limit_update(unsigned long key) { + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.DisableSpriteLimit", val); +} + +static void throttle_update(unsigned long key) { + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.FPSThrottle", val); +} + +static void showfps_update(unsigned long key) { + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.ShowFPS", val); +} + +static void show_mouse_update(unsigned long key) { + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.ShowMouseCursor", val); +} + +static void mouse_update(unsigned long key) { + int val; + g_config->getOption("SDL.MouseSpeed", &val); + + if (key == DINGOO_RIGHT) + val = val < 8 ? val + 1 : 8; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 0; + + g_config->setOption("SDL.MouseSpeed", val); +} + +// Frameskip +#if 0 //def FRAMESKIP +static void frameskip_update(unsigned long key) { + int val; + g_config->getOption("SDL.Frameskip", &val); + + if (key == DINGOO_RIGHT) val = val < 9 ? val+1 : 9; + if (key == DINGOO_LEFT) val = val > 0 ? val-1 : 0; + + g_config->setOption("SDL.Frameskip", val); +} +#endif + +// Custom palette +static void custom_update(unsigned long key) { + const char *types[] = { ".pal", NULL }; + char palname[128] = ""; + + #ifdef WIN32 + if (!RunFileBrowser("d:\\", palname, types, "Choose nes palette (.pal)")) + #else + if (!RunFileBrowser(NULL, palname, types, "Choose nes palette (.pal)")) + #endif + { + CloseGame(); + SDL_Quit(); + exit(-1); + } + + std::string cpalette = std::string(palname); + g_config->setOption("SDL.Palette", cpalette); +} + +/* MAIN SETTINGS MENU */ + +static SettingEntry + st_menu[] = { + { "PAL", "Use PAL timing", "SDL.PAL", pal_update }, + { "Game Genie", "Emulate Game Genie", "SDL.GameGenie", gg_update }, + { "No sprite limit", "Disable sprite limit", "SDL.DisableSpriteLimit", sprite_limit_update }, + { "FPS Throttle", "Use fps throttling", "SDL.FPSThrottle", throttle_update }, + { "Show FPS", "Show frames per second", "SDL.ShowFPS", showfps_update }, + { "Show mouse", "Show/hide mouse cursor", "SDL.ShowMouseCursor", show_mouse_update }, + { "Mouse speed", "Mouse cursor speed", "SDL.MouseSpeed", mouse_update }, +#if 0 //def FRAMESKIP + { "Frameskip", "Frameskip [0-9]", "SDL.Frameskip", frameskip_update}, +#endif + { "Custom palette", "Load custom palette", "SDL.Palette", custom_update }, +}; + +int RunMainSettings() { + static int index = 0; + static int spy = 72; + int done = 0, y, i; + + int max_entries = 8; +#if 0 //def FRAMESKIP + int menu_size = 9; +#else + int menu_size = 8; +#endif + + static int offset_start = 0; + static int offset_end = menu_size > max_entries ? max_entries : menu_size; + + char tmp[32]; + int itmp; + + g_dirty = 1; + while (!done) { + // Parse input + readkey(); + if (parsekey(DINGOO_B)) + done = 1; + if (parsekey(DINGOO_UP, 1)) { + if (index > 0) { + index--; + + if (index >= offset_start) + spy -= 15; + + if ((offset_start > 0) && (index < offset_start)) { + offset_start--; + offset_end--; + } + } else { + index = menu_size-1; + offset_end = menu_size; + offset_start = menu_size <= max_entries ? 0 : offset_end - max_entries; + spy = 72 + 15*(index - offset_start); + } + } + + if (parsekey(DINGOO_DOWN, 1)) { + if (index < (menu_size - 1)) { + index++; + + if (index < offset_end) + spy += 15; + + if ((offset_end < menu_size) && (index >= offset_end)) { + offset_end++; + offset_start++; + } + } else { + index = 0; + offset_start = 0; + offset_end = menu_size <= max_entries ? menu_size : max_entries; + spy = 72; + } + } + + if (parsekey(DINGOO_LEFT, 1) || parsekey(DINGOO_RIGHT, 1) || parsekey( + DINGOO_A)) + st_menu[index].update(g_key); + + // Draw stuff + if (g_dirty) { + draw_bg(g_bg); + + //Draw Top and Bottom Bars + DrawChar(gui_screen, SP_SELECTOR, 0, 37); + DrawChar(gui_screen, SP_SELECTOR, 81, 37); + DrawChar(gui_screen, SP_SELECTOR, 0, 225); + DrawChar(gui_screen, SP_SELECTOR, 81, 225); + DrawText(gui_screen, "B - Go Back", 235, 225); + DrawChar(gui_screen, SP_LOGO, 12, 9); + + // Draw selector + DrawChar(gui_screen, SP_SELECTOR, 56, spy); + DrawChar(gui_screen, SP_SELECTOR, 77, spy); + + DrawText(gui_screen, "Main Settings", 8, 37); + + // Draw menu + for (i = offset_start, y = 72; i < offset_end; i++, y += 15) { + DrawText(gui_screen, st_menu[i].name, 60, y); + + g_config->getOption(st_menu[i].option, &itmp); + + if (!strncmp(st_menu[i].name, "Custom palette", 6)) { + std::string palname; + g_config->getOption(st_menu[i].option, &palname); + + // Remove path of string + const int sz = static_cast (palname.size()); + const int path_sz = palname.rfind("/", palname.size()); + + if (path_sz == sz) + strncpy(tmp, palname.c_str(), 32); + else + strncpy(tmp, palname.substr(path_sz + 1, sz - 1 + - path_sz).c_str(), 32); + } else if (!strncmp(st_menu[i].name, "Mouse speed", 11)) { + sprintf(tmp, "%d", itmp); + } else + sprintf(tmp, "%s", itmp ? "on" : "off"); + DrawText(gui_screen, tmp, 210, y); + } + + // Draw info + DrawText(gui_screen, st_menu[index].info, 8, 225); + + // Draw offset marks + if (offset_start > 0) + DrawChar(gui_screen, SP_UPARROW, 274, 62); + if (offset_end < menu_size) + DrawChar(gui_screen, SP_DOWNARROW, 274, 203); + + g_dirty = 0; + } + + SDL_Delay(16); + + // Update real screen + FCEUGUI_Flip(); + } + + // Clear screen + dingoo_clear_video(); + + g_dirty = 1; + return 0; +} diff --git a/src/drivers/dingux-sdl/gui/settings_menu.cpp b/src/drivers/dingux-sdl/gui/settings_menu.cpp new file mode 100644 index 000000000..275131f88 --- /dev/null +++ b/src/drivers/dingux-sdl/gui/settings_menu.cpp @@ -0,0 +1,126 @@ +#include "../config.h" + +typedef struct _setting_entry { + const char *name; + const char *info; + const std::string option; + void (*update)(unsigned long); +} SettingEntry; + +#include "main_settings.cpp" +#include "video_settings.cpp" +#include "sound_settings.cpp" +#include "control_settings.cpp" + +#define SETTINGS_MENUSIZE 5 + +static int cmd_main_settings() { + return RunMainSettings(); +} + +static int cmd_video_settings() { + return RunVideoSettings(); +} + +static int cmd_sound_settings() { + return RunSoundSettings(); +} + +static int cmd_control_settings() { + return RunControlSettings(); +} + +static int cmd_config_save() { + extern Config *g_config; + g_config->save(); +} + +static MenuEntry + settings_menu[] = { + { "Main Setup", "Change fceux main config", cmd_main_settings }, + { "Video Setup", "Change video config", cmd_video_settings }, + { "Sound Setup", "Change sound config", cmd_sound_settings }, + { "Control Setup", "Change control config", cmd_control_settings }, + { "Save config as default", "Override default config", cmd_config_save } }; + +int RunSettingsMenu() { + static int index = 0; + static int spy = 72; + int done = 0, y, i; + + g_dirty = 1; + while (!done) { + // Parse input + readkey(); + if (parsekey(DINGOO_B)) + done = 1; + + if (parsekey(DINGOO_UP, 1)) { + if (index > 0) { + index--; + spy -= 16; + } else { + index = SETTINGS_MENUSIZE - 1; + spy = 72 + 16*index; + } + } + + if (parsekey(DINGOO_DOWN, 1)) { + if (index < SETTINGS_MENUSIZE - 1) { + index++; + spy += 16; + } else { + index = 0; + spy = 72; + } + } + + if (parsekey(DINGOO_A)) { + done = settings_menu[index].command(); + } + + // Must draw bg only when needed + // Draw stuff + if (g_dirty) { + draw_bg(g_bg); + + //Draw Top and Bottom Bars + DrawChar(gui_screen, SP_SELECTOR, 0, 37); + DrawChar(gui_screen, SP_SELECTOR, 81, 37); + DrawChar(gui_screen, SP_SELECTOR, 0, 225); + DrawChar(gui_screen, SP_SELECTOR, 81, 225); + DrawText(gui_screen, "B - Go Back", 235, 225); + DrawChar(gui_screen, SP_LOGO, 12, 9); + + // Draw selector + DrawChar(gui_screen, SP_SELECTOR, 56, spy); + DrawChar(gui_screen, SP_SELECTOR, 77, spy); + + DrawText(gui_screen, "Settings", 8, 37); + + // Draw menu + for (i = 0, y = 72; i < SETTINGS_MENUSIZE; i++, y += 16) { + DrawText(gui_screen, settings_menu[i].name, 60, y); + } + + // Draw info + DrawText(gui_screen, settings_menu[index].info, 8, 225); + + g_dirty = 0; + } + + SDL_Delay(16); + + // Update real screen + FCEUGUI_Flip(); + } + + // Must update emulation core and drivers + UpdateEMUCore(g_config); + FCEUD_DriverReset(); + + // Clear screen + dingoo_clear_video(); + + g_dirty = 1; +} diff --git a/src/drivers/dingux-sdl/gui/sound_settings.cpp b/src/drivers/dingux-sdl/gui/sound_settings.cpp new file mode 100644 index 000000000..f26b257e0 --- /dev/null +++ b/src/drivers/dingux-sdl/gui/sound_settings.cpp @@ -0,0 +1,270 @@ + +// Externals +extern Config *g_config; + +/* MENU COMMANDS */ + +// Custom palette +static void sound_update(unsigned long key) { + int val; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.Sound", val); +} + +// Sound rate +static void soundrate_update(unsigned long key) { + const int rates[] = { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 }; + int i = 0, val; + g_config->getOption("SDL.Sound.Rate", &val); + + for (i = 0; i < 8; i++) + if (val == rates[i]) + break; + + if (key == DINGOO_RIGHT) + i = i < 7 ? i + 1 : 0; + if (key == DINGOO_LEFT) + i = i > 0 ? i - 1 : 7; + + g_config->setOption("SDL.Sound.Rate", rates[i]); +} + +// Sound quality +static void soundhq_update(unsigned long key) { + int val; + g_config->getOption("SDL.Sound.Quality", &val); + + if (key == DINGOO_RIGHT) + val = val < 2 ? val + 1 : 0; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 2; + + g_config->setOption("SDL.Sound.Quality", val); +} + +// Custom palette +static void lowpass_update(unsigned long key) { + int val, tmp; + + if (key == DINGOO_RIGHT) + val = 1; + if (key == DINGOO_LEFT) + val = 0; + + g_config->setOption("SDL.Sound.LowPass", val); +} + +// Sound volume +static void volume_update(unsigned long key) { + int val; + g_config->getOption("SDL.Sound.Volume", &val); + + if (key == DINGOO_RIGHT) + val = val < 256 ? val + 1 : 0; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 256; + + g_config->setOption("SDL.Sound.Volume", val); +} + +// Triangle volume +static void triangle_update(unsigned long key) { + int val; + g_config->getOption("SDL.Sound.TriangleVolume", &val); + + if (key == DINGOO_RIGHT) + val = val < 256 ? val + 1 : 0; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 256; + + g_config->setOption("SDL.Sound.TriangleVolume", val); +} + +// Square 1 volume +static void square1_update(unsigned long key) { + int val; + g_config->getOption("SDL.Sound.Square1Volume", &val); + + if (key == DINGOO_RIGHT) + val = val < 256 ? val + 1 : 0; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 256; + + g_config->setOption("SDL.Sound.Square1Volume", val); +} + +// Square 2 volume +static void square2_update(unsigned long key) { + int val; + g_config->getOption("SDL.Sound.Square2Volume", &val); + + if (key == DINGOO_RIGHT) + val = val < 256 ? val + 1 : 0; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 256; + + g_config->setOption("SDL.Sound.Square2Volume", val); +} + +// Noise volume +static void noise_update(unsigned long key) { + int val; + g_config->getOption("SDL.Sound.NoiseVolume", &val); + + if (key == DINGOO_RIGHT) + val = val < 256 ? val + 1 : 0; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 256; + + g_config->setOption("SDL.Sound.NoiseVolume", val); +} + +// PCM volume +static void pcm_update(unsigned long key) { + int val; + g_config->getOption("SDL.Sound.PCMVolume", &val); + + if (key == DINGOO_RIGHT) + val = val < 256 ? val + 1 : 0; + if (key == DINGOO_LEFT) + val = val > 0 ? val - 1 : 256; + + g_config->setOption("SDL.Sound.PCMVolume", val); +} + +/* SOUND SETTINGS MENU */ +static SettingEntry sd_menu[] = { + { "Toggle sound", "Enable sound", "SDL.Sound", sound_update }, + { "Sound rate", "Sound playback rate (Hz)", "SDL.Sound.Rate", soundrate_update }, + { "Quality", "Sound quality", "SDL.Sound.Quality", soundhq_update}, + { "Lowpass", "Enables low-pass filter", "SDL.Sound.LowPass", lowpass_update }, + { "Volume", "Sets global volume", "SDL.Sound.Volume", volume_update }, + { "Triangle volume", "Sets Triangle volume", "SDL.Sound.TriangleVolume", triangle_update }, + { "Square1 volume", "Sets Square 1 volume", "SDL.Sound.Square1Volume", square1_update }, + { "Square2 volume", "Sets Square 2 volume", "SDL.Sound.Square2Volume", square2_update }, + { "Noise volume", "Sets Noise volume", "SDL.Sound.NoiseVolume", noise_update }, + { "PCM volume", "Sets PCM volume", "SDL.Sound.PCMVolume", pcm_update } +}; + +int RunSoundSettings() { + static int index = 0; + static int spy = 72; + int done = 0, y, i; + + int max_entries = 8; + int menu_size = 10; + + static int offset_start = 0; + static int offset_end = menu_size > max_entries ? max_entries : menu_size; + + char tmp[32]; + int itmp; + + g_dirty = 1; + while (!done) { + // Parse input + readkey(); + if (parsekey(DINGOO_B)) + done = 1; + if (parsekey(DINGOO_UP, 1)) { + if (index > 0) { + index--; + + if (index >= offset_start) + spy -= 15; + + if ((offset_start > 0) && (index < offset_start)) { + offset_start--; + offset_end--; + } + } else { + index = menu_size-1; + offset_end = menu_size; + offset_start = menu_size <= max_entries ? 0 : offset_end - max_entries; + spy = 72 + 15*(index - offset_start); + } + } + + if (parsekey(DINGOO_DOWN, 1)) { + if (index < (menu_size - 1)) { + index++; + + if (index < offset_end) + spy += 15; + + if ((offset_end < menu_size) && (index >= offset_end)) { + offset_end++; + offset_start++; + } + } else { + index = 0; + offset_start = 0; + offset_end = menu_size <= max_entries ? menu_size : max_entries; + spy = 72; + } + } + + if (parsekey(DINGOO_RIGHT, 1) || parsekey(DINGOO_LEFT, 1)) + sd_menu[index].update(g_key); + + // Draw stuff + if (g_dirty) { + draw_bg(g_bg); + + //Draw Top and Bottom Bars + DrawChar(gui_screen, SP_SELECTOR, 0, 37); + DrawChar(gui_screen, SP_SELECTOR, 81, 37); + DrawChar(gui_screen, SP_SELECTOR, 0, 225); + DrawChar(gui_screen, SP_SELECTOR, 81, 225); + DrawText(gui_screen, "B - Go Back", 235, 225); + DrawChar(gui_screen, SP_LOGO, 12, 9); + + // Draw selector + DrawChar(gui_screen, SP_SELECTOR, 56, spy); + DrawChar(gui_screen, SP_SELECTOR, 77, spy); + + DrawText(gui_screen, "Sound Settings", 8, 37); + + // Draw menu + for (i = offset_start, y = 72; i < offset_end; i++, y += 15) { + DrawText(gui_screen, sd_menu[i].name, 60, y); + + g_config->getOption(sd_menu[i].option, &itmp); + + if (!strncmp(sd_menu[i].name, "Toggle sound", 12) \ + || !strncmp(sd_menu[i].name, "Lowpass", 7)) { + sprintf(tmp, "%s", itmp ? "on" : "off"); + } else + sprintf(tmp, "%d", itmp); + DrawText(gui_screen, tmp, 210, y); + } + + // Draw info + DrawText(gui_screen, sd_menu[index].info, 8, 225); + + // Draw offset marks + if (offset_start > 0) + DrawChar(gui_screen, SP_UPARROW, 218, 57); + if (offset_end < menu_size) + DrawChar(gui_screen, SP_DOWNARROW, 218, 197); + + g_dirty = 0; + } + + SDL_Delay(16); + + // Update real screen + FCEUGUI_Flip(); + } + + // Clear screen + dingoo_clear_video(); + + g_dirty = 1; + return 0; +} diff --git a/src/drivers/dingux-sdl/gui/sp.bmp b/src/drivers/dingux-sdl/gui/sp.bmp new file mode 100644 index 000000000..eab9c9e8c Binary files /dev/null and b/src/drivers/dingux-sdl/gui/sp.bmp differ diff --git a/src/drivers/dingux-sdl/gui/video_settings.cpp b/src/drivers/dingux-sdl/gui/video_settings.cpp new file mode 100644 index 000000000..46b5be515 --- /dev/null +++ b/src/drivers/dingux-sdl/gui/video_settings.cpp @@ -0,0 +1,214 @@ + +// Externals +extern Config *g_config; + +/* MENU COMMANDS */ + +// Fullscreen mode +static char *scale_tag[] = { + "Original", + "Aspect", + "FS Fast", + "FS Smooth" +}; + +static void fullscreen_update(unsigned long key) +{ + int val; + g_config->getOption("SDL.Fullscreen", &val); + + if (key == DINGOO_RIGHT) val = val < 3 ? val+1 : 3; + if (key == DINGOO_LEFT) val = val > 0 ? val-1 : 0; + + g_config->setOption("SDL.Fullscreen", val); +} + +// Clip sides +static void clip_update(unsigned long key) +{ + int val, tmp; + g_config->getOption("SDL.ClipSides", &tmp); + + if (key == DINGOO_RIGHT) val = 1; + if (key == DINGOO_LEFT) val = 0; + + g_config->setOption("SDL.ClipSides", val); +} + +// PPU emulation +static void newppu_update(unsigned long key) +{ + int val, tmp; + g_config->getOption("SDL.NewPPU", &tmp); + + if (key == DINGOO_RIGHT) val = 1; + if (key == DINGOO_LEFT) val = 0; + + g_config->setOption("SDL.NewPPU", val); +} + +// NTSC TV's colors +static void ntsc_update(unsigned long key) +{ + int val; + + if (key == DINGOO_RIGHT) val = 1; + if (key == DINGOO_LEFT) val = 0; + + g_config->setOption("SDL.NTSCpalette", val); +} + +// NTSC Tint +static void tint_update(unsigned long key) +{ + int val; + g_config->getOption("SDL.Tint", &val); + + if (key == DINGOO_RIGHT) val = val < 255 ? val+1 : 255; + if (key == DINGOO_LEFT) val = val > 0 ? val-1 : 0; + + g_config->setOption("SDL.Tint", val); +} + +// NTSC Hue +static void hue_update(unsigned long key) +{ + int val; + g_config->getOption("SDL.Hue", &val); + + if (key == DINGOO_RIGHT) val = val < 255 ? val+1 : 255; + if (key == DINGOO_LEFT) val = val > 0 ? val-1 : 0; + + g_config->setOption("SDL.Hue", val); +} + +// Scanline start +static void slstart_update(unsigned long key) +{ + int val; + g_config->getOption("SDL.ScanLineStart", &val); + + if (key == DINGOO_RIGHT) val = val < 239 ? val+1 : 239; + if (key == DINGOO_LEFT) val = val > 0 ? val-1 : 0; + + g_config->setOption("SDL.ScanLineStart", val); +} + +// Scanline end +static void slend_update(unsigned long key) +{ + int val; + g_config->getOption("SDL.ScanLineEnd", &val); + + if (key == DINGOO_RIGHT) val = val < 239 ? val+1 : 239; + if (key == DINGOO_LEFT) val = val > 0 ? val-1 : 0; + + g_config->setOption("SDL.ScanLineEnd", val); +} + + +/* VIDEO SETTINGS MENU */ + +static SettingEntry vd_menu[] = +{ + {"Video scaling", "Select video scale mode", "SDL.Fullscreen", fullscreen_update}, + {"Clip sides", "Clips left and right columns", "SDL.ClipSides", clip_update}, + {"New PPU", "New PPU emulation engine", "SDL.NewPPU", newppu_update}, + {"NTSC Palette", "Emulate NTSC TV's colors", "SDL.NTSCpalette", ntsc_update}, + {"Tint", "Sets tint for NTSC color", "SDL.Tint", tint_update}, + {"Hue", "Sets hue for NTSC color", "SDL.Hue", hue_update}, + {"Scanline start", "The first drawn scanline", "SDL.ScanLineStart", slstart_update}, + {"Scanline end", "The last drawn scanline", "SDL.ScanLineEnd", slend_update}, +}; + +int RunVideoSettings() +{ + static int index = 0; + static int spy = 72; + int done = 0, y, i; + + char tmp[32]; + int itmp; + + g_dirty = 1; + while (!done) { + // Parse input + readkey(); + if (parsekey(DINGOO_B)) done = 1; + if (parsekey(DINGOO_UP, 1)) { + if (index > 0) { + index--; + spy -= 15; + } else { + index = 7; + spy = 72 + 15*index; + } + } + + if (parsekey(DINGOO_DOWN, 1)) { + if (index < 7) { + index++; + spy += 15; + } else { + index = 0; + spy = 72; + } + } + if (parsekey(DINGOO_RIGHT, 1) || parsekey(DINGOO_LEFT, 1)) + vd_menu[index].update(g_key); + + // Draw stuff + if( g_dirty ) + { + draw_bg(g_bg); + + //Draw Top and Bottom Bars + DrawChar(gui_screen, SP_SELECTOR, 0, 37); + DrawChar(gui_screen, SP_SELECTOR, 81, 37); + DrawChar(gui_screen, SP_SELECTOR, 0, 225); + DrawChar(gui_screen, SP_SELECTOR, 81, 225); + DrawText(gui_screen, "B - Go Back", 235, 225); + DrawChar(gui_screen, SP_LOGO, 12, 9); + + // Draw selector + DrawChar(gui_screen, SP_SELECTOR, 56, spy); + DrawChar(gui_screen, SP_SELECTOR, 77, spy); + + DrawText(gui_screen, "Video Settings", 8, 37); + + // Draw menu + for(i=0,y=72;i < 8;i++,y+=15) { + DrawText(gui_screen, vd_menu[i].name, 60, y); + + g_config->getOption(vd_menu[i].option, &itmp); + if (!strncmp(vd_menu[i].name, "Video scaling", 5)) { + sprintf(tmp, "%s", scale_tag[itmp]); + } + else if (!strncmp(vd_menu[i].name, "Clip sides", 10) \ + || !strncmp(vd_menu[i].name, "New PPU", 7) \ + || !strncmp(vd_menu[i].name, "NTSC Palette", 12)) { + sprintf(tmp, "%s", itmp ? "on" : "off"); + } + else sprintf(tmp, "%d", itmp); + + DrawText(gui_screen, tmp, 210, y); + } + + // Draw info + DrawText(gui_screen, vd_menu[index].info, 8, 225); + + g_dirty = 0; + } + + SDL_Delay(16); + + // Update real screen + FCEUGUI_Flip(); + } + + // Clear screen + dingoo_clear_video(); + + g_dirty = 1; + return 0; +} diff --git a/src/drivers/dingux-sdl/input.cpp b/src/drivers/dingux-sdl/input.cpp new file mode 100644 index 000000000..9e1245ba3 --- /dev/null +++ b/src/drivers/dingux-sdl/input.cpp @@ -0,0 +1,1488 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "main.h" +#include "dface.h" +#include "input.h" +#include "config.h" + +#include "dingoo-video.h" +#include "dingoo.h" + +#include "gui/gui.h" + +#include "../common/cheat.h" +#include "../../movie.h" +#include "../../fceu.h" +#include "../../driver.h" +#include "../../utils/xstring.h" +#ifdef _S9XLUA_H +#include "../../fceulua.h" +#endif + +#ifdef _GTK_LITE +#include +#endif + +/** GLOBALS **/ +int NoWaiting = 1; +extern Config *g_config; +extern bool bindSavestate, frameAdvanceLagSkip, lagCounterDisplay; + +/* UsrInputType[] is user-specified. InputType[] is current + (game loading can override user settings) + */ +static int UsrInputType[NUM_INPUT_DEVICES]; +static int InputType[NUM_INPUT_DEVICES]; +static int cspec = 0; + +extern int gametype; + +static bool MenuRequested = false; + +static int frameAdvanceKey = 0; + +/** + * Necessary for proper GUI functioning (configuring when a game isn't loaded). + */ +void InputUserActiveFix() { + int x; + for (x = 0; x < 3; x++) { + InputType[x] = UsrInputType[x]; + } +} + +/** + * Parse game information and configure the input devices accordingly. + */ +void ParseGIInput(FCEUGI *gi) { + gametype = gi->type; + + InputType[0] = UsrInputType[0]; + InputType[1] = UsrInputType[1]; + InputType[2] = UsrInputType[2]; + + if (gi->input[0] >= 0) { + InputType[0] = gi->input[0]; + } + if (gi->input[1] >= 0) { + InputType[1] = gi->input[1]; + } + if (gi->inputfc >= 0) { + InputType[2] = gi->inputfc; + } + cspec = gi->cspecial; +} + +static uint8 QuizKingData = 0; +static uint8 HyperShotData = 0; +// static uint32 MahjongData = 0; +// static uint32 FTrainerData = 0; +static uint8 TopRiderData = 0; +// static uint8 BWorldData[1+13+1]; + +// static void UpdateFKB(void); +static void UpdateGamepad(void); +static void UpdateQuizKing(void); +static void UpdateHyperShot(void); +// static void UpdateMahjong(void); +//static void UpdateFTrainer(void); +static void UpdateTopRider(void); + +static uint32 JSreturn = 0; + +/** + * Configure cheat devices (game genie, etc.). Restarts the keyboard + * and video subsystems. + */ +static void DoCheatSeq() { + SilenceSound(1); + KillVideo(); + + DoConsoleCheatConfig(); + InitVideo(GameInfo); + SilenceSound(0); +} + +#include "keyscan.h" +static uint8 *g_keyState = 0; +static int DIPS = 0; + +static uint8 keyonce[MKK_COUNT]; +#define KEY(__a) g_keyState[MKK(__a)] +#define keyonly(__a) _keyonly(MKK(__a)) + +static int _keyonly(int a) +{ + // check for valid key + if(a > SDLK_LAST+1 || a < 0) + return(0); + #if SDL_VERSION_ATLEAST(1, 3, 0) + if(g_keyState[SDL_GetScancodeFromKey((SDLKey)a)]) + #else + if(g_keyState[a]) + #endif + { + + if(!keyonce[a]) { + keyonce[a] = 1; + return(1); + } + } else { + keyonce[a] = 0; + } + return(0); +} + +// a hack to check DINGOO_R hotkey combo +static int ispressed(int sdlk_code) +{ + Uint8 *keystate = SDL_GetKeyState(NULL); + + if(keystate[sdlk_code]) return 1; + + return 0; +} + +// mega hack to reset once pressed key +static int resetkey(int sdlk_code) +{ + Uint8 *keystate = SDL_GetKeyState(NULL); + keystate[sdlk_code] = 0; +} + +static int g_fkbEnabled = 0; + +// this function loads the sdl hotkeys from the config file into the +// global scope. this elimates the need for accessing the config file + +int Hotkeys[HK_MAX] = { 0 }; + +// on every cycle of keyboardinput() +void setHotKeys() +{ + std::string prefix = "SDL.Hotkeys."; + for (int i = 0; i < HK_MAX; i++) { + g_config->getOption(prefix + HotkeyStrings[i], &Hotkeys[i]); + } + + //frameAdvanceKey = DINGOO_R | Hotkeys[HK_FRAME_ADVANCE]; + return; +} + +/** + * Lets the user start a new .fm2 movie file + **/ +void FCEUD_MovieRecordTo() { +#if 0 + std::string fname = GetFilename("Save FM2 movie for recording", true, "FM2 movies|*.fm2"); + if (!fname.size()) + return; // no filename selected, quit the whole thing + std::wstring author = mbstowcs(GetUserText("Author name")); // the author can be empty, so no need to check here + + FCEUI_SaveMovie(fname.c_str(), MOVIE_FLAG_FROM_POWERON, author); +#endif +} + +/** + * Lets the user save a savestate to a specific file + **/ +void FCEUD_SaveStateAs() { +#if 0 + std::string fname = GetFilename("Save savestate as...", true, "Savestates|*.fc0"); + if (!fname.size()) + return; // no filename selected, quit the whole thing + + FCEUI_SaveState(fname.c_str()); +#endif +} + +/** + * Lets the user load a savestate from a specific file + */ +void FCEUD_LoadStateFrom() { +#if 0 + std::string fname = GetFilename("Load savestate from...", false, "Savestates|*.fc?"); + if (!fname.size()) + return; // no filename selected, quit the whole thing + + FCEUI_LoadState(fname.c_str()); +#endif +} + +/** +* Hook for transformer board +*/ +unsigned int *GetKeyboard(void) +{ + int size = 256; + Uint8* keystate = SDL_GetKeyState(&size); + return (unsigned int*)(keystate); +} + +/** + * Parse hotkey commands and execute accordingly. + */ +static void KeyboardCommands() { + int is_shift, is_alt; + + // get the keyboard input + #if SDL_VERSION_ATLEAST(1, 3, 0) + g_keyState = SDL_GetKeyboardState(NULL); + #else + g_keyState = SDL_GetKeyState(NULL); + #endif + + /* NOT SUPPORTED + // check if the family keyboard is enabled + if(InputType[2] == SIFC_FKB) { + if(keyonly(SCROLLLOCK)) { + g_fkbEnabled ^= 1; + FCEUI_DispMessage("Family Keyboard %sabled.", 0, + g_fkbEnabled ? "en" : "dis"); + } + SDL_WM_GrabInput(g_fkbEnabled ? SDL_GRAB_ON : SDL_GRAB_OFF); + if(g_fkbEnabled) { + return; + } + } + }*/ + + #if SDL_VERSION_ATLEAST(1, 3, 0) + if(g_keyState[SDL_GetScancodeFromKey(SDLK_LSHIFT)] || g_keyState[SDL_GetScancodeFromKey(SDLK_RSHIFT)]) + #else + if(g_keyState[SDLK_LSHIFT] || g_keyState[SDLK_RSHIFT]) + #endif + is_shift = 1; + else + is_shift = 0; + #if SDL_VERSION_ATLEAST(1, 3, 0) + if(g_keyState[SDL_GetScancodeFromKey(SDLK_LALT)] || g_keyState[SDL_GetScancodeFromKey(SDLK_RALT)]) + #else + if(g_keyState[SDLK_LALT] || g_keyState[SDLK_RALT]) + #endif + is_alt = 1; + else + is_alt = 0; + + if (_keyonly(Hotkeys[HK_QUIT])) { + CloseGame(); + exit(0); + } + + if (_keyonly(Hotkeys[HK_TOGGLE_BG])) { + static int state = 1; + state = !state; + FCEUI_SetRenderPlanes(true, state); + } + + // L (SDLK_TAB), Start+Select or Power flick (SDLK_HOME) - enter GUI + if (_keyonly(DINGOO_L) + || MenuRequested + || (ispressed(DINGOO_START) && ispressed(DINGOO_SELECT))) { + SilenceSound(1); + MenuRequested = false; + FCEUGUI_Run(); + SilenceSound(0); + return; + } + + // R shift + combokeys + if(ispressed(DINGOO_R)) { + extern int g_slot; // import from gui.cpp + void save_preview(); // import from gui.cpp + if(_keyonly(DINGOO_A)) { // R + A save state + FCEUI_SelectState(g_slot, 0); + FCEUI_SaveState(NULL); + save_preview(); + resetkey(DINGOO_A); + } + if(_keyonly(DINGOO_B)) { // R + B load state + FCEUI_SelectState(g_slot, 0); + FCEUI_LoadState(NULL); + resetkey(DINGOO_B); + } + if(_keyonly(DINGOO_X)) { // R + X toggle fullscreen + extern int s_fullscreen; // from dingoo_video.cpp + s_fullscreen = (s_fullscreen + 1) % 4; + g_config->setOption("SDL.Fullscreen", s_fullscreen); + dingoo_clear_video(); + resetkey(DINGOO_X); + } + if(_keyonly(DINGOO_Y)) { // R + Y flip fds disk + if(gametype == GIT_FDS) FCEUI_FDSFlip(); + resetkey(DINGOO_Y); + } + if(_keyonly(DINGOO_UP)) { // R + UP tooggle fps show + extern int showfps; // from dingoo.cpp + showfps ^= 1; + g_config->setOption("SDL.ShowFPS", showfps); + resetkey(DINGOO_UP); + } + if(_keyonly(DINGOO_DOWN)) {// R + DOWN activate subtitle display (??) is this really needed + resetkey(DINGOO_DOWN); + } + if(_keyonly(DINGOO_LEFT)) { // R + LEFT insert vsuini coin + if (gametype == GIT_VSUNI) FCEUI_VSUniCoin(); + resetkey(DINGOO_LEFT); + } + if(_keyonly(DINGOO_RIGHT)) { // R + RIGHT frame advancing (??) + resetkey(DINGOO_RIGHT); + } + if(_keyonly(DINGOO_SELECT)) { // R + SELECT + FCEUI_SaveSnapshot(); + resetkey(DINGOO_SELECT); + } + if(_keyonly(DINGOO_START)) { // R + START pause emulation + FCEUI_ToggleEmulationPause(); + resetkey(DINGOO_START); + } + } + + /* + // Toggle Movie auto-backup + if(keyonly(M) && is_shift) { + autoMovieBackup ^= 1; + FCEUI_DispMessage("Automatic movie backup %sabled.", 0, + autoMovieBackup ? "en" : "dis"); + } + */ + + /* NOT SUPPORTED + // Start recording an FM2 movie on Alt+R + if(keyonly(R) && is_alt) { + FCEUD_MovieRecordTo(); + } + */ + + // Famicom disk-system games + if (gametype == GIT_FDS) { + if (_keyonly(Hotkeys[HK_FDS_FLIP])) + FCEUI_FDSFlip(); + if (_keyonly(Hotkeys[HK_FDS_SELECT])) + FCEUI_FDSSelect(); + if (_keyonly(Hotkeys[HK_FDS_EJECT])) + FCEUI_FDSInsert(); + } + + // if not NES Sound Format + if (gametype != GIT_NSF) { + if (_keyonly(Hotkeys[HK_CHEAT_MENU])) + DoCheatSeq(); + + if (_keyonly(Hotkeys[HK_SAVE_STATE])) { + /*if(is_shift) { + movie_fname = const_cast(FCEU_MakeFName(FCEUMKF_MOVIE, 0, 0).c_str()); + FCEUI_printf("Recording movie to %s\n", movie_fname); + FCEUI_SaveMovie(movie_fname, MOVIE_FLAG_NONE, ""); + } else */ + FCEUI_SaveState(NULL); + } + + // f7 to load state, Shift-f7 to load movie + if (_keyonly(Hotkeys[HK_LOAD_STATE])) { + /* + if(is_shift) { + FCEUI_StopMovie(); + std::string fname; + fname = GetFilename("Open FM2 movie for playback...", false, "FM2 movies|*.fm2"); + if(fname != "") { + if(fname.find(".fm2") != std::string::npos) { + FCEUI_printf("Playing back movie located at %s\n", fname.c_str()); + FCEUI_LoadMovie(fname.c_str(), false, false, false); + } else + FCEUI_printf("Only FM2 movies are supported.\n"); + } + } else */ + FCEUI_LoadState(NULL); + } + } + + if (_keyonly(Hotkeys[HK_DECREASE_SPEED])) + DecreaseEmulationSpeed(); + + if (_keyonly(Hotkeys[HK_INCREASE_SPEED])) + IncreaseEmulationSpeed(); + + if (_keyonly(Hotkeys[HK_TOGGLE_FRAME_DISPLAY])) + FCEUI_MovieToggleFrameDisplay(); + + if (_keyonly(Hotkeys[HK_TOGGLE_INPUT_DISPLAY])) { + FCEUI_ToggleInputDisplay(); + extern int input_display; + g_config->setOption("SDL.InputDisplay", input_display); + } + + if (_keyonly(Hotkeys[HK_MOVIE_TOGGLE_RW])) + FCEUI_SetMovieToggleReadOnly(!FCEUI_GetMovieToggleReadOnly()); + +#ifdef CREATE_AVI + if(_keyonly(Hotkeys[HK_MUTE_CAPTURE])) { + extern int mutecapture; + mutecapture ^= 1; + } +#endif + + if (_keyonly(Hotkeys[HK_PAUSE])) + FCEUI_ToggleEmulationPause(); + + // Toggle throttling + NoWaiting &= ~1; + //if (dingoo_key & 1 << Hotkeys[HK_TURBO]) + // NoWaiting |= 1; +/* + static bool frameAdvancing = false; + if ((dingoo_key & frameAdvanceKey) == frameAdvanceKey) { + if (frameAdvancing == false) { + FCEUI_FrameAdvance(); + frameAdvancing = true; + } + } else { + if (frameAdvancing) { + FCEUI_FrameAdvanceEnd(); + frameAdvancing = false; + } + } +*/ + if (_keyonly(Hotkeys[HK_RESET])) + FCEUI_ResetNES(); + + //if(_keyonly(Hotkeys[HK_POWER])) + // FCEUI_PowerNES(); + + if (_keyonly(Hotkeys[HK_QUIT])) + CloseGame(); + +#ifdef _S9XLUA_H + if(_keyonly(Hotkeys[HK_LOAD_LUA])) { + std::string fname; + fname = GetFilename("Open LUA script...", false, "Lua scripts|*.lua"); + if(fname != "") + FCEU_LoadLuaCode(fname.c_str()); + } +#endif + + for (int i = 0; i < 10; i++) + if (_keyonly(Hotkeys[HK_SELECT_STATE_0 + i])) + FCEUI_SelectState(i, 1); + + if (_keyonly(Hotkeys[HK_BIND_STATE])) { + bindSavestate ^= 1; + FCEUI_DispMessage("Savestate binding to movie %sabled.", 0, + bindSavestate ? "en" : "dis"); + } + + if (_keyonly(Hotkeys[HK_FA_LAG_SKIP])) { + frameAdvanceLagSkip ^= 1; + FCEUI_DispMessage("Skipping lag in Frame Advance %sabled.", 0, + frameAdvanceLagSkip ? "en" : "dis"); + } + + if (_keyonly(Hotkeys[HK_LAG_COUNTER_DISPLAY])) + lagCounterDisplay ^= 1; +#if 0 + if (_keyonly(Hotkeys[HK_TOGGLE_SUBTITLE])) { + extern int movieSubtitles; + movieSubtitles ^= 1; + FCEUI_DispMessage("Movie subtitles o%s.", 0, movieSubtitles ? "n" : "ff"); + } +#endif + // VS Unisystem games + if (gametype == GIT_VSUNI) { + // insert coin + if (_keyonly(Hotkeys[HK_VS_INSERT_COIN])) + FCEUI_VSUniCoin(); + + /* NOT SUPPORTED + // toggle dipswitch display + if(_keyonly(Hotkeys[HK_VS_TOGGLE_DIPSWITCH])) { + DIPS^=1; + FCEUI_VSUniToggleDIPView(); + } + if(!(DIPS&1)) + goto DIPSless; + + // toggle the various dipswitches + if(keyonly(1)) FCEUI_VSUniToggleDIP(0); + if(keyonly(2)) FCEUI_VSUniToggleDIP(1); + if(keyonly(3)) FCEUI_VSUniToggleDIP(2); + if(keyonly(4)) FCEUI_VSUniToggleDIP(3); + if(keyonly(5)) FCEUI_VSUniToggleDIP(4); + if(keyonly(6)) FCEUI_VSUniToggleDIP(5); + if(keyonly(7)) FCEUI_VSUniToggleDIP(6); + if(keyonly(8)) FCEUI_VSUniToggleDIP(7); + */ + } else { + /* NOT SUPPORTED + static uint8 bbuf[32]; + static int bbuft; + static int barcoder = 0; + */ + + /* NOT SUPPORTED + if(keyonly(H)) FCEUI_NTSCSELHUE(); + if(keyonly(T)) FCEUI_NTSCSELTINT(); + */ + + if (_keyonly(Hotkeys[HK_DECREASE_SPEED])) + FCEUI_NTSCDEC(); + if (_keyonly(Hotkeys[HK_INCREASE_SPEED])) + FCEUI_NTSCINC(); + + /* NOT SUPPORTED + if((InputType[2] == SIFC_BWORLD) || (cspec == SIS_DATACH)) { + if(keyonly(F8)) { + barcoder ^= 1; + if(!barcoder) { + if(InputType[2] == SIFC_BWORLD) { + strcpy((char *)&BWorldData[1], (char *)bbuf); + BWorldData[0] = 1; + } else { + FCEUI_GetDatachSet(bbuf); + } + FCEUI_DispMessage("Barcode Entered", 0); + } else { + bbuft = 0; + FCEUI_DispMessage("Enter Barcode", 0); + } + } + } else { + barcoder = 0; + } + + #define SSM(x) \ + do { \ + if(barcoder) { \ + if(bbuft < 13) { \ + bbuf[bbuft++] = '0' + x; \ + bbuf[bbuft] = 0; \ + } \ + FCEUI_DispMessage("Barcode: %s", 0, bbuf); \ + } \ + } while(0) + + DIPSless: + if(keyonly(0)) SSM(0); + if(keyonly(1)) SSM(1); + if(keyonly(2)) SSM(2); + if(keyonly(3)) SSM(3); + if(keyonly(4)) SSM(4); + if(keyonly(5)) SSM(5); + if(keyonly(6)) SSM(6); + if(keyonly(7)) SSM(7); + if(keyonly(8)) SSM(8); + if(keyonly(9)) SSM(9); + #undef SSM */ + } +} + +/** + * Return the state of the mouse buttons. Input 'd' is an array of 3 + * integers that store . + */ +void // removed static for a call in lua-engine.cpp +GetMouseData(uint32(&d)[3]) +{ + int x,y; + uint32 t; + + // Don't get input when a movie is playing back + if(FCEUMOV_Mode(MOVIEMODE_PLAY)) + return; + + // retrieve the state of the mouse from SDL + t = SDL_GetMouseState(&x, &y); + + d[2] = 0; + if(t & SDL_BUTTON(1)) { + d[2] |= 0x1; + } + if(t & SDL_BUTTON(3)) { + d[2] |= 0x2; + } + + // get the mouse position from the SDL video driver + t = PtoV(x, y); + d[0] = t & 0xFFFF; + d[1] = (t >> 16) & 0xFFFF; +} + +/** + * Handles outstanding SDL events. + */ +static void UpdatePhysicalInput() +{ + SDL_Event event; + + // loop, handling all pending events + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_QUIT: + CloseGame(); + puts("Quit"); + break; + case SDL_FCEU_HOTKEY_EVENT: + switch(event.user.code) { + case HK_PAUSE: + FCEUI_ToggleEmulationPause(); + break; + default: + FCEU_printf("Warning: unknown hotkey event %d\n", event.user.code); + } + break; + case SDL_KEYDOWN: + if (event.key.keysym.sym == DINGOO_MENU) + // Because a KEYUP is sent straight after the KEYDOWN for the + // Power switch, SDL_GetKeyState will not ever see this. + // Keep a record of it. + MenuRequested = true; + break; + default: + // do nothing + break; + } + } + //SDL_PumpEvents(); +} + +/** + * Tests to see if a specified button is currently pressed. + */ +static int DTestButton(ButtConfig *bc){ + int x; + + for(x = 0; x < bc->NumC; x++) { + if(bc->ButtType[x] == BUTTC_KEYBOARD) { + #if SDL_VERSION_ATLEAST(1,3,0) + if(g_keyState[SDL_GetScancodeFromKey((SDLKey)bc->ButtonNum[x])]) { + #else + if(g_keyState[bc->ButtonNum[x]]) { + #endif + return(1); + } + } else if(bc->ButtType[x] == BUTTC_JOYSTICK) { + if(DTestButtonJoy(bc)) { + return(1); + } + } + } + return(0); +} + +#define MK(x) {{BUTTC_KEYBOARD},{0},{MKK(x)},1} +#define MK2(x1,x2) {{BUTTC_KEYBOARD},{0},{MKK(x1),MKK(x2)},2} +#define MKZ() {{0},{0},{0},0} +#define GPZ() {MKZ(), MKZ(), MKZ(), MKZ()} + +//#define MK(x) {{BUTTC_JOYSTICK},{0},{x},1} +//#define MK2(x1,x2) {{BUTTC_JOYSTICK},{0},{x1,x2},2} +//#define MKZ() {{-1},{-1},{-1},-1} +//#define GPZ() {MKZ(), MKZ(), MKZ(), MKZ()} + +ButtConfig GamePadConfig[4][10] = { + /* Gamepad 1 */ + { MK(LCTRL), MK(LALT), MK(ESCAPE), MK(RETURN), MK(UP), MK(DOWN), MK(LEFT), MK(RIGHT), + MK(SPACE), MK(LSHIFT) }, + + /* Gamepad 2 */ + GPZ(), + + /* Gamepad 3 */ + GPZ(), + + /* Gamepad 4 */ + GPZ() }; + +/** + * Update the status of the gamepad input devices. + */ +static void UpdateGamepad(void) { + // don't update during movie playback + if (FCEUMOV_Mode(MOVIEMODE_PLAY)) { + return; + } + + static int rapid = 0; + uint32 JS = 0; + int x; + int wg; + int merge; + + rapid ^= 1; + + g_config->getOption("SDL.MergeControls", &merge); + + // go through just one device for the little dingoo :) + for (wg = 0; wg < 1; wg++) { + // the 4 directional buttons, start, select, a, b + for (x = 0; x < 8; x++) { + if (DTestButton(&GamePadConfig[wg][x])) { + JS |= (1 << x) << (wg << 3); + // Inject gamepad 1 input into gamepad 2 if enabled + if (merge) { + JS |= (1 << x) << ((wg + 1) << 3); + } + } + } + + // rapid-fire a, rapid-fire b + if (rapid) { + for (x = 0; x < 2; x++) { + if (DTestButton(&GamePadConfig[wg][8 + x])) { + JS |= (1 << x) << (wg << 3); + // Inject gamepad 1 input into gamepad 2 if enabled + if (merge) { + JS |= (1 << x) << ((wg + 1) << 3); + } + } + } + } + } + + // for(x=0;x<32;x+=8) { /* Now, test to see if anything weird(up+down at same time) + // is happening, and correct */ + // if((JS & (0xC0<getOption(buf, &device); + + if (device == "None") { + UsrInputType[i] = SI_NONE; + } else if (device.find("GamePad") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_GAMEPAD : (int) SIFC_NONE; +#if 0 + } else if(device.find("PowerPad.0") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int)SI_POWERPADA : (int)SIFC_NONE; + } else if(device.find("PowerPad.1") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int)SI_POWERPADB : (int)SIFC_NONE; +#endif + } else if (device.find("QuizKing") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_QUIZKING; + } else if (device.find("HyperShot") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_HYPERSHOT; +#if 0 + } else if(device.find("Mahjong") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int)SI_NONE : (int)SIFC_MAHJONG; +#endif + } else if (device.find("TopRider") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_TOPRIDER; +#if 0 + } else if(device.find("FTrainer") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int)SI_NONE : (int)SIFC_FTRAINERA; + } else if(device.find("FamilyKeyBoard") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int)SI_NONE : (int)SIFC_FKB; +#endif + } else if (device.find("OekaKids") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_OEKAKIDS; + } else if (device.find("Arkanoid") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_ARKANOID : (int) SIFC_ARKANOID; + } else if (device.find("Shadow") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_SHADOW; + } else if (device.find("Zapper") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_ZAPPER : (int) SIFC_NONE; +#if 0 + } else if(device.find("BWorld") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int)SI_NONE : (int)SIFC_BWORLD; +#endif + } else if (device.find("4Player") != std::string::npos) { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_4PLAYER; + } else { + // Unknown device + UsrInputType[i] = SI_NONE; + } + } + + // update each of the devices' configuration structure + // XXX soules - this is temporary until this file is cleaned up to + // simplify the interface between configuration and + // structure data. This will likely include the + // removal of multiple input buttons for a single + // input device key. + int type, devnum, button; + + // gamepad 0 - 3 + for (unsigned int i = 0; i < GAMEPAD_NUM_DEVICES; i++) { + char buf[64]; + snprintf(buf, 20, "SDL.Input.GamePad.%d.", i); + prefix = buf; + + config->getOption(prefix + "DeviceType", &device); + if (device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if (device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + + config->getOption(prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) { + config->getOption(prefix + GamePadNames[j], &button); + + GamePadConfig[i][j].ButtType[0] = type; + GamePadConfig[i][j].DeviceNum[0] = devnum; + GamePadConfig[i][j].ButtonNum[0] = button; + GamePadConfig[i][j].NumC = 1; + } + } + +#if 0 + // PowerPad 0 - 1 + for(unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) { + char buf[64]; + snprintf(buf, 20, "SDL.Input.PowerPad.%d.", i); + prefix = buf; + + config->getOption(prefix + "DeviceType", &device); + if(device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if(device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + + config->getOption(prefix + "DeviceNum", &devnum); + for(unsigned int j = 0; j < POWERPAD_NUM_BUTTONS; j++) { + config->getOption(prefix + PowerPadNames[j], &button); + + powerpadsc[i][j].ButtType[0] = type; + powerpadsc[i][j].DeviceNum[0] = devnum; + powerpadsc[i][j].ButtonNum[0] = button; + powerpadsc[i][j].NumC = 1; + } + } +#endif + + // QuizKing + prefix = "SDL.Input.QuizKing."; + config->getOption(prefix + "DeviceType", &device); + if (device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if (device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + config->getOption(prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < QUIZKING_NUM_BUTTONS; j++) { + config->getOption(prefix + QuizKingNames[j], &button); + + QuizKingButtons[j].ButtType[0] = type; + QuizKingButtons[j].DeviceNum[0] = devnum; + QuizKingButtons[j].ButtonNum[0] = button; + QuizKingButtons[j].NumC = 1; + } + + // HyperShot + prefix = "SDL.Input.HyperShot."; + config->getOption(prefix + "DeviceType", &device); + if (device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if (device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + config->getOption(prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < HYPERSHOT_NUM_BUTTONS; j++) { + config->getOption(prefix + HyperShotNames[j], &button); + + HyperShotButtons[j].ButtType[0] = type; + HyperShotButtons[j].DeviceNum[0] = devnum; + HyperShotButtons[j].ButtonNum[0] = button; + HyperShotButtons[j].NumC = 1; + } + +#if 0 + // Mahjong + prefix = "SDL.Input.Mahjong."; + config->getOption(prefix + "DeviceType", &device); + if(device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if(device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + config->getOption(prefix + "DeviceNum", &devnum); + for(unsigned int j = 0; j < MAHJONG_NUM_BUTTONS; j++) { + config->getOption(prefix + MahjongNames[j], &button); + + MahjongButtons[j].ButtType[0] = type; + MahjongButtons[j].DeviceNum[0] = devnum; + MahjongButtons[j].ButtonNum[0] = button; + MahjongButtons[j].NumC = 1; + } +#endif + + // TopRider + prefix = "SDL.Input.TopRider."; + config->getOption(prefix + "DeviceType", &device); + if (device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if (device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + config->getOption(prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < TOPRIDER_NUM_BUTTONS; j++) { + config->getOption(prefix + TopRiderNames[j], &button); + + TopRiderButtons[j].ButtType[0] = type; + TopRiderButtons[j].DeviceNum[0] = devnum; + TopRiderButtons[j].ButtonNum[0] = button; + TopRiderButtons[j].NumC = 1; + } + +#if 0 + // FTrainer + prefix = "SDL.Input.FTrainer."; + config->getOption(prefix + "DeviceType", &device); + if(device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if(device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + config->getOption(prefix + "DeviceNum", &devnum); + for(unsigned int j = 0; j < FTRAINER_NUM_BUTTONS; j++) { + config->getOption(prefix + FTrainerNames[j], &button); + + FTrainerButtons[j].ButtType[0] = type; + FTrainerButtons[j].DeviceNum[0] = devnum; + FTrainerButtons[j].ButtonNum[0] = button; + FTrainerButtons[j].NumC = 1; + } + + // FamilyKeyBoard + prefix = "SDL.Input.FamilyKeyBoard."; + config->getOption(prefix + "DeviceType", &device); + if(device.find("Keyboard") != std::string::npos) { + type = BUTTC_KEYBOARD; + } else if(device.find("Joystick") != std::string::npos) { + type = BUTTC_JOYSTICK; + } else { + type = 0; + } + config->getOption(prefix + "DeviceNum", &devnum); + for(unsigned int j = 0; j < FAMILYKEYBOARD_NUM_BUTTONS; j++) { + config->getOption(prefix + FamilyKeyBoardNames[j], &button); + + fkbmap[j].ButtType[0] = type; + fkbmap[j].DeviceNum[0] = devnum; + fkbmap[j].ButtonNum[0] = button; + fkbmap[j].NumC = 1; + } +#endif +} +// Definitions from main.h: +// GamePad defaults +const char *GamePadNames[GAMEPAD_NUM_BUTTONS] = +{ + "A", "B", "Select", "Start", "Up", "Down", "Left", "Right", "TurboA", "TurboB" +}; + +const char *DefaultGamePadDevice[GAMEPAD_NUM_DEVICES] = +{ + "Keyboard", "None", "None", "None" +}; + +const int DefaultGamePad[GAMEPAD_NUM_DEVICES][GAMEPAD_NUM_BUTTONS] = +{ + { SDLK_LCTRL, SDLK_LALT, SDLK_ESCAPE, SDLK_RETURN, SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, SDLK_SPACE, SDLK_LSHIFT }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +#if 0 +// PowerPad defaults +const char *PowerPadNames[POWERPAD_NUM_BUTTONS] = +{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B"}; +const char *DefaultPowerPadDevice[POWERPAD_NUM_DEVICES] = +{ "Keyboard", "None"}; +const int DefaultPowerPad[POWERPAD_NUM_DEVICES][POWERPAD_NUM_BUTTONS] = +{ { SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, + SDLK_k, SDLK_l, SDLK_SEMICOLON, SDLK_QUOTE, + SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; +#endif +// QuizKing defaults +const char *QuizKingNames[QUIZKING_NUM_BUTTONS] = { "0", "1", "2", "3", "4", + "5" }; +const char *DefaultQuizKingDevice = "Keyboard"; +const int DefaultQuizKing[QUIZKING_NUM_BUTTONS] = { 0, 1, 19, 2, 17, 16 }; + +// HyperShot defaults +const char *HyperShotNames[HYPERSHOT_NUM_BUTTONS] = { "0", "1", "2", "3" }; +const char *DefaultHyperShotDevice = "Keyboard"; +const int DefaultHyperShot[HYPERSHOT_NUM_BUTTONS] = { 0, 1, 19, 2 }; + +#if 0 +// Mahjong defaults +const char *MahjongNames[MAHJONG_NUM_BUTTONS] = +{ "00", "01", "02", "03", "04", "05", "06", "07", + "08", "09", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20"}; +const char *DefaultMahjongDevice = "Keyboard"; +const int DefaultMahjong[MAHJONG_NUM_BUTTONS] = +{ SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_a, SDLK_s, SDLK_d, + SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_z, SDLK_x, + SDLK_c, SDLK_v, SDLK_b, SDLK_n, SDLK_m}; +#endif + +// TopRider defaults +const char *TopRiderNames[TOPRIDER_NUM_BUTTONS] = { "0", "1", "2", "3", "4", + "5", "6", "7" }; +const char *DefaultTopRiderDevice = "Keyboard"; +const int DefaultTopRider[TOPRIDER_NUM_BUTTONS] = { 6, 27, 5, 18, 0, 1, 19, 2 }; + +#if 0 +// FTrainer defaults +const char *FTrainerNames[FTRAINER_NUM_BUTTONS] = +{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B"}; +const char *DefaultFTrainerDevice = "Keyboard"; +const int DefaultFTrainer[FTRAINER_NUM_BUTTONS] = +{ SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, + SDLK_k, SDLK_l, SDLK_SEMICOLON, SDLK_QUOTE, + SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH}; + +// FamilyKeyBoard defaults +const char *FamilyKeyBoardNames[FAMILYKEYBOARD_NUM_BUTTONS] = +{ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", + "MINUS", "EQUAL", "BACKSLASH", "BACKSPACE", + "ESCAPE", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", + "P", "GRAVE", "BRACKET_LEFT", "ENTER", + "LEFTCONTROL", "A", "S", "D", "F", "G", "H", "J", "K", + "L", "SEMICOLON", "APOSTROPHE", "BRACKET_RIGHT", "INSERT", + "LEFTSHIFT", "Z", "X", "C", "V", "B", "N", "M", "COMMA", + "PERIOD", "SLASH", "RIGHTALT", "RIGHTSHIFT", "LEFTALT", "SPACE", + "DELETE", "END", "PAGEDOWN", + "CURSORUP", "CURSORLEFT", "CURSORRIGHT", "CURSORDOWN"}; +const char *DefaultFamilyKeyBoardDevice = "Keyboard"; +const int DefaultFamilyKeyBoard[FAMILYKEYBOARD_NUM_BUTTONS] = +{ SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8, + SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, + SDLK_6, SDLK_7, SDLK_8, SDLK_9, SDLK_0, + SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSLASH, SDLK_BACKSPACE, + SDLK_ESCAPE, SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, + SDLK_i, SDLK_o, SDLK_p, SDLK_BACKQUOTE, SDLK_LEFTBRACKET, SDLK_RETURN, + SDLK_LCTRL, SDLK_a, SDLK_s, SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, + SDLK_k, SDLK_l, SDLK_SEMICOLON, SDLK_QUOTE, SDLK_RIGHTBRACKET, + SDLK_INSERT, SDLK_LSHIFT, SDLK_z, SDLK_x, SDLK_c, SDLK_v, SDLK_b, + SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RALT, + SDLK_RSHIFT, SDLK_LALT, SDLK_SPACE, SDLK_DELETE, SDLK_END, SDLK_PAGEDOWN, + SDLK_UP, SDLK_LEFT, SDLK_RIGHT, SDLK_DOWN}; +#endif diff --git a/src/drivers/dingux-sdl/input.h b/src/drivers/dingux-sdl/input.h new file mode 100644 index 000000000..20b9c5cdb --- /dev/null +++ b/src/drivers/dingux-sdl/input.h @@ -0,0 +1,53 @@ +#ifndef _aosdfjk02fmasf +#define _aosdfjk02fmasf + +#include "../common/configSys.h" + +#define MAXBUTTCONFIG 4 +typedef struct { + uint8 ButtType[MAXBUTTCONFIG]; + uint8 DeviceNum[MAXBUTTCONFIG]; + uint16 ButtonNum[MAXBUTTCONFIG]; + uint32 NumC; + //uint64 DeviceID[MAXBUTTCONFIG]; /* TODO */ +} ButtConfig; + +extern CFGSTRUCT InputConfig[]; +extern ARGPSTRUCT InputArgs[]; +void ParseGIInput(FCEUGI *GI); +void setHotKeys(); +int ButtonConfigBegin(); +void ButtonConfigEnd(); +void ConfigButton(char *text, ButtConfig *bc); + +#define BUTTC_KEYBOARD 0x00 +#define BUTTC_JOYSTICK 0x01 +#define BUTTC_MOUSE 0x02 + +#define FCFGD_GAMEPAD 1 +#define FCFGD_POWERPAD 2 +#define FCFGD_HYPERSHOT 3 +#define FCFGD_QUIZKING 4 + +#define SDL_FCEU_HOTKEY_EVENT SDL_USEREVENT + +void InitInputInterface(void); +void InputUserActiveFix(void); +extern ButtConfig GamePadConfig[4][10]; +//extern ButtConfig powerpadsc[2][12]; +//extern ButtConfig QuizKingButtons[6]; +//extern ButtConfig FTrainerButtons[12]; + +void IncreaseEmulationSpeed(void); +void DecreaseEmulationSpeed(void); + +int DTestButtonJoy(ButtConfig *bc); + +void FCEUD_UpdateInput(void); + +void UpdateInput(Config *config); +void InputCfg(const std::string &); + +std::string GetUserText(const char* title); + +#endif diff --git a/src/drivers/dingux-sdl/keyscan.h b/src/drivers/dingux-sdl/keyscan.h new file mode 100644 index 000000000..e26fb6fd1 --- /dev/null +++ b/src/drivers/dingux-sdl/keyscan.h @@ -0,0 +1,66 @@ +#include + +#define SDLK_A SDLK_a +#define SDLK_B SDLK_b +#define SDLK_C SDLK_c +#define SDLK_D SDLK_d +#define SDLK_E SDLK_e +#define SDLK_F SDLK_f +#define SDLK_G SDLK_g +#define SDLK_H SDLK_h +#define SDLK_I SDLK_i +#define SDLK_J SDLK_j +#define SDLK_K SDLK_k +#define SDLK_L SDLK_l +#define SDLK_M SDLK_m +#define SDLK_N SDLK_n +#define SDLK_O SDLK_o +#define SDLK_P SDLK_p +#define SDLK_Q SDLK_q +#define SDLK_R SDLK_r +#define SDLK_S SDLK_s +#define SDLK_T SDLK_t +#define SDLK_U SDLK_u +#define SDLK_V SDLK_v +#define SDLK_W SDLK_w +#define SDLK_X SDLK_x +#define SDLK_Y SDLK_y +#define SDLK_Z SDLK_z +#define SDLK_LEFTCONTROL SDLK_LCTRL +#define SDLK_RIGHTCONTROL SDLK_RCTRL +#define SDLK_LEFTALT SDLK_LALT +#define SDLK_RIGHTALT SDLK_RALT +#define SDLK_LEFTSHIFT SDLK_LSHIFT +#define SDLK_RIGHTSHIFT SDLK_RSHIFT +#define SDLK_CURSORDOWN SDLK_DOWN +#define SDLK_CURSORUP SDLK_UP +#define SDLK_CURSORLEFT SDLK_LEFT +#define SDLK_CURSORRIGHT SDLK_RIGHT +#define SDLK_ENTER SDLK_RETURN +#define SDLK_EQUAL SDLK_EQUALS +#define SDLK_APOSTROPHE SDLK_QUOTE +#define SDLK_BRACKET_LEFT SDLK_LEFTBRACKET +#define SDLK_BRACKET_RIGHT SDLK_RIGHTBRACKET +#define SDLK_SCROLLLOCK SDLK_SCROLLOCK /* I guess the SDL people don't like lots of Ls... */ +#define SDLK_GRAVE SDLK_BACKQUOTE +#define MKK(k) SDLK_##k + +#if SDL_VERSION_ATLEAST(1, 3, 0) +#define SDLK_LAST SDL_NUM_SCANCODES +#endif + +#define MKK_COUNT (SDLK_LAST+1) + +#define DINGOO_UP SDLK_UP +#define DINGOO_DOWN SDLK_DOWN +#define DINGOO_LEFT SDLK_LEFT +#define DINGOO_RIGHT SDLK_RIGHT +#define DINGOO_A SDLK_LCTRL +#define DINGOO_B SDLK_LALT +#define DINGOO_X SDLK_SPACE +#define DINGOO_Y SDLK_LSHIFT +#define DINGOO_L SDLK_TAB +#define DINGOO_R SDLK_BACKSPACE +#define DINGOO_START SDLK_RETURN +#define DINGOO_SELECT SDLK_ESCAPE +#define DINGOO_MENU SDLK_HOME diff --git a/src/drivers/dingux-sdl/main.h b/src/drivers/dingux-sdl/main.h new file mode 100644 index 000000000..9d6d0b7d2 --- /dev/null +++ b/src/drivers/dingux-sdl/main.h @@ -0,0 +1,100 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __FCEU_SDL_MAIN_H +#define __FCEU_SDL_MAIN_H + +#include "../../driver.h" +#include "../common/config.h" +#include "../common/args.h" + +extern int eoptions; +#define EO_NO8LIM 1 +#define EO_SUBASE 2 +#define EO_CLIPSIDES 8 +#define EO_SNAPNAME 16 +#define EO_FOURSCORE 32 +#define EO_NOTHROTTLE 64 +#define EO_GAMEGENIE 128 +#define EO_PAL 256 +#define EO_LOWPASS 512 +#define EO_AUTOHIDE 1024 + +extern int NoWaiting; + +extern int _sound; +extern long soundrate; +extern long soundbufsize; + +int CLImain(int argc, char *argv[]); + +// Device management defaults +#define NUM_INPUT_DEVICES 3 + +// GamePad defaults +#define GAMEPAD_NUM_DEVICES 4 +#define GAMEPAD_NUM_BUTTONS 10 +extern const char *GamePadNames[GAMEPAD_NUM_BUTTONS]; +extern const char *DefaultGamePadDevice[GAMEPAD_NUM_DEVICES]; +extern const int DefaultGamePad[GAMEPAD_NUM_DEVICES][GAMEPAD_NUM_BUTTONS]; + +// PowerPad defaults +#define POWERPAD_NUM_DEVICES 2 +#define POWERPAD_NUM_BUTTONS 12 +extern const char *PowerPadNames[POWERPAD_NUM_BUTTONS]; +extern const char *DefaultPowerPadDevice[POWERPAD_NUM_DEVICES]; +extern const int DefaultPowerPad[POWERPAD_NUM_DEVICES][POWERPAD_NUM_BUTTONS]; + +// QuizKing defaults +#define QUIZKING_NUM_BUTTONS 6 +extern const char *QuizKingNames[QUIZKING_NUM_BUTTONS]; +extern const char *DefaultQuizKingDevice; +extern const int DefaultQuizKing[QUIZKING_NUM_BUTTONS]; + +// HyperShot defaults +#define HYPERSHOT_NUM_BUTTONS 4 +extern const char *HyperShotNames[HYPERSHOT_NUM_BUTTONS]; +extern const char *DefaultHyperShotDevice; +extern const int DefaultHyperShot[HYPERSHOT_NUM_BUTTONS]; + +// Mahjong defaults +#define MAHJONG_NUM_BUTTONS 21 +extern const char *MahjongNames[MAHJONG_NUM_BUTTONS]; +extern const char *DefaultMahjongDevice; +extern const int DefaultMahjong[MAHJONG_NUM_BUTTONS]; + +// TopRider defaults +#define TOPRIDER_NUM_BUTTONS 8 +extern const char *TopRiderNames[TOPRIDER_NUM_BUTTONS]; +extern const char *DefaultTopRiderDevice; +extern const int DefaultTopRider[TOPRIDER_NUM_BUTTONS]; + +// FTrainer defaults +#define FTRAINER_NUM_BUTTONS 12 +extern const char *FTrainerNames[FTRAINER_NUM_BUTTONS]; +extern const char *DefaultFTrainerDevice; +extern const int DefaultFTrainer[FTRAINER_NUM_BUTTONS]; + +// FamilyKeyBoard defaults +#define FAMILYKEYBOARD_NUM_BUTTONS 0x48 +extern const char *FamilyKeyBoardNames[FAMILYKEYBOARD_NUM_BUTTONS]; +extern const char *DefaultFamilyKeyBoardDevice; +extern const int DefaultFamilyKeyBoard[FAMILYKEYBOARD_NUM_BUTTONS]; + +#endif diff --git a/src/drivers/dingux-sdl/scaler.cpp b/src/drivers/dingux-sdl/scaler.cpp new file mode 100644 index 000000000..42d04d4e5 --- /dev/null +++ b/src/drivers/dingux-sdl/scaler.cpp @@ -0,0 +1,777 @@ + +#include "scaler.h" + +#define AVERAGE(z, x) ((((z) & 0xF7DEF7DE) >> 1) + (((x) & 0xF7DEF7DE) >> 1)) +#define AVERAGEHI(AB) ((((AB) & 0xF7DE0000) >> 1) + (((AB) & 0xF7DE) << 15)) +#define AVERAGELO(CD) ((((CD) & 0xF7DE) >> 1) + (((CD) & 0xF7DE0000) >> 17)) + +extern uint32 palettetranslate[65536 * 4]; + +/* + Upscale 256x224 -> 320x240 + + Horizontal upscale: + 320/256=1.25 -- do some horizontal interpolation + 8p -> 10p + 4dw -> 5dw + + coarse interpolation: + [ab][cd][ef][gh] -> [ab][(bc)c][de][f(fg)][gh] + + fine interpolation + [ab][cd][ef][gh] -> [a(0.25a+0.75b)][(0.5b+0.5c)(0.75c+0.25d)][de][(0.25e+0.75f)(0.5f+0.5g)][(0.75g+0.25h)h] + + + Vertical upscale: + Bresenham algo with simple interpolation + + Parameters: + uint32 *dst - pointer to 320x240x16bpp buffer + uint8 *src - pointer to 256x224x8bpp buffer + palette is taken from palettetranslate[] + no pitch corrections are made! +*/ + +void upscale_320x240(uint32 *dst, uint8 *src) +{ + int midh = 240 * 3 / 4; + int Eh = 0; + int source = 0; + int dh = 0; + int y, x; + + for (y = 0; y < 240; y++) + { + source = dh * 256; + + for (x = 0; x < 320/10; x++) + { + register uint32 ab, cd, ef, gh; + + __builtin_prefetch(dst + 4, 1); + __builtin_prefetch(src + source + 4, 0); + + ab = palettetranslate[*(uint16 *)(src + source)] & 0xF7DEF7DE; + cd = palettetranslate[*(uint16 *)(src + source + 2)] & 0xF7DEF7DE; + ef = palettetranslate[*(uint16 *)(src + source + 4)] & 0xF7DEF7DE; + gh = palettetranslate[*(uint16 *)(src + source + 6)] & 0xF7DEF7DE; + + if(Eh >= midh) { // average + 256 + ab = AVERAGE(ab, palettetranslate[*(uint16 *)(src + source + 256)]) & 0xF7DEF7DE; // to prevent overflow + cd = AVERAGE(cd, palettetranslate[*(uint16 *)(src + source + 256 + 2)]) & 0xF7DEF7DE; // to prevent overflow + ef = AVERAGE(ef, palettetranslate[*(uint16 *)(src + source + 256 + 4)]) & 0xF7DEF7DE; // to prevent overflow + gh = AVERAGE(gh, palettetranslate[*(uint16 *)(src + source + 256 + 6)]) & 0xF7DEF7DE; // to prevent overflow + } + + *dst++ = ab; + *dst++ = ((ab >> 17) + ((cd & 0xFFFF) >> 1)) + (cd << 16); + *dst++ = (cd >> 16) + (ef << 16); + *dst++ = (ef >> 16) + (((ef & 0xFFFF0000) >> 1) + ((gh & 0xFFFF) << 15)); + *dst++ = gh; + + source += 8; + + } + Eh += 224; if(Eh >= 240) { Eh -= 240; dh++; } + } +} + +/* + Upscale 256x224 -> 384x240 (for 400x240) + + Horizontal interpolation + 384/256=1.5 + 4p -> 6p + 2dw -> 3dw + + for each line: 4 pixels => 6 pixels (*1.5) (64 blocks) + [ab][cd] => [a(ab)][bc][(cd)d] + + Vertical upscale: + Bresenham algo with simple interpolation + + Parameters: + uint32 *dst - pointer to 400x240x16bpp buffer + uint8 *src - pointer to 256x224x8bpp buffer + palette is taken from palettetranslate[] + pitch correction +*/ + +void upscale_384x240(uint32 *dst, uint8 *src) +{ + int midh = 240 * 3 / 4; + int Eh = 0; + int source = 0; + int dh = 0; + int y, x; + + dst += (400 - 384) / 4; + + for (y = 0; y < 240; y++) + { + source = dh * 256; + + for (x = 0; x < 384/6; x++) + { + register uint32 ab, cd; + + __builtin_prefetch(dst + 4, 1); + __builtin_prefetch(src + source + 4, 0); + + ab = palettetranslate[*(uint16 *)(src + source)] & 0xF7DEF7DE; + cd = palettetranslate[*(uint16 *)(src + source + 2)] & 0xF7DEF7DE; + + if(Eh >= midh) { // average + 256 + ab = AVERAGE(ab, palettetranslate[*(uint16 *)(src + source + 256)]) & 0xF7DEF7DE; // to prevent overflow + cd = AVERAGE(cd, palettetranslate[*(uint16 *)(src + source + 256 + 2)]) & 0xF7DEF7DE; // to prevent overflow + } + + *dst++ = (ab & 0xFFFF) + AVERAGEHI(ab); + *dst++ = (ab >> 16) + ((cd & 0xFFFF) << 16); + *dst++ = (cd & 0xFFFF0000) + AVERAGELO(cd); + + source += 4; + + } + dst += (400 - 384) / 2; + Eh += 224; if(Eh >= 240) { Eh -= 240; dh++; } + } +} + +/* + Upscale 256x224 -> 384x272 (for 480x240) + + Horizontal interpolation + 384/256=1.5 + 4p -> 6p + 2dw -> 3dw + + for each line: 4 pixels => 6 pixels (*1.5) (64 blocks) + [ab][cd] => [a(ab)][bc][(cd)d] + + Vertical upscale: + Bresenham algo with simple interpolation + + Parameters: + uint32 *dst - pointer to 480x272x16bpp buffer + uint8 *src - pointer to 256x224x8bpp buffer + palette is taken from palettetranslate[] + pitch correction +*/ + +void upscale_384x272(uint32 *dst, uint8 *src) +{ + int midh = 272 * 3 / 4; + int Eh = 0; + int source = 0; + int dh = 0; + int y, x; + + dst += (480 - 384) / 4; + + for (y = 0; y < 272; y++) + { + source = dh * 256; + + for (x = 0; x < 384/6; x++) + { + register uint32 ab, cd; + + __builtin_prefetch(dst + 4, 1); + __builtin_prefetch(src + source + 4, 0); + + ab = palettetranslate[*(uint16 *)(src + source)] & 0xF7DEF7DE; + cd = palettetranslate[*(uint16 *)(src + source + 2)] & 0xF7DEF7DE; + + if(Eh >= midh) { // average + 256 + ab = AVERAGE(ab, palettetranslate[*(uint16 *)(src + source + 256)]) & 0xF7DEF7DE; // to prevent overflow + cd = AVERAGE(cd, palettetranslate[*(uint16 *)(src + source + 256 + 2)]) & 0xF7DEF7DE; // to prevent overflow + } + + *dst++ = (ab & 0xFFFF) + AVERAGEHI(ab); + *dst++ = (ab >> 16) + ((cd & 0xFFFF) << 16); + *dst++ = (cd & 0xFFFF0000) + AVERAGELO(cd); + + source += 4; + + } + dst += (480 - 384) / 2; + Eh += 224; if(Eh >= 272) { Eh -= 272; dh++; } + } +} + +/* + Upscale 256x224 -> 480x272 + + Horizontal interpolation + 480/256=1.875 + 16p -> 30p + 8dw -> 15dw + + For each line 16 pixels => 30 pixels (*1.875) (32 blocks) + Coarse: + [ab][cd][ef][gh][ij][kl][mn][op] + => + [aa][bb][cc][d(de)][ef][fg][gh][hi][ij][jk][kl][(lm)m][nn][oo][pp] + Fine: + ab` = a, (0.875a + 0.125b) + cd` = b, (0.75b + 0.25c) + ef` = c, (0.625c + 0.375d) + gh` = d, (0.5d + 0.5e) + ij` = e, (0.375e + 0.625f) + kl` = f, (0.25f + 0.75g) + mn` = g, (0.125g + 0.875h) + op` = h, i + qr` = (0.875i + 0.125j), j + st` = (0.75j + 0.25k), k + uv` = (0.625k + 0.375l), l + wx` = (0.5l + 0.5m), m + yz` = (0.375m + 0.625n), n + 12` = (0.25n + 0.75o), o + 34` = (0.125o + 0.875p), p + + Vertical upscale: + Bresenham algo with simple interpolation +*/ + +void upscale_480x272(uint32 *dst, uint8 *src) +{ + int midh = 272 / 2; + int Eh = 0; + int source = 0; + int dh = 0; + int y, x; + + for (y = 0; y < 272; y++) + { + source = dh * 256; + + for (x = 0; x < 480/30; x++) + { + register uint32 ab, cd, ef, gh, ij, kl, mn, op; + + __builtin_prefetch(dst + 4, 1); + __builtin_prefetch(src + source + 4, 0); + + ab = palettetranslate[*(uint16 *)(src + source)] & 0xF7DEF7DE; + cd = palettetranslate[*(uint16 *)(src + source + 2)] & 0xF7DEF7DE; + ef = palettetranslate[*(uint16 *)(src + source + 4)] & 0xF7DEF7DE; + gh = palettetranslate[*(uint16 *)(src + source + 6)] & 0xF7DEF7DE; + ij = palettetranslate[*(uint16 *)(src + source + 8)] & 0xF7DEF7DE; + kl = palettetranslate[*(uint16 *)(src + source + 10)] & 0xF7DEF7DE; + mn = palettetranslate[*(uint16 *)(src + source + 12)] & 0xF7DEF7DE; + op = palettetranslate[*(uint16 *)(src + source + 14)] & 0xF7DEF7DE; + + if(Eh >= midh) { + ab = AVERAGE(ab, palettetranslate[*(uint16 *)(src + source + 256)]) & 0xF7DEF7DE; + cd = AVERAGE(cd, palettetranslate[*(uint16 *)(src + source + 256 + 2)]) & 0xF7DEF7DE; + ef = AVERAGE(ef, palettetranslate[*(uint16 *)(src + source + 256 + 4)]) & 0xF7DEF7DE; + gh = AVERAGE(gh, palettetranslate[*(uint16 *)(src + source + 256 + 6)]) & 0xF7DEF7DE; + ij = AVERAGE(ij, palettetranslate[*(uint16 *)(src + source + 256 + 8)]) & 0xF7DEF7DE; + kl = AVERAGE(kl, palettetranslate[*(uint16 *)(src + source + 256 + 10)]) & 0xF7DEF7DE; + mn = AVERAGE(mn, palettetranslate[*(uint16 *)(src + source + 256 + 12)]) & 0xF7DEF7DE; + op = AVERAGE(op, palettetranslate[*(uint16 *)(src + source + 256 + 14)]) & 0xF7DEF7DE; + } + + *dst++ = (ab & 0xFFFF) + (ab << 16); // [aa] + *dst++ = (ab >> 16) + (ab & 0xFFFF0000); // [bb] + *dst++ = (cd & 0xFFFF) + (cd << 16); // [cc] + *dst++ = (cd >> 16) + (((cd & 0xF7DE0000) >> 1) + ((ef & 0xF7DE) << 15)); // [d(de)] + *dst++ = ef; // [ef] + *dst++ = (ef >> 16) + (gh << 16); // [fg] + *dst++ = gh; // [gh] + *dst++ = (gh >> 16) + (ij << 16); // [hi] + *dst++ = ij; // [ij] + *dst++ = (ij >> 16) + (kl << 16); // [jk] + *dst++ = kl; // [kl] + *dst++ = (((kl & 0xF7DE0000) >> 17) + ((mn & 0xF7DE) >> 1)) + (mn << 16); // [(lm)m] + *dst++ = (mn >> 16) + (mn & 0xFFFF0000); // [nn] + *dst++ = (op & 0xFFFF) + (op << 16); // [oo] + *dst++ = (op >> 16) + (op & 0xFFFF0000); // [pp] + + source += 16; + } + Eh += 224; if(Eh >= 272) { Eh -= 272; dh++; } + } +} + +/* + * Approximately bilinear scaler, 256x224 to 320x240 + * + * Copyright (C) 2014 hi-ban, Nebuleon + * + * This function and all auxiliary functions are free software; you can + * redistribute them and/or modify them 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. + * + * These functions are distributed in the hope that they will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// Support math +#define Half(A) (((A) >> 1) & 0x7BEF) +#define Quarter(A) (((A) >> 2) & 0x39E7) +// Error correction expressions to piece back the lower bits together +#define RestHalf(A) ((A) & 0x0821) +#define RestQuarter(A) ((A) & 0x1863) + +// Error correction expressions for quarters of pixels +#define Corr1_3(A, B) Quarter(RestQuarter(A) + (RestHalf(B) << 1) + RestQuarter(B)) +#define Corr3_1(A, B) Quarter((RestHalf(A) << 1) + RestQuarter(A) + RestQuarter(B)) + +// Error correction expressions for halves +#define Corr1_1(A, B) ((A) & (B) & 0x0821) + +// Quarters +#define Weight1_3(A, B) (Quarter(A) + Half(B) + Quarter(B) + Corr1_3(A, B)) +#define Weight3_1(A, B) (Half(A) + Quarter(A) + Quarter(B) + Corr3_1(A, B)) + +// Halves +#define Weight1_1(A, B) (Half(A) + Half(B) + Corr1_1(A, B)) + +/* Upscales a 256x224 image to 320x240 using an approximate bilinear + * resampling algorithm that only uses integer math. + * + * Input: + * src: A packed 256x224 pixel image. The pixel format of this image is + * RGB 565. + * width: The width of the source image. Should always be 256. + * Output: + * dst: A packed 320x240 pixel image. The pixel format of this image is + * RGB 565. + */ +void upscale_320x240_bilinearish_clip(uint32_t* dst, uint8 *src, int width) +{ + uint8* Src16 = (uint8*) src; + uint16_t* Dst16 = (uint16_t*) dst; + // There are 80 blocks of 3 pixels horizontally, and 14 of 16 vertically. + // Each block of 3x16 becomes 4x17. + uint32_t BlockX, BlockY; + uint8* BlockSrc; + uint16_t* BlockDst; + for (BlockY = 0; BlockY < 14; BlockY++) + { + BlockSrc = Src16 + BlockY * 256 * 16; + BlockDst = Dst16 + BlockY * 320 * 17; + for (BlockX = 0; BlockX < 80; BlockX++) + { + /* Horizontally: + * Before(3): + * (a)(b)(c) + * After(4): + * (a)(abbb)(bbbc)(c) + * + * Vertically: + * Before(16): After(17): + * (a) (a) + * (b) (b) + * (c) (c) + * (d) (cddd) + * (e) (deee) + * (f) (efff) + * (g) (fggg) + * (h) (ghhh) + * (i) (hi) + * (j) (iiij) + * (k) (jjjk) + * (l) (kkkl) + * (m) (lllm) + * (n) (mmmn) + * (o) (n) + * (p) (o) + * (p) + */ + + // -- Row 1 -- + uint16_t _1 = palettetranslate[*(BlockSrc + 8)]; + *(BlockDst + 0) = _1; + uint16_t _2 = palettetranslate[*(BlockSrc + 1 + 8)]; + *(BlockDst + 1) = Weight1_3( _1, _2); + uint16_t _3 = palettetranslate[*(BlockSrc + 2 + 8)]; + *(BlockDst + 2) = Weight3_1( _2, _3); + *(BlockDst + 3) = _3; + + // -- Row 2 -- + uint16_t _4 = palettetranslate[*(BlockSrc + 256 * 1 + 8)]; + *(BlockDst + 320 * 1 + 0) = _4; + uint16_t _5 = palettetranslate[*(BlockSrc + 256 * 1 + 1 + 8)]; + *(BlockDst + 320 * 1 + 1) = Weight1_3( _4, _5); + uint16_t _6 = palettetranslate[*(BlockSrc + 256 * 1 + 2 + 8)]; + *(BlockDst + 320 * 1 + 2) = Weight3_1( _5, _6); + *(BlockDst + 320 * 1 + 3) = _6; + + // -- Row 3 -- + uint16_t _7 = palettetranslate[*(BlockSrc + 256 * 2 + 8)]; + *(BlockDst + 320 * 2 + 0) = _7; + uint16_t _8 = palettetranslate[*(BlockSrc + 256 * 2 + 1 + 8)]; + *(BlockDst + 320 * 2 + 1) = Weight1_3( _7, _8); + uint16_t _9 = palettetranslate[*(BlockSrc + 256 * 2 + 2 + 8)]; + *(BlockDst + 320 * 2 + 2) = Weight3_1(_8, _9); + *(BlockDst + 320 * 2 + 3) = _9; + + // -- Row 4 -- + uint16_t _10 = palettetranslate[*(BlockSrc + 256 * 3 + 8)]; + *(BlockDst + 320 * 3 + 0) = Weight1_3( _7, _10); + uint16_t _11 = palettetranslate[*(BlockSrc + 256 * 3 + 1 + 8)]; + *(BlockDst + 320 * 3 + 1) = Weight1_3(Weight1_3( _7, _8), Weight1_3(_10, _11)); + uint16_t _12 = palettetranslate[*(BlockSrc + 256 * 3 + 2 + 8)]; + *(BlockDst + 320 * 3 + 2) = Weight1_3(Weight3_1(_8, _9), Weight3_1(_11, _12)); + *(BlockDst + 320 * 3 + 3) = Weight1_3(_9, _12); + + // -- Row 5 -- + uint16_t _13 = palettetranslate[*(BlockSrc + 256 * 4 + 8)]; + *(BlockDst + 320 * 4 + 0) = Weight1_3(_10, _13); + uint16_t _14 = palettetranslate[*(BlockSrc + 256 * 4 + 1 + 8)]; + *(BlockDst + 320 * 4 + 1) = Weight1_3(Weight1_3(_10, _11), Weight1_3(_13, _14)); + uint16_t _15 = palettetranslate[*(BlockSrc + 256 * 4 + 2 + 8)]; + *(BlockDst + 320 * 4 + 2) = Weight1_3(Weight3_1(_11, _12), Weight3_1(_14, _15)); + *(BlockDst + 320 * 4 + 3) = Weight1_3(_12, _15); + + // -- Row 6 -- + uint16_t _16 = palettetranslate[*(BlockSrc + 256 * 5 + 8)]; + *(BlockDst + 320 * 5 + 0) = Weight1_3(_13, _16); + uint16_t _17 = palettetranslate[*(BlockSrc + 256 * 5 + 1 + 8)]; + *(BlockDst + 320 * 5 + 1) = Weight1_3(Weight1_3(_13, _14), Weight1_3(_16, _17)); + uint16_t _18 = palettetranslate[*(BlockSrc + 256 * 5 + 2 + 8)]; + *(BlockDst + 320 * 5 + 2) = Weight1_3(Weight3_1(_14, _15), Weight3_1(_17, _18)); + *(BlockDst + 320 * 5 + 3) = Weight1_3(_15, _18); + + // -- Row 7 -- + uint16_t _19 = palettetranslate[*(BlockSrc + 256 * 6 + 8)]; + *(BlockDst + 320 * 6 + 0) = Weight1_3(_16, _19); + uint16_t _20 = palettetranslate[*(BlockSrc + 256 * 6 + 1 + 8)]; + *(BlockDst + 320 * 6 + 1) = Weight1_3(Weight1_3(_16, _17), Weight1_3(_19, _20)); + uint16_t _21 = palettetranslate[*(BlockSrc + 256 * 6 + 2 + 8)]; + *(BlockDst + 320 * 6 + 2) = Weight1_3(Weight3_1(_17, _18), Weight3_1(_20, _21)); + *(BlockDst + 320 * 6 + 3) = Weight1_3(_18, _21); + + // -- Row 8 -- + uint16_t _22 = palettetranslate[*(BlockSrc + 256 * 7 + 8)]; + *(BlockDst + 320 * 7 + 0) = Weight1_3(_19, _22); + uint16_t _23 = palettetranslate[*(BlockSrc + 256 * 7 + 1 + 8)]; + *(BlockDst + 320 * 7 + 1) = Weight1_3(Weight1_3(_19, _20), Weight1_3(_22, _23)); + uint16_t _24 = palettetranslate[*(BlockSrc + 256 * 7 + 2 + 8)]; + *(BlockDst + 320 * 7 + 2) = Weight1_3(Weight3_1(_20, _21), Weight3_1(_23, _24)); + *(BlockDst + 320 * 7 + 3) = Weight1_3(_21, _24); + + // -- Row 9 -- + uint16_t _25 = palettetranslate[*(BlockSrc + 256 * 8 + 8)]; + *(BlockDst + 320 * 8 + 0) = Weight1_1(_22, _25); + uint16_t _26 = palettetranslate[*(BlockSrc + 256 * 8 + 1 + 8)]; + *(BlockDst + 320 * 8 + 1) = Weight1_1(Weight1_3(_22, _23), Weight1_3(_25, _26)); + uint16_t _27 = palettetranslate[*(BlockSrc + 256 * 8 + 2 + 8)]; + *(BlockDst + 320 * 8 + 2) = Weight1_1(Weight3_1(_23, _24), Weight3_1(_26, _27)); + *(BlockDst + 320 * 8 + 3) = Weight1_1(_24, _27); + + // -- Row 10 -- + uint16_t _28 = palettetranslate[*(BlockSrc + 256 * 9 + 8)]; + *(BlockDst + 320 * 9 + 0) = Weight3_1(_25, _28); + uint16_t _29 = palettetranslate[*(BlockSrc + 256 * 9 + 1 + 8)]; + *(BlockDst + 320 * 9 + 1) = Weight3_1(Weight1_3(_25, _26), Weight1_3(_28, _29)); + uint16_t _30 = palettetranslate[*(BlockSrc + 256 * 9 + 2 + 8)]; + *(BlockDst + 320 * 9 + 2) = Weight3_1(Weight3_1(_26, _27), Weight3_1(_29, _30)); + *(BlockDst + 320 * 9 + 3) = Weight3_1(_27, _30); + + // -- Row 11 -- + uint16_t _31 = palettetranslate[*(BlockSrc + 256 * 10 + 8)]; + *(BlockDst + 320 * 10 + 0) = Weight3_1(_28, _31); + uint16_t _32 = palettetranslate[*(BlockSrc + 256 * 10 + 1 + 8)]; + *(BlockDst + 320 * 10 + 1) = Weight3_1(Weight1_3(_28, _29), Weight1_3(_31, _32)); + uint16_t _33 = palettetranslate[*(BlockSrc + 256 * 10 + 2 + 8)]; + *(BlockDst + 320 * 10 + 2) = Weight3_1(Weight3_1(_29, _30), Weight3_1(_32, _33)); + *(BlockDst + 320 * 10 + 3) = Weight3_1(_30, _33); + + // -- Row 12 -- + uint16_t _34 = palettetranslate[*(BlockSrc + 256 * 11 + 8)]; + *(BlockDst + 320 * 11 + 0) = Weight3_1(_31, _34); + uint16_t _35 = palettetranslate[*(BlockSrc + 256 * 11 + 1 + 8)]; + *(BlockDst + 320 * 11 + 1) = Weight3_1(Weight1_3(_31, _32), Weight1_3(_34, _35)); + uint16_t _36 = palettetranslate[*(BlockSrc + 256 * 11 + 2 + 8)]; + *(BlockDst + 320 * 11 + 2) = Weight3_1(Weight3_1(_32, _33), Weight3_1(_35, _36)); + *(BlockDst + 320 * 11 + 3) = Weight3_1(_33, _36); + + // -- Row 13 -- + uint16_t _37 = palettetranslate[*(BlockSrc + 256 * 12 + 8)]; + *(BlockDst + 320 * 12 + 0) = Weight3_1(_34, _37); + uint16_t _38 = palettetranslate[*(BlockSrc + 256 * 12 + 1 + 8)]; + *(BlockDst + 320 * 12 + 1) = Weight3_1(Weight1_3(_34, _35), Weight1_3(_37, _38)); + uint16_t _39 = palettetranslate[*(BlockSrc + 256 * 12 + 2 + 8)]; + *(BlockDst + 320 * 12 + 2) = Weight3_1(Weight3_1(_35, _36), Weight3_1(_38, _39)); + *(BlockDst + 320 * 12 + 3) = Weight3_1(_36, _39); + + // -- Row 14 -- + uint16_t _40 = palettetranslate[*(BlockSrc + 256 * 13 + 8)]; + *(BlockDst + 320 * 13 + 0) = Weight3_1(_37, _40); + uint16_t _41 = palettetranslate[*(BlockSrc + 256 * 13 + 1 + 8)]; + *(BlockDst + 320 * 13 + 1) = Weight3_1(Weight1_3(_37, _38), Weight1_3(_40, _41)); + uint16_t _42 = palettetranslate[*(BlockSrc + 256 * 13 + 2 + 8)]; + *(BlockDst + 320 * 13 + 2) = Weight3_1(Weight3_1(_38, _39), Weight3_1(_41, _42)); + *(BlockDst + 320 * 13 + 3) = Weight3_1(_39, _42); + + // -- Row 15 -- + *(BlockDst + 320 * 14 + 0) = _40; + *(BlockDst + 320 * 14 + 1) = Weight1_3(_40, _41); + *(BlockDst + 320 * 14 + 2) = Weight3_1(_41, _42); + *(BlockDst + 320 * 14 + 3) = _42; + + // -- Row 16 -- + uint16_t _43 = palettetranslate[*(BlockSrc + 256 * 14 + 8)]; + *(BlockDst + 320 * 15 + 0) = _43; + uint16_t _44 = palettetranslate[*(BlockSrc + 256 * 14 + 1 + 8)]; + *(BlockDst + 320 * 15 + 1) = Weight1_3(_43, _44); + uint16_t _45 = palettetranslate[*(BlockSrc + 256 * 14 + 2 + 8)]; + *(BlockDst + 320 * 15 + 2) = Weight3_1(_44, _45); + *(BlockDst + 320 * 15 + 3) = _45; + + // -- Row 17 -- + uint16_t _46 = palettetranslate[*(BlockSrc + 256 * 15 + 8)]; + *(BlockDst + 320 * 16 + 0) = _46; + uint16_t _47 = palettetranslate[*(BlockSrc + 256 * 15 + 1 + 8)]; + *(BlockDst + 320 * 16 + 1) = Weight1_3(_46, _47); + uint16_t _48 = palettetranslate[*(BlockSrc + 256 * 15 + 2 + 8)]; + *(BlockDst + 320 * 16 + 2) = Weight3_1(_47, _48); + *(BlockDst + 320 * 16 + 3) = _48; + + BlockSrc += 3; + BlockDst += 4; + } + } +} + +void upscale_320x240_bilinearish_noclip(uint32_t* dst, uint8 *src, int width) +{ + uint8* Src16 = (uint8*) src; + uint16_t* Dst16 = (uint16_t*) dst; + // There are 64 blocks of 4 pixels horizontally, and 14 of 16 vertically. + // Each block of 4x16 becomes 5x17. + uint32_t BlockX, BlockY; + uint8* BlockSrc; + uint16_t* BlockDst; + for (BlockY = 0; BlockY < 14; BlockY++) + { + BlockSrc = Src16 + BlockY * 256 * 16; + BlockDst = Dst16 + BlockY * 320 * 17; + for (BlockX = 0; BlockX < 64; BlockX++) + { + /* Horizontally: + * Before(4): + * (a)(b)(c)(d) + * After(5): + * (a)(abbb)(bc)(cccd)(d) + * + * Vertically: + * Before(16): After(17): + * (a) (a) + * (b) (b) + * (c) (c) + * (d) (cddd) + * (e) (deee) + * (f) (efff) + * (g) (fggg) + * (h) (ghhh) + * (i) (hi) + * (j) (iiij) + * (k) (jjjk) + * (l) (kkkl) + * (m) (lllm) + * (n) (mmmn) + * (o) (n) + * (p) (o) + * (p) + */ + + // -- Row 1 -- + uint16_t _1 = palettetranslate[*(BlockSrc )]; + *(BlockDst + 0) = _1; + uint16_t _2 = palettetranslate[*(BlockSrc + 1)]; + *(BlockDst + 1) = Weight1_3( _1, _2); + uint16_t _3 = palettetranslate[*(BlockSrc + 2)]; + *(BlockDst + 2) = Weight1_1( _2, _3); + uint16_t _4 = palettetranslate[*(BlockSrc + 3)]; + *(BlockDst + 3) = Weight3_1( _3, _4); + *(BlockDst + 4) = _4; + + // -- Row 2 -- + uint16_t _5 = palettetranslate[*(BlockSrc + 256 * 1 )]; + *(BlockDst + 320 * 1 + 0) = _5; + uint16_t _6 = palettetranslate[*(BlockSrc + 256 * 1 + 1)]; + *(BlockDst + 320 * 1 + 1) = Weight1_3( _5, _6); + uint16_t _7 = palettetranslate[*(BlockSrc + 256 * 1 + 2)]; + *(BlockDst + 320 * 1 + 2) = Weight1_1( _6, _7); + uint16_t _8 = palettetranslate[*(BlockSrc + 256 * 1 + 3)]; + *(BlockDst + 320 * 1 + 3) = Weight3_1( _7, _8); + *(BlockDst + 320 * 1 + 4) = _8; + + // -- Row 3 -- + uint16_t _9 = palettetranslate[*(BlockSrc + 256 * 2 )]; + *(BlockDst + 320 * 2 + 0) = _9; + uint16_t _10 = palettetranslate[*(BlockSrc + 256 * 2 + 1)]; + *(BlockDst + 320 * 2 + 1) = Weight1_3( _9, _10); + uint16_t _11 = palettetranslate[*(BlockSrc + 256 * 2 + 2)]; + *(BlockDst + 320 * 2 + 2) = Weight1_1(_10, _11); + uint16_t _12 = palettetranslate[*(BlockSrc + 256 * 2 + 3)]; + *(BlockDst + 320 * 2 + 3) = Weight3_1(_11, _12); + *(BlockDst + 320 * 2 + 4) = _12; + + // -- Row 4 -- + uint16_t _13 = palettetranslate[*(BlockSrc + 256 * 3 )]; + *(BlockDst + 320 * 3 + 0) = Weight1_3( _9, _13); + uint16_t _14 = palettetranslate[*(BlockSrc + 256 * 3 + 1)]; + *(BlockDst + 320 * 3 + 1) = Weight1_3(Weight1_3( _9, _10), Weight1_3(_13, _14)); + uint16_t _15 = palettetranslate[*(BlockSrc + 256 * 3 + 2)]; + *(BlockDst + 320 * 3 + 2) = Weight1_3(Weight1_1(_10, _11), Weight1_1(_14, _15)); + uint16_t _16 = palettetranslate[*(BlockSrc + 256 * 3 + 3)]; + *(BlockDst + 320 * 3 + 3) = Weight1_3(Weight3_1(_11, _12), Weight3_1(_15, _16)); + *(BlockDst + 320 * 3 + 4) = Weight1_3(_12, _16); + + // -- Row 5 -- + uint16_t _17 = palettetranslate[*(BlockSrc + 256 * 4 )]; + *(BlockDst + 320 * 4 + 0) = Weight1_3(_13, _17); + uint16_t _18 = palettetranslate[*(BlockSrc + 256 * 4 + 1)]; + *(BlockDst + 320 * 4 + 1) = Weight1_3(Weight1_3(_13, _14), Weight1_3(_17, _18)); + uint16_t _19 = palettetranslate[*(BlockSrc + 256 * 4 + 2)]; + *(BlockDst + 320 * 4 + 2) = Weight1_3(Weight1_1(_14, _15), Weight1_1(_18, _19)); + uint16_t _20 = palettetranslate[*(BlockSrc + 256 * 4 + 3)]; + *(BlockDst + 320 * 4 + 3) = Weight1_3(Weight3_1(_15, _16), Weight3_1(_19, _20)); + *(BlockDst + 320 * 4 + 4) = Weight1_3(_16, _20); + + // -- Row 6 -- + uint16_t _21 = palettetranslate[*(BlockSrc + 256 * 5 )]; + *(BlockDst + 320 * 5 + 0) = Weight1_3(_17, _21); + uint16_t _22 = palettetranslate[*(BlockSrc + 256 * 5 + 1)]; + *(BlockDst + 320 * 5 + 1) = Weight1_3(Weight1_3(_17, _18), Weight1_3(_21, _22)); + uint16_t _23 = palettetranslate[*(BlockSrc + 256 * 5 + 2)]; + *(BlockDst + 320 * 5 + 2) = Weight1_3(Weight1_1(_18, _19), Weight1_1(_22, _23)); + uint16_t _24 = palettetranslate[*(BlockSrc + 256 * 5 + 3)]; + *(BlockDst + 320 * 5 + 3) = Weight1_3(Weight3_1(_19, _20), Weight3_1(_23, _24)); + *(BlockDst + 320 * 5 + 4) = Weight1_3(_20, _24); + + // -- Row 7 -- + uint16_t _25 = palettetranslate[*(BlockSrc + 256 * 6 )]; + *(BlockDst + 320 * 6 + 0) = Weight1_3(_21, _25); + uint16_t _26 = palettetranslate[*(BlockSrc + 256 * 6 + 1)]; + *(BlockDst + 320 * 6 + 1) = Weight1_3(Weight1_3(_21, _22), Weight1_3(_25, _26)); + uint16_t _27 = palettetranslate[*(BlockSrc + 256 * 6 + 2)]; + *(BlockDst + 320 * 6 + 2) = Weight1_3(Weight1_1(_22, _23), Weight1_1(_26, _27)); + uint16_t _28 = palettetranslate[*(BlockSrc + 256 * 6 + 3)]; + *(BlockDst + 320 * 6 + 3) = Weight1_3(Weight3_1(_23, _24), Weight3_1(_27, _28)); + *(BlockDst + 320 * 6 + 4) = Weight1_3(_24, _28); + + // -- Row 8 -- + uint16_t _29 = palettetranslate[*(BlockSrc + 256 * 7 )]; + *(BlockDst + 320 * 7 + 0) = Weight1_3(_25, _29); + uint16_t _30 = palettetranslate[*(BlockSrc + 256 * 7 + 1)]; + *(BlockDst + 320 * 7 + 1) = Weight1_3(Weight1_3(_25, _26), Weight1_3(_29, _30)); + uint16_t _31 = palettetranslate[*(BlockSrc + 256 * 7 + 2)]; + *(BlockDst + 320 * 7 + 2) = Weight1_3(Weight1_1(_26, _27), Weight1_1(_30, _31)); + uint16_t _32 = palettetranslate[*(BlockSrc + 256 * 7 + 3)]; + *(BlockDst + 320 * 7 + 3) = Weight1_3(Weight3_1(_27, _28), Weight3_1(_31, _32)); + *(BlockDst + 320 * 7 + 4) = Weight1_3(_28, _32); + + // -- Row 9 -- + uint16_t _33 = palettetranslate[*(BlockSrc + 256 * 8 )]; + *(BlockDst + 320 * 8 + 0) = Weight1_1(_29, _33); + uint16_t _34 = palettetranslate[*(BlockSrc + 256 * 8 + 1)]; + *(BlockDst + 320 * 8 + 1) = Weight1_1(Weight1_3(_29, _30), Weight1_3(_33, _34)); + uint16_t _35 = palettetranslate[*(BlockSrc + 256 * 8 + 2)]; + *(BlockDst + 320 * 8 + 2) = Weight1_1(Weight1_1(_30, _31), Weight1_1(_34, _35)); + uint16_t _36 = palettetranslate[*(BlockSrc + 256 * 8 + 3)]; + *(BlockDst + 320 * 8 + 3) = Weight1_1(Weight3_1(_31, _32), Weight3_1(_35, _36)); + *(BlockDst + 320 * 8 + 4) = Weight1_1(_32, _36); + + // -- Row 10 -- + uint16_t _37 = palettetranslate[*(BlockSrc + 256 * 9 )]; + *(BlockDst + 320 * 9 + 0) = Weight3_1(_33, _37); + uint16_t _38 = palettetranslate[*(BlockSrc + 256 * 9 + 1)]; + *(BlockDst + 320 * 9 + 1) = Weight3_1(Weight1_3(_33, _34), Weight1_3(_37, _38)); + uint16_t _39 = palettetranslate[*(BlockSrc + 256 * 9 + 2)]; + *(BlockDst + 320 * 9 + 2) = Weight3_1(Weight1_1(_34, _35), Weight1_1(_38, _39)); + uint16_t _40 = palettetranslate[*(BlockSrc + 256 * 9 + 3)]; + *(BlockDst + 320 * 9 + 3) = Weight3_1(Weight3_1(_35, _36), Weight3_1(_39, _40)); + *(BlockDst + 320 * 9 + 4) = Weight3_1(_36, _40); + + // -- Row 11 -- + uint16_t _41 = palettetranslate[*(BlockSrc + 256 * 10 )]; + *(BlockDst + 320 * 10 + 0) = Weight3_1(_37, _41); + uint16_t _42 = palettetranslate[*(BlockSrc + 256 * 10 + 1)]; + *(BlockDst + 320 * 10 + 1) = Weight3_1(Weight1_3(_37, _38), Weight1_3(_41, _42)); + uint16_t _43 = palettetranslate[*(BlockSrc + 256 * 10 + 2)]; + *(BlockDst + 320 * 10 + 2) = Weight3_1(Weight1_1(_38, _39), Weight1_1(_42, _43)); + uint16_t _44 = palettetranslate[*(BlockSrc + 256 * 10 + 3)]; + *(BlockDst + 320 * 10 + 3) = Weight3_1(Weight3_1(_39, _40), Weight3_1(_43, _44)); + *(BlockDst + 320 * 10 + 4) = Weight3_1(_40, _44); + + // -- Row 12 -- + uint16_t _45 = palettetranslate[*(BlockSrc + 256 * 11 )]; + *(BlockDst + 320 * 11 + 0) = Weight3_1(_41, _45); + uint16_t _46 = palettetranslate[*(BlockSrc + 256 * 11 + 1)]; + *(BlockDst + 320 * 11 + 1) = Weight3_1(Weight1_3(_41, _42), Weight1_3(_45, _46)); + uint16_t _47 = palettetranslate[*(BlockSrc + 256 * 11 + 2)]; + *(BlockDst + 320 * 11 + 2) = Weight3_1(Weight1_1(_42, _43), Weight1_1(_46, _47)); + uint16_t _48 = palettetranslate[*(BlockSrc + 256 * 11 + 3)]; + *(BlockDst + 320 * 11 + 3) = Weight3_1(Weight3_1(_43, _44), Weight3_1(_47, _48)); + *(BlockDst + 320 * 11 + 4) = Weight3_1(_44, _48); + + // -- Row 13 -- + uint16_t _49 = palettetranslate[*(BlockSrc + 256 * 12 )]; + *(BlockDst + 320 * 12 + 0) = Weight3_1(_45, _49); + uint16_t _50 = palettetranslate[*(BlockSrc + 256 * 12 + 1)]; + *(BlockDst + 320 * 12 + 1) = Weight3_1(Weight1_3(_45, _46), Weight1_3(_49, _50)); + uint16_t _51 = palettetranslate[*(BlockSrc + 256 * 12 + 2)]; + *(BlockDst + 320 * 12 + 2) = Weight3_1(Weight1_1(_46, _47), Weight1_1(_50, _51)); + uint16_t _52 = palettetranslate[*(BlockSrc + 256 * 12 + 3)]; + *(BlockDst + 320 * 12 + 3) = Weight3_1(Weight3_1(_47, _48), Weight3_1(_51, _52)); + *(BlockDst + 320 * 12 + 4) = Weight3_1(_48, _52); + + // -- Row 14 -- + uint16_t _53 = palettetranslate[*(BlockSrc + 256 * 13 )]; + *(BlockDst + 320 * 13 + 0) = Weight3_1(_49, _53); + uint16_t _54 = palettetranslate[*(BlockSrc + 256 * 13 + 1)]; + *(BlockDst + 320 * 13 + 1) = Weight3_1(Weight1_3(_49, _50), Weight1_3(_53, _54)); + uint16_t _55 = palettetranslate[*(BlockSrc + 256 * 13 + 2)]; + *(BlockDst + 320 * 13 + 2) = Weight3_1(Weight1_1(_50, _51), Weight1_1(_54, _55)); + uint16_t _56 = palettetranslate[*(BlockSrc + 256 * 13 + 3)]; + *(BlockDst + 320 * 13 + 3) = Weight3_1(Weight3_1(_51, _52), Weight3_1(_55, _56)); + *(BlockDst + 320 * 13 + 4) = Weight3_1(_52, _56); + + // -- Row 15 -- + *(BlockDst + 320 * 14 + 0) = _53; + *(BlockDst + 320 * 14 + 1) = Weight1_3(_53, _54); + *(BlockDst + 320 * 14 + 2) = Weight1_1(_54, _55); + *(BlockDst + 320 * 14 + 3) = Weight3_1(_55, _56); + *(BlockDst + 320 * 14 + 4) = _56; + + // -- Row 16 -- + uint16_t _57 = palettetranslate[*(BlockSrc + 256 * 14 )]; + *(BlockDst + 320 * 15 + 0) = _57; + uint16_t _58 = palettetranslate[*(BlockSrc + 256 * 14 + 1)]; + *(BlockDst + 320 * 15 + 1) = Weight1_3(_57, _58); + uint16_t _59 = palettetranslate[*(BlockSrc + 256 * 14 + 2)]; + *(BlockDst + 320 * 15 + 2) = Weight1_1(_58, _59); + uint16_t _60 = palettetranslate[*(BlockSrc + 256 * 14 + 3)]; + *(BlockDst + 320 * 15 + 3) = Weight3_1(_59, _60); + *(BlockDst + 320 * 15 + 4) = _60; + + // -- Row 17 -- + uint16_t _61 = palettetranslate[*(BlockSrc + 256 * 15 )]; + *(BlockDst + 320 * 16 + 0) = _61; + uint16_t _62 = palettetranslate[*(BlockSrc + 256 * 15 + 1)]; + *(BlockDst + 320 * 16 + 1) = Weight1_3(_61, _62); + uint16_t _63 = palettetranslate[*(BlockSrc + 256 * 15 + 2)]; + *(BlockDst + 320 * 16 + 2) = Weight1_1(_62, _63); + uint16_t _64 = palettetranslate[*(BlockSrc + 256 * 15 + 3)]; + *(BlockDst + 320 * 16 + 3) = Weight3_1(_63, _64); + *(BlockDst + 320 * 16 + 4) = _64; + + BlockSrc += 4; + BlockDst += 5; + } + } +} \ No newline at end of file diff --git a/src/drivers/dingux-sdl/scaler.h b/src/drivers/dingux-sdl/scaler.h new file mode 100644 index 000000000..45572c61d --- /dev/null +++ b/src/drivers/dingux-sdl/scaler.h @@ -0,0 +1,10 @@ + + +#include "../../types.h" + +void upscale_320x240(uint32 *dst, uint8 *src); +void upscale_384x240(uint32 *dst, uint8 *src); +void upscale_384x272(uint32 *dst, uint8 *src); +void upscale_480x272(uint32 *dst, uint8 *src); +void upscale_320x240_bilinearish_clip(uint32_t* dst, uint8 *src, int width); +void upscale_320x240_bilinearish_noclip(uint32_t* dst, uint8 *src, int width); \ No newline at end of file diff --git a/src/drivers/dingux-sdl/throttle.h b/src/drivers/dingux-sdl/throttle.h new file mode 100644 index 000000000..59984fba0 --- /dev/null +++ b/src/drivers/dingux-sdl/throttle.h @@ -0,0 +1,2 @@ +void RefreshThrottleFPS(void); +int SpeedThrottle(void); diff --git a/src/drivers/dingux-sdl/types.h b/src/drivers/dingux-sdl/types.h new file mode 100644 index 000000000..10d9fb687 --- /dev/null +++ b/src/drivers/dingux-sdl/types.h @@ -0,0 +1,22 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned long +#define s8 signed char +#define s16 signed short +#define s32 signed long + +#endif \ No newline at end of file diff --git a/src/fceu.cpp b/src/fceu.cpp index 599158228..54a8846b5 100644 --- a/src/fceu.cpp +++ b/src/fceu.cpp @@ -74,6 +74,8 @@ extern void RefreshThrottleFPS(); #include "drivers/win/ramwatch.h" #include "drivers/win/memwatch.h" #include "drivers/win/tracer.h" +#elif defined(DINGUX) +#include "drivers/dingux-sdl/dingoo.h" #else #include "drivers/sdl/sdl.h" #endif @@ -747,7 +749,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski extern int KillFCEUXonFrame; if (KillFCEUXonFrame && (FCEUMOV_GetFrame() >= KillFCEUXonFrame)) DoFCEUExit(); -#else +#elif !defined(DINGUX) extern int KillFCEUXonFrame; if (KillFCEUXonFrame && (FCEUMOV_GetFrame() >= KillFCEUXonFrame)) exit(0); diff --git a/src/file.cpp b/src/file.cpp index 9860d87e2..8a2432fef 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -758,6 +758,9 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1) else sprintf(ret,"%s" PSS "fcs" PSS "%s*.fc?",BaseDirectory.c_str(),FileBase); break; + case FCEUMKF_CFG: + sprintf(ret,"%s" PSS "cfg" PSS "%s.cfg",BaseDirectory.c_str(),FileBase); + break; } //convert | to . for archive filenames. diff --git a/src/file.h b/src/file.h index 3afb99670..58fcdf2ea 100644 --- a/src/file.h +++ b/src/file.h @@ -167,4 +167,5 @@ void FCEU_SplitArchiveFilename(std::string src, std::string& archive, std::strin #define FCEUMKF_AVI 21 #define FCEUMKF_TASEDITOR 22 #define FCEUMKF_RESUMESTATE 23 +#define FCEUMKF_CFG 24 #endif diff --git a/src/video.cpp b/src/video.cpp index d9654c965..f0cef6e84 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -523,7 +523,11 @@ int SaveSnapshot(void) int x,u,y; FILE *pp=NULL; uint8 *compmem=NULL; +#ifdef DINGUX + uLongf compmemsize=(totallines*263+12); +#else uLongf compmemsize=(totallines*263+12)*3; +#endif if(!(compmem=(uint8 *)FCEU_malloc(compmemsize))) return 0; @@ -558,7 +562,11 @@ int SaveSnapshot(void) chunko[7]=totallines; // Height chunko[8]=8; // 8 bits per sample(24 bits per pixel) +#ifdef DINGUX + chunko[9]=3; // Color type; indexed 8-bit +#else chunko[9]=2; // Color type; RGB triplet +#endif chunko[10]=0; // compression: deflate chunko[11]=0; // Basic adapative filter set(though none are used). chunko[12]=0; // No interlace. @@ -567,11 +575,25 @@ int SaveSnapshot(void) goto PNGerr; } +#ifdef DINGUX + { + uint8 pdata[256*3]; + for(x=0;x<256;x++) + FCEUD_GetPalette(x,pdata+x*3,pdata+x*3+1,pdata+x*3+2); + if(!WritePNGChunk(pp,256*3,"PLTE",pdata)) + goto PNGerr; + } +#endif + { uint8 *tmp=XBuf+FSettings.FirstSLine*256; uint8 *dest,*mal,*mork; +#ifdef DINGUX + int bufsize = (totallines<<8)+totallines; +#else int bufsize = (256*3+1)*totallines; +#endif if(!(mal=mork=dest=(uint8 *)FCEU_dmalloc(bufsize))) goto PNGerr; // mork=dest=XBuf; @@ -580,6 +602,10 @@ int SaveSnapshot(void) { *dest=0; // No filter. dest++; +#ifdef DINGUX + for(x=256;x;x--,tmp++,dest++) + *dest=*tmp; +#else for(x=256;x;x--) { u32 color = ModernDeemphColorMap(tmp,XBuf,1,1); @@ -588,6 +614,7 @@ int SaveSnapshot(void) *dest++=(color>>0x00)&0xFF; tmp++; } +#endif } if(compress(compmem,&compmemsize,mork,bufsize)!=Z_OK) @@ -736,7 +763,12 @@ static int boopcount = 0; void ShowFPS(void) { +#ifdef DINGUX + extern int showfps; // in dingoo.cpp + if (!showfps) +#else if(Show_FPS == false) +#endif return; uint64 da = FCEUD_GetTime() - boop[boopcount]; char fpsmsg[16];