Compare commits

..

3 Commits
v051 ... v054

Author SHA1 Message Date
byuu
6a17b5ed4f Update to bsnes v054 release.
After a half-dozen hours of installing and compiling various combinations of MinGW and Qt, I've finally found a combination that once again allows for profile-guided optimizations: MinGW GCC 4.3.3 and Qt 4.6.0-beta 1. Though Qt 4.4 still has broken PGO, the latest Qt beta no longer has the process freeze issue upon termination.
This release is essentially the same as v053, but it's now at least as fast as v052 was, and ~10% faster than v053, which lacked profiling.
I did add in two quick changes, however: first, when starting in fullscreen mode, the video output size was being incorrectly set to the windowed size; second, by requiring save states to match the CRC32 of games, it made debugging with them impossible, so I've turned off the CRC32 matching.
2009-10-19 16:58:29 +00:00
byuu
8135dfdac9 Update to bsnes v053 release.
This release greatly polishes the user interface, adds a new cheat code search utility, adds the snesfilter library, and adds Qt-based GUI support to both snesfilter and snesreader. snesfilter gains 2xSaI, Super 2xSaI and Super Eagle support, plus full configuration for both the NTSC and scanline filters; and snesreader gains support support for multi-file ROM archives (eg GoodMerge sets.)
Statically linking Qt to bsnes, snesfilter and snesreader would be too prohibitive size-wise (~10MB or so.) I have to link dynamically so that all three can share the same Qt runtime, which gets all of bsnes and its modules to ~1MB (including the debugger build); and Qt itself to about ~2.5MB.
However, there is some bad news. There's a serious bug in MinGW 4.4+, where it is not generating profile-guided input files (*.gcno files.) There is also a serious bug in Qt 4.5.2/Windows when using dynamic linking: the library is hanging indefinitely, forcing me to manually terminate the process upon exit. This prevents the creation of profile-guided output files (*.gcda files.) It would be tough enough to work around one, but facing both of these issues at once is too much.
I'm afraid I have no choice but to disable profile-guided optimizations until these issues can be addressed. I did not know about these bugs until trying to build the official v053 release, so it's too late to revert to an all-in-one binary now. And I'm simply not willing to stop releasing new builds because of bugs in third-party software. As soon as I can work around this, I'll post a new optimized binary. In the mean time, despite the fact that this release is actually more optimized, please understand that the Windows binary will run approximately ~10% slower than previous releases. I recommend keeping v052 for now if you need the performance. Linux and OS X users are unaffected.
Changelog:
    - save RAM is initialized to 0xff again to work around Ken Griffey Jr Baseball issue
    - libco adds assembly-optimized targets for Win64 and PPC-ELF [the latter courtesy of Kernigh]
    - libco/x86 and libco/amd64 use pre-assembled blocks now, obviates need for custom compilation flags
    - added a new cheat code search utility to the tools menu
    - separated filters from main bsnes binary to libsnesfilter / snesfilter.dll
    - added 2xSaI, Super 2xSaI and Super Eagle filters [kode54]
    - added full configuration settings for NTSC and scanline filters (12+ new options)
    - further optimized HQ2x filter [blargg]
    - added Vsync support to the Mac OS X OpenGL driver
    - added folder creation button to custom file load dialog
    - fixed a few oddities with loading of "game folders" (see older news for an explanation on what this is)
    - updated to blargg's file_extractor v1.0.0
    - added full support for multi-file archives (eg GoodMerge sets)
    - split multi-cart loading again (BS-X, Sufami Turbo, etc) as required for multi-file support
    - cleaned up handling of file placement detection for save files (.srm, .cht, etc)
    - file load dialog now remembers your previous folder path across runs even without a custom games folder assigned
    - windows now save their exact positioning and size across runs, they no longer forcibly center
    - menus now have radio button and check box icons where appropriate
    - debugger's hex editor now has a working scrollbar widget
    - added resize splitter to settings and tools windows
    - worked around Qt style sheet bug where subclassed widgets were not properly applying style properties
2009-10-18 17:33:04 +00:00
byuu
a0000c7846 Update to bsnes v052 release.
This is a maintenance release, which fixes a few important bugs. It also adds some graphical icons to soften the user interface. Note that if you have set any custom paths with v051, you'll need to set them again for the fix to work. As always, my apologies for releasing two versions so close together. I felt the bugs were important enough to warrant it.
Changelog:
    - fixed loading of files and folders containing non-ANSI characters (Chinese, Japanese, etc)
    - fixed a slight lag on startup due to the new file browser
    - fixed path selection setting, screenshots will now be saved to the correct directory
    - hid memory editor scrollbar since it does not work yet
    - disabled window positioning on Linux due to bugs in the Compiz compositor
    - added icons from the Tango icon library to the menus and panels
2009-09-29 12:25:41 +00:00
145 changed files with 2667 additions and 3229 deletions

View File

@@ -37,8 +37,8 @@ else ifeq ($(platform),osx)
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win)
link += -mwindows
# link += -mconsole
link += -mwindows -mthreads
# link += -mconsole -mthreads
link += -s -luuid -lkernel32 -luser32 -lgdi32 -lshell32
# statically link Qt for Windows build
link += -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
@@ -76,7 +76,7 @@ link += $(call ifhas,input.rawinput,$(ruby),-ldinput8 -ldxguid)
### objects ###
###############
objects := libco ruby libfilter
objects := libco ruby
objects += system cartridge cheat
objects += memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu
objects += sgb superfx sa1
@@ -111,8 +111,6 @@ rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
obj/ruby.o: lib/ruby/ruby.cpp $(call rwildcard,lib/ruby/*)
$(call compile,$(rubydef) $(rubyflags))
obj/libco.o: lib/libco/libco.c lib/libco/*
$(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@
obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/*
#################
### utilities ###

View File

@@ -1,4 +1,4 @@
static const char bsnesVersion[] = "0.051";
static const char bsnesVersion[] = "0.054";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSaveStateVersion = 3;
@@ -23,7 +23,6 @@ static const unsigned bsnesSaveStateVersion = 3;
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/new.hpp>
#include <nall/platform.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/property.hpp>

View File

@@ -1,5 +1,6 @@
#include <../base.hpp>
#include <nall/crc32.hpp>
#include <nall/sha256.hpp>
#define CARTRIDGE_CPP
namespace SNES {
@@ -24,25 +25,25 @@ void Cartridge::load(Mode cartridge_mode) {
set(mode, cartridge_mode);
if(cartinfo.ram_size > 0) {
memory::cartram.map(new(zeromemory) uint8_t[cartinfo.ram_size], cartinfo.ram_size);
memory::cartram.map(allocate<uint8_t>(cartinfo.ram_size, 0xff), cartinfo.ram_size);
}
if(cartinfo.srtc || cartinfo.spc7110rtc) {
memory::cartrtc.map(new(zeromemory) uint8_t[20], 20);
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
}
if(mode() == ModeBsx) {
memory::bsxram.map (new(zeromemory) uint8_t[ 32 * 1024], 32 * 1024);
memory::bsxpram.map(new(zeromemory) uint8_t[512 * 1024], 512 * 1024);
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
}
if(mode() == ModeSufamiTurbo) {
if(memory::stArom.data()) memory::stAram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
}
if(mode() == ModeSuperGameBoy) {
if(memory::gbrom.data()) memory::gbram.map(new(zeromemory) uint8_t[64 * 1024], 64 * 1024);
if(memory::gbrom.data()) memory::gbram.map(allocate<uint8_t>(64 * 1024, 0xff), 64 * 1024);
}
memory::cartrom.write_protect(true);
@@ -70,6 +71,21 @@ void Cartridge::load(Mode cartridge_mode) {
for(unsigned n = 0; n < memory::gbrom.size(); n++) checksum = crc32_adjust(checksum, memory::gbrom[n]);
set(crc32, ~checksum);
#if 0
fprintf(stdout, "crc32 = %.8x\n", crc32());
sha256_ctx sha;
uint8_t shahash[32];
sha256_init(&sha);
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
sha256_final(&sha);
sha256_hash(&sha, shahash);
fprintf(stdout, "sha256 = ");
for(unsigned i = 0; i < 32; i++) fprintf(stdout, "%.2x", shahash[i]);
fprintf(stdout, "\n");
#endif
bus.load_cart();
system.serialize_init();
set(loaded, true);

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

104
src/lib/libco/amd64.c Normal file
View File

@@ -0,0 +1,104 @@
/*
libco.amd64 (2009-10-12)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (*co_swap)(cothread_t, cothread_t) = 0;
#ifdef _WIN32
//ABI: Win64
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x22, 0x48, 0x8B, 0x21, 0x58, 0x48, 0x89, 0x6A, 0x08, 0x48, 0x89, 0x72, 0x10, 0x48,
0x89, 0x7A, 0x18, 0x48, 0x89, 0x5A, 0x20, 0x4C, 0x89, 0x62, 0x28, 0x4C, 0x89, 0x6A, 0x30, 0x4C,
0x89, 0x72, 0x38, 0x4C, 0x89, 0x7A, 0x40, 0x48, 0x81, 0xC2, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE2, 0xF0, 0x0F, 0x29, 0x32, 0x0F, 0x29, 0x7A, 0x10, 0x44, 0x0F, 0x29, 0x42, 0x20, 0x44, 0x0F,
0x29, 0x4A, 0x30, 0x44, 0x0F, 0x29, 0x52, 0x40, 0x44, 0x0F, 0x29, 0x5A, 0x50, 0x44, 0x0F, 0x29,
0x62, 0x60, 0x44, 0x0F, 0x29, 0x6A, 0x70, 0x44, 0x0F, 0x29, 0xB2, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xBA, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x69, 0x08, 0x48, 0x8B, 0x71, 0x10, 0x48,
0x8B, 0x79, 0x18, 0x48, 0x8B, 0x59, 0x20, 0x4C, 0x8B, 0x61, 0x28, 0x4C, 0x8B, 0x69, 0x30, 0x4C,
0x8B, 0x71, 0x38, 0x4C, 0x8B, 0x79, 0x40, 0x48, 0x81, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE1, 0xF0, 0x0F, 0x29, 0x31, 0x0F, 0x29, 0x79, 0x10, 0x44, 0x0F, 0x29, 0x41, 0x20, 0x44, 0x0F,
0x29, 0x49, 0x30, 0x44, 0x0F, 0x29, 0x51, 0x40, 0x44, 0x0F, 0x29, 0x59, 0x50, 0x44, 0x0F, 0x29,
0x61, 0x60, 0x44, 0x0F, 0x29, 0x69, 0x70, 0x44, 0x0F, 0x29, 0xB1, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xB9, 0x90, 0x00, 0x00, 0x00, 0xFF, 0xE0,
};
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
//ABI: SystemV
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x26, 0x48, 0x8B, 0x27, 0x58, 0x48, 0x89, 0x6E, 0x08, 0x48, 0x89, 0x5E, 0x10, 0x4C,
0x89, 0x66, 0x18, 0x4C, 0x89, 0x6E, 0x20, 0x4C, 0x89, 0x76, 0x28, 0x4C, 0x89, 0x7E, 0x30, 0x48,
0x8B, 0x6F, 0x08, 0x48, 0x8B, 0x5F, 0x10, 0x4C, 0x8B, 0x67, 0x18, 0x4C, 0x8B, 0x6F, 0x20, 0x4C,
0x8B, 0x77, 0x28, 0x4C, 0x8B, 0x7F, 0x30, 0xFF, 0xE0,
};
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long long addr = (unsigned long long)co_swap_function;
unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
if(!co_swap) {
co_init();
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 512; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)malloc(size)) {
long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
*--p = (long long)crash; /* crash if entrypoint returns */
*--p = (long long)entrypoint; /* start of function */
*(long long*)handle = (long long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t handle) {
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#ifdef __cplusplus
}
#endif

View File

@@ -6,15 +6,17 @@
#if defined(__GNUC__) && defined(__i386__)
#include "x86.c"
#elif defined(__GNUC__) && defined(__amd64__) && !defined(__MINGW64__)
#include "x86-64.c"
#elif defined(__MINGW64__)
#include "fiber.c"
#elif defined(__GNUC__) && defined(__amd64__)
#include "amd64.c"
#elif defined(__GNUC__) && defined(__powerpc__) && defined(__ELF__)
#include "ppc-elf.c"
#elif defined(__GNUC__)
#include "sjlj.c"
#elif defined(_MSC_VER) && defined(_M_IX86)
#include "x86.c"
#elif defined(_MSC_VER) && defined(_M_AMD64)
#include "amd64.c"
#elif defined(_MSC_VER)
#include "fiber.c"
#else
#error "libco: unsupported processor, compiler or operating system"

View File

@@ -1,6 +1,6 @@
/*
libco
version: 0.13 rc2 (2008-01-28)
version: 0.15 (2009-10-12)
license: public domain
*/

325
src/lib/libco/ppc-elf.c Normal file
View File

@@ -0,0 +1,325 @@
/*
* libco.ppc-elf
* author: Kernigh
* license: public domain
*
* PowerPC 32-bit ELF implementation of libco (for compile with GCC),
* ported from PowerPC Mac OS X implementation (ppc.s) by Vas Crabb.
* This ELF version works for OpenBSD, and might also work for FreeBSD,
* NetBSD and Linux.
*
* Note 1: This implementation does not handle the AltiVec/VMX
* registers, because the ELF ABI does not mention them,
* and my OpenBSD system is not using them.
*
* Note 2: If you want position-independent code, then you must
* define __PIC__. gcc -fpic or -fPIC defines __PIC__, but
* gcc -fpie or -fPIE might not. If you want to use -fpie
* or -fPIE, then you might need a manual definition:
* gcc -fpie -D__PIC__=1
* gcc -fPIE -D__PIC__=2
*
* The ELF ABI is "System V Application Binary Interface, PowerPC
* Processor Supplement", which you can get from
* <http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf>
* (PDF file, hosted by Linux Foundation).
*
* ELF and Mac OS X use similar conventions to allocate the registers,
* and to pass arguments and return values through registers. The main
* differences are that ELF has a slightly different stack format, that
* symbols are different (and without an extra underscore at the start),
* and that the assembly syntax is different.
*
* A function may destroy the values of volatile registers, but must
* preserve the values of nonvolatile registers. So the co_switch()
* function only saves the nonvolatile registers.
*
* [nonvolatile registers in ELF]
* %r1, %r14..%r31
* %f14..%f31
* %cr2..%cr4 in cr
*
* [volatile registers in ELF]
* %r0, %r3..%r10
* %f0..%f13
* %cr0, %cr1, %cr5..%cr7 in cr
* ctr, lr, xer
*
* lr (link register) is volatile, but it contains the return address,
* so co_switch must save lr.
*
* %r13 is the small data pointer. This is constant across threads, so
* co_switch() does not touch %r13.
*
* %r2 is a reserved register, so co_switch() does not touch %r2. Some
* systems might borrow an idea from the PowerPC Embedded ABI, and might
* use %r2 as a small read-only data pointer, which is constant across
* threads.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef void * cothread_t;
/*
* co_active_context is either in a global offset table (if we are
* compiling -fPIC or -fPIE) or has an absolute position.
*/
static void *co_main_stack_pointer;
static cothread_t co_active_context = &co_main_stack_pointer;
extern cothread_t co_active() {
return co_active_context;
}
/*
* Embedded assembly.
*
* We are not using the percent-sign substitution feature,
* so we must write "%r1", not "%%r1".
*
* We always write 'bl malloc@plt', not 'bl malloc'. The '@plt'
* is necessary in position-indepent code and seems to have no
* significant effect in fixed-position code.
*
* We never use the 'lmw' or 'stmw' instructions. The ELF ABI
* mentions that these instructions "are usually slower than
* a sequence of other instructions that have the same effect."
* We instead use sequences of 'lwz' or 'stz' instructions.
*/
__asm__("\n"
"### embedded assembly \n"
".section \".text\" \n"
" .balign 4 \n"
" \n"
/*
* void co_switch(co_thread to %r3)
*
* Allocate our stack frame of 240 bytes:
* Old New Value
* 4(%r1) 244(%r1) return address, used by us
* 0(%r1) 240(%r1) frame pointer
* 232(%r1) %f31
* 224(%r1) %f30
* ...
* 96(%r1) %f14
* 92(%r1) %r31
* 88(%r1) %r30
* ...
* 24(%r1) %r14
* 20(%r1) condition register
* 8(%r1) padding of 12 bytes
* 4(%r1) return address, never used
* 0(%r1) frame pointer
*
* Save our registers in our stack frame.
* Save our stack pointer in 0(%r4).
* Switch to the stack of the other thread.
* Restore registers and return.
*/
" .globl co_switch \n"
" .type co_switch, @function \n"
"co_switch: \n"
" mflr %r0 # %r0 = return address \n"
" mfcr %r9 # %r9 = condition register \n"
" stwu %r1, -240(%r1) # allocate stack frame \n"
" \n"
" stw %r0, 244(%r1) # save return address \n"
" stfd %f31, 232(%r1) # save floating-point regs \n"
" stfd %f30, 224(%r1) \n"
" stfd %f29, 216(%r1) \n"
" stfd %f28, 208(%r1) \n"
" stfd %f27, 200(%r1) \n"
" stfd %f26, 192(%r1) \n"
" stfd %f25, 184(%r1) \n"
" stfd %f24, 176(%r1) \n"
" stfd %f23, 168(%r1) \n"
" stfd %f22, 160(%r1) \n"
" stfd %f21, 152(%r1) \n"
" stfd %f20, 144(%r1) \n"
" stfd %f19, 136(%r1) \n"
" stfd %f18, 128(%r1) \n"
" stfd %f17, 120(%r1) \n"
" stfd %f16, 112(%r1) \n"
" stfd %f16, 104(%r1) \n"
" stfd %f14, 96(%r1) \n"
" stw %r31, 92(%r1) # save general-purpose regs \n"
" stw %r30, 88(%r1) \n"
" stw %r29, 84(%r1) \n"
" stw %r28, 80(%r1) \n"
" stw %r27, 76(%r1) \n"
" stw %r26, 72(%r1) \n"
" stw %r25, 68(%r1) \n"
" stw %r24, 64(%r1) \n"
" stw %r23, 60(%r1) \n"
" stw %r22, 56(%r1) \n"
" stw %r21, 52(%r1) \n"
" stw %r20, 48(%r1) \n"
" stw %r19, 44(%r1) \n"
" stw %r18, 40(%r1) \n"
" stw %r17, 36(%r1) \n"
" stw %r16, 32(%r1) \n"
" stw %r15, 28(%r1) \n"
" stw %r14, 24(%r1) \n"
" stw %r9, 20(%r1) # save condition reg \n"
" \n"
" # save current context, set new context \n"
" # %r4 = co_active_context \n"
" # co_active_context = %r3 \n"
#if __PIC__ == 2
" # position-independent code, large model (-fPIC) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" addis %r7, %r8, co_active_context@got@ha \n"
" lwz %r6, co_active_context@got@l(%r7) \n"
" lwz %r4, 0(%r6) \n"
" stw %r3, 0(%r6) \n"
#elif __PIC__ == 1
" # position-independent code, small model (-fpic) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" lwz %r7, co_active_context@got(%r8) \n"
" lwz %r4, 0(%r7) \n"
" stw %r3, 0(%r7) \n"
#else
" # fixed-position code \n"
" lis %r8, co_active_context@ha \n"
" lwz %r4, co_active_context@l(%r8) \n"
" stw %r3, co_active_context@l(%r8) \n"
#endif
" \n"
" # save current stack pointer \n"
" stw %r1, 0(%r4) \n"
" # get new stack pointer \n"
" lwz %r1, 0(%r3) \n"
" \n"
" lwz %r0, 244(%r1) # get return address \n"
" lfd %f31, 232(%r1) # restore floating-point regs \n"
" lfd %f30, 224(%r1) \n"
" lfd %f29, 216(%r1) \n"
" lfd %f28, 208(%r1) \n"
" lfd %f27, 200(%r1) \n"
" lfd %f26, 192(%r1) \n"
" lfd %f25, 184(%r1) \n"
" lfd %f24, 176(%r1) \n"
" lfd %f23, 168(%r1) \n"
" lfd %f22, 160(%r1) \n"
" lfd %f21, 152(%r1) \n"
" lfd %f20, 144(%r1) \n"
" lfd %f19, 136(%r1) \n"
" lfd %f18, 128(%r1) \n"
" lfd %f17, 120(%r1) \n"
" lfd %f16, 112(%r1) \n"
" lfd %f16, 104(%r1) \n"
" lfd %f14, 96(%r1) \n"
" lwz %r31, 92(%r1) # restore general-purpose regs \n"
" lwz %r30, 88(%r1) \n"
" lwz %r29, 84(%r1) \n"
" lwz %r28, 80(%r1) \n"
" lwz %r27, 76(%r1) \n"
" lwz %r26, 72(%r1) \n"
" lwz %r25, 68(%r1) \n"
" lwz %r24, 64(%r1) \n"
" lwz %r23, 60(%r1) \n"
" lwz %r22, 56(%r1) \n"
" lwz %r21, 52(%r1) \n"
" lwz %r20, 48(%r1) \n"
" lwz %r19, 44(%r1) \n"
" lwz %r18, 40(%r1) \n"
" lwz %r17, 36(%r1) \n"
" lwz %r16, 32(%r1) \n"
" lwz %r15, 28(%r1) \n"
" lwz %r14, 24(%r1) \n"
" lwz %r9, 20(%r1) # get condition reg \n"
" \n"
" addi %r1, %r1, 240 # free stack frame \n"
" mtlr %r0 # restore return address \n"
" mtcr %r9 # restore condition register \n"
" blr # return \n"
" .size co_switch, . - co_switch \n"
" \n"
/*
* cothread_t %r3 co_create(unsigned int stack_size %r3,
* void (*coentry %r4)())
*
* Allocate a new stack, such that when you co_switch to that
* stack, then co_switch returns to coentry.
*/
" .globl co_create \n"
" .type co_create, @function \n"
"co_create: \n"
" mflr %r0 # %r0 = return address \n"
" stwu %r1, -16(%r1) # allocate my stack frame \n"
" stw %r0, 20(%r1) # save return address \n"
" stw %r31, 12(%r1) # save %r31 \n"
" stw %r30, 8(%r1) # save %r30 \n"
" \n"
" mr %r30, %r3 # %r30 = stack_size \n"
" mr %r31, %r4 # %r31 = coentry \n"
" \n"
" # Call malloc(stack_size %r3) to allocate stack; \n"
" # malloc() probably uses good alignment. \n"
" # \n"
" bl malloc@plt # returns %r3 = low end \n"
" cmpwi %r3, 0 # if returned NULL, \n"
" beq- 1f # then abort \n"
" \n"
" # we return %r3 = low end of stack \n"
" add %r4, %r3, %r30 # %r4 = high end of stack \n"
" \n"
" # uncomment if malloc() uses wrong alignment \n"
" #rlwinm %r4,%r4,0,0,27 # force 16-byte alignment \n"
" \n"
/*
* Allocate two stack frames:
* 16 bytes for stack frame with return address
* 240 bytes for co_switch stack frame
*
* Old New Value
* -8(%r4) 248(%r5) padding of 8 bytes
* -12(%r4) 244(%r5) return address = coentry
* -16(%r4) 240(%r5) frame pointer = NULL
* 232(%r5) %f31 = 0
* ...
* 20(%r5) condition register = 0
* 0(%r5) frame pointer
*/
" li %r9, (240-20)/4+1 \n"
" addi %r5, %r4, -16 # allocate first stack frame \n"
" li %r0, 0 \n"
" stwu %r5, -240(%r5) # allocate second stack frame \n"
" li %r8, 20 \n"
" mtctr %r9 # loop %r9 times \n"
"2: # loop to store zero to 20(%r5) through 240(%r5) \n"
" stwx %r0, %r5, %r8 \n"
" addi %r8, %r8, 4 # index += 4 \n"
" bdnz+ 2b # ctr -= 1, branch if nonzero \n"
" \n"
" stw %r31, 244(%r5) # return address = coentry \n"
" stw %r5, 0(%r3) # save stack pointer \n"
" \n"
" lwz %r0, 20(%r1) # get return address \n"
" lwz %r31, 12(%r1) # restore %r31 \n"
" lwz %r30, 8(%r1) # restore %r30 \n"
" mtlr %r0 # restore return address \n"
" addi %r1, %r1, 16 # free stack frame \n"
" blr # return \n"
" \n"
"1: b abort@plt # branch 1f to abort \n"
" .size co_create, . - co_create \n"
" \n"
/*
* void co_delete(cothread_t) => void free(void *)
*/
" .globl co_delete \n"
" .type co_delete, @function \n"
"co_delete: \n"
" b free@plt \n"
" \n"
);
#ifdef __cplusplus
}
#endif

View File

@@ -1,81 +0,0 @@
/*
libco.x86-64 (2008-01-28)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 8);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
*(long*)handle = (long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movq %%rsp,(%1) \n\t" /* save old stack pointer */
"movq (%0),%%rsp \n\t" /* load new stack pointer */
"addq $8,%%rsp \n\t" /* "pop" return address off stack */
"movq %%rbp, 8(%1) \n\t" /* backup non-volatile registers */
"movq %%rbx,16(%1) \n\t"
"movq %%r12,24(%1) \n\t"
"movq %%r13,32(%1) \n\t"
"movq %%r14,40(%1) \n\t"
"movq %%r15,48(%1) \n\t"
"movq 8(%0),%%rbp \n\t" /* restore non-volatile registers */
"movq 16(%0),%%rbx \n\t"
"movq 24(%0),%%r12 \n\t"
"movq 32(%0),%%r13 \n\t"
"movq 40(%0),%%r14 \n\t"
"movq 48(%0),%%r15 \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
libco.x86 (2008-01-28)
libco.x86 (2009-10-12)
author: byuu
license: public domain
*/
@@ -13,26 +13,63 @@
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
#if defined(_MSC_VER)
#define fastcall __fastcall
#elif defined(__GNUC__)
#define fastcall __attribute__((fastcall))
#else
#error "libco: please define fastcall macro"
#endif
static thread_local long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
//ABI: fastcall
static unsigned char co_swap_function[] = {
0x89, 0x22, 0x8B, 0x21, 0x58, 0x89, 0x6A, 0x04, 0x89, 0x72, 0x08, 0x89, 0x7A, 0x0C, 0x89, 0x5A,
0x10, 0x8B, 0x69, 0x04, 0x8B, 0x71, 0x08, 0x8B, 0x79, 0x0C, 0x8B, 0x59, 0x10, 0xFF, 0xE0,
};
#ifdef _WIN32
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long addr = (unsigned long)co_swap_function;
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 4);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
if(!co_swap) {
co_init();
co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 256; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
if(handle = (cothread_t)malloc(size)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
@@ -46,65 +83,11 @@ void co_delete(cothread_t handle) {
free(handle);
}
#if defined(__GNUC__)
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movl %%esp,(%1) \n\t" /* save old stack pointer */
"movl (%0),%%esp \n\t" /* load new stack pointer */
"addl $4,%%esp \n\t" /* "pop" return address off stack */
"movl %%ebp, 4(%1) \n\t" /* backup non-volatile registers */
"movl %%esi, 8(%1) \n\t"
"movl %%edi,12(%1) \n\t"
"movl %%ebx,16(%1) \n\t"
"movl 4(%0),%%ebp \n\t" /* restore non-volatile registers */
"movl 8(%0),%%esi \n\t"
"movl 12(%0),%%edi \n\t"
"movl 16(%0),%%ebx \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#elif defined(_MSC_VER)
__declspec(naked) __declspec(noinline)
static void __fastcall co_swap(register cothread_t to, register cothread_t from) {
/* ecx = to, edx = from */
__asm {
mov [edx],esp
mov esp,[ecx]
pop eax
mov [edx+ 4],ebp
mov [edx+ 8],esi
mov [edx+12],edi
mov [edx+16],ebx
mov ebp,[ecx+ 4]
mov esi,[ecx+ 8]
mov edi,[ecx+12]
mov ebx,[ecx+16]
jmp eax
}
}
void co_switch(cothread_t handle) {
register cothread_t co_prev_ = co_active_;
co_swap(co_active_ = handle, co_prev_);
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -1,44 +0,0 @@
class Colortable {
public:
enum Format {
RGB555,
RGB565,
RGB888,
};
const inline uint32_t operator[](uint16_t index) const { return table[index]; }
void set_format(Format);
void set_contrast(signed);
void set_brightness(signed);
void set_gamma(signed);
void enable_gamma_ramp(bool);
void enable_sepia(bool);
void enable_grayscale(bool);
void enable_invert(bool);
void update();
Colortable();
~Colortable();
private:
uint32_t *table;
Format format;
signed contrast;
signed brightness;
signed gamma;
bool gamma_ramp;
bool sepia;
bool grayscale;
bool invert;
static const uint8_t gamma_ramp_table[32];
uint8_t contrast_adjust(uint8_t input);
uint8_t brightness_adjust(uint8_t input);
uint8_t gamma_adjust(uint8_t input);
};
extern Colortable colortable;

View File

@@ -1,32 +0,0 @@
DirectFilter filter_direct;
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
}
void DirectFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
pitch >>= 1;
outpitch >>= 2;
for(unsigned y = 0; y < height; y++) {
if(width == 512 && line[y] == 256) {
for(unsigned x = 0; x < 256; x++) {
uint16_t p = *input++;
*output++ = colortable[p];
*output++ = colortable[p];
}
input += 256;
} else {
for(unsigned x = 0; x < width; x++) {
uint16_t p = *input++;
*output++ = colortable[p];
}
}
input += pitch - width;
output += outpitch - width;
}
}

View File

@@ -1,7 +0,0 @@
class DirectFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern DirectFilter filter_direct;

View File

@@ -1,32 +0,0 @@
FilterInterface filter;
void FilterInterface::set(FilterInterface::FilterType type) {
active_filter = type;
}
void FilterInterface::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
switch(active_filter) { default:
case Direct: return filter_direct.size(outwidth, outheight, width, height);
case Scanline: return filter_scanline.size(outwidth, outheight, width, height);
case Scale2x: return filter_scale2x.size(outwidth, outheight, width, height);
case LQ2x: return filter_lq2x.size(outwidth, outheight, width, height);
case HQ2x: return filter_hq2x.size(outwidth, outheight, width, height);
case NTSC: return filter_ntsc.size(outwidth, outheight, width, height);
}
}
void FilterInterface::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
switch(active_filter) { default:
case Direct: return filter_direct.render(output, outpitch, input, pitch, line, width, height);
case Scanline: return filter_scanline.render(output, outpitch, input, pitch, line, width, height);
case Scale2x: return filter_scale2x.render(output, outpitch, input, pitch, line, width, height);
case LQ2x: return filter_lq2x.render(output, outpitch, input, pitch, line, width, height);
case HQ2x: return filter_hq2x.render(output, outpitch, input, pitch, line, width, height);
case NTSC: return filter_ntsc.render(output, outpitch, input, pitch, line, width, height);
}
}
FilterInterface::FilterInterface() : active_filter(FilterInterface::Direct) {}

View File

@@ -1,37 +0,0 @@
class Filter {
public:
virtual void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) = 0;
virtual void render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) = 0;
};
class FilterInterface : public Filter {
public:
enum FilterType {
Direct,
Scanline,
Scale2x,
LQ2x,
HQ2x,
NTSC,
};
void set(FilterType type);
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
);
FilterInterface();
private:
FilterType active_filter;
};
extern FilterInterface filter;

View File

@@ -1,204 +0,0 @@
//HQ2x filter
//authors: byuu and blargg
//license: public domain
//
//note: this is a clean reimplementation of the original HQ2x filter, which was
//written by Maxim Stepin (MaxSt). it is not 100% identical, but very similar.
HQ2xFilter filter_hq2x;
const uint8_t HQ2xFilter::hqTable[256] = {
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
};
bool HQ2xFilter::same(uint16_t x, uint16_t y) {
return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask);
}
bool HQ2xFilter::diff(uint32_t x, uint16_t y) {
return ((x - yuvTable[y]) & diff_mask);
}
void HQ2xFilter::grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; }
uint16_t HQ2xFilter::pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); }
uint16_t HQ2xFilter::blend1(uint32_t A, uint32_t B) {
grow(A); grow(B);
A = (A * 3 + B) >> 2;
return pack(A);
}
uint16_t HQ2xFilter::blend2(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + B + C) >> 2);
}
uint16_t HQ2xFilter::blend3(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 5 + B * 2 + C) >> 3);
}
uint16_t HQ2xFilter::blend4(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 6 + B + C) >> 3);
}
uint16_t HQ2xFilter::blend5(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + (B + C) * 3) >> 3);
}
uint16_t HQ2xFilter::blend6(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 14 + B + C) >> 4);
}
alwaysinline uint16_t HQ2xFilter::blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) {
switch(rule) { default:
case 0: return E;
case 1: return blend1(E, A);
case 2: return blend1(E, D);
case 3: return blend1(E, B);
case 4: return blend2(E, D, B);
case 5: return blend2(E, A, B);
case 6: return blend2(E, A, D);
case 7: return blend3(E, B, D);
case 8: return blend3(E, D, B);
case 9: return blend4(E, D, B);
case 10: return blend5(E, D, B);
case 11: return blend6(E, D, B);
case 12: return same(B, D) ? blend2(E, D, B) : E;
case 13: return same(B, D) ? blend5(E, D, B) : E;
case 14: return same(B, D) ? blend6(E, D, B) : E;
case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
}
}
void HQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void HQ2xFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
int prevline = (y == 0) ? 0 : pitch;
int nextline = (y == height - 1) ? 0 : pitch;
input++;
*out0++ = 0; *out0++ = 0;
*out1++ = 0; *out1++ = 0;
for(unsigned x = 1; x < 256 - 1; x++) {
uint16_t A = *(input - prevline - 1);
uint16_t B = *(input - prevline + 0);
uint16_t C = *(input - prevline + 1);
uint16_t D = *(input - 1);
uint16_t E = *(input + 0);
uint16_t F = *(input + 1);
uint16_t G = *(input + nextline - 1);
uint16_t H = *(input + nextline + 0);
uint16_t I = *(input + nextline + 1);
uint32_t e = yuvTable[E] + diff_offset;
uint8_t pattern;
pattern = diff(e, A) << 0;
pattern |= diff(e, B) << 1;
pattern |= diff(e, C) << 2;
pattern |= diff(e, D) << 3;
pattern |= diff(e, F) << 4;
pattern |= diff(e, G) << 5;
pattern |= diff(e, H) << 6;
pattern |= diff(e, I) << 7;
*(out0 + 0) = colortable[blend(hqTable[pattern], E, A, B, D, F, H)]; pattern = rotate[pattern];
*(out0 + 1) = colortable[blend(hqTable[pattern], E, C, F, B, H, D)]; pattern = rotate[pattern];
*(out1 + 1) = colortable[blend(hqTable[pattern], E, I, H, F, D, B)]; pattern = rotate[pattern];
*(out1 + 0) = colortable[blend(hqTable[pattern], E, G, D, H, B, F)];
input++;
out0 += 2;
out1 += 2;
}
input++;
*out0++ = 0; *out0++ = 0;
*out1++ = 0; *out1++ = 0;
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}
HQ2xFilter::HQ2xFilter() {
yuvTable = new uint32_t[32768];
for(unsigned i = 0; i < 32768; i++) {
uint8_t R = (i >> 0) & 31;
uint8_t G = (i >> 5) & 31;
uint8_t B = (i >> 10) & 31;
//bgr555->bgr888
double r = (R << 3) | (R >> 2);
double g = (G << 3) | (G >> 2);
double b = (B << 3) | (B >> 2);
//bgr888->yuv888
double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v);
}
diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407;
diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0;
for(unsigned n = 0; n < 256; n++) {
rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
| ((n & 0x01) << 5) | ((n & 0x08) << 3)
| ((n & 0x10) >> 3) | ((n & 0x80) >> 5);
}
}
HQ2xFilter::~HQ2xFilter() {
delete[] yuvTable;
}

View File

@@ -1,31 +0,0 @@
class HQ2xFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
HQ2xFilter();
~HQ2xFilter();
private:
static const uint8_t hqTable[256];
uint32_t *yuvTable;
uint32_t diff_offset;
uint32_t diff_mask;
uint8_t rotate[256];
bool same(uint16_t, uint16_t);
bool diff(uint32_t, uint16_t);
void grow(uint32_t&);
uint16_t pack(uint32_t);
uint16_t blend1(uint32_t, uint32_t);
uint16_t blend2(uint32_t, uint32_t, uint32_t);
uint16_t blend3(uint32_t, uint32_t, uint32_t);
uint16_t blend4(uint32_t, uint32_t, uint32_t);
uint16_t blend5(uint32_t, uint32_t, uint32_t);
uint16_t blend6(uint32_t, uint32_t, uint32_t);
uint16_t blend (unsigned, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t);
};
extern HQ2xFilter filter_hq2x;

View File

@@ -1,15 +0,0 @@
#include "libfilter.hpp"
using nall::min;
using nall::max;
namespace libfilter {
#include "colortable.cpp"
#include "filter.cpp"
#include "direct.cpp"
#include "scanline.cpp"
#include "scale2x.cpp"
#include "lq2x.cpp"
#include "hq2x.cpp"
#include "ntsc.cpp"
}

View File

@@ -1,24 +0,0 @@
#ifndef LIBFILTER_H
#define LIBFILTER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <nall/algorithm.hpp>
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
namespace libfilter {
#include "colortable.hpp"
#include "filter.hpp"
#include "direct.hpp"
#include "scanline.hpp"
#include "scale2x.hpp"
#include "lq2x.hpp"
#include "hq2x.hpp"
#include "ntsc.hpp"
};
#endif

View File

@@ -1,57 +0,0 @@
LQ2xFilter filter_lq2x;
void LQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void LQ2xFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
int prevline = (y == 0) ? 0 : pitch;
int nextline = (y == height - 1) ? 0 : pitch;
for(unsigned x = 0; x < 256; x++) {
uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C];
if(A != E && B != D) {
*out0++ = (A == B ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
*out0++ = (A == D ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
*out1++ = (E == B ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
*out1++ = (E == D ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
} else {
*out0++ = c;
*out0++ = c;
*out1++ = c;
*out1++ = c;
}
}
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}

View File

@@ -1,7 +0,0 @@
class LQ2xFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern LQ2xFilter filter_lq2x;

View File

@@ -1,79 +0,0 @@
#include "snes_ntsc/snes_ntsc.c"
NTSCFilter filter_ntsc;
void NTSCFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = SNES_NTSC_OUT_WIDTH(256);
outheight = height;
}
void NTSCFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(!ntsc) return;
width = SNES_NTSC_OUT_WIDTH(256);
burst ^= burst_toggle;
pitch >>= 1;
outpitch >>= 2;
unsigned line_burst = burst;
for(unsigned y = 0; y < height; y++) {
uint16_t *in = input + y * pitch;
uint32_t *out = output + y * outpitch;
//render as many lines in one snes_ntsc_blit as possible:
//do this by determining for how many lines the width stays the same
unsigned rheight = 1;
unsigned rwidth = line[y];
while(y + rheight < height && rwidth == line[y + rheight]) rheight++;
if(rwidth == 256) {
snes_ntsc_blit (ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
}
line_burst = (line_burst + rheight) % 3;
y += rheight;
}
}
void NTSCFilter::adjust(
float hue, float saturation, float contrast,
float brightness, float sharpness, bool merge_fields
) {
static snes_ntsc_setup_t defaults;
snes_ntsc_setup_t setup = defaults;
setup.hue = hue;
setup.saturation = saturation;
setup.contrast = contrast;
setup.brightness = brightness;
setup.sharpness = sharpness;
setup.resolution = sharpness;
setup.merge_fields = merge_fields;
setup.bsnes_colortbl = 0;
if(!ntsc) {
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
if(!ntsc) {
fprintf(stderr, "error: snes_ntsc: out of memory\n");
return;
}
}
burst = 0;
burst_toggle = (merge_fields ? 0 : 1); //don't toggle burst when fields are merged
snes_ntsc_init(ntsc, &setup);
}
NTSCFilter::NTSCFilter() {
ntsc = 0;
adjust(0, 0, 0, 0, 0, false);
}
NTSCFilter::~NTSCFilter() {
if(ntsc) free(ntsc);
}

View File

@@ -1,17 +0,0 @@
#include "snes_ntsc/snes_ntsc.h"
class NTSCFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields);
NTSCFilter();
~NTSCFilter();
private:
struct snes_ntsc_t *ntsc;
int burst, burst_toggle;
};
extern NTSCFilter filter_ntsc;

View File

@@ -1,57 +0,0 @@
Scale2xFilter filter_scale2x;
void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void Scale2xFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
int prevline = (y == 0) ? 0 : pitch;
int nextline = (y == height - 1) ? 0 : pitch;
for(unsigned x = 0; x < 256; x++) {
uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C];
if(A != E && B != D) {
*out0++ = (A == B ? colortable[A] : c);
*out0++ = (A == D ? colortable[A] : c);
*out1++ = (E == B ? colortable[E] : c);
*out1++ = (E == D ? colortable[E] : c);
} else {
*out0++ = c;
*out0++ = c;
*out1++ = c;
*out1++ = c;
}
}
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}

View File

@@ -1,7 +0,0 @@
class Scale2xFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern Scale2xFilter filter_scale2x;

View File

@@ -1,42 +0,0 @@
ScanlineFilter filter_scanline;
void ScanlineFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height > 240 ? height : height * 2;
}
void ScanlineFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
for(unsigned y = 0; y < height; y++) {
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
if(width == 512 && line[y] == 256) {
for(unsigned x = 0; x < 256; x++) {
uint16_t p = *input++;
*out0++ = colortable[p];
*out0++ = colortable[p];
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
}
input += 256;
} else {
for(unsigned x = 0; x < width; x++) {
uint16_t p = *input++;
*out0++ = colortable[p];
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
}
}
input += pitch - width;
output += outpitch * 2;
}
}

View File

@@ -1,7 +0,0 @@
class ScanlineFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern ScanlineFilter filter_scanline;

View File

@@ -1,251 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "snes_ntsc.h"
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
#define alignment_count 3
#define burst_count 3
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
#define std_decoder_hue 0
#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */
#define gamma_size 32
#include "snes_ntsc_impl.h"
/* 3 input pixels -> 8 composite samples */
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
};
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
{
int n;
for ( n = burst_size; n; --n )
{
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
/* merge colors without losing precision */
io [burst_size * 0] =
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 1] =
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 2] =
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
++io;
}
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
snes_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
{
int merge_fields;
int entry;
init_t impl;
if ( !setup )
setup = &snes_ntsc_composite;
init( &impl, setup );
merge_fields = setup->merge_fields;
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
merge_fields = 1;
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
{
/* Reduce number of significant bits of source color. Clearing the
low bits of R and B were least notictable. Modifying green was too
noticeable. */
int ir = entry >> 8 & 0x1E;
int ig = entry >> 4 & 0x1F;
int ib = entry << 1 & 0x1E;
#if SNES_NTSC_BSNES_COLORTBL
if ( setup->bsnes_colortbl )
{
int bgr15 = (ib << 10) | (ig << 5) | ir;
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
ir = rgb16 >> 11 & 0x1E;
ig = rgb16 >> 6 & 0x1F;
ib = rgb16 & 0x1E;
}
#endif
{
float rr = impl.to_float [ir];
float gg = impl.to_float [ig];
float bb = impl.to_float [ib];
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
snes_ntsc_rgb_t* out = ntsc->table [entry];
gen_kernel( &impl, y, i, q, out );
if ( merge_fields )
merge_kernel_fields( out );
correct_errors( rgb, out );
}
}
}
#ifndef SNES_NTSC_NO_BLITTERS
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 3;
line_out += 7;
}
/* finish final pixels */
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
SNES_NTSC_ADJ_IN( line_in [0] ),
SNES_NTSC_ADJ_IN( line_in [1] ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
line_in += 2;
for ( n = chunk_count; n; --n )
{
/* twice as many input pixels per chunk */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 6;
line_out += 7;
}
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif

View File

@@ -1,228 +0,0 @@
/* SNES NTSC video filter */
/* snes_ntsc 0.2.2 */
#ifndef SNES_NTSC_H
#define SNES_NTSC_H
#include "snes_ntsc_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */
typedef struct snes_ntsc_setup_t
{
/* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
} snes_ntsc_setup_t;
/* Video format presets */
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
/* Initializes and adjusts parameters. Can be called multiple times on the same
snes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct snes_ntsc_t snes_ntsc_t;
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. */
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
/* Number of output pixels written by low-res blitter for given input width. Width
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define SNES_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk)
/* Number of low-res input pixels that will fit within given output width. Might be
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define SNES_NTSC_IN_WIDTH( out_width ) \
(((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters */
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { snes_ntsc_black = 0 }; /* palette index for black */
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable )
/* Begins input pixel */
#define SNES_NTSC_COLOR_IN( index, color ) \
SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable )
/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \
SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 )
/* Hires equivalents */
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\
unsigned const snes_ntsc_pixel3_ = (pixel3);\
snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\
unsigned const snes_ntsc_pixel4_ = (pixel4);\
snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\
unsigned const snes_ntsc_pixel5_ = (pixel5);\
snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\
snes_ntsc_rgb_t const* kernel0 = kernel1;\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel1;\
snes_ntsc_rgb_t const* kernelx2 = kernel1;\
snes_ntsc_rgb_t const* kernelx3 = kernel1;\
snes_ntsc_rgb_t const* kernelx4 = kernel1;\
snes_ntsc_rgb_t const* kernelx5 = kernel1
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
SNES_NTSC_CLAMP_( raw_, 0 );\
SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\
}
/* private */
enum { snes_ntsc_entry_size = 128 };
enum { snes_ntsc_palette_size = 0x2000 };
typedef unsigned long snes_ntsc_rgb_t;
struct snes_ntsc_t {
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
};
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
#define SNES_NTSC_RGB16( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
#define SNES_NTSC_BGR15( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
/* common 3->7 ntsc macros */
#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
unsigned const snes_ntsc_pixel0_ = (pixel0);\
snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel0;\
snes_ntsc_rgb_t const* kernelx2 = kernel0
#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
SNES_NTSC_CLAMP_( raw_, shift );\
SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2)
#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101)
#define SNES_NTSC_CLAMP_( io, shift ) {\
snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\
snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* x is always zero except in snes_ntsc library */
/* original routine */
/*
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 24 || bits == 32 )\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
if ( bits == 15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 14 )\
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\
if ( bits == 0 )\
rgb_out = raw_ << x;\
}
*/
/* custom bsnes routine -- hooks into bsnes colortable */
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 ) {\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 24 || bits == 32 ) {\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 15 ) {\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else {\
rgb_out = raw_ << x;\
}\
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,26 +0,0 @@
/* Configure library by modifying this file */
#ifndef SNES_NTSC_CONFIG_H
#define SNES_NTSC_CONFIG_H
/* Format of source pixels */
/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
/* The following affect the built-in blitter only; a custom blitter can
handle things however it wants. */
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
#define SNES_NTSC_OUT_DEPTH 32
/* Type of input pixel values */
#define SNES_NTSC_IN_T unsigned short
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define SNES_NTSC_ADJ_IN( in ) in
/* For each pixel, this is the basic operation:
output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */
#endif

View File

@@ -1,439 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* Common implementation of NTSC filters */
#include <assert.h>
#include <math.h>
/* Copyright (C) 2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define DISABLE_CORRECTION 0
#undef PI
#define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20
#endif
#ifndef gamma_size
#define gamma_size 1
#endif
#ifndef rgb_bits
#define rgb_bits 8
#endif
#ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f)
#endif
#ifndef fringing_max
#define fringing_max (fringing_mid * 2)
#endif
#ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1
#endif
#define ext_decoder_hue (std_decoder_hue + 15)
#define rgb_unit (1 << rgb_bits)
#define rgb_offset (rgb_unit * 2 + 0.5f)
enum { burst_size = snes_ntsc_entry_size / burst_count };
enum { kernel_half = 16 };
enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t
{
float to_rgb [burst_count * 6];
float to_float [gamma_size];
float contrast;
float brightness;
float artifacts;
float fringing;
float kernel [rescale_out * kernel_size * 2];
} init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\
t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\
i = t;\
}
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
{
#if rescale_out > 1
float kernels [kernel_size * 2];
#else
float* const kernels = impl->kernel;
#endif
/* generate luma (y) filter using sinc kernel */
{
/* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh );
float sum;
int i;
/* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = i - kernel_half;
float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{
float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
}
}
/* apply blackman window and find sum */
sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
}
/* normalize kernel */
sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
/* generate chroma (iq) filter using gaussian kernel */
{
float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed;
int i;
if ( cutoff < 0 )
{
/* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= -30.0f / 0.65f;
}
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ )
{
float sum = 0;
int x;
for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x];
sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 )
{
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
}
/*
printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] );
printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] );
*/
/* generate linear rescale kernels */
#if rescale_out > 1
{
float weight = 1.0f;
float* out = impl->kernel;
int n = rescale_out;
do
{
float remain = 0;
int i;
weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ )
{
float cur = kernels [i];
float m = cur * weight;
*out++ = m + remain;
remain = cur - m;
}
}
while ( --n );
}
#endif
}
static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
static void init( init_t* impl, snes_ntsc_setup_t const* setup )
{
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast
if ( !setup->palette )
impl->contrast *= default_palette_contrast;
#endif
impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup );
/* generate gamma table */
if ( gamma_size > 1 )
{
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i;
for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
}
/* setup decoder matricies */
{
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix;
if ( !decoder )
{
decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
}
{
float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb;
int n;
n = burst_count;
do
{
float const* in = decoder;
int n = 3;
do
{
float i = *in++;
float q = *in++;
*out++ = i * c - q * s;
*out++ = i * s + q * c;
}
while ( --n );
if ( burst_count <= 1 )
break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
}
while ( --n );
}
}
}
/* kernel generation */
#define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
)
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
enum { rgb_kernel_size = burst_size / alignment_count };
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
typedef struct pixel_info_t
{
int offset;
float negate;
float kernel [4];
} pixel_info_t;
#if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2))
#else
#define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2))
#endif
extern pixel_info_t const snes_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
{
/* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count;
y -= rgb_offset;
do
{
/* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = snes_ntsc_pixels;
int alignment_remain = alignment_count;
do
{
/* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset];
int n;
++pixel;
for ( n = rgb_kernel_size; n; --n )
{
float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 )
k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1;
else
k -= kernel_size * 2 * (rescale_out - 1) + 2;
{
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
}
}
}
while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 )
break;
to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
}
while ( --burst_remain );
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
#if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
#else
#define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c ) {\
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\
out [a] += fourth;\
out [b] += fourth;\
out [c] += fourth;\
out [i] += error - (fourth * 3);\
}
#endif
#define RGB_PALETTE_OUT( rgb, out_ )\
{\
unsigned char* out = (out_);\
snes_ntsc_rgb_t clamped = (rgb);\
SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\
}
/* blitter related */
#ifndef restrict
#if defined (__GNUC__)
#define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict __restrict
#else
/* no support for restricted pointers */
#define restrict
#endif
#endif
#include <limits.h>
#if SNES_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF
typedef unsigned short snes_ntsc_out_t;
#else
#error "Need 16-bit int type"
#endif
#else
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int snes_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long snes_ntsc_out_t;
#else
#error "Need 32-bit int type"
#endif
#endif

View File

@@ -47,8 +47,8 @@ else ifeq ($(platform),win)
qtlib := -L$(qtpath)/lib
qtlib += -L$(qtpath)/plugins/imageformats
qtlib += -lmingw32 -lqtmain -lQtGui -lcomdlg32 -loleaut32 -limm32 -lwinmm
qtlib += -lwinspool -lmsimg32 -lQtCore -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
qtlib += -lmingw32 -lqtmain -lQtGui4 -lcomdlg32 -loleaut32 -limm32 -lwinmm
qtlib += -lwinspool -lmsimg32 -lQtCore4 -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
# optional image-file support:
# qtlib += -lqjpeg -lqmng

View File

@@ -2,15 +2,13 @@
#define NALL_BASE64_HPP
#include <string.h>
#include <nall/new.hpp>
#include <nall/stdint.hpp>
namespace nall {
class base64 {
public:
static bool encode(char *&output, const uint8_t* input, unsigned inlength) {
output = new(zeromemory) char[inlength * 8 / 6 + 6];
output = new char[inlength * 8 / 6 + 6]();
unsigned i = 0, o = 0;
while(i < inlength) {
@@ -41,7 +39,7 @@ namespace nall {
static bool decode(uint8_t *&output, unsigned &outlength, const char *input) {
unsigned inlength = strlen(input), infix = 0;
output = new(zeromemory) uint8_t[inlength];
output = new uint8_t[inlength]();
unsigned i = 0, o = 0;
while(i < inlength) {

View File

@@ -17,6 +17,7 @@
namespace nall {
struct library : noncopyable {
bool opened() const { return handle; }
bool open(const char*);
void* sym(const char*);
void close();

View File

@@ -15,6 +15,14 @@
#include <nall/utility.hpp>
namespace nall {
inline FILE* fopen_utf8(const char *utf8_filename, const char *mode) {
#if !defined(_WIN32)
return fopen(utf8_filename, mode);
#else
return _wfopen(utf16_t(utf8_filename), utf16_t(mode));
#endif
}
class file : noncopyable {
public:
enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread };

View File

@@ -1,7 +1,6 @@
#ifndef NALL_MODULO_HPP
#define NALL_MODULO_HPP
#include <nall/new.hpp>
#include <nall/serializer.hpp>
namespace nall {
@@ -26,7 +25,7 @@ namespace nall {
}
modulo_array() {
buffer = new(zeromemory) T[size * 3];
buffer = new T[size * 3]();
}
~modulo_array() {

View File

@@ -1,25 +0,0 @@
#ifndef NALL_NEW_HPP
#define NALL_NEW_HPP
#include <string.h>
#include <new>
#include <nall/stdint.hpp>
namespace nall {
struct zeromemory_t {};
static zeromemory_t zeromemory;
}
inline void* operator new[](size_t size, const nall::zeromemory_t&) throw(std::bad_alloc) {
void *p = new uint8_t[size];
memset(p, 0, size);
return p;
}
inline void* operator new[](size_t size, const std::nothrow_t&, const nall::zeromemory_t&) throw() {
void *p = new(std::nothrow) uint8_t[size];
if(p) memset(p, 0, size);
return p;
}
#endif

View File

@@ -1,7 +1,6 @@
#ifndef NALL_SERIALIZER_HPP
#define NALL_SERIALIZER_HPP
#include <nall/new.hpp>
#include <nall/stdint.hpp>
#include <nall/traits.hpp>
#include <nall/utility.hpp>
@@ -92,7 +91,7 @@ namespace nall {
serializer(unsigned capacity) {
mode = Save;
idata = new(zeromemory) uint8_t[capacity];
idata = new uint8_t[capacity]();
isize = 0;
icapacity = capacity;
}

143
src/lib/nall/sha256.hpp Normal file
View File

@@ -0,0 +1,143 @@
#ifndef NALL_SHA256_HPP
#define NALL_SHA256_HPP
//author: vladitx
namespace nall {
#define PTR(t, a) ((t*)(a))
#define SWAP32(x) ((uint32_t)( \
(((uint32_t)(x) & 0x000000ff) << 24) | \
(((uint32_t)(x) & 0x0000ff00) << 8) | \
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
(((uint32_t)(x) & 0xff000000) >> 24) \
))
#define ST32(a, d) *PTR(uint32_t, a) = (d)
#define ST32BE(a, d) ST32(a, SWAP32(d))
#define LD32(a) *PTR(uint32_t, a)
#define LD32BE(a) SWAP32(LD32(a))
#define LSL32(x, n) ((uint32_t)(x) << (n))
#define LSR32(x, n) ((uint32_t)(x) >> (n))
#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))
//first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
static const uint32_t T_H[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
};
//first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
static const uint32_t T_K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
};
struct sha256_ctx {
uint8_t in[64];
unsigned inlen;
uint32_t w[64];
uint32_t h[8];
uint64_t len;
};
void sha256_init(sha256_ctx *p) {
memset(p, 0, sizeof(sha256_ctx));
memcpy(p->h, T_H, sizeof(T_H));
}
static void sha256_block(sha256_ctx *p) {
unsigned i;
uint32_t s0, s1;
uint32_t a, b, c, d, e, f, g, h;
uint32_t t1, t2, maj, ch;
for(i = 0; i < 16; i++) p->w[i] = LD32BE(p->in + i * 4);
for(i = 16; i < 64; i++) {
s0 = ROR32(p->w[i - 15], 7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15], 3);
s1 = ROR32(p->w[i - 2], 17) ^ ROR32(p->w[i - 2], 19) ^ LSR32(p->w[i - 2], 10);
p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;
}
a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];
e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];
for(i = 0; i < 64; i++) {
s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
maj = (a & b) ^ (a & c) ^ (b & c);
t2 = s0 + maj;
s1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
ch = (e & f) ^ (~e & g);
t1 = h + s1 + ch + T_K[i] + p->w[i];
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;
p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;
//next block
p->inlen = 0;
}
void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
unsigned l;
p->len += len;
while(len) {
l = 64 - p->inlen;
l = (len < l) ? len : l;
memcpy(p->in + p->inlen, s, l);
s += l;
p->inlen += l;
len -= l;
if(p->inlen == 64) sha256_block(p);
}
}
void sha256_final(sha256_ctx *p) {
uint64_t len;
p->in[p->inlen++] = 0x80;
if(p->inlen > 56) {
memset(p->in + p->inlen, 0, 64 - p->inlen);
sha256_block(p);
}
memset(p->in + p->inlen, 0, 56 - p->inlen);
len = p->len << 3;
ST32BE(p->in + 56, len >> 32);
ST32BE(p->in + 60, len);
sha256_block(p);
}
void sha256_hash(sha256_ctx *p, uint8_t *s) {
uint32_t *t = (uint32_t*)s;
for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]);
}
#undef PTR
#undef SWAP32
#undef ST32
#undef ST32BE
#undef LD32
#undef LD32BE
#undef LSL32
#undef LSR32
#undef ROR32
}
#endif

View File

@@ -6,6 +6,7 @@
#include <nall/string/cast.hpp>
#include <nall/string/compare.hpp>
#include <nall/string/convert.hpp>
#include <nall/string/filename.hpp>
#include <nall/string/match.hpp>
#include <nall/string/math.hpp>
#include <nall/string/strl.hpp>

View File

@@ -0,0 +1,43 @@
#ifndef NALL_FILENAME_HPP
#define NALL_FILENAME_HPP
namespace nall {
// "foo/bar.c" -> "foo/", "bar.c" -> "./"
inline string dir(char const *name) {
string result = name;
for(signed i = strlen(result); i >= 0; i--) {
if(result[i] == '/' || result[i] == '\\') {
result[i + 1] = 0;
break;
}
if(i == 0) result = "./";
}
return result;
}
// "foo/bar.c" -> "bar.c"
inline string notdir(char const *name) {
for(signed i = strlen(name); i >= 0; i--) {
if(name[i] == '/' || name[i] == '\\') {
name += i + 1;
break;
}
}
string result = name;
return result;
}
// "foo/bar.c" -> "foo/bar"
inline string basename(char const *name) {
string result = name;
for(signed i = strlen(result); i >= 0; i--) {
if(result[i] == '.') {
result[i] = 0;
break;
}
}
return result;
}
}
#endif

View File

@@ -3,7 +3,14 @@
char* ltrim(char *str, const char *key) {
if(!key || !*key) return str;
while(strbegin(str, key)) strcpy(str, str + strlen(key));
while(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key);
while(true) {
*dest = *src++;
if(!*dest) break;
dest++;
}
}
return str;
}
@@ -19,7 +26,14 @@ char* trim(char *str, const char *key) {
char* ltrim_once(char *str, const char *key) {
if(!key || !*key) return str;
if(strbegin(str, key)) strcpy(str, str + strlen(key));
if(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key);
while(true) {
*dest = *src++;
if(!*dest) break;
dest++;
}
}
return str;
}

View File

@@ -6,7 +6,6 @@
#include <nall/algorithm.hpp>
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/new.hpp>
#include <nall/stdint.hpp>
namespace nall {
@@ -98,7 +97,7 @@ namespace nall {
//mirror
if(x_size != px_size && x_size != py_size) return input_invalid;
y_size = (x_size == px_size) ? py_size : px_size;
y_data = new(zeromemory) uint8_t[y_size];
y_data = new uint8_t[y_size]();
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;

View File

@@ -1,8 +1,6 @@
#ifndef NALL_UTF8_HPP
#define NALL_UTF8_HPP
#include <nall/new.hpp>
//UTF-8 <> UTF-16 conversion
//used only for Win32; Linux, etc use UTF-8 internally
@@ -30,7 +28,7 @@ namespace nall {
utf16_t(const char *s = "") {
if(!s) s = "";
unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
buffer = new(zeromemory) wchar_t[length + 1];
buffer = new wchar_t[length + 1]();
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
}
@@ -56,7 +54,7 @@ namespace nall {
utf8_t(const wchar_t *s = L"") {
if(!s) s = L"";
unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, 0, 0, (const char*)0, (BOOL*)0);
buffer = new(zeromemory) char[length + 1];
buffer = new char[length + 1]();
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, (const char*)0, (BOOL*)0);
}

View File

@@ -24,6 +24,13 @@ namespace nall {
noncopyable(const noncopyable&);
const noncopyable& operator=(const noncopyable&);
};
template<typename T>
inline T* allocate(size_t size, const T &value) {
T *array = new T[size];
for(size_t i = 0; i < size; i++) array[i] = value;
return array;
}
}
#endif

View File

@@ -13,7 +13,6 @@
#include <nall/bit.hpp>
#include <nall/detect.hpp>
#include <nall/input.hpp>
#include <nall/new.hpp>
#include <nall/sort.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>

View File

@@ -1,3 +1,7 @@
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
namespace ruby {
class pVideoQtOpenGL {
@@ -13,6 +17,7 @@ public:
uint32_t *buffer;
unsigned rasterWidth, rasterHeight;
bool synchronize;
unsigned filter;
void resize(unsigned width, unsigned height) {
@@ -35,6 +40,15 @@ public:
}
}
void updateSynchronization() {
#ifdef __APPLE__
makeCurrent();
CGLContextObj context = CGLGetCurrentContext();
GLint value = synchronize; //0 = draw immediately (no vsync), 1 = draw once per frame (vsync)
CGLSetParameter(context, kCGLCPSwapInterval, &value);
#endif
}
void paintGL() {
unsigned outputWidth = width();
unsigned outputHeight = height();
@@ -85,18 +99,26 @@ public:
} *widget;
bool cap(const string& name) {
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == "QWidget") return true;
return false;
}
any get(const string& name) {
if(name == Video::Synchronize) return widget->synchronize;
if(name == Video::Filter) return widget->filter;
if(name == "QWidget") return parent;
return false;
}
bool set(const string& name, const any& value) {
if(name == Video::Synchronize) {
widget->synchronize = any_cast<bool>(value);
widget->updateSynchronization();
return true;
}
if(name == Video::Filter) {
widget->filter = any_cast<unsigned>(value);
return true;

View File

@@ -1,8 +1,12 @@
rm -r libco
rm -r nall
rm -r ruby
cp -r ../../../libco ./libco
cp -r ../../../nall ./nall
cp -r ../../../ruby ./ruby
rm -r libco/doc
rm -r libco/test
rm ruby/test*
rm ruby/cc.*

View File

@@ -35,7 +35,7 @@ void MappedRAM::map(uint8 *source, unsigned length) {
void MappedRAM::copy(uint8 *data, unsigned size) {
if(!data_) {
size_ = (size & ~255) + ((bool)(size & 255) << 8);
data_ = new(zeromemory) uint8[size_];
data_ = new uint8[size_]();
}
memcpy(data_, data, min(size_, size));
}

View File

@@ -120,12 +120,12 @@ void bPPU::flush_pixel_cache() {
}
void bPPU::alloc_tiledata_cache() {
bg_tiledata[TILE_2BIT] = new(zeromemory) uint8_t[262144];
bg_tiledata[TILE_4BIT] = new(zeromemory) uint8_t[131072];
bg_tiledata[TILE_8BIT] = new(zeromemory) uint8_t[ 65536];
bg_tiledata_state[TILE_2BIT] = new(zeromemory) uint8_t[ 4096];
bg_tiledata_state[TILE_4BIT] = new(zeromemory) uint8_t[ 2048];
bg_tiledata_state[TILE_8BIT] = new(zeromemory) uint8_t[ 1024];
bg_tiledata[TILE_2BIT] = new uint8_t[262144]();
bg_tiledata[TILE_4BIT] = new uint8_t[131072]();
bg_tiledata[TILE_8BIT] = new uint8_t[ 65536]();
bg_tiledata_state[TILE_2BIT] = new uint8_t[ 4096]();
bg_tiledata_state[TILE_4BIT] = new uint8_t[ 2048]();
bg_tiledata_state[TILE_8BIT] = new uint8_t[ 1024]();
}
//marks all tiledata cache entries as dirty

View File

@@ -37,7 +37,7 @@ void PPU::reset() {
}
PPU::PPU() {
output = new(zeromemory) uint16[512 * 480];
output = new uint16[512 * 480];
status.render_output = true;
status.frames_updated = false;

View File

@@ -20,7 +20,7 @@ bool System::unserialize(serializer &s) {
if(signature != 0x31545342) return false;
if(version != bsnesSaveStateVersion) return false;
if(crc32 != cartridge.crc32()) return false;
//if(crc32 != cartridge.crc32()) return false;
scheduler.init();
serialize_all(s);

View File

@@ -1,4 +1,5 @@
objects := main $(if $(call streq,$(platform),win),resource) $(objects)
objects := ui-main $(objects)
objects += $(if $(call streq,$(platform),win),resource)
link += $(qtlib)
moc_headers := $(call rwildcard,$(ui)/,%.moc.hpp)
@@ -12,7 +13,7 @@ moc_objects := $(patsubst %.moc.hpp,%.moc,$(moc_headers))
%.moc: $<; $(moc) -f $< -o $@
$(foreach f,$(moc_objects),$(eval $f: $(patsubst %.moc,%.moc.hpp,$f)))
obj/main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/)
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/)
$(call compile,$(qtinc))
$(ui)/resource/resource.rcc: $(ui)/resource/resource.qrc data/*

View File

@@ -1,27 +1,5 @@
#include "init.cpp"
const char* FileReader::direct_supported() {
return "";
}
bool FileReader::direct_load(const char *filename, uint8_t **outdata, unsigned *outsize) {
if(file::exists(filename) == false) return false;
file fp;
if(fp.open(filename, file::mode_read) == false) return false;
unsigned size;
uint8_t *data = new uint8_t[size = fp.size()];
fp.read(data, size);
fp.close();
//remove copier header, if it exists
if((size & 0x7fff) == 512) memmove(data, data + 512, size -= 512);
*outdata = data;
*outsize = size;
return true;
}
#include "qb.cpp"
void Application::initPaths(const char *basename) {
char temp[PATH_MAX];
@@ -94,7 +72,7 @@ int Application::main(int &argc, char **argv) {
if(argc == 2) {
//if valid file was specified on the command-line, attempt to load it now
utility.loadCartridge(argv[1]);
utility.loadCartridgeNormal(argv[1]);
}
timer = new QTimer(this);
@@ -102,6 +80,22 @@ int Application::main(int &argc, char **argv) {
timer->start(0);
app->exec();
//QbWindow::hide() saves window geometry for next run
loaderWindow->window->hide();
htmlViewerWindow->window->hide();
aboutWindow->window->hide();
diskBrowser->window->hide();
folderCreator->window->hide();
settingsWindow->window->hide();
inputCaptureWindow->window->hide();
inputMouseCaptureWindow->window->hide();
inputCalibrationWindow->window->hide();
toolsWindow->window->hide();
debugger->window->hide();
breakpointEditor->window->hide();
memoryEditor->window->hide();
vramViewer->window->hide();
utility.unloadCartridge();
config.save(configFilename);
return 0;

View File

@@ -1,14 +1,4 @@
struct FileReader : public library {
string filterList;
function<const char* ()> supported;
function<bool (const char*, uint8_t**, unsigned*)> load;
const char* direct_supported();
bool direct_load(const char*, uint8_t**, unsigned*);
FileReader();
} libsnesreader;
#include "qb.hpp"
class Application : public QObject {
Q_OBJECT

View File

@@ -16,27 +16,6 @@
#include "../settings/settings.cpp"
#include "../tools/tools.cpp"
FileReader::FileReader() {
if(open("snesreader")) {
supported = sym("snesreader_supported");
load = sym("snesreader_load");
}
if(!supported || !load) {
supported = bind(&FileReader::direct_supported, this);
load = bind(&FileReader::direct_load, this);
}
filterList = supported();
if(filterList.length() > 0) {
filterList = string()
<< " *.swc *.fig *.ufo *.gd3 *.gd7 *.dx2 *.mgd *.mgh"
<< " *.048 *.058 *.068 *.078 *.bin"
<< " *.usa *.eur *.jap *.aus *.bsx"
<< " " << filterList;
}
}
void Application::init() {
if(config.system.crashedOnLastRun == true) {
//emulator crashed on last run, disable all drivers
@@ -135,6 +114,7 @@ void Application::init() {
inputManager.refresh();
inputManager.onInput = bind(&Utility::inputEvent, &utility);
utility.resizeMainWindow();
utility.updateAvSync();
utility.updateVideoMode();
utility.updateColorFilter();

View File

@@ -0,0 +1,86 @@
void QbWindow::shrink() {
for(unsigned i = 0; i < 2; i++) {
resize(0, 0);
usleep(2000);
QApplication::processEvents();
}
}
void QbWindow::show() {
if(isVisible() == false) {
uint8_t *data;
unsigned length;
base64::decode(data, length, geometryString);
QByteArray array((const char*)data, length);
delete[] data;
restoreGeometry(array);
QWidget::show();
}
QApplication::processEvents();
activateWindow();
raise();
}
void QbWindow::hide() {
if(isVisible() == true) {
char *data;
QByteArray geometry = saveGeometry();
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
geometryString = data;
delete[] data;
QWidget::hide();
}
}
void QbWindow::closeEvent(QCloseEvent *event) {
char *data;
QByteArray geometry = saveGeometry();
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
geometryString = data;
delete[] data;
QWidget::hide();
}
QbWindow::QbWindow(string &geometryString_) : geometryString(geometryString_) {
}
//
bool QbCheckAction::isChecked() const {
return checked;
}
void QbCheckAction::setChecked(bool checked_) {
checked = checked_;
if(checked) setIcon(QIcon(":/16x16/item-check-on.png"));
else setIcon(QIcon(":/16x16/item-check-off.png"));
}
void QbCheckAction::toggleChecked() {
setChecked(!isChecked());
}
QbCheckAction::QbCheckAction(const QString &text, QObject *parent) : QAction(text, parent) {
setChecked(false);
}
//
bool QbRadioAction::isChecked() const {
return checked;
}
void QbRadioAction::setChecked(bool checked_) {
checked = checked_;
if(checked) setIcon(QIcon(":/16x16/item-radio-on.png"));
else setIcon(QIcon(":/16x16/item-radio-off.png"));
}
void QbRadioAction::toggleChecked() {
setChecked(!isChecked());
}
QbRadioAction::QbRadioAction(const QString &text, QObject *parent) : QAction(text, parent) {
setChecked(false);
}

View File

@@ -0,0 +1,33 @@
class QbWindow : public QWidget {
public:
void shrink();
void show();
void hide();
void closeEvent(QCloseEvent*);
QbWindow(string&);
private:
string &geometryString;
};
class QbCheckAction : public QAction {
public:
bool isChecked() const;
void setChecked(bool);
void toggleChecked();
QbCheckAction(const QString&, QObject*);
private:
bool checked;
};
class QbRadioAction : public QAction {
public:
bool isChecked() const;
void setChecked(bool);
void toggleChecked();
QbRadioAction(const QString&, QObject*);
private:
bool checked;
};

View File

@@ -1,26 +1,26 @@
AboutWindow::AboutWindow() {
setObjectName("about-window");
setWindowTitle("About bsnes ...");
window = new QbWindow(config.geometry.aboutWindow);
window->setObjectName("about-window");
window->setWindowTitle("About bsnes ...");
layout = new QVBoxLayout;
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing); {
logo = new Logo;
logo->setFixedSize(600, 106);
layout->addWidget(logo);
layout->setSpacing(Style::WidgetSpacing);
window->setLayout(layout);
info = new QLabel(utf8() <<
"<table>"
"<tr><td align='right'><b>Version: </b></td><td>" << bsnesVersion << "</td></tr>"
"<tr><td align='right'><b>Author: </b></td><td>byuu</td></tr>"
"<tr><td align='right'><b>Homepage: </b></td><td>http://byuu.org/</td></tr>"
"</table>"
);
layout->addWidget(info);
}
logo = new Logo;
logo->setFixedSize(600, 106);
layout->addWidget(logo);
setLayout(layout);
info = new QLabel(utf8() <<
"<table>"
"<tr><td align='right'><b>Version: </b></td><td>" << bsnesVersion << "</td></tr>"
"<tr><td align='right'><b>Author: </b></td><td>byuu</td></tr>"
"<tr><td align='right'><b>Homepage: </b></td><td>http://byuu.org/</td></tr>"
"</table>"
);
layout->addWidget(info);
}
void AboutWindow::Logo::paintEvent(QPaintEvent*) {

View File

@@ -1,7 +1,8 @@
class AboutWindow : public QbWindow {
class AboutWindow : public QObject {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
struct Logo : public QWidget {
void paintEvent(QPaintEvent*);

View File

@@ -1,211 +1,474 @@
void DiskBrowser::ScreenshotPreview::paintEvent(QPaintEvent*) {
//=============
//FolderCreator
//=============
FolderCreator::FolderCreator() {
window = new QbWindow(config.geometry.folderCreator);
window->setObjectName("folder-creator");
window->setWindowTitle("Create New Folder");
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
layout->setAlignment(Qt::AlignTop);
window->setLayout(layout);
label = new QLabel("Folder name:");
layout->addWidget(label);
name = new QLineEdit;
layout->addWidget(name);
controlLayout = new QHBoxLayout;
controlLayout->setAlignment(Qt::AlignRight);
layout->addLayout(controlLayout);
ok = new QPushButton("Ok");
controlLayout->addWidget(ok);
cancel = new QPushButton("Cancel");
controlLayout->addWidget(cancel);
connect(name, SIGNAL(returnPressed()), this, SLOT(createFolder()));
connect(ok, SIGNAL(released()), this, SLOT(createFolder()));
connect(cancel, SIGNAL(released()), window, SLOT(hide()));
}
void FolderCreator::show() {
name->setText("");
window->show();
name->setFocus();
}
void FolderCreator::createFolder() {
if(name->text().length() == 0) {
QMessageBox::warning(0, "Create New Folder", "<b>Note:</b> you must enter a folder name.");
} else {
string folderName = string()
<< diskBrowser->path->currentText().toUtf8().constData()
<< "/"
<< name->text().toUtf8().constData();
if(mkdir(folderName) == 0) {
window->hide();
} else {
QMessageBox::warning(0, "Create new Folder", "<b>Error:</b> failed to create folder. Please ensure only valid characters were used in the folder name.");
}
}
}
//===============
//DiskBrowserView
//===============
void DiskBrowserView::keyPressEvent(QKeyEvent *event) {
//enhance consistency: OS X by default doesn't activate items for these keypresses
if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
emit activated(currentIndex());
return;
}
//simulate popular file managers; backspace = go up one directory
if(event->key() == Qt::Key_Backspace) {
emit cdUp();
return;
}
//fallback: unrecognized keypresses get handled by the widget itself
QTreeView::keyPressEvent(event);
}
void DiskBrowserView::keyReleaseEvent(QKeyEvent *event) {
//act like a modal dialog; close window on escape keypress
if(event->key() == Qt::Key_Escape) {
emit escape();
return;
}
//fallback: unrecognized keypresses get handled by the widget itself
QTreeView::keyReleaseEvent(event);
}
void DiskBrowserView::currentChanged(const QModelIndex &current, const QModelIndex &previous) {
QAbstractItemView::currentChanged(current, previous);
emit changed(current);
}
//================
//DiskBrowserImage
//================
void DiskBrowserImage::paintEvent(QPaintEvent*) {
QPainter painter(this);
if(screenshotName != "") {
QImage image(screenshotName);
if(name != "") {
QImage image(name);
painter.drawImage(0, 0, image);
}
}
void DiskBrowser::onActivate(const QString &file, bool isDir) {
if(browseMode == Folder) {
setPath(file);
return;
}
if(isDir) {
QDir directory(file);
directory.setNameFilters(QStringList() << "*.sfc" << "*.smc");
QStringList list = directory.entryList(QDir::Files | QDir::NoDotAndDotDot);
if(list.count() == 1) {
imageName = string() << file.toUtf8().constData() << "/" << list[0].toUtf8().constData();
onLoad();
} else {
setPath(file);
}
} else {
imageName = file.toUtf8().constData();
onLoad();
}
}
void DiskBrowser::onChange(const QString &file, bool isDir) {
if(browseMode == Folder) {
imageName = file.toUtf8().constData();
load->setEnabled(isDir);
applyPatch->setVisible(false);
return;
}
imageName = queryAbsoluteImageName(file, isDir);
if(imageName.length() == 0) {
load->setEnabled(false);
screenshot->screenshotName = "";
info->setText("");
applyPatch->setVisible(false);
} else {
load->setEnabled(true);
screenshot->screenshotName = string() << utility.basepath(imageName) << "/" << utility.basename(imageName) << ".png";
if(file::exists(screenshot->screenshotName) == false) screenshot->screenshotName = "";
info->setText(utf8() << queryImageInformation(imageName));
string patch = string() << utility.basepath(imageName) << utility.basename(imageName) << ".ups";
applyPatch->setVisible(file::exists(patch));
}
screenshot->update();
}
void DiskBrowser::onLoad() {
hide();
switch(browseMode) { default:
case Folder: activePath->selectPath(imageName); break;
case AnyCartridge: utility.loadCartridge(imageName); break;
case BaseCartridge: loaderWindow->selectBaseCartridge(imageName); break;
case BsxCartridge: loaderWindow->selectSlot1Cartridge(imageName); break;
case SufamiTurboCartridge1: loaderWindow->selectSlot1Cartridge(imageName); break;
case SufamiTurboCartridge2: loaderWindow->selectSlot2Cartridge(imageName); break;
case SuperGameBoyCartridge: loaderWindow->selectSlot1Cartridge(imageName); break;
}
}
//===========
//DiskBrowser
//===========
void DiskBrowser::chooseFolder(PathSettingWidget *widget, const char *title) {
browseMode = Folder;
activePath = widget;
hide();
panel()->hide();
acceptButton()->setText("Choose");
setWindowTitle(utf8() << title);
window->hide();
group->hide();
ok->setText("Choose");
window->setWindowTitle(utf8() << title);
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters("Folders ()");
showAt(0.0, 0.0);
window->show();
}
void DiskBrowser::loadAnyCartridge() {
browseMode = AnyCartridge;
hide();
panel()->show();
acceptButton()->setText("Load");
setWindowTitle("Load Cartridge");
void DiskBrowser::loadCartridge() {
browseMode = Cartridge;
window->hide();
group->show();
ok->setText("Load");
window->setWindowTitle("Load Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "All cartridges (*.sfc *.smc *.bs *.st" << libsnesreader.filterList << ");;All files (*)");
showAt(0.0, 0.0);
setNameFilters(utf8() << "SNES cartridges (*.sfc *.smc" << reader.filterList << ");;All files (*)");
window->show();
}
void DiskBrowser::loadBaseCartridge() {
browseMode = BaseCartridge;
hide();
panel()->show();
acceptButton()->setText("Load");
setWindowTitle("Load Base Cartridge");
window->hide();
group->show();
ok->setText("Load");
window->setWindowTitle("Load Base Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "SNES cartridges (*.sfc *.smc" << libsnesreader.filterList << ");;All files (*)");
showAt(0.0, 0.0);
setNameFilters(utf8() << "SNES cartridges (*.sfc *.smc" << reader.filterList << ");;All files (*)");
window->show();
}
void DiskBrowser::loadBsxCartridge() {
browseMode = BsxCartridge;
hide();
panel()->show();
acceptButton()->setText("Load");
setWindowTitle("Load BS-X Cartridge");
window->hide();
group->show();
ok->setText("Load");
window->setWindowTitle("Load BS-X Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "BS-X cartridges (*.bs" << libsnesreader.filterList << ");;All files (*)");
showAt(0.0, 0.0);
setNameFilters(utf8() << "BS-X cartridges (*.bs" << reader.filterList << ");;All files (*)");
window->show();
}
void DiskBrowser::loadSufamiTurboCartridge1() {
browseMode = SufamiTurboCartridge1;
hide();
panel()->show();
acceptButton()->setText("Load");
setWindowTitle("Load Slot-A Sufami Turbo Cartridge");
window->hide();
group->show();
ok->setText("Load");
window->setWindowTitle("Load Slot-A Sufami Turbo Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "Sufami Turbo cartridges (*.st" << libsnesreader.filterList << ");;All files (*)");
showAt(0.0, 0.0);
setNameFilters(utf8() << "Sufami Turbo cartridges (*.st" << reader.filterList << ");;All files (*)");
window->show();
}
void DiskBrowser::loadSufamiTurboCartridge2() {
browseMode = SufamiTurboCartridge2;
hide();
panel()->show();
acceptButton()->setText("Load");
setWindowTitle("Load Slot-B Sufami Turbo Cartridge");
window->hide();
group->show();
ok->setText("Load");
window->setWindowTitle("Load Slot-B Sufami Turbo Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "Sufami Turbo Cartridges (*.st" << libsnesreader.filterList << ");;All files (*)");
showAt(0.0, 0.0);
setNameFilters(utf8() << "Sufami Turbo Cartridges (*.st" << reader.filterList << ");;All files (*)");
window->show();
}
void DiskBrowser::loadSuperGameBoyCartridge() {
browseMode = SuperGameBoyCartridge;
hide();
panel()->show();
acceptButton()->setText("Load");
setWindowTitle("Load Super Game Boy Cartridge");
window->hide();
group->show();
ok->setText("Load");
window->setWindowTitle("Load Super Game Boy Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "Game Boy cartridges (*.gb *.gbc" << libsnesreader.filterList << ");;All files (*)");
showAt(0.0, 0.0);
setNameFilters(utf8() << "Game Boy cartridges (*.gb *.gbc" << reader.filterList << ");;All files (*)");
window->show();
}
string DiskBrowser::queryAbsoluteImageName(const QString &file, bool isDir) {
if(isDir) {
QDir directory(file);
directory.setNameFilters(QStringList() << "*.sfc" << "*.smc");
QStringList list = directory.entryList(QDir::Files | QDir::NoDotAndDotDot);
if(list.count() == 1) {
return string() << file.toUtf8().constData() << "/" << list[0].toUtf8().constData();
} else {
return "";
}
} else {
return file.toUtf8().constData();
}
}
string DiskBrowser::queryImageInformation(const char *filename) {
string DiskBrowser::queryImageInformation() {
string text;
unsigned size = file::size(filename);
text << "<b>" << utility.basename(imageName) << "</b>";
text << "<small><table cellspacing='5'>";
if(striend(filename, ".sfc") || striend(filename, ".smc")) {
text << "<tr><td><b>ROM size:</b></td><td>" << size * 8 / 1024 / 1024 << "mbit</td></tr>";
} else {
text << "<tr><td><b>File size:</b></td><td>" << size * 8 / 1024 / 1024 << "mbit</td></tr>";
string filename;
if(currentFilename(filename) == true) {
if(striend(filename, ".sfc") || striend(filename, ".smc")) {
unsigned size = file::size(filename);
text << "<b>" << notdir(nall::basename(filename)) << "</b>";
text << "<small><table cellspacing='5'>";
text << "<tr><td><b>ROM size:</b></td><td>" << size * 8 / 1024 / 1024 << "mbit</td></tr>";
text << "</table></small>";
}
}
text << "</table></small>";
return text;
}
void DiskBrowser::activateItem(const QModelIndex &item) {
if(browseMode == Folder) {
setPath(model->filePath(item));
} else {
loadSelected();
}
}
void DiskBrowser::changeItem(const QModelIndex &item) {
if(browseMode == Folder) {
ok->setEnabled(model->isDir(item));
image->name = "";
info->setText("");
applyPatch->setVisible(false);
} else {
string filename;
currentFilename(filename);
if(filename.length() == 0) {
//nothing selected?
ok->setEnabled(false);
image->name = "";
info->setText("");
applyPatch->setVisible(false);
} else {
ok->setEnabled(true);
image->name = nall::basename(filename) << ".png";
if(file::exists(image->name) == false) image->name = "";
info->setText(utf8() << queryImageInformation());
string patch = nall::basename(filename) << ".ups";
applyPatch->setVisible(file::exists(patch));
}
}
image->update();
}
void DiskBrowser::loadSelected() {
string filename;
bool loadable = currentFilename(filename);
if(browseMode == Folder || loadable == true) {
QModelIndex item = view->currentIndex();
config.path.current = dir(model->filePath(item).toUtf8().constData());
window->hide();
switch(browseMode) { default:
case Folder: activePath->selectPath(filename); break;
case Cartridge: utility.loadCartridgeNormal(filename); break;
case BaseCartridge: loaderWindow->selectBaseCartridge(filename); break;
case BsxCartridge: loaderWindow->selectSlot1Cartridge(filename); break;
case SufamiTurboCartridge1: loaderWindow->selectSlot1Cartridge(filename); break;
case SufamiTurboCartridge2: loaderWindow->selectSlot2Cartridge(filename); break;
case SuperGameBoyCartridge: loaderWindow->selectSlot1Cartridge(filename); break;
}
} else {
//this is a standard folder in ROM loading mode; enter into the folder
QModelIndex item = view->currentIndex();
setPath(model->filePath(item));
}
}
//
void DiskBrowser::setPath(const QString &reqPath) {
disconnect(path, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePath()));
QString effectivePath = reqPath;
if(effectivePath == "<root>") {
effectivePath = "";
newFolder->setEnabled(false);
} else {
newFolder->setEnabled(true);
}
path->clear();
model->setRootPath(effectivePath);
view->setRootIndex(model->index(effectivePath));
view->setCurrentIndex(view->rootIndex());
view->setFocus();
if(effectivePath.length() > 0) {
QDir directory(effectivePath);
while(true) {
path->addItem(directory.absolutePath());
if(directory.isRoot()) break;
directory.cdUp();
}
}
path->addItem("<root>");
connect(path, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePath()));
}
void DiskBrowser::setNameFilters(const QString &filters) {
disconnect(filter, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFilter()));
filter->clear();
string filterData = filters.toUtf8().constData();
lstring filterPart;
filterPart.split(";;", filterData);
for(unsigned i = 0; i < filterPart.size(); i++) {
filter->addItem(utf8() << filterPart[i]);
}
connect(filter, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFilter()));
updateFilter();
}
void DiskBrowser::cdUp() {
folderCreator->window->hide();
//if we aren't already at the root node, select the second node, which is one path higher than the current
if(path->count() > 1) path->setCurrentIndex(1);
}
void DiskBrowser::updatePath() {
setPath(path->currentText());
}
void DiskBrowser::updateFilter() {
QString currentText = filter->currentText();
if(currentText.length() == 0) {
model->setNameFilters(QStringList() << "*");
} else {
string filters = currentText.toUtf8().constData();
filters = substr(filters, strpos(filters, "("));
ltrim(filters, "(");
rtrim(filters, ")");
lstring filterPart;
filterPart.split(" ", filters);
QStringList filterList;
for(unsigned i = 0; i < filterPart.size(); i++) filterList << (const char*)filterPart[i];
model->setNameFilters(filterList);
}
}
//true means filename can be loaded directly
//false means it cannot (eg this is a folder and we are attempting to load a ROM)
bool DiskBrowser::currentFilename(string &filename) {
bool loadable = false;
QModelIndex item = view->currentIndex();
filename = model->filePath(item).toUtf8().constData();
if(browseMode != Folder) {
if(model->isDir(item) == true) {
QDir directory(utf8() << filename);
directory.setNameFilters(QStringList() << "*.sfc" << "*.smc");
QStringList list = directory.entryList(QDir::Files | QDir::NoDotAndDotDot);
if(list.count() == 1) {
filename << "/" << list[0].toUtf8().constData();
loadable = true;
}
} else {
loadable = true;
}
}
return loadable;
}
DiskBrowser::DiskBrowser() {
setMinimumSize(720, 480);
window = new QbWindow(config.geometry.diskBrowser);
window->setObjectName("disk-browser");
window->resize(720, 480);
layout = new QVBoxLayout;
panel()->setLayout(layout);
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
window->setLayout(layout);
topLayout = new QHBoxLayout;
layout->addLayout(topLayout);
browseLayout = new QVBoxLayout;
topLayout->addLayout(browseLayout);
pathLayout = new QHBoxLayout;
browseLayout->addLayout(pathLayout);
path = new QComboBox;
path->setMinimumContentsLength(16);
path->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
path->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
pathLayout->addWidget(path);
newFolder = new QPushButton;
newFolder->setIconSize(QSize(16, 16));
newFolder->setIcon(QIcon(":/16x16/folder-new.png"));
pathLayout->addWidget(newFolder);
view = new DiskBrowserView;
view->setIconSize(QSize(16, 16));
browseLayout->addWidget(view);
panelLayout = new QVBoxLayout;
topLayout->addLayout(panelLayout);
group = new QGroupBox;
panelLayout->addWidget(group);
groupLayout = new QVBoxLayout;
group->setLayout(groupLayout);
info = new QLabel;
info->setFixedWidth(256);
layout->addWidget(info);
groupLayout->addWidget(info);
screenshot = new ScreenshotPreview;
screenshot->setFixedSize(256, 239);
layout->addWidget(screenshot);
image = new DiskBrowserImage;
image->setFixedSize(256, 239);
groupLayout->addWidget(image);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
layout->addWidget(spacer);
groupLayout->addWidget(spacer);
applyPatch = new QCheckBox("Apply UPS patch");
applyPatch->setChecked(true);
applyPatch->setVisible(false);
//applyPatch->setEnabled(false);
layout->addWidget(applyPatch);
applyPatch->setEnabled(false);
groupLayout->addWidget(applyPatch);
connect(this, SIGNAL(itemActivated(const QString&, bool)), this, SLOT(onActivate(const QString&, bool)));
connect(this, SIGNAL(itemChanged(const QString&, bool)), this, SLOT(onChange(const QString&, bool)));
connect(load, SIGNAL(released()), this, SLOT(onLoad()));
controlLayout = new QHBoxLayout;
layout->addLayout(controlLayout);
filter = new QComboBox;
filter->setMinimumContentsLength(16);
filter->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
filter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
controlLayout->addWidget(filter);
options = new QPushButton("Options");
options->setEnabled(false);
controlLayout->addWidget(options);
QMenu *menu = new QMenu;
options->setMenu(menu);
ok = new QPushButton("Ok");
ok->setEnabled(false);
controlLayout->addWidget(ok);
cancel = new QPushButton("Cancel");
controlLayout->addWidget(cancel);
model = new QFileSystemModel;
model->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
model->setNameFilterDisables(false);
view->setModel(model);
view->setExpandsOnDoubleClick(false);
view->setAllColumnsShowFocus(true);
view->setUniformRowHeights(true);
view->setSortingEnabled(true);
view->sortByColumn(0, Qt::AscendingOrder);
view->setColumnHidden(1, true);
view->setColumnHidden(2, true);
view->setColumnHidden(3, true);
view->setHeaderHidden(true);
folderCreator = new FolderCreator;
connect(newFolder, SIGNAL(released()), folderCreator, SLOT(show()));
connect(view, SIGNAL(cdUp()), this, SLOT(cdUp()));
connect(view, SIGNAL(activated(const QModelIndex&)), this, SLOT(activateItem(const QModelIndex&)));
connect(view, SIGNAL(changed(const QModelIndex&)), this, SLOT(changeItem(const QModelIndex&)));
connect(view, SIGNAL(escape()), window, SLOT(hide()));
connect(ok, SIGNAL(released()), this, SLOT(loadSelected()));
connect(cancel, SIGNAL(released()), window, SLOT(hide()));
}

View File

@@ -1,33 +1,99 @@
class PathSettingWidget;
class DiskBrowser : public QbDiskBrowser {
class FolderCreator : public QObject {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QLabel *label;
QLineEdit *name;
QHBoxLayout *controlLayout;
QPushButton *ok;
QPushButton *cancel;
FolderCreator();
public slots:
void show();
void createFolder();
} *folderCreator;
class DiskBrowserView : public QTreeView {
Q_OBJECT
public:
void keyPressEvent(QKeyEvent*);
void keyReleaseEvent(QKeyEvent*);
signals:
void cdUp();
void changed(const QModelIndex&);
void escape();
public slots:
void currentChanged(const QModelIndex&, const QModelIndex&);
};
class DiskBrowserImage : public QWidget {
public:
string name;
void paintEvent(QPaintEvent*);
};
class DiskBrowser : public QObject {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QHBoxLayout *topLayout;
QVBoxLayout *browseLayout;
QHBoxLayout *pathLayout;
QComboBox *path;
QPushButton *newFolder;
DiskBrowserView *view;
QVBoxLayout *panelLayout;
QGroupBox *group;
QVBoxLayout *groupLayout;
QLabel *info;
DiskBrowserImage *image;
QWidget *spacer;
QCheckBox *applyPatch;
QHBoxLayout *controlLayout;
QComboBox *filter;
QPushButton *options;
QPushButton *ok;
QPushButton *cancel;
QFileSystemModel *model;
PathSettingWidget *activePath;
void chooseFolder(PathSettingWidget*, const char*);
void loadAnyCartridge();
void loadCartridge();
void loadBaseCartridge();
void loadBsxCartridge();
void loadSufamiTurboCartridge1();
void loadSufamiTurboCartridge2();
void loadSuperGameBoyCartridge();
string queryImageInformation();
string queryAbsoluteImageName(const QString&, bool);
string queryImageInformation(const char*);
void setPath(const QString&);
void setNameFilters(const QString&);
DiskBrowser();
public slots:
void onActivate(const QString&, bool);
void onChange(const QString&, bool);
void onLoad();
void cdUp();
void updatePath();
void updateFilter();
void activateItem(const QModelIndex&);
void changeItem(const QModelIndex&);
void loadSelected();
private:
enum BrowseMode {
Folder,
AnyCartridge,
Cartridge,
BaseCartridge,
BsxCartridge,
SufamiTurboCartridge1,
@@ -35,15 +101,5 @@ private:
SuperGameBoyCartridge,
} browseMode;
QVBoxLayout *layout;
QLabel *info;
class ScreenshotPreview : public QWidget {
public:
string screenshotName;
void paintEvent(QPaintEvent*);
} *screenshot;
QWidget *spacer;
QCheckBox *applyPatch;
string imageName;
bool currentFilename(string&);
} *diskBrowser;

View File

@@ -1,20 +1,19 @@
HtmlViewerWindow::HtmlViewerWindow() {
setObjectName("html-window");
window = new QbWindow(config.geometry.htmlViewerWindow);
window->setObjectName("html-window");
window->resize(560, 480);
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0); {
document = new QTextBrowser;
layout->addWidget(document);
}
layout->setSpacing(0);
window->setLayout(layout);
setLayout(layout);
setMinimumSize(560, 480);
document = new QTextBrowser;
layout->addWidget(document);
}
void HtmlViewerWindow::show(const char *title, const char *htmlData) {
document->setHtml(utf8() << htmlData);
setWindowTitle(title);
showAt(0.0, 0.0);
setFocus();
window->setWindowTitle(title);
window->show();
}

View File

@@ -1,7 +1,8 @@
class HtmlViewerWindow : public QbWindow {
class HtmlViewerWindow : public QObject {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QTextBrowser *document;

View File

@@ -1,11 +1,12 @@
LoaderWindow::LoaderWindow() {
setObjectName("loader-window");
setMinimumWidth(520);
window = new QbWindow(config.geometry.loaderWindow);
window->setObjectName("loader-window");
window->setMinimumWidth(520);
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0);
setLayout(layout);
window->setLayout(layout);
grid = new QGridLayout; {
baseLabel = new QLabel("Base cartridge:");
@@ -81,7 +82,7 @@ void LoaderWindow::syncUi() {
}
void LoaderWindow::loadBsxSlottedCartridge(const char *filebase, const char *fileSlot1) {
hide();
window->hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->hide(), slot2File->hide(), slot2Browse->hide(), slot2Clear->hide();
@@ -97,7 +98,7 @@ void LoaderWindow::loadBsxSlottedCartridge(const char *filebase, const char *fil
}
void LoaderWindow::loadBsxCartridge(const char *fileBase, const char *fileSlot1) {
hide();
window->hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->hide(), slot2File->hide(), slot2Browse->hide(), slot2Clear->hide();
@@ -113,7 +114,7 @@ void LoaderWindow::loadBsxCartridge(const char *fileBase, const char *fileSlot1)
}
void LoaderWindow::loadSufamiTurboCartridge(const char *fileBase, const char *fileSlot1, const char *fileSlot2) {
hide();
window->hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->show(), slot2File->show(), slot2Browse->show(), slot2Clear->show();
@@ -131,7 +132,7 @@ void LoaderWindow::loadSufamiTurboCartridge(const char *fileBase, const char *fi
}
void LoaderWindow::loadSuperGameBoyCartridge(const char *fileBase, const char *fileSlot1) {
hide();
window->hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->hide(), slot2File->hide(), slot2Browse->hide(), slot2Clear->hide();
@@ -147,9 +148,9 @@ void LoaderWindow::loadSuperGameBoyCartridge(const char *fileBase, const char *f
}
void LoaderWindow::showWindow(const char *title) {
setWindowTitle(title);
showAt(0.0, 0.0);
setFocus();
window->setWindowTitle(title);
window->show();
window->shrink();
load->setFocus();
}
@@ -207,7 +208,7 @@ void LoaderWindow::clearSlot2Cartridge() {
}
void LoaderWindow::onLoad() {
hide();
window->hide();
string base = baseFile->text().toUtf8().data();
string slot1 = slot1File->text().toUtf8().data();
string slot2 = slot2File->text().toUtf8().data();
@@ -235,5 +236,5 @@ void LoaderWindow::onLoad() {
}
void LoaderWindow::onCancel() {
hide();
window->hide();
}

View File

@@ -1,7 +1,8 @@
class LoaderWindow : public QbWindow {
class LoaderWindow : public QObject {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QGridLayout *grid;
QLabel *baseLabel;

View File

@@ -1,6 +1,7 @@
MainWindow::MainWindow() {
setObjectName("main-window");
setWindowTitle(utf8() << bsnesTitle << " v" << bsnesVersion);
window = new Window(config.geometry.mainWindow);
window->setObjectName("main-window");
window->setWindowTitle(utf8() << bsnesTitle << " v" << bsnesVersion);
//menu bar
#if defined(PLATFORM_OSX)
@@ -11,125 +12,124 @@ MainWindow::MainWindow() {
system = menuBar->addMenu("System");
system_load = system->addAction("Load Cartridge ...");
system_load->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial = system->addMenu("Load Special");
system_loadSpecial->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_bsxSlotted = system_loadSpecial->addAction("Load BS-X Slotted Cartridge ...");
system_loadSpecial_bsxSlotted->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_bsx = system_loadSpecial->addAction("Load BS-X Cartridge ...");
system_loadSpecial_bsx->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_sufamiTurbo = system_loadSpecial->addAction("Load Sufami Turbo Cartridge ...");
system_loadSpecial_sufamiTurbo->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_superGameBoy = system_loadSpecial->addAction("Load Super Game Boy Cartridge ...");
system_loadSpecial_superGameBoy->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_superGameBoy->setVisible(false);
system->addSeparator();
system_power = system->addMenu("Power");
system_power_on = system_power->addAction("On");
system_power_on->setCheckable(true);
system_power_off = system_power->addAction("Off");
system_power_off->setCheckable(true);
system->addAction(system_power = new QbCheckAction("Power", 0));
system_reset = system->addAction("Reset");
system_reset->setIcon(QIcon(":/16x16/view-refresh.png"));
system->addSeparator();
system_port1 = system->addMenu("Controller Port 1");
system_port1_none = system_port1->addAction("None");
system_port1_none->setCheckable(true);
system_port1_joypad = system_port1->addAction("Joypad");
system_port1_joypad->setCheckable(true);
system_port1_multitap = system_port1->addAction("Multitap");
system_port1_multitap->setCheckable(true);
system_port1_mouse = system_port1->addAction("Mouse");
system_port1_mouse->setCheckable(true);
system_port1->setIcon(QIcon(":/16x16/input-gaming.png"));
system_port1->addAction(system_port1_none = new QbRadioAction("None", 0));
system_port1->addAction(system_port1_joypad = new QbRadioAction("Joypad", 0));
system_port1->addAction(system_port1_multitap = new QbRadioAction("Multitap", 0));
system_port1->addAction(system_port1_mouse = new QbRadioAction("Mouse", 0));
system_port2 = system->addMenu("Controller Port 2");
system_port2_none = system_port2->addAction("None");
system_port2_none->setCheckable(true);
system_port2_joypad = system_port2->addAction("Joypad");
system_port2_joypad->setCheckable(true);
system_port2_multitap = system_port2->addAction("Multitap");
system_port2_multitap->setCheckable(true);
system_port2_mouse = system_port2->addAction("Mouse");
system_port2_mouse->setCheckable(true);
system_port2_superscope = system_port2->addAction("Super Scope");
system_port2_superscope->setCheckable(true);
system_port2_justifier = system_port2->addAction("Justifier");
system_port2_justifier->setCheckable(true);
system_port2_justifiers = system_port2->addAction("Two Justifiers");
system_port2_justifiers->setCheckable(true);
system_port2->setIcon(QIcon(":/16x16/input-gaming.png"));
system_port2->addAction(system_port2_none = new QbRadioAction("None", 0));
system_port2->addAction(system_port2_joypad = new QbRadioAction("Joypad", 0));
system_port2->addAction(system_port2_multitap = new QbRadioAction("Multitap", 0));
system_port2->addAction(system_port2_mouse = new QbRadioAction("Mouse", 0));
system_port2->addAction(system_port2_superscope = new QbRadioAction("Super Scope", 0));
system_port2->addAction(system_port2_justifier = new QbRadioAction("Justifier", 0));
system_port2->addAction(system_port2_justifiers = new QbRadioAction("Two Justifiers", 0));
#if !defined(PLATFORM_OSX)
system->addSeparator();
#endif
system_exit = system->addAction("Exit");
system_exit->setIcon(QIcon(":/16x16/process-stop.png"));
system_exit->setMenuRole(QAction::QuitRole);
settings = menuBar->addMenu("Settings");
settings_videoMode = settings->addMenu("Video Mode");
settings_videoMode_1x = settings_videoMode->addAction("Scale 1x");
settings_videoMode_1x->setCheckable(true);
settings_videoMode_2x = settings_videoMode->addAction("Scale 2x");
settings_videoMode_2x->setCheckable(true);
settings_videoMode_3x = settings_videoMode->addAction("Scale 3x");
settings_videoMode_3x->setCheckable(true);
settings_videoMode_4x = settings_videoMode->addAction("Scale 4x");
settings_videoMode_4x->setCheckable(true);
settings_videoMode_max = settings_videoMode->addAction("Scale Max");
settings_videoMode_max->setCheckable(true);
settings_videoMode->setIcon(QIcon(":/16x16/video-display.png"));
settings_videoMode->addAction(settings_videoMode_1x = new QbRadioAction("Scale 1x", 0));
settings_videoMode->addAction(settings_videoMode_2x = new QbRadioAction("Scale 2x", 0));
settings_videoMode->addAction(settings_videoMode_3x = new QbRadioAction("Scale 3x", 0));
settings_videoMode->addAction(settings_videoMode_4x = new QbRadioAction("Scale 4x", 0));
settings_videoMode->addAction(settings_videoMode_max = new QbRadioAction("Scale Max", 0));
settings_videoMode->addSeparator();
settings_videoMode_correctAspectRatio = settings_videoMode->addAction("Correct Aspect Ratio");
settings_videoMode_correctAspectRatio->setCheckable(true);
settings_videoMode_fullscreen = settings_videoMode->addAction("Fullscreen");
settings_videoMode_fullscreen->setCheckable(true);
settings_videoMode->addAction(settings_videoMode_correctAspectRatio = new QbCheckAction("Correct Aspect Ratio", 0));
settings_videoMode->addAction(settings_videoMode_fullscreen = new QbCheckAction("Fullscreen", 0));
settings_videoMode->addSeparator();
settings_videoMode_ntsc = settings_videoMode->addAction("NTSC");
settings_videoMode_ntsc->setCheckable(true);
settings_videoMode_pal = settings_videoMode->addAction("PAL");
settings_videoMode_pal->setCheckable(true);
settings_videoFilter = settings->addMenu("Video Filter");
settings_videoFilter_point = settings_videoFilter->addAction("Point");
settings_videoFilter_point->setCheckable(true);
settings_videoFilter_linear = settings_videoFilter->addAction("Linear");
settings_videoFilter_linear->setCheckable(true);
settings_videoMode->addAction(settings_videoMode_ntsc = new QbRadioAction("NTSC", 0));
settings_videoMode->addAction(settings_videoMode_pal = new QbRadioAction("PAL", 0));
if(filter.opened()) {
settings_videoFilter = settings->addMenu("Video Filter");
settings_videoFilter->setIcon(QIcon(":/16x16/image-x-generic.png"));
settings_videoFilter_configure = settings_videoFilter->addAction("Configure Active Filter ...");
settings_videoFilter_configure->setIcon(QIcon(":/16x16/preferences-desktop.png"));
settings_videoFilter->addSeparator();
settings_videoFilter_none = settings_videoFilter->addAction("None");
settings_videoFilter_none->setCheckable(true);
settings_videoFilter_scanline = settings_videoFilter->addAction("Scanline");
settings_videoFilter_scanline->setCheckable(true);
settings_videoFilter_scale2x = settings_videoFilter->addAction("Scale2x");
settings_videoFilter_scale2x->setCheckable(true);
settings_videoFilter_lq2x = settings_videoFilter->addAction("LQ2x");
settings_videoFilter_lq2x->setCheckable(true);
settings_videoFilter_hq2x = settings_videoFilter->addAction("HQ2x");
settings_videoFilter_hq2x->setCheckable(true);
settings_videoFilter_ntsc = settings_videoFilter->addAction("NTSC");
settings_videoFilter_ntsc->setCheckable(true);
settings_videoFilter->addAction(settings_videoFilter_none = new QbRadioAction("None", 0));
settings_videoFilter_list.add(settings_videoFilter_none);
lstring filterlist;
filterlist.split(";", filter.dl_supported());
for(unsigned i = 0; i < filterlist.size(); i++) {
QbRadioAction *action = new QbRadioAction(utf8() << filterlist[i], 0);
settings_videoFilter->addAction(action);
settings_videoFilter_list.add(action);
}
}
settings->addAction(settings_smoothVideo = new QbCheckAction("Smooth Video Output", 0));
settings->addSeparator();
settings_muteAudio = settings->addAction("Mute Audio Output");
settings_muteAudio->setCheckable(true);
settings->addAction(settings_muteAudio = new QbCheckAction("Mute Audio Output", 0));
settings->addSeparator();
settings_emulationSpeed = settings->addMenu("Emulation Speed");
settings_emulationSpeed_slowest = settings_emulationSpeed->addAction("50%");
settings_emulationSpeed_slowest->setCheckable(true);
settings_emulationSpeed_slow = settings_emulationSpeed->addAction("75%");
settings_emulationSpeed_slow->setCheckable(true);
settings_emulationSpeed_normal = settings_emulationSpeed->addAction("100%");
settings_emulationSpeed_normal->setCheckable(true);
settings_emulationSpeed_fast = settings_emulationSpeed->addAction("150%");
settings_emulationSpeed_fast->setCheckable(true);
settings_emulationSpeed_fastest = settings_emulationSpeed->addAction("200%");
settings_emulationSpeed_fastest->setCheckable(true);
settings_emulationSpeed->setIcon(QIcon(":/16x16/appointment-new.png"));
settings_emulationSpeed->addAction(settings_emulationSpeed_slowest = new QbRadioAction("50%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_slow = new QbRadioAction("75%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_normal = new QbRadioAction("100%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_fast = new QbRadioAction("150%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_fastest = new QbRadioAction("200%", 0));
settings_emulationSpeed->addSeparator();
settings_emulationSpeed_syncVideo = settings_emulationSpeed->addAction("Sync Video");
settings_emulationSpeed_syncVideo->setCheckable(true);
settings_emulationSpeed_syncAudio = settings_emulationSpeed->addAction("Sync Audio");
settings_emulationSpeed_syncAudio->setCheckable(true);
settings_emulationSpeed->addAction(settings_emulationSpeed_syncVideo = new QbCheckAction("Sync Video", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_syncAudio = new QbCheckAction("Sync Audio", 0));
settings_configuration = settings->addAction("Configuration ...");
settings_configuration->setIcon(QIcon(":/16x16/preferences-desktop.png"));
settings_configuration->setMenuRole(QAction::PreferencesRole);
tools = menuBar->addMenu("Tools");
tools_cheatEditor = tools->addAction("Cheat Editor ...");
tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png"));
tools_cheatFinder = tools->addAction("Cheat Finder ...");
tools_cheatFinder->setIcon(QIcon(":/16x16/system-search.png"));
tools_stateManager = tools->addAction("State Manager ...");
tools_stateManager->setIcon(QIcon(":/16x16/system-file-manager.png"));
#if defined(DEBUGGER)
tools->addSeparator();
#endif
tools_debugger = tools->addAction("Debugger ...");
tools_debugger->setIcon(QIcon(":/16x16/utilities-terminal.png"));
#if !defined(DEBUGGER)
tools_debugger->setVisible(false);
#endif
help = menuBar->addMenu("Help");
help_documentation = help->addAction("Documentation ...");
help_documentation->setIcon(QIcon(":/16x16/text-x-generic.png"));
help_license = help->addAction("License ...");
help_license->setIcon(QIcon(":/16x16/text-x-generic.png"));
#if !defined(PLATFORM_OSX)
help->addSeparator();
#endif
help_about = help->addAction("About ...");
help_about->setIcon(QIcon(":/16x16/help-browser.png"));
help_about->setMenuRole(QAction::AboutRole);
//canvas
@@ -171,12 +171,15 @@ MainWindow::MainWindow() {
#endif
layout->addWidget(canvasContainer);
layout->addWidget(statusBar);
setLayout(layout);
window->setLayout(layout);
//slots
connect(system_load, SIGNAL(triggered()), this, SLOT(loadCartridge()));
connect(system_power_on, SIGNAL(triggered()), this, SLOT(powerOn()));
connect(system_power_off, SIGNAL(triggered()), this, SLOT(powerOff()));
connect(system_loadSpecial_bsxSlotted, SIGNAL(triggered()), this, SLOT(loadBsxSlottedCartridge()));
connect(system_loadSpecial_bsx, SIGNAL(triggered()), this, SLOT(loadBsxCartridge()));
connect(system_loadSpecial_sufamiTurbo, SIGNAL(triggered()), this, SLOT(loadSufamiTurboCartridge()));
connect(system_loadSpecial_superGameBoy, SIGNAL(triggered()), this, SLOT(loadSuperGameBoyCartridge()));
connect(system_power, SIGNAL(triggered()), this, SLOT(power()));
connect(system_reset, SIGNAL(triggered()), this, SLOT(reset()));
connect(system_port1_none, SIGNAL(triggered()), this, SLOT(setPort1None()));
connect(system_port1_joypad, SIGNAL(triggered()), this, SLOT(setPort1Joypad()));
@@ -199,14 +202,13 @@ MainWindow::MainWindow() {
connect(settings_videoMode_fullscreen, SIGNAL(triggered()), this, SLOT(toggleFullscreen()));
connect(settings_videoMode_ntsc, SIGNAL(triggered()), this, SLOT(setVideoNtsc()));
connect(settings_videoMode_pal, SIGNAL(triggered()), this, SLOT(setVideoPal()));
connect(settings_videoFilter_point, SIGNAL(triggered()), this, SLOT(setPointFilter()));
connect(settings_videoFilter_linear, SIGNAL(triggered()), this, SLOT(setLinearFilter()));
connect(settings_videoFilter_none, SIGNAL(triggered()), this, SLOT(setNoFilter()));
connect(settings_videoFilter_scanline, SIGNAL(triggered()), this, SLOT(setScanlineFilter()));
connect(settings_videoFilter_scale2x, SIGNAL(triggered()), this, SLOT(setScale2xFilter()));
connect(settings_videoFilter_lq2x, SIGNAL(triggered()), this, SLOT(setLq2xFilter()));
connect(settings_videoFilter_hq2x, SIGNAL(triggered()), this, SLOT(setHq2xFilter()));
connect(settings_videoFilter_ntsc, SIGNAL(triggered()), this, SLOT(setNtscFilter()));
if(filter.opened()) {
connect(settings_videoFilter_configure, SIGNAL(triggered()), this, SLOT(configureFilter()));
for(unsigned i = 0; i < settings_videoFilter_list.size(); i++) {
connect(settings_videoFilter_list[i], SIGNAL(triggered()), this, SLOT(setFilter()));
}
}
connect(settings_smoothVideo, SIGNAL(triggered()), this, SLOT(toggleSmoothVideo()));
connect(settings_muteAudio, SIGNAL(triggered()), this, SLOT(muteAudio()));
connect(settings_emulationSpeed_slowest, SIGNAL(triggered()), this, SLOT(setSpeedSlowest()));
connect(settings_emulationSpeed_slow, SIGNAL(triggered()), this, SLOT(setSpeedSlow()));
@@ -217,6 +219,7 @@ MainWindow::MainWindow() {
connect(settings_emulationSpeed_syncAudio, SIGNAL(triggered()), this, SLOT(syncAudio()));
connect(settings_configuration, SIGNAL(triggered()), this, SLOT(showConfigWindow()));
connect(tools_cheatEditor, SIGNAL(triggered()), this, SLOT(showCheatEditor()));
connect(tools_cheatFinder, SIGNAL(triggered()), this, SLOT(showCheatFinder()));
connect(tools_stateManager, SIGNAL(triggered()), this, SLOT(showStateManager()));
connect(tools_debugger, SIGNAL(triggered()), this, SLOT(showDebugger()));
connect(help_documentation, SIGNAL(triggered()), this, SLOT(showDocumentation()));
@@ -228,8 +231,8 @@ MainWindow::MainWindow() {
void MainWindow::syncUi() {
system_power->setEnabled(SNES::cartridge.loaded());
system_power_on->setChecked (application.power == true);
system_power_off->setChecked(application.power == false);
system_power->setChecked (application.power == true);
system_power->setEnabled(SNES::cartridge.loaded());
system_reset->setEnabled(SNES::cartridge.loaded() && application.power);
system_port1_none->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceNone);
@@ -255,15 +258,16 @@ void MainWindow::syncUi() {
settings_videoMode_ntsc->setChecked(config.video.context->region == 0);
settings_videoMode_pal->setChecked (config.video.context->region == 1);
settings_videoFilter_point->setChecked (config.video.context->hwFilter == 0);
settings_videoFilter_linear->setChecked (config.video.context->hwFilter == 1);
settings_videoFilter_none->setChecked (config.video.context->swFilter == 0);
settings_videoFilter_scanline->setChecked(config.video.context->swFilter == 1);
settings_videoFilter_scale2x->setChecked (config.video.context->swFilter == 2);
settings_videoFilter_lq2x->setChecked (config.video.context->swFilter == 3);
settings_videoFilter_hq2x->setChecked (config.video.context->swFilter == 4);
settings_videoFilter_ntsc->setChecked (config.video.context->swFilter == 5);
if(filter.opened()) {
//only enable configuration option if the active filter supports it ...
settings_videoFilter_configure->setEnabled(filter.settings());
for(unsigned i = 0; i < settings_videoFilter_list.size(); i++) {
settings_videoFilter_list[i]->setChecked(config.video.context->swFilter == i);
}
}
settings_smoothVideo->setChecked(config.video.context->hwFilter == 1);
settings_muteAudio->setChecked(config.audio.mute);
settings_emulationSpeed_slowest->setChecked(config.system.speed == 0);
@@ -277,16 +281,41 @@ void MainWindow::syncUi() {
}
bool MainWindow::isActive() {
return isActiveWindow() && !isMinimized();
return window->isActiveWindow() && !window->isMinimized();
}
void MainWindow::loadCartridge() {
diskBrowser->loadAnyCartridge();
diskBrowser->loadCartridge();
}
void MainWindow::powerOn() { utility.modifySystemState(Utility::PowerOn); }
void MainWindow::powerOff() { utility.modifySystemState(Utility::PowerOff); }
void MainWindow::reset() { utility.modifySystemState(Utility::Reset); }
void MainWindow::loadBsxSlottedCartridge() {
loaderWindow->loadBsxSlottedCartridge("", "");
}
void MainWindow::loadBsxCartridge() {
loaderWindow->loadBsxCartridge(config.path.bsx, "");
}
void MainWindow::loadSufamiTurboCartridge() {
loaderWindow->loadSufamiTurboCartridge(config.path.st, "", "");
}
void MainWindow::loadSuperGameBoyCartridge() {
loaderWindow->loadSuperGameBoyCartridge(config.path.sgb, "");
}
void MainWindow::power() {
system_power->toggleChecked();
if(system_power->isChecked()) {
utility.modifySystemState(Utility::PowerOn);
} else {
utility.modifySystemState(Utility::PowerOff);
}
}
void MainWindow::reset() {
utility.modifySystemState(Utility::Reset);
}
void MainWindow::setPort1None() { SNES::config.controller_port1 = SNES::Input::DeviceNone; utility.updateControllers(); syncUi(); }
void MainWindow::setPort1Joypad() { SNES::config.controller_port1 = SNES::Input::DeviceJoypad; utility.updateControllers(); syncUi(); }
@@ -301,6 +330,7 @@ void MainWindow::setPort2Justifier() { SNES::config.controller_port2 = SNES::In
void MainWindow::setPort2Justifiers() { SNES::config.controller_port2 = SNES::Input::DeviceJustifiers; utility.updateControllers(); syncUi(); }
void MainWindow::quit() {
window->hide();
application.terminate = true;
}
@@ -311,11 +341,13 @@ void MainWindow::setVideoMode4x() { config.video.context->multiplier = 4; utili
void MainWindow::setVideoModeMax() { config.video.context->multiplier = 9; utility.resizeMainWindow(); syncUi(); }
void MainWindow::toggleAspectCorrection() {
settings_videoMode_correctAspectRatio->toggleChecked();
config.video.context->correctAspectRatio = settings_videoMode_correctAspectRatio->isChecked();
utility.resizeMainWindow();
}
void MainWindow::toggleFullscreen() {
settings_videoMode_fullscreen->toggleChecked();
config.video.isFullscreen = settings_videoMode_fullscreen->isChecked();
utility.updateFullscreenState();
utility.resizeMainWindow();
@@ -325,16 +357,37 @@ void MainWindow::toggleFullscreen() {
void MainWindow::setVideoNtsc() { config.video.context->region = 0; utility.updateVideoMode(); utility.resizeMainWindow(); syncUi(); }
void MainWindow::setVideoPal() { config.video.context->region = 1; utility.updateVideoMode(); utility.resizeMainWindow(); syncUi(); }
void MainWindow::setPointFilter() { config.video.context->hwFilter = 0; utility.updateHardwareFilter(); syncUi(); }
void MainWindow::setLinearFilter() { config.video.context->hwFilter = 1; utility.updateHardwareFilter(); syncUi(); }
void MainWindow::setNoFilter() { config.video.context->swFilter = 0; utility.updateSoftwareFilter(); syncUi(); }
void MainWindow::setScanlineFilter() { config.video.context->swFilter = 1; utility.updateSoftwareFilter(); syncUi(); }
void MainWindow::setScale2xFilter() { config.video.context->swFilter = 2; utility.updateSoftwareFilter(); syncUi(); }
void MainWindow::setLq2xFilter() { config.video.context->swFilter = 3; utility.updateSoftwareFilter(); syncUi(); }
void MainWindow::setHq2xFilter() { config.video.context->swFilter = 4; utility.updateSoftwareFilter(); syncUi(); }
void MainWindow::setNtscFilter() { config.video.context->swFilter = 5; utility.updateSoftwareFilter(); syncUi(); }
void MainWindow::toggleSmoothVideo() {
settings_smoothVideo->toggleChecked();
config.video.context->hwFilter = settings_smoothVideo->isChecked();
utility.updateHardwareFilter();
syncUi();
}
void MainWindow::muteAudio() { config.audio.mute = settings_muteAudio->isChecked(); }
void MainWindow::configureFilter() {
QWidget *widget = filter.settings();
if(widget) {
widget->show();
widget->activateWindow();
widget->raise();
}
}
void MainWindow::setFilter() {
for(unsigned i = 0; i < settings_videoFilter_list.size(); i++) {
if(sender() == settings_videoFilter_list[i]) {
config.video.context->swFilter = i;
utility.updateSoftwareFilter();
syncUi();
return;
}
}
}
void MainWindow::muteAudio() {
settings_muteAudio->toggleChecked();
config.audio.mute = settings_muteAudio->isChecked();
}
void MainWindow::setSpeedSlowest() { config.system.speed = 0; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedSlow() { config.system.speed = 1; utility.updateEmulationSpeed(); syncUi(); }
@@ -342,17 +395,24 @@ void MainWindow::setSpeedNormal() { config.system.speed = 2; utility.updateEmul
void MainWindow::setSpeedFast() { config.system.speed = 3; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedFastest() { config.system.speed = 4; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::syncVideo() { config.video.synchronize = settings_emulationSpeed_syncVideo->isChecked(); utility.updateAvSync(); }
void MainWindow::syncAudio() { config.audio.synchronize = settings_emulationSpeed_syncAudio->isChecked(); utility.updateAvSync(); }
void MainWindow::showConfigWindow() {
settingsWindow->showAt(-1.0, 1.0);
settingsWindow->setFocus();
void MainWindow::syncVideo() {
settings_emulationSpeed_syncVideo->toggleChecked();
config.video.synchronize = settings_emulationSpeed_syncVideo->isChecked();
utility.updateAvSync();
}
void MainWindow::showCheatEditor() { toolsWindow->showCheatEditor(); }
void MainWindow::syncAudio() {
settings_emulationSpeed_syncAudio->toggleChecked();
config.audio.synchronize = settings_emulationSpeed_syncAudio->isChecked();
utility.updateAvSync();
}
void MainWindow::showConfigWindow() { settingsWindow->window->show(); }
void MainWindow::showCheatEditor() { toolsWindow->showCheatEditor(); }
void MainWindow::showCheatFinder() { toolsWindow->showCheatFinder(); }
void MainWindow::showStateManager() { toolsWindow->showStateManager(); }
void MainWindow::showDebugger() { debugger->show(); }
void MainWindow::showDebugger() { debugger->window->show(); }
void MainWindow::showDocumentation() {
QFile file(":/documentation.html");
@@ -370,12 +430,14 @@ void MainWindow::showLicense() {
}
}
void MainWindow::showAbout() {
aboutWindow->showAt(0.0, 0.0);
aboutWindow->setFocus();
aboutWindow->window->show();
}
void MainWindow::closeEvent(QCloseEvent*) {
quit();
void MainWindow::Window::closeEvent(QCloseEvent*) {
mainWindow->quit();
}
MainWindow::Window::Window(string &geometry) : QbWindow(geometry) {
}
//============
@@ -395,7 +457,7 @@ void CanvasObject::dragEnterEvent(QDragEnterEvent *event) {
void CanvasObject::dropEvent(QDropEvent *event) {
if(event->mimeData()->hasUrls()) {
QList<QUrl> list = event->mimeData()->urls();
if(list.count() == 1) utility.loadCartridge(list.at(0).toLocalFile().toUtf8().constData());
if(list.count() == 1) utility.loadCartridgeNormal(list.at(0).toLocalFile().toUtf8().constData());
}
}

View File

@@ -13,67 +13,69 @@ public:
void paintEvent(QPaintEvent*);
};
class MainWindow : public QbWindow {
class MainWindow : public QObject {
Q_OBJECT
public:
struct Window : public QbWindow {
void closeEvent(QCloseEvent*);
Window(string&);
} *window;
QMenuBar *menuBar;
QStatusBar *statusBar;
void closeEvent(QCloseEvent*);
QVBoxLayout *layout;
QMenu *system;
QAction *system_load;
QMenu *system_power;
QAction *system_power_on;
QAction *system_power_off;
QMenu *system_loadSpecial;
QAction *system_loadSpecial_bsxSlotted;
QAction *system_loadSpecial_bsx;
QAction *system_loadSpecial_sufamiTurbo;
QAction *system_loadSpecial_superGameBoy;
QbCheckAction *system_power;
QAction *system_reset;
QMenu *system_port1;
QAction *system_port1_none;
QAction *system_port1_joypad;
QAction *system_port1_multitap;
QAction *system_port1_mouse;
QbRadioAction *system_port1_none;
QbRadioAction *system_port1_joypad;
QbRadioAction *system_port1_multitap;
QbRadioAction *system_port1_mouse;
QMenu *system_port2;
QAction *system_port2_none;
QAction *system_port2_joypad;
QAction *system_port2_multitap;
QAction *system_port2_mouse;
QAction *system_port2_superscope;
QAction *system_port2_justifier;
QAction *system_port2_justifiers;
QbRadioAction *system_port2_none;
QbRadioAction *system_port2_joypad;
QbRadioAction *system_port2_multitap;
QbRadioAction *system_port2_mouse;
QbRadioAction *system_port2_superscope;
QbRadioAction *system_port2_justifier;
QbRadioAction *system_port2_justifiers;
QAction *system_exit;
QMenu *settings;
QMenu *settings_videoMode;
QAction *settings_videoMode_1x;
QAction *settings_videoMode_2x;
QAction *settings_videoMode_3x;
QAction *settings_videoMode_4x;
QAction *settings_videoMode_max;
QAction *settings_videoMode_correctAspectRatio;
QAction *settings_videoMode_fullscreen;
QAction *settings_videoMode_ntsc;
QAction *settings_videoMode_pal;
QbRadioAction *settings_videoMode_1x;
QbRadioAction *settings_videoMode_2x;
QbRadioAction *settings_videoMode_3x;
QbRadioAction *settings_videoMode_4x;
QbRadioAction *settings_videoMode_max;
QbCheckAction *settings_videoMode_correctAspectRatio;
QbCheckAction *settings_videoMode_fullscreen;
QbRadioAction *settings_videoMode_ntsc;
QbRadioAction *settings_videoMode_pal;
QMenu *settings_videoFilter;
QAction *settings_videoFilter_point;
QAction *settings_videoFilter_linear;
QAction *settings_videoFilter_none;
QAction *settings_videoFilter_scanline;
QAction *settings_videoFilter_scale2x;
QAction *settings_videoFilter_lq2x;
QAction *settings_videoFilter_hq2x;
QAction *settings_videoFilter_ntsc;
QAction *settings_muteAudio;
QAction *settings_videoFilter_configure;
QbRadioAction *settings_videoFilter_none;
array<QbRadioAction*> settings_videoFilter_list;
QbCheckAction *settings_smoothVideo;
QbCheckAction *settings_muteAudio;
QMenu *settings_emulationSpeed;
QAction *settings_emulationSpeed_slowest;
QAction *settings_emulationSpeed_slow;
QAction *settings_emulationSpeed_normal;
QAction *settings_emulationSpeed_fast;
QAction *settings_emulationSpeed_fastest;
QAction *settings_emulationSpeed_syncVideo;
QAction *settings_emulationSpeed_syncAudio;
QbRadioAction *settings_emulationSpeed_slowest;
QbRadioAction *settings_emulationSpeed_slow;
QbRadioAction *settings_emulationSpeed_normal;
QbRadioAction *settings_emulationSpeed_fast;
QbRadioAction *settings_emulationSpeed_fastest;
QbCheckAction *settings_emulationSpeed_syncVideo;
QbCheckAction *settings_emulationSpeed_syncAudio;
QAction *settings_configuration;
QMenu *tools;
QAction *tools_cheatEditor;
QAction *tools_cheatFinder;
QAction *tools_stateManager;
QAction *tools_debugger;
QMenu *help;
@@ -92,8 +94,11 @@ public:
public slots:
void loadCartridge();
void powerOn();
void powerOff();
void loadBsxSlottedCartridge();
void loadBsxCartridge();
void loadSufamiTurboCartridge();
void loadSuperGameBoyCartridge();
void power();
void reset();
void setPort1None();
void setPort1Joypad();
@@ -116,14 +121,9 @@ public slots:
void toggleFullscreen();
void setVideoNtsc();
void setVideoPal();
void setPointFilter();
void setLinearFilter();
void setNoFilter();
void setScanlineFilter();
void setScale2xFilter();
void setLq2xFilter();
void setHq2xFilter();
void setNtscFilter();
void configureFilter();
void setFilter();
void toggleSmoothVideo();
void muteAudio();
void setSpeedSlowest();
void setSpeedSlow();
@@ -134,6 +134,7 @@ public slots:
void syncAudio();
void showConfigWindow();
void showCheatEditor();
void showCheatFinder();
void showStateManager();
void showDebugger();
void showDocumentation();

View File

@@ -60,26 +60,25 @@ Configuration::Configuration() {
attach(file.autodetect_type = false, "file.autodetectType");
attach(file.bypass_patch_crc32 = false, "file.bypassPatchCrc32");
attach(path.rom = "", "path.rom");
attach(path.save = "", "path.save");
attach(path.state = "", "path.state");
attach(path.patch = "", "path.patch");
attach(path.cheat = "", "path.cheat");
attach(path.data = "", "path.data");
attach(path.bsx = "", "path.bsx");
attach(path.st = "", "path.st");
attach(path.sgb = "", "path.sgb");
attach(path.current = "", "path.current");
attach(path.rom = "", "path.rom");
attach(path.save = "", "path.save");
attach(path.state = "", "path.state");
attach(path.patch = "", "path.patch");
attach(path.cheat = "", "path.cheat");
attach(path.data = "", "path.data");
attach(path.bsx = "", "path.bsx");
attach(path.st = "", "path.st");
attach(path.sgb = "", "path.sgb");
video.context = &video.windowed;
attach(video.isFullscreen = false, "video.isFullscreen");
attach(video.synchronize = false, "video.synchronize");
attach(video.contrastAdjust = 0, "video.contrastAdjust");
attach(video.brightnessAdjust = 0, "video.brightnessAdjust");
attach(video.gammaAdjust = 0, "video.gammaAdjust");
attach(video.enableGammaRamp = true, "video.enableGammaRamp");
attach(video.enableNtscMergeFields = false, "video.enableNtscMergeFields");
attach(video.contrastAdjust = 0, "video.contrastAdjust");
attach(video.brightnessAdjust = 0, "video.brightnessAdjust");
attach(video.gammaAdjust = 0, "video.gammaAdjust");
attach(video.enableGammaRamp = true, "video.enableGammaRamp");
attach(video.ntscAspectRatio = 54.0 / 47.0, "video.ntscAspectRatio", "NTSC aspect ratio (x / y)");
attach(video.palAspectRatio = 32.0 / 23.0, "video.palAspectRatio", "PAL aspect ratio (x / y)");
@@ -106,7 +105,7 @@ Configuration::Configuration() {
attach(audio.outputFrequency = 48000, "audio.outputFrequency");
attach(audio.inputFrequency = 32000, "audio.inputFrequency");
attach(input.focusPolicy = Input::FocusPolicyPauseEmulation, "input.focusPolicy");
attach(input.focusPolicy = Input::FocusPolicyIgnoreInput, "input.focusPolicy");
attach(input.allowInvalidInput = false, "input.allowInvalidInput", "Allow up+down / left+right combinations; may trigger bugs in some games");
attach(input.joypad1.up = "keyboard00.up", "input.joypad1.up");
@@ -184,4 +183,20 @@ Configuration::Configuration() {
attach(input.uiGeneral.toggleMenu = "keyboard00.escape", "input.uiGeneral.toggleMenu");
attach(input.uiGeneral.toggleStatus = "keyboard00.escape", "input.uiGeneral.toggleStatus");
attach(input.uiGeneral.exitEmulator = "none", "input.uiGeneral.exitEmulator");
attach(geometry.mainWindow = "", "geometry.mainWindow");
attach(geometry.loaderWindow = "", "geometry.loaderWindow");
attach(geometry.htmlViewerWindow = "", "geometry.htmlViewerWindow");
attach(geometry.aboutWindow = "", "geometry.aboutWindow");
attach(geometry.diskBrowser = "", "geometry.diskBrowser");
attach(geometry.folderCreator = "", "geometry.folderCreator");
attach(geometry.settingsWindow = "", "geometry.settingsWindow");
attach(geometry.inputCaptureWindow = "", "geometry.inputCaptureWindow");
attach(geometry.inputMouseCaptureWindow = "", "geometry.inputMouseCaptureWindow");
attach(geometry.inputCalibrationWindow = "", "geometry.inputCalibrationWindow");
attach(geometry.toolsWindow = "", "geometry.toolsWindow");
attach(geometry.debugger = "", "geometry.debugger");
attach(geometry.breakpointEditor = "", "geometry.breakpointEditor");
attach(geometry.memoryEditor = "", "geometry.memoryEditor");
attach(geometry.vramViewer = "", "geometry.vramViewer");
}

View File

@@ -26,7 +26,6 @@ public:
bool synchronize;
signed contrastAdjust, brightnessAdjust, gammaAdjust;
bool enableGammaRamp;
bool enableNtscMergeFields;
double ntscAspectRatio, palAspectRatio;
struct Context {
@@ -88,6 +87,27 @@ public:
} uiGeneral;
} input;
struct Geometry {
string mainWindow;
string loaderWindow;
string htmlViewerWindow;
string aboutWindow;
string diskBrowser;
string folderCreator;
string settingsWindow;
string inputCaptureWindow;
string inputMouseCaptureWindow;
string inputCalibrationWindow;
string toolsWindow;
string debugger;
string breakpointEditor;
string memoryEditor;
string vramViewer;
} geometry;
bool load(const char *filename);
void attachJoypad(Configuration::Input::Joypad &joypad, const char *name);
Configuration();

View File

@@ -59,19 +59,18 @@ void BreakpointItem::toggle() {
}
BreakpointEditor::BreakpointEditor() {
setObjectName("breakpoint-editor");
setWindowTitle("Breakpoint Editor");
window = new QbWindow(config.geometry.breakpointEditor);
window->setObjectName("breakpoint-editor");
window->setWindowTitle("Breakpoint Editor");
layout = new QVBoxLayout;
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
setLayout(layout);
window->setLayout(layout);
for(unsigned n = 0; n < SNES::Debugger::Breakpoints; n++) {
breakpoint[n] = new BreakpointItem(n);
layout->addWidget(breakpoint[n]);
}
resize(0, 0);
}

View File

@@ -17,10 +17,11 @@ private:
const unsigned id;
};
class BreakpointEditor : public QbWindow {
class BreakpointEditor : public QObject {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
BreakpointItem *breakpoint[SNES::Debugger::Breakpoints];

View File

@@ -1,26 +1,32 @@
#include "hexeditor.cpp"
#include "breakpoint.cpp"
#include "memory.cpp"
#include "vramviewer.cpp"
Debugger::Debugger() {
setObjectName("debugger");
setWindowTitle("Debugger");
window = new QbWindow(config.geometry.debugger);
window->setObjectName("debugger");
window->setWindowTitle("Debugger");
layout = new QHBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
setLayout(layout);
window->setLayout(layout);
menu = new QMenuBar;
layout->setMenuBar(menu);
tools = menu->addMenu("Tools");
tools_breakpoint = tools->addAction("Breakpoint Editor ...");
tools_breakpoint->setIcon(QIcon(":/16x16/process-stop.png"));
tools_memory = tools->addAction("Memory Editor ...");
tools_memory->setIcon(QIcon(":/16x16/text-x-generic.png"));
tools_vramViewer = tools->addAction("Video RAM Viewer ...");
tools_vramViewer->setIcon(QIcon(":/16x16/image-x-generic.png"));
miscOptions = menu->addMenu("Misc");
miscOptions_clear = miscOptions->addAction("Clear Console");
miscOptions_clear->setIcon(QIcon(":/16x16/document-new.png"));
console = new QTextEdit;
console->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -63,8 +69,6 @@ Debugger::Debugger() {
spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
controlLayout->addWidget(spacer);
resize(855, 425);
connect(tools_breakpoint, SIGNAL(triggered()), this, SLOT(showBreakpointEditor()));
connect(tools_memory, SIGNAL(triggered()), this, SLOT(showMemoryEditor()));
connect(tools_vramViewer, SIGNAL(triggered()), this, SLOT(showVramViewer()));
@@ -83,6 +87,7 @@ Debugger::Debugger() {
frameCounter = 0;
synchronize();
window->resize(855, 425);
}
void Debugger::synchronize() {
@@ -94,11 +99,6 @@ void Debugger::synchronize() {
memoryEditor->synchronize();
}
void Debugger::show() {
showAt(-1.0, +1.0);
setFocus();
}
void Debugger::echo(const char *message) {
console->moveCursor(QTextCursor::End);
console->insertHtml(message);
@@ -109,18 +109,15 @@ void Debugger::clear() {
}
void Debugger::showBreakpointEditor() {
breakpointEditor->showAt(-1.0, -1.0);
breakpointEditor->setFocus();
breakpointEditor->window->show();
}
void Debugger::showMemoryEditor() {
memoryEditor->showAt(0.0, -1.0);
memoryEditor->setFocus();
memoryEditor->window->show();
}
void Debugger::showVramViewer() {
vramViewer->showAt(+1.0, -1.0);
vramViewer->setFocus();
vramViewer->window->show();
vramViewer->refresh();
}

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