From 805398e5a89d0ddaeb12b6eaab922e2cdf63c999 Mon Sep 17 00:00:00 2001 From: byuu Date: Tue, 18 Mar 2008 06:19:43 +0000 Subject: [PATCH] Update to bsnes v029 release. A new version of bsnes has been released. It contains a few minor emulation fixes, as well as user interface improvements. Behind the scenes, the source has been cleaned up more in preparation for running the CPU and PPU (video processor) separately from each other (eg with no enslavement.) This is required for implementing a clock cycle based PPU renderer. - Greatly improved invalid DMA transfer behavior, should be nearly perfect now - Major code cleanup -- most importantly, almost all PPU timing-related settings moved back to PPU, from CPU - Added option to auto-detect file type by inspecting file headers rather than file extensions - Rewrote video filter system to move it out of the emulation core -- HQ2x and Scale2x will work even in hires and interlace modes now, 50% scanline filter added - Re-added bsnes window icon - Added new controller graphic when assigning joypad keys [FitzRoy] - Redundant "Advanced" panel settings which can be configured via the GUI are no longer displayed - Improved speed regulation settings - XP and Vista themes will now apply to bsnes controls - Added "Path Settings" window to allow easy selection of default file directories - Tab key now mostly works throughout most of the GUI (needs improvement) - Main window will no longer disappear when setting a video multipler which results in a window size larger than the current desktop resolution - Added two new advanced options: one to control GUI window opacity, and one to adjust the statusbar text --- readme.txt | 3 +- src/Makefile | 65 +- src/base.h | 16 +- src/cart/cart.cpp | 18 +- src/cart/cart.h | 23 +- src/cart/cart_bsc.cpp | 19 +- src/cart/cart_bsx.cpp | 11 +- src/cart/cart_file.cpp | 93 +- src/cart/cart_header.cpp | 373 +++--- src/cart/cart_normal.cpp | 14 +- src/cart/cart_st.cpp | 29 +- src/cheat/cheat.cpp | 97 +- src/cheat/cheat.h | 60 +- src/chip/bsx/bsx.cpp | 3 +- src/chip/bsx/bsx_base.cpp | 4 + src/chip/bsx/bsx_cart.cpp | 4 + src/chip/bsx/bsx_flash.cpp | 4 + src/chip/cx4/cx4.cpp | 3 +- src/chip/cx4/cx4data.cpp | 4 + src/chip/cx4/cx4fn.cpp | 4 + src/chip/cx4/cx4oam.cpp | 4 + src/chip/cx4/cx4ops.cpp | 4 + src/chip/dsp1/dsp1.cpp | 3 +- src/chip/dsp1/dsp1emu.cpp | 3 + src/chip/dsp2/dsp2.cpp | 3 +- src/chip/dsp2/dsp2_op.cpp | 4 + src/chip/dsp3/dsp3.cpp | 3 +- src/chip/dsp3/dsp3emu.c | 4 + src/chip/dsp4/dsp4.cpp | 3 +- src/chip/dsp4/dsp4emu.c | 4 + src/chip/sdd1/sdd1.cpp | 3 +- src/chip/sdd1/sdd1emu.cpp | 4 + src/chip/st010/st010.cpp | 4 +- src/chip/st010/st010_op.cpp | 4 + src/config/config.cpp | 52 +- src/config/config.h | 10 +- src/cpu/cpu.cpp | 4 +- src/cpu/cpu.h | 118 +- src/cpu/cpuregs.h | 40 +- src/cpu/dcpu.cpp | 6 +- src/cpu/scpu/core/core.cpp | 6 +- src/cpu/scpu/core/core.h | 100 +- src/cpu/scpu/core/opfn.cpp | 4 + src/cpu/scpu/dma/dma.cpp | 562 ++++----- src/cpu/scpu/dma/dma.h | 104 +- src/cpu/scpu/memory/memory.cpp | 4 + src/cpu/scpu/memory/memory.h | 64 +- src/cpu/scpu/mmio/mmio.cpp | 202 ++-- src/cpu/scpu/mmio/mmio.h | 134 +-- src/cpu/scpu/scpu.cpp | 7 +- src/cpu/scpu/scpu.h | 204 ++-- src/cpu/scpu/timing/irq.cpp | 179 ++- src/cpu/scpu/timing/irqtiming.cpp | 105 -- src/cpu/scpu/timing/joypad.cpp | 12 +- src/cpu/scpu/timing/timeshift.cpp | 22 - src/cpu/scpu/timing/timing.cpp | 154 +-- src/cpu/scpu/timing/timing.h | 84 +- src/data/controller.h | 1013 +++++++++++++++++ src/data/icon48.h | 40 + src/dsp/adsp/adsp.cpp | 6 +- src/dsp/adsp/adsp_tables.cpp | 4 + src/dsp/bdsp/bdsp.cpp | 4 +- src/dsp/dsp.h | 13 +- src/lib/{hiro_gtk => hiro/gtk}/button.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/button.h | 0 src/lib/{hiro_gtk => hiro/gtk}/canvas.cpp | 8 +- src/lib/{hiro_gtk => hiro/gtk}/canvas.h | 0 src/lib/{hiro_gtk => hiro/gtk}/checkbox.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/checkbox.h | 0 src/lib/{hiro_gtk => hiro/gtk}/combobox.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/combobox.h | 0 src/lib/{hiro_gtk => hiro/gtk}/editbox.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/editbox.h | 0 .../{hiro_gtk => hiro/gtk}/formcontrol.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/formcontrol.h | 0 src/lib/{hiro_gtk => hiro/gtk}/frame.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/frame.h | 0 src/lib/{hiro_gtk => hiro/gtk}/hiro.cpp | 76 +- src/lib/{hiro_gtk => hiro/gtk}/hiro.h | 17 +- src/lib/{hiro_gtk => hiro/gtk}/keymap.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/label.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/label.h | 0 src/lib/{hiro_gtk => hiro/gtk}/listbox.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/listbox.h | 0 .../{hiro_gtk => hiro/gtk}/menucheckitem.cpp | 0 .../{hiro_gtk => hiro/gtk}/menucheckitem.h | 0 .../{hiro_gtk => hiro/gtk}/menucontrol.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/menucontrol.h | 0 src/lib/{hiro_gtk => hiro/gtk}/menugroup.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/menugroup.h | 0 src/lib/{hiro_gtk => hiro/gtk}/menuitem.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/menuitem.h | 0 .../{hiro_gtk => hiro/gtk}/menuradioitem.cpp | 0 .../{hiro_gtk => hiro/gtk}/menuradioitem.h | 0 .../{hiro_gtk => hiro/gtk}/menuseparator.cpp | 0 .../{hiro_gtk => hiro/gtk}/menuseparator.h | 0 .../{hiro_gtk => hiro/gtk}/progressbar.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/progressbar.h | 0 src/lib/{hiro_gtk => hiro/gtk}/radiobox.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/radiobox.h | 0 src/lib/{hiro_gtk => hiro/gtk}/slider.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/slider.h | 0 src/lib/{hiro_gtk => hiro/gtk}/widget.cpp | 0 src/lib/{hiro_gtk => hiro/gtk}/widget.h | 0 src/lib/{hiro_gtk => hiro/gtk}/window.cpp | 64 +- src/lib/{hiro_gtk => hiro/gtk}/window.h | 3 + src/lib/{ => hiro}/hiro.cpp | 15 +- src/lib/{ => hiro}/hiro.h | 12 +- src/lib/{hiro_win => hiro/win}/button.cpp | 2 +- src/lib/{hiro_win => hiro/win}/button.h | 0 src/lib/{hiro_win => hiro/win}/canvas.cpp | 2 +- src/lib/{hiro_win => hiro/win}/canvas.h | 0 src/lib/{hiro_win => hiro/win}/checkbox.cpp | 2 +- src/lib/{hiro_win => hiro/win}/checkbox.h | 0 src/lib/{hiro_win => hiro/win}/combobox.cpp | 12 +- src/lib/{hiro_win => hiro/win}/combobox.h | 0 src/lib/{hiro_win => hiro/win}/editbox.cpp | 2 +- src/lib/{hiro_win => hiro/win}/editbox.h | 0 .../{hiro_win => hiro/win}/formcontrol.cpp | 14 + src/lib/{hiro_win => hiro/win}/formcontrol.h | 4 + src/lib/{hiro_win => hiro/win}/frame.cpp | 0 src/lib/{hiro_win => hiro/win}/frame.h | 0 src/lib/{hiro_win => hiro/win}/hiro.cpp | 81 +- src/lib/{hiro_win => hiro/win}/hiro.h | 11 +- src/lib/{hiro_win => hiro/win}/keymap.cpp | 0 src/lib/{hiro_win => hiro/win}/label.cpp | 0 src/lib/{hiro_win => hiro/win}/label.h | 0 src/lib/{hiro_win => hiro/win}/listbox.cpp | 3 +- src/lib/{hiro_win => hiro/win}/listbox.h | 0 .../{hiro_win => hiro/win}/menucheckitem.cpp | 0 .../{hiro_win => hiro/win}/menucheckitem.h | 0 .../{hiro_win => hiro/win}/menucontrol.cpp | 0 src/lib/{hiro_win => hiro/win}/menucontrol.h | 0 src/lib/{hiro_win => hiro/win}/menugroup.cpp | 0 src/lib/{hiro_win => hiro/win}/menugroup.h | 0 src/lib/{hiro_win => hiro/win}/menuitem.cpp | 0 src/lib/{hiro_win => hiro/win}/menuitem.h | 0 .../{hiro_win => hiro/win}/menuradioitem.cpp | 0 .../{hiro_win => hiro/win}/menuradioitem.h | 0 .../{hiro_win => hiro/win}/menuseparator.cpp | 0 .../{hiro_win => hiro/win}/menuseparator.h | 0 .../{hiro_win => hiro/win}/progressbar.cpp | 0 src/lib/{hiro_win => hiro/win}/progressbar.h | 0 src/lib/{hiro_win => hiro/win}/radiobox.cpp | 2 +- src/lib/{hiro_win => hiro/win}/radiobox.h | 0 src/lib/{hiro_win => hiro/win}/slider.cpp | 2 +- src/lib/{hiro_win => hiro/win}/slider.h | 0 src/lib/{hiro_win => hiro/win}/widget.cpp | 0 src/lib/{hiro_win => hiro/win}/widget.h | 0 src/lib/{hiro_win => hiro/win}/window.cpp | 112 +- src/lib/{hiro_win => hiro/win}/window.h | 4 + src/lib/libco/fiber.c | 2 +- src/lib/{ => libco}/libco.c | 12 +- src/lib/{ => libco}/libco.h | 0 src/lib/libco/sjlj.c | 2 +- src/lib/libco/ucontext.c | 2 +- src/lib/libco/x86-64.c | 2 +- src/lib/libco/x86.c | 2 +- src/lib/libfilter/colortable.cpp | 123 ++ src/lib/libfilter/colortable.h | 44 + src/lib/libfilter/direct.cpp | 30 + src/lib/libfilter/direct.h | 6 + src/lib/libfilter/filter.cpp | 34 + src/lib/libfilter/filter.h | 32 + src/lib/libfilter/hq2x.cpp | 160 +++ src/lib/libfilter/hq2x.h | 14 + .../libfilter/hq2x_table.h} | 15 +- src/lib/libfilter/libfilter.cpp | 14 + src/lib/libfilter/libfilter.h | 22 + src/lib/libfilter/ntsc.cpp | 73 ++ src/lib/libfilter/ntsc.h | 17 + src/lib/libfilter/scale2x.cpp | 47 + src/lib/libfilter/scale2x.h | 6 + src/lib/libfilter/scanline.cpp | 40 + src/lib/libfilter/scanline.h | 6 + .../libfilter/snes_ntsc}/snes_ntsc.c | 0 .../libfilter/snes_ntsc}/snes_ntsc.h | 6 +- .../libfilter/snes_ntsc}/snes_ntsc_config.h | 2 +- .../libfilter/snes_ntsc}/snes_ntsc_impl.h | 0 src/lib/nall/base64.hpp | 94 ++ src/lib/nall/detect.hpp | 30 + src/lib/nall/lzss.hpp | 83 ++ src/lib/nall/string.cpp | 5 +- src/lib/nall/string/class.cpp | 5 +- src/lib/nall/string/compare.cpp | 5 +- src/lib/nall/string/convert.cpp | 9 +- src/lib/nall/string/match.cpp | 5 +- src/lib/nall/string/math.cpp | 5 +- src/lib/nall/string/replace.cpp | 5 +- src/lib/nall/string/split.cpp | 5 +- src/lib/nall/string/strl.cpp | 5 +- src/lib/nall/string/trim.cpp | 5 +- src/lib/ruby/audio/openal.cpp | 5 +- src/lib/ruby/input/directinput.cpp | 1 - src/lib/ruby/input/sdl.cpp | 3 - src/lib/ruby/input/x.cpp | 3 - src/lib/ruby/ruby.cpp | 5 +- src/lib/ruby/ruby.h | 2 +- src/lib/ruby/ruby.impl.h | 57 - src/lib/ruby/ruby_impl.cpp | 57 + src/lib/ruby/video.h | 2 +- src/lib/ruby/video/direct3d.cpp | 13 +- src/lib/ruby/video/direct3d.h | 2 +- src/lib/ruby/video/directdraw.cpp | 34 +- src/lib/ruby/video/directdraw.h | 2 +- src/lib/ruby/video/gdi.cpp | 15 +- src/lib/ruby/video/gdi.h | 2 +- src/lib/ruby/video/glx.cpp | 18 +- src/lib/ruby/video/glx.h | 2 +- src/lib/ruby/video/sdl.cpp | 10 +- src/lib/ruby/video/sdl.h | 2 +- src/lib/ruby/video/xv.cpp | 57 +- src/lib/ruby/video/xv.h | 2 +- src/memory/memory.cpp | 14 +- src/memory/memory.h | 14 +- src/memory/memory_rw.cpp | 116 +- src/memory/smemory/mapper/chip.cpp | 4 + src/memory/smemory/mapper/generic.cpp | 10 +- src/memory/smemory/mapper/system.cpp | 8 +- src/memory/smemory/smemory.cpp | 4 +- src/ppu/bppu/bppu.cpp | 163 ++- src/ppu/bppu/bppu.h | 271 ++--- src/ppu/bppu/bppu_mmio.cpp | 113 +- src/ppu/bppu/bppu_render.cpp | 4 + src/ppu/bppu/bppu_render_addsub.cpp | 11 +- src/ppu/bppu/bppu_render_bg.cpp | 8 +- src/ppu/bppu/bppu_render_cache.cpp | 4 + src/ppu/bppu/bppu_render_line.cpp | 8 +- src/ppu/bppu/bppu_render_mode7.cpp | 4 + src/ppu/bppu/bppu_render_oam.cpp | 6 +- src/ppu/bppu/bppu_render_windows.cpp | 4 + src/ppu/ppu.cpp | 11 +- src/ppu/ppu.h | 47 +- src/reader/filereader.cpp | 46 +- src/reader/filereader.h | 14 +- src/reader/gzreader.cpp | 45 +- src/reader/gzreader.h | 10 +- src/reader/jmareader.cpp | 43 +- src/reader/jmareader.h | 19 +- src/reader/reader.cpp | 41 +- src/reader/reader.h | 30 +- src/reader/zipreader.cpp | 61 +- src/reader/zipreader.h | 25 +- src/smp/dsmp.cpp | 4 + src/smp/smp.cpp | 4 +- src/smp/smp.h | 27 +- src/smp/smpregs.h | 24 +- src/smp/ssmp/core/core.cpp | 4 + src/smp/ssmp/core/opfn.cpp | 4 + src/smp/ssmp/memory/memory.cpp | 281 +++-- src/smp/ssmp/memory/memory.h | 32 +- src/smp/ssmp/ssmp.cpp | 18 +- src/smp/ssmp/ssmp.h | 46 +- src/smp/ssmp/timing/timing.cpp | 4 + src/smp/ssmp/timing/timing.h | 31 +- src/snes/audio/audio.cpp | 63 +- src/snes/audio/audio.h | 22 +- src/snes/input/input.cpp | 99 +- src/snes/input/input.h | 53 +- src/snes/interface/interface.h | 10 +- src/snes/scheduler/scheduler.cpp | 28 +- src/snes/scheduler/scheduler.h | 55 +- src/snes/snes.cpp | 52 +- src/snes/snes.h | 26 +- src/snes/tracer/tracer.cpp | 4 + src/snes/video/filter.cpp | 6 - src/snes/video/filter.h | 35 - src/snes/video/filter_direct.cpp | 27 - src/snes/video/filter_direct.h | 6 - src/snes/video/filter_hq2x.cpp | 180 --- src/snes/video/filter_hq2x.h | 13 - src/snes/video/filter_ntsc.cpp | 83 -- src/snes/video/filter_ntsc.h | 24 - src/snes/video/filter_scale2x.cpp | 64 -- src/snes/video/filter_scale2x.h | 9 - src/snes/video/video.cpp | 150 +-- src/snes/video/video.h | 82 +- src/snes/video/video_colortable.cpp | 103 -- src/snes/video/video_normalize.cpp | 150 --- src/ui/base/about.cpp | 40 + src/ui/base/about.h | 11 + src/ui/{ui_main.cpp => base/main.cpp} | 685 +++++------ src/ui/{ui_main.h => base/main.h} | 9 +- src/ui/{ui_message.cpp => base/message.cpp} | 0 src/ui/{ui_message.h => base/message.h} | 0 src/ui/bsnes.Manifest | 9 + src/ui/bsnes.rc | 3 +- src/ui/config.cpp | 128 ++- src/ui/event.cpp | 131 ++- src/ui/event.h | 3 +- src/ui/{inputmgr.cpp => inputmanager.cpp} | 52 +- src/ui/interface.cpp | 38 +- .../{ui_bsxloader.cpp => bsxloader.cpp} | 1 + src/ui/loader/{ui_bsxloader.h => bsxloader.h} | 0 .../loader/{ui_stloader.cpp => stloader.cpp} | 1 + src/ui/loader/{ui_stloader.h => stloader.h} | 0 src/ui/main.cpp | 44 +- src/ui/main.h | 7 + src/ui/resource.cpp | 36 + src/ui/settings/advanced.cpp | 113 ++ src/ui/settings/{ui_advanced.h => advanced.h} | 7 +- .../{ui_cheateditor.cpp => cheateditor.cpp} | 30 +- .../{ui_cheateditor.h => cheateditor.h} | 0 .../{ui_inputconfig.cpp => inputconfig.cpp} | 20 +- .../{ui_inputconfig.h => inputconfig.h} | 3 +- src/ui/settings/pathsettings.cpp | 94 ++ src/ui/settings/pathsettings.h | 28 + ..._rastersettings.cpp => rastersettings.cpp} | 89 +- .../{ui_rastersettings.h => rastersettings.h} | 0 .../{ui_settings.cpp => settings.cpp} | 12 +- src/ui/settings/{ui_settings.h => settings.h} | 0 src/ui/settings/ui_advanced.cpp | 93 -- src/ui/ui.cpp | 41 +- src/ui/ui.h | 24 +- src/ui/ui_about.cpp | 21 - src/ui/ui_about.h | 8 - 316 files changed, 6230 insertions(+), 4402 deletions(-) delete mode 100644 src/cpu/scpu/timing/irqtiming.cpp delete mode 100644 src/cpu/scpu/timing/timeshift.cpp create mode 100644 src/data/controller.h create mode 100644 src/data/icon48.h rename src/lib/{hiro_gtk => hiro/gtk}/button.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/button.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/canvas.cpp (94%) rename src/lib/{hiro_gtk => hiro/gtk}/canvas.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/checkbox.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/checkbox.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/combobox.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/combobox.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/editbox.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/editbox.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/formcontrol.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/formcontrol.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/frame.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/frame.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/hiro.cpp (54%) rename src/lib/{hiro_gtk => hiro/gtk}/hiro.h (63%) rename src/lib/{hiro_gtk => hiro/gtk}/keymap.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/label.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/label.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/listbox.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/listbox.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menucheckitem.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menucheckitem.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menucontrol.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menucontrol.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menugroup.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menugroup.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menuitem.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menuitem.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menuradioitem.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menuradioitem.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menuseparator.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/menuseparator.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/progressbar.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/progressbar.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/radiobox.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/radiobox.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/slider.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/slider.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/widget.cpp (100%) rename src/lib/{hiro_gtk => hiro/gtk}/widget.h (100%) rename src/lib/{hiro_gtk => hiro/gtk}/window.cpp (78%) rename src/lib/{hiro_gtk => hiro/gtk}/window.h (92%) rename src/lib/{ => hiro}/hiro.cpp (94%) rename src/lib/{ => hiro}/hiro.h (95%) rename src/lib/{hiro_win => hiro/win}/button.cpp (95%) rename src/lib/{hiro_win => hiro/win}/button.h (100%) rename src/lib/{hiro_win => hiro/win}/canvas.cpp (98%) rename src/lib/{hiro_win => hiro/win}/canvas.h (100%) rename src/lib/{hiro_win => hiro/win}/checkbox.cpp (95%) rename src/lib/{hiro_win => hiro/win}/checkbox.h (100%) rename src/lib/{hiro_win => hiro/win}/combobox.cpp (55%) rename src/lib/{hiro_win => hiro/win}/combobox.h (100%) rename src/lib/{hiro_win => hiro/win}/editbox.cpp (94%) rename src/lib/{hiro_win => hiro/win}/editbox.h (100%) rename src/lib/{hiro_win => hiro/win}/formcontrol.cpp (71%) rename src/lib/{hiro_win => hiro/win}/formcontrol.h (78%) rename src/lib/{hiro_win => hiro/win}/frame.cpp (100%) rename src/lib/{hiro_win => hiro/win}/frame.h (100%) rename src/lib/{hiro_win => hiro/win}/hiro.cpp (84%) rename src/lib/{hiro_win => hiro/win}/hiro.h (77%) rename src/lib/{hiro_win => hiro/win}/keymap.cpp (100%) rename src/lib/{hiro_win => hiro/win}/label.cpp (100%) rename src/lib/{hiro_win => hiro/win}/label.h (100%) rename src/lib/{hiro_win => hiro/win}/listbox.cpp (95%) rename src/lib/{hiro_win => hiro/win}/listbox.h (100%) rename src/lib/{hiro_win => hiro/win}/menucheckitem.cpp (100%) rename src/lib/{hiro_win => hiro/win}/menucheckitem.h (100%) rename src/lib/{hiro_win => hiro/win}/menucontrol.cpp (100%) rename src/lib/{hiro_win => hiro/win}/menucontrol.h (100%) rename src/lib/{hiro_win => hiro/win}/menugroup.cpp (100%) rename src/lib/{hiro_win => hiro/win}/menugroup.h (100%) rename src/lib/{hiro_win => hiro/win}/menuitem.cpp (100%) rename src/lib/{hiro_win => hiro/win}/menuitem.h (100%) rename src/lib/{hiro_win => hiro/win}/menuradioitem.cpp (100%) rename src/lib/{hiro_win => hiro/win}/menuradioitem.h (100%) rename src/lib/{hiro_win => hiro/win}/menuseparator.cpp (100%) rename src/lib/{hiro_win => hiro/win}/menuseparator.h (100%) rename src/lib/{hiro_win => hiro/win}/progressbar.cpp (100%) rename src/lib/{hiro_win => hiro/win}/progressbar.h (100%) rename src/lib/{hiro_win => hiro/win}/radiobox.cpp (95%) rename src/lib/{hiro_win => hiro/win}/radiobox.h (100%) rename src/lib/{hiro_win => hiro/win}/slider.cpp (92%) rename src/lib/{hiro_win => hiro/win}/slider.h (100%) rename src/lib/{hiro_win => hiro/win}/widget.cpp (100%) rename src/lib/{hiro_win => hiro/win}/widget.h (100%) rename src/lib/{hiro_win => hiro/win}/window.cpp (59%) rename src/lib/{hiro_win => hiro/win}/window.h (91%) rename src/lib/{ => libco}/libco.c (71%) rename src/lib/{ => libco}/libco.h (100%) create mode 100644 src/lib/libfilter/colortable.cpp create mode 100644 src/lib/libfilter/colortable.h create mode 100644 src/lib/libfilter/direct.cpp create mode 100644 src/lib/libfilter/direct.h create mode 100644 src/lib/libfilter/filter.cpp create mode 100644 src/lib/libfilter/filter.h create mode 100644 src/lib/libfilter/hq2x.cpp create mode 100644 src/lib/libfilter/hq2x.h rename src/{snes/video/filter_hq2x_lookuptbl.h => lib/libfilter/hq2x_table.h} (93%) create mode 100644 src/lib/libfilter/libfilter.cpp create mode 100644 src/lib/libfilter/libfilter.h create mode 100644 src/lib/libfilter/ntsc.cpp create mode 100644 src/lib/libfilter/ntsc.h create mode 100644 src/lib/libfilter/scale2x.cpp create mode 100644 src/lib/libfilter/scale2x.h create mode 100644 src/lib/libfilter/scanline.cpp create mode 100644 src/lib/libfilter/scanline.h rename src/{snes/video/ntsc => lib/libfilter/snes_ntsc}/snes_ntsc.c (100%) rename src/{snes/video/ntsc => lib/libfilter/snes_ntsc}/snes_ntsc.h (96%) rename src/{snes/video/ntsc => lib/libfilter/snes_ntsc}/snes_ntsc_config.h (93%) rename src/{snes/video/ntsc => lib/libfilter/snes_ntsc}/snes_ntsc_impl.h (100%) create mode 100644 src/lib/nall/base64.hpp create mode 100644 src/lib/nall/detect.hpp create mode 100644 src/lib/nall/lzss.hpp delete mode 100644 src/lib/ruby/ruby.impl.h create mode 100644 src/lib/ruby/ruby_impl.cpp delete mode 100644 src/snes/video/filter.cpp delete mode 100644 src/snes/video/filter.h delete mode 100644 src/snes/video/filter_direct.cpp delete mode 100644 src/snes/video/filter_direct.h delete mode 100644 src/snes/video/filter_hq2x.cpp delete mode 100644 src/snes/video/filter_hq2x.h delete mode 100644 src/snes/video/filter_ntsc.cpp delete mode 100644 src/snes/video/filter_ntsc.h delete mode 100644 src/snes/video/filter_scale2x.cpp delete mode 100644 src/snes/video/filter_scale2x.h delete mode 100644 src/snes/video/video_colortable.cpp delete mode 100644 src/snes/video/video_normalize.cpp create mode 100644 src/ui/base/about.cpp create mode 100644 src/ui/base/about.h rename src/ui/{ui_main.cpp => base/main.cpp} (84%) rename src/ui/{ui_main.h => base/main.h} (93%) rename src/ui/{ui_message.cpp => base/message.cpp} (100%) rename src/ui/{ui_message.h => base/message.h} (100%) create mode 100644 src/ui/bsnes.Manifest rename src/ui/{inputmgr.cpp => inputmanager.cpp} (75%) rename src/ui/loader/{ui_bsxloader.cpp => bsxloader.cpp} (97%) rename src/ui/loader/{ui_bsxloader.h => bsxloader.h} (100%) rename src/ui/loader/{ui_stloader.cpp => stloader.cpp} (98%) rename src/ui/loader/{ui_stloader.h => stloader.h} (100%) create mode 100644 src/ui/main.h create mode 100644 src/ui/resource.cpp create mode 100644 src/ui/settings/advanced.cpp rename src/ui/settings/{ui_advanced.h => advanced.h} (84%) rename src/ui/settings/{ui_cheateditor.cpp => cheateditor.cpp} (81%) rename src/ui/settings/{ui_cheateditor.h => cheateditor.h} (100%) rename src/ui/settings/{ui_inputconfig.cpp => inputconfig.cpp} (91%) rename src/ui/settings/{ui_inputconfig.h => inputconfig.h} (94%) create mode 100644 src/ui/settings/pathsettings.cpp create mode 100644 src/ui/settings/pathsettings.h rename src/ui/settings/{ui_rastersettings.cpp => rastersettings.cpp} (54%) rename src/ui/settings/{ui_rastersettings.h => rastersettings.h} (100%) rename src/ui/settings/{ui_settings.cpp => settings.cpp} (76%) rename src/ui/settings/{ui_settings.h => settings.h} (100%) delete mode 100644 src/ui/settings/ui_advanced.cpp delete mode 100644 src/ui/ui_about.cpp delete mode 100644 src/ui/ui_about.h diff --git a/readme.txt b/readme.txt index 76b555ba8..5d74c4f5c 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ bsnes -Version: 0.028 +Version: 0.029 Author: byuu -------- @@ -17,7 +17,6 @@ Please see license.txt for important licensing information. Known Limitations: ------------------ S-CPU -- Invalid DMA / HDMA transfers not fully emulated - Multiply / Divide register delays not implemented S-PPU diff --git a/src/Makefile b/src/Makefile index 013479784..cba8839e2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,5 @@ include lib/nall/Makefile.string - prefix = /usr/local -arch = ARCH_LSB ################ ### compiler ### @@ -37,12 +35,11 @@ endif ifeq ($(platform),x) # X11 ruby = video.glx video.xv video.sdl audio.openal audio.oss audio.ao input.sdl input.x - arch += PLATFORM_X link += `pkg-config --libs gtk+-2.0` + link += $(call mklib,Xtst) delete = rm -f $1 else ifeq ($(platform),win) # Windows ruby = video.direct3d video.directdraw video.gdi audio.directsound input.directinput - arch += PLATFORM_WIN link += $(if $(findstring mingw,$(compiler)),-mwindows) link += $(call mklib,uuid) link += $(call mklib,kernel32) @@ -61,13 +58,16 @@ endif ### ruby ### ############ +rubyflags = +rubyflags += $(if $(findstring .sdl,$(ruby)),`sdl-config --cflags`) + link += $(if $(findstring video.direct3d,$(ruby)),$(call mklib,d3d9)) link += $(if $(findstring video.directdraw,$(ruby)),$(call mklib,ddraw)) link += $(if $(findstring video.glx,$(ruby)),$(call mklib,GL)) link += $(if $(findstring video.xv,$(ruby)),$(call mklib,Xv)) link += $(if $(findstring audio.ao,$(ruby)),$(call mklib,ao)) link += $(if $(findstring audio.directsound,$(ruby)),$(call mklib,dsound)) -link += $(if $(findstring audio.openal,$(ruby)),$(call mklib,openal) $(call mklib,alut)) +link += $(if $(findstring audio.openal,$(ruby)),$(if $(call streq,$(platform),x),$(call mklib,openal),$(call mklib,openal32))) link += $(if $(findstring input.directinput,$(ruby)),$(call mklib,dinput8) $(call mklib,dxguid)) link += $(if $(findstring input.sdl,$(ruby)),`sdl-config --libs`) @@ -75,7 +75,7 @@ link += $(if $(findstring input.sdl,$(ruby)),`sdl-config --libs`) ### main target and dependencies ### #################################### -objects = main libco hiro ruby $(ruby) string reader cart cheat \ +objects = main libco hiro ruby libfilter string reader cart cheat \ memory smemory cpu scpu smp ssmp bdsp ppu bppu snes \ bsx srtc sdd1 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010 @@ -89,7 +89,6 @@ ifeq ($(enable_jma),true) flags += $(call mkdef,JMA_SUPPORT) endif -arch := $(patsubst %,$(call mkdef,%),$(arch)) objects := $(patsubst %,obj/%.$(obj),$(objects)) rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),$(call mkdef,$c)) @@ -124,47 +123,22 @@ all: build; ### main ### ############ -obj/main.$(obj): ui/main.cpp config/* lib/nall/* lib/ruby/* ui/* ui/loader/* ui/settings/* - $(call compile,$(arch)) - -obj/bsnes.res : ui/bsnes.rc; rc /r /foobj/bsnes.res ui/bsnes.rc -obj/bsnesrc.$(obj): ui/bsnes.rc; windres -I data ui/bsnes.rc obj/bsnesrc.$(obj) - -############ -### ruby ### -############ - -obj/ruby.$(obj) : lib/ruby/ruby.cpp lib/ruby/* - $(call compile,$(rubydef)) -obj/video.direct3d.$(obj) : lib/ruby/video/direct3d.cpp lib/ruby/video/direct3d.* -obj/video.directdraw.$(obj) : lib/ruby/video/directdraw.cpp lib/ruby/video/directdraw.* -obj/video.gdi.$(obj) : lib/ruby/video/gdi.cpp lib/ruby/video/gdi.* -obj/video.glx.$(obj) : lib/ruby/video/glx.cpp lib/ruby/video/glx.* -obj/video.sdl.$(obj) : lib/ruby/video/sdl.cpp lib/ruby/video/sdl.* - $(call compile,`sdl-config --cflags`) -obj/video.xv.$(obj) : lib/ruby/video/xv.cpp lib/ruby/video/xv.* -obj/audio.ao.$(obj) : lib/ruby/audio/ao.cpp lib/ruby/audio/ao.* -obj/audio.directsound.$(obj): lib/ruby/audio/directsound.cpp lib/ruby/audio/directsound.* -obj/audio.openal.$(obj) : lib/ruby/audio/openal.cpp lib/ruby/audio/openal.* -obj/audio.oss.$(obj) : lib/ruby/audio/oss.cpp lib/ruby/audio/oss.* -obj/input.directinput.$(obj): lib/ruby/input/directinput.cpp lib/ruby/input/directinput.* -obj/input.sdl.$(obj) : lib/ruby/input/sdl.cpp lib/ruby/input/sdl.* - $(call compile,`sdl-config --cflags`) -obj/input.x.$(obj) : lib/ruby/input/x.cpp lib/ruby/input/x.* - -############ -### hiro ### -############ - -obj/hiro.$(obj): lib/hiro.cpp lib/hiro.* lib/hiro_gtk/* lib/hiro_win/* - $(call compile,$(if $(call streq,$(platform),x),`pkg-config --cflags gtk+-2.0`)) +obj/main.$(obj): ui/main.cpp ui/* ui/base/* ui/loader/* ui/settings/* +obj/bsnes.res: ui/bsnes.rc; rc /r /foobj/bsnes.res ui/bsnes.rc +obj/bsnesrc.$(obj): ui/bsnes.rc; windres ui/bsnes.rc obj/bsnesrc.$(obj) ################# ### libraries ### ################# -obj/libco.$(obj): lib/libco.c lib/libco.* lib/libco/* -obj/string.$(obj): lib/nall/string.cpp lib/nall/* +obj/ruby.$(obj): lib/ruby/ruby.cpp lib/ruby/* + $(call compile,$(rubydef) $(rubyflags)) +obj/hiro.$(obj): lib/hiro/hiro.cpp lib/hiro/* lib/hiro/gtk/* lib/hiro/win/* + $(call compile,$(if $(call streq,$(platform),x),`pkg-config --cflags gtk+-2.0`)) +obj/libco.$(obj): lib/libco/libco.c lib/libco/* + $(call compile,-static) +obj/libfilter.$(obj): lib/libfilter/libfilter.cpp lib/libfilter/* +obj/string.$(obj): lib/nall/string.cpp lib/nall/* ################# ### utilities ### @@ -179,7 +153,6 @@ obj/cheat.$(obj) : cheat/cheat.cpp cheat/* ############## obj/memory.$(obj) : memory/memory.cpp memory/* -obj/bmemory.$(obj): memory/bmemory/bmemory.cpp memory/bmemory/* memory/bmemory/mapper/* obj/smemory.$(obj): memory/smemory/smemory.cpp memory/smemory/* memory/smemory/mapper/* ########### @@ -270,8 +243,8 @@ build: $(objects) $(strip $(cpp) $(call mkbin,../bsnes) $(objects) $(link)) install: - install -D -m 755 ../bsnes $(prefix)/bin/bsnes - install -D -m 644 data/bsnes.png $(prefix)/share/icons/bsnes.png + install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes + install -D -m 644 data/bsnes.png $(DESTDIR)$(prefix)/share/icons/bsnes.png clean: -@$(call delete,obj/*.$(obj)) diff --git a/src/base.h b/src/base.h index ba31bd72b..6966e20bb 100644 --- a/src/base.h +++ b/src/base.h @@ -1,4 +1,4 @@ -#define BSNES_VERSION "0.028.01" +#define BSNES_VERSION "0.029" #define BSNES_TITLE "bsnes v" BSNES_VERSION #define BUSCORE sBus @@ -7,32 +7,28 @@ #define DSPCORE bDSP #define PPUCORE bPPU -//FAVOR_ACCURACY calculates RTO during frameskip, whereas FAVOR_SPEED does not +//FAST_FRAMESKIP disables calculation of RTO during frameskip //frameskip offers near-zero speedup if RTO is calculated //accuracy is not affected by this define when frameskipping is off - -//#define FAVOR_ACCURACY -#define FAVOR_SPEED +#define FAST_FRAMESKIP //game genie + pro action replay code support (~1-3% speed hit) #define CHEAT_SYSTEM -#if !defined(ARCH_LSB) && !defined(ARCH_MSB) - #define ARCH_LSB //guess -#endif - #include #include #include #include +#include #include #include #include +#include #include #include using namespace nall; -#include +#include #include //platform-specific global functions diff --git a/src/cart/cart.cpp b/src/cart/cart.cpp index 8ad84b627..c309ea7d8 100644 --- a/src/cart/cart.cpp +++ b/src/cart/cart.cpp @@ -1,5 +1,6 @@ -#include "../base.h" - +#include "../base.h" +#define CART_CPP + #include "cart_normal.cpp" #include "cart_bsx.cpp" #include "cart_bsc.cpp" @@ -82,12 +83,9 @@ void Cartridge::load_end() { memory::stBrom.write_protect(true); memory::stBram.write_protect(false); -char fn[PATH_MAX]; - strcpy(fn, cart.fn); - modify_extension(fn, "cht"); - if(fexists(fn)) { + if(fexists(get_cheat_filename(cart.fn, "cht"))) { cheat.clear(); - cheat.load(fn); + cheat.load(cheatfn); } cart.loaded = true; @@ -114,11 +112,11 @@ bool Cartridge::unload() { safe_free(stB.rom); safe_free(stB.ram); -char fn[PATH_MAX]; + char fn[PATH_MAX]; strcpy(fn, cart.fn); modify_extension(fn, "cht"); - if(cheat.count() > 0 || fexists(fn)) { - cheat.save(fn); + if(cheat.count() > 0 || fexists(get_cheat_filename(cart.fn, "cht"))) { + cheat.save(cheatfn); cheat.clear(); } diff --git a/src/cart/cart.h b/src/cart/cart.h index 886526e2f..9d580172d 100644 --- a/src/cart/cart.h +++ b/src/cart/cart.h @@ -20,11 +20,11 @@ public: CKSUM = 0x1e, RESL = 0x3c, RESH = 0x3d, - }; - - enum Region { - NTSC, - PAL, + }; + + enum Region { + NTSC, + PAL, }; enum MemoryMapper { @@ -67,7 +67,8 @@ public: struct { CartridgeType type; - uint32 crc32; + uint32 crc32; + char filename[PATH_MAX * 4]; char name[128]; Region region; @@ -122,14 +123,18 @@ public: bool load_file(const char *fn, uint8 *&data, uint &size); bool save_file(const char *fn, uint8 *data, uint size); - char* modify_extension(char *filename, const char *extension); - char* get_save_filename(const char *source, const char *extension); + char* modify_extension(char *filename, const char *extension); + char* get_base_filename(char *filename); + char* get_path_filename(char *filename, const char *path, const char *source, const char *extension); + char* get_save_filename(const char *source, const char *extension); + char* get_cheat_filename(const char *source, const char *extension); Cartridge(); ~Cartridge(); private: - char savefn[PATH_MAX]; + char savefn[PATH_MAX]; + char cheatfn[PATH_MAX]; }; namespace memory { diff --git a/src/cart/cart_bsc.cpp b/src/cart/cart_bsc.cpp index 18e81267a..704d0a221 100644 --- a/src/cart/cart_bsc.cpp +++ b/src/cart/cart_bsc.cpp @@ -1,3 +1,5 @@ +#ifdef CART_CPP + void Cartridge::load_cart_bsc(const char *base, const char *slot) { if(!base || !*base) return; @@ -5,8 +7,8 @@ void Cartridge::load_cart_bsc(const char *base, const char *slot) { strcpy(bs.fn, slot ? slot : ""); load_begin(CartridgeBSC); -uint8 *data; -uint size; + uint8_t *data = 0; + unsigned size; load_file(cart.fn, data, size); cart.rom = data, cart.rom_size = size; @@ -34,8 +36,21 @@ uint size; } load_end(); + + //set base filename + strcpy(info.filename, cart.fn); + get_base_filename(info.filename); + if(*bs.fn) { + char filenameBS[PATH_MAX]; + strcpy(filenameBS, bs.fn); + get_base_filename(filenameBS); + strcat(info.filename, " + "); + strcat(info.filename, filenameBS); + } } void Cartridge::unload_cart_bsc() { if(cart.ram) save_file(get_save_filename(cart.fn, "srm"), cart.ram, cart.ram_size); } + +#endif //ifdef CART_CPP diff --git a/src/cart/cart_bsx.cpp b/src/cart/cart_bsx.cpp index eaee15af3..aaf1e5c0c 100644 --- a/src/cart/cart_bsx.cpp +++ b/src/cart/cart_bsx.cpp @@ -1,3 +1,5 @@ +#ifdef CART_CPP + void Cartridge::load_cart_bsx(const char *base, const char *slot) { if(!base || !*base) return; @@ -10,8 +12,8 @@ void Cartridge::load_cart_bsx(const char *base, const char *slot) { info.mapper = BSXROM; info.region = NTSC; -uint8 *data; -uint size; + uint8_t *data = 0; + unsigned size; load_file(cart.fn, data, size); cart.rom = data, cart.rom_size = size; cart.ram = 0, cart.ram_size = 0; @@ -37,9 +39,14 @@ uint size; } load_end(); + + strcpy(info.filename, !*bs.fn ? cart.fn : bs.fn); + get_base_filename(info.filename); } void Cartridge::unload_cart_bsx() { save_file(get_save_filename(cart.fn, "srm"), bsxcart.sram.handle (), bsxcart.sram.size ()); save_file(get_save_filename(cart.fn, "psr"), bsxcart.psram.handle(), bsxcart.psram.size()); } + +#endif //ifdef CART_CPP diff --git a/src/cart/cart_file.cpp b/src/cart/cart_file.cpp index d2ed54993..6f71ae4aa 100644 --- a/src/cart/cart_file.cpp +++ b/src/cart/cart_file.cpp @@ -1,3 +1,5 @@ +#ifdef CART_CPP + #include "../reader/filereader.h" #if defined(GZIP_SUPPORT) @@ -10,7 +12,7 @@ #endif char* Cartridge::modify_extension(char *filename, const char *extension) { -int i; + int i; for(i = strlen(filename); i >= 0; i--) { if(filename[i] == '.') break; if(filename[i] == '/') break; @@ -20,32 +22,65 @@ int i; strcat(filename, "."); strcat(filename, extension); return filename; +} + +//remove directory information and file extension ("/foo/bar.ext" -> "bar") +char* Cartridge::get_base_filename(char *filename) { + //remove extension + for(int i = strlen(filename) - 1; i >= 0; i--) { + if(filename[i] == '.') { + filename[i] = 0; + break; + } + } + + //remove directory information + for(int i = strlen(filename) - 1; i >= 0; i--) { + if(filename[i] == '/' || filename[i] == '\\') { + i++; + char *output = filename; + while(true) { + *output++ = filename[i]; + if(!filename[i]) break; + i++; + } + break; + } + } } -char* Cartridge::get_save_filename(const char *source, const char *extension) { - strcpy(savefn, source); - for(char *p = savefn; *p; p++) { if(*p == '\\') *p = '/'; } - modify_extension(savefn, extension); +char* Cartridge::get_path_filename(char *filename, const char *path, const char *source, const char *extension) { + strcpy(filename, source); + for(char *p = filename; *p; p++) { if(*p == '\\') *p = '/'; } + modify_extension(filename, extension); -//override path with user-specified folder, if one was defined - if(config::path.save != "") { - lstring part; - split(part, "/", savefn); - string fn = (const char*)config::path.save; + //override path with user-specified folder, if one was defined + if(path != "") { + lstring part; + split(part, "/", filename); + string fn = path; if(strend(fn, "/") == false) strcat(fn, "/"); strcat(fn, part[count(part) - 1]); - strcpy(savefn, fn); + strcpy(filename, fn); - //resolve relative path, if found + //resolve relative path, if found if(strbegin(fn, "./") == true) { ltrim(fn, "./"); - strcpy(savefn, config::path.base); - strcat(savefn, fn); + strcpy(filename, config::path.base); + strcat(filename, fn); } } - return savefn; + return filename; } + +char* Cartridge::get_save_filename(const char *source, const char *extension) { + return get_path_filename(savefn, config::path.save, source, extension); +} + +char* Cartridge::get_cheat_filename(const char *source, const char *extension) { + return get_path_filename(cheatfn, config::path.cheat, source, extension); +} bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { dprintf("* Loading \"%s\"...", fn); @@ -54,8 +89,8 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { switch(Reader::detect(fn)) { default: - case Reader::RF_NORMAL: { - FileReader ff(fn); + case Reader::Normal: { + FileReader ff(fn); if(!ff.ready()) { alert("Error loading image file (%s)!", fn); return false; @@ -64,9 +99,9 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { data = ff.read(); } break; - #ifdef GZIP_SUPPORT - case Reader::RF_GZ: { - GZReader gf(fn); + #ifdef GZIP_SUPPORT + case Reader::GZIP: { + GZReader gf(fn); if(!gf.ready()) { alert("Error loading image file (%s)!", fn); return false; @@ -75,17 +110,17 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { data = gf.read(); } break; - case Reader::RF_ZIP: { - ZipReader zf(fn); + case Reader::ZIP: { + ZipReader zf(fn); size = zf.size(); data = zf.read(); } break; - #endif + #endif - #ifdef JMA_SUPPORT - case Reader::RF_JMA: { + #ifdef JMA_SUPPORT + case Reader::JMA: { try { - JMAReader jf(fn); + JMAReader jf(fn); size = jf.size(); data = jf.read(); } catch(JMA::jma_errors jma_error) { @@ -93,15 +128,17 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { return false; } } break; - #endif + #endif } return true; } bool Cartridge::save_file(const char *fn, uint8 *data, uint size) { -FileWriter ff(fn); + FileWriter ff(fn); if(!ff.ready())return false; ff.write(data, size); return true; } + +#endif //ifdef CART_CPP diff --git a/src/cart/cart_header.cpp b/src/cart/cart_header.cpp index e929c4652..bd96e7748 100644 --- a/src/cart/cart_header.cpp +++ b/src/cart/cart_header.cpp @@ -1,184 +1,189 @@ -void Cartridge::read_header() { -uint8 *rom = cart.rom; -uint index = info.header_index; -uint8 mapper = rom[index + MAPPER]; -uint8 rom_type = rom[index + ROM_TYPE]; -uint8 company = rom[index + COMPANY]; -uint8 region = rom[index + REGION] & 0x7f; - -//detect presence of BS-X flash cartridge connector (reads extended header information) -bool has_bsxflash = false; - if(rom[index - 14] == 'Z') { - if(rom[index - 11] == 'J') { - uint8 n13 = rom[index - 13]; - if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) { - if(company == 0x33 || (rom[index - 10] == 0x00 && rom[index - 4] == 0x00)) { - has_bsxflash = true; - } - } - } - } - - if(has_bsxflash == true) { - info.mapper = index == 0x7fc0 ? BSCLoROM : BSCHiROM; - } else if(index == 0x7fc0 && cart.rom_size >= 0x401000) { - info.mapper = ExLoROM; - } else if(index == 0x7fc0 && mapper == 0x32) { - info.mapper = ExLoROM; - } else if(index == 0x7fc0) { - info.mapper = LoROM; - } else if(index == 0xffc0) { - info.mapper = HiROM; - } else { //index == 0x40ffc0 - info.mapper = ExHiROM; - } - - if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { - info.superfx = true; - } - - if(mapper == 0x23 && (rom_type == 0x34 || rom_type == 0x35)) { - info.sa1 = true; - } - - if(mapper == 0x35 && rom_type == 0x55) { - info.srtc = true; - } - - if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) { - info.sdd1 = true; - } - - if(mapper == 0x20 && rom_type == 0xf3) { - info.cx4 = true; - } - - if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) { - info.dsp1 = true; - } - - if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) { - info.dsp1 = true; - } - - if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) { - info.dsp1 = true; - } - - if(info.dsp1 == true) { - if((mapper & 0x2f) == 0x20 && cart.rom_size <= 0x100000) { - info.dsp1_mapper = DSP1LoROM1MB; - } else if((mapper & 0x2f) == 0x20) { - info.dsp1_mapper = DSP1LoROM2MB; - } else if((mapper & 0x2f) == 0x21) { - info.dsp1_mapper = DSP1HiROM; - } - } - - if(mapper == 0x20 && rom_type == 0x05) { - info.dsp2 = true; - } - - if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) { - info.dsp3 = true; - } - - if(mapper == 0x30 && rom_type == 0x03) { - info.dsp4 = true; - } - - if(mapper == 0x30 && rom_type == 0x25) { - info.obc1 = true; - } - - if(mapper == 0x30 && rom_type == 0xf6) { - //TODO: both ST010 and ST011 share the same mapper + rom_type - //need way to determine which is which - //for now, default to supported ST010 - info.st010 = true; - } - - if(mapper == 0x30 && rom_type == 0xf5) { - info.st018 = true; - } - - if(rom[info.header_index + RAM_SIZE] & 7) { - info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7); - } else { - info.ram_size = 0; - } - -//0, 1, 13 = NTSC; 2 - 12 = PAL - info.region = (region <= 1 || region >= 13) ? NTSC : PAL; - - memcpy(&info.name, &rom[info.header_index + CART_NAME], 21); - info.name[21] = 0; - - for(int i = 0; i < 22; i++) { - if(info.name[i] & 0x80) { - info.name[i] = '?'; - } - } -} - -void Cartridge::find_header() { -int32 score_lo = 0, - score_hi = 0, - score_ex = 0; -uint8 *rom = cart.rom; - - if(cart.rom_size < 0x010000) { - //cart too small to be anything but lorom - info.header_index = 0x007fc0; - return; - } - - if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++; - if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++; - - if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++; - if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++; - - if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++; - if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++; - - if(rom[0x7fc0 + RAM_SIZE] < 0x08)score_lo++; - if(rom[0xffc0 + RAM_SIZE] < 0x08)score_hi++; - - if(rom[0x7fc0 + REGION] < 14)score_lo++; - if(rom[0xffc0 + REGION] < 14)score_hi++; - - if(rom[0x7fc0 + COMPANY] < 3)score_lo++; - if(rom[0xffc0 + COMPANY] < 3)score_hi++; - - if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2; - if(rom[0xffc0 + RESH] & 0x80)score_hi += 2; - -uint16 cksum, icksum; - cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8); - icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8); - if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) { - score_lo += 8; - } - - cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8); - icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8); - if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) { - score_hi += 8; - } - - if(cart.rom_size < 0x401000) { - score_ex = 0; - } else { - if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++; - else score_ex += 16; - } - - if(score_lo >= score_hi && score_lo >= score_ex) { - info.header_index = 0x007fc0; - } else if(score_hi >= score_ex) { - info.header_index = 0x00ffc0; - } else { - info.header_index = 0x40ffc0; - } -} +#ifdef CART_CPP + +void Cartridge::read_header() { + uint8 *rom = cart.rom; + uint index = info.header_index; + uint8 mapper = rom[index + MAPPER]; + uint8 rom_type = rom[index + ROM_TYPE]; + uint8 company = rom[index + COMPANY]; + uint8 region = rom[index + REGION] & 0x7f; + + //detect presence of BS-X flash cartridge connector (reads extended header information) + bool has_bsxflash = false; + if(rom[index - 14] == 'Z') { + if(rom[index - 11] == 'J') { + uint8 n13 = rom[index - 13]; + if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) { + if(company == 0x33 || (rom[index - 10] == 0x00 && rom[index - 4] == 0x00)) { + has_bsxflash = true; + } + } + } + } + + if(has_bsxflash == true) { + info.mapper = index == 0x7fc0 ? BSCLoROM : BSCHiROM; + } else if(index == 0x7fc0 && cart.rom_size >= 0x401000) { + info.mapper = ExLoROM; + } else if(index == 0x7fc0 && mapper == 0x32) { + info.mapper = ExLoROM; + } else if(index == 0x7fc0) { + info.mapper = LoROM; + } else if(index == 0xffc0) { + info.mapper = HiROM; + } else { //index == 0x40ffc0 + info.mapper = ExHiROM; + } + + if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { + info.superfx = true; + } + + if(mapper == 0x23 && (rom_type == 0x34 || rom_type == 0x35)) { + info.sa1 = true; + } + + if(mapper == 0x35 && rom_type == 0x55) { + info.srtc = true; + } + + if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) { + info.sdd1 = true; + } + + if(mapper == 0x20 && rom_type == 0xf3) { + info.cx4 = true; + } + + if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) { + info.dsp1 = true; + } + + if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) { + info.dsp1 = true; + } + + if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) { + info.dsp1 = true; + } + + if(info.dsp1 == true) { + if((mapper & 0x2f) == 0x20 && cart.rom_size <= 0x100000) { + info.dsp1_mapper = DSP1LoROM1MB; + } else if((mapper & 0x2f) == 0x20) { + info.dsp1_mapper = DSP1LoROM2MB; + } else if((mapper & 0x2f) == 0x21) { + info.dsp1_mapper = DSP1HiROM; + } + } + + if(mapper == 0x20 && rom_type == 0x05) { + info.dsp2 = true; + } + + if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) { + info.dsp3 = true; + } + + if(mapper == 0x30 && rom_type == 0x03) { + info.dsp4 = true; + } + + if(mapper == 0x30 && rom_type == 0x25) { + info.obc1 = true; + } + + if(mapper == 0x30 && rom_type == 0xf6) { + //TODO: both ST010 and ST011 share the same mapper + rom_type. + //need way to determine which is which. + //for now, default to supported ST010. + info.st010 = true; + } + + if(mapper == 0x30 && rom_type == 0xf5) { + info.st018 = true; + } + + if(rom[info.header_index + RAM_SIZE] & 7) { + info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7); + } else { + info.ram_size = 0; + } + + //0, 1, 13 = NTSC; 2 - 12 = PAL + info.region = (region <= 1 || region >= 13) ? NTSC : PAL; + + memcpy(&info.name, &rom[info.header_index + CART_NAME], 21); + info.name[21] = 0; + trim(info.name); + + //convert undisplayable characters (half-width katakana, etc) to '?' characters + for(int i = 0; i < 21; i++) { + if(info.name[i] & 0x80) info.name[i] = '?'; + } + + //always display something + if(!info.name[0]) strcpy(info.name, "(untitled)"); +} + +void Cartridge::find_header() { + int32 score_lo = 0, score_hi = 0, score_ex = 0; + uint8_t *rom = cart.rom; + + if(cart.rom_size < 0x010000) { + //cart too small to be anything but lorom + info.header_index = 0x007fc0; + return; + } + + if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20) score_lo++; + if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21) score_hi++; + + if(rom[0x7fc0 + ROM_TYPE] < 0x08) score_lo++; + if(rom[0xffc0 + ROM_TYPE] < 0x08) score_hi++; + + if(rom[0x7fc0 + ROM_SIZE] < 0x10) score_lo++; + if(rom[0xffc0 + ROM_SIZE] < 0x10) score_hi++; + + if(rom[0x7fc0 + RAM_SIZE] < 0x08) score_lo++; + if(rom[0xffc0 + RAM_SIZE] < 0x08) score_hi++; + + if(rom[0x7fc0 + REGION] < 14) score_lo++; + if(rom[0xffc0 + REGION] < 14) score_hi++; + + if(rom[0x7fc0 + COMPANY] < 3) score_lo++; + if(rom[0xffc0 + COMPANY] < 3) score_hi++; + + if(rom[0x7fc0 + RESH] & 0x80) score_lo += 2; + if(rom[0xffc0 + RESH] & 0x80) score_hi += 2; + + uint16 cksum, icksum; + cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8); + icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8); + if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) { + score_lo += 8; + } + + cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8); + icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8); + if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) { + score_hi += 8; + } + + if(cart.rom_size < 0x401000) { + score_ex = 0; + } else { + if(rom[0x7fc0 + MAPPER] == 0x32) score_lo++; + else score_ex += 16; + } + + if(score_lo >= score_hi && score_lo >= score_ex) { + info.header_index = 0x007fc0; + } else if(score_hi >= score_ex) { + info.header_index = 0x00ffc0; + } else { + info.header_index = 0x40ffc0; + } +} + +#endif //ifdef CART_CPP diff --git a/src/cart/cart_normal.cpp b/src/cart/cart_normal.cpp index cf227007f..c809af751 100644 --- a/src/cart/cart_normal.cpp +++ b/src/cart/cart_normal.cpp @@ -1,14 +1,16 @@ +#ifdef CART_CPP + void Cartridge::load_cart_normal(const char *filename) { if(!filename || !*filename) return; -uint8 *data; -uint size; + uint8_t *data = 0; + unsigned size; if(load_file(filename, data, size) == false) return; strcpy(cart.fn, filename); load_begin(CartridgeNormal); -//load ROM data, ignore 512-byte header if detected + //load ROM data, ignore 512-byte header if detected if((size & 0x7fff) != 512) { cart.rom = (uint8*)malloc(cart.rom_size = size); memcpy(cart.rom, data, size); @@ -34,8 +36,14 @@ uint size; } load_end(); + + //set base filename + strcpy(info.filename, cart.fn); + get_base_filename(info.filename); } void Cartridge::unload_cart_normal() { if(cart.ram) save_file(get_save_filename(cart.fn, "srm"), cart.ram, cart.ram_size); } + +#endif //ifdef CART_CPP diff --git a/src/cart/cart_st.cpp b/src/cart/cart_st.cpp index 4eac85ed4..1f4cb686c 100644 --- a/src/cart/cart_st.cpp +++ b/src/cart/cart_st.cpp @@ -1,3 +1,5 @@ +#ifdef CART_CPP + void Cartridge::load_cart_st(const char *base, const char *slotA, const char *slotB) { if(!base || !*base) return; @@ -10,8 +12,8 @@ void Cartridge::load_cart_st(const char *base, const char *slotA, const char *sl info.mapper = STROM; info.region = NTSC; -uint8 *data; -uint size; + uint8_t *data = 0; + unsigned size; if(load_file(cart.fn, data, size) == true) { cart.rom = (uint8*)malloc(cart.rom_size = 0x040000); memcpy(cart.rom, data, min(size, cart.rom_size)); @@ -51,9 +53,32 @@ uint size; } load_end(); + + //set base filename + if(!*stA.fn && !*stB.fn) { + strcpy(info.filename, cart.fn); + get_base_filename(info.filename); + } else if(*stA.fn && !*stB.fn) { + strcpy(info.filename, stA.fn); + get_base_filename(info.filename); + } else if(!*stA.fn && *stB.fn) { + strcpy(info.filename, stB.fn); + get_base_filename(info.filename); + } else { + char filenameA[PATH_MAX], filenameB[PATH_MAX]; + strcpy(filenameA, stA.fn); + get_base_filename(filenameA); + strcpy(filenameB, stB.fn); + get_base_filename(filenameB); + strcpy(info.filename, filenameA); + strcat(info.filename, " + "); + strcat(info.filename, filenameB); + } } void Cartridge::unload_cart_st() { if(stA.ram) save_file(get_save_filename(stA.fn, "srm"), stA.ram, stA.ram_size); if(stB.ram) save_file(get_save_filename(stB.fn, "srm"), stB.ram, stB.ram_size); } + +#endif //ifdef CART_CPP diff --git a/src/cheat/cheat.cpp b/src/cheat/cheat.cpp index 73aa96f41..ba1a1a3da 100644 --- a/src/cheat/cheat.cpp +++ b/src/cheat/cheat.cpp @@ -10,24 +10,24 @@ Cheat cheat; *****/ bool Cheat::decode(char *str, uint32 &addr, uint8 &data, uint8 &type) { -string t, part; + string t, part; strcpy(t, str); strlower(t()); if(strlen(t) == 8 || (strlen(t) == 9 && t()[6] == ':')) { - type = CT_PRO_ACTION_REPLAY; + type = ProActionReplay; replace(t, ":", ""); - uint32 r = strhex((const char*)t); + uint32 r = strhex((const char*)t); addr = r >> 8; data = r & 0xff; return true; } else if(strlen(t) == 9 && t()[4] == '-') { - type = CT_GAME_GENIE; + type = GameGenie; replace(t, "-", ""); strtr(t, "df4709156bc8a23e", "0123456789abcdef"); - uint32 r = strhex((const char*)t); - //8421 8421 8421 8421 8421 8421 - //abcd efgh ijkl mnop qrst uvwx - //ijkl qrst opab cduv wxef ghmn + uint32 r = strhex((const char*)t); + //8421 8421 8421 8421 8421 8421 + //abcd efgh ijkl mnop qrst uvwx + //ijkl qrst opab cduv wxef ghmn addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22) | (!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20) | (!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18) | @@ -47,10 +47,10 @@ string t, part; } bool Cheat::encode(char *str, uint32 addr, uint8 data, uint8 type) { - if(type == CT_PRO_ACTION_REPLAY) { + if(type == ProActionReplay) { sprintf(str, "%0.6x:%0.2x", addr, data); return true; - } else if(type == CT_GAME_GENIE) { + } else if(type == GameGenie) { uint32 r = addr; addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22) | (!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20) | @@ -79,9 +79,9 @@ bool Cheat::encode(char *str, uint32 addr, uint8 data, uint8 type) { *****/ uint Cheat::mirror_address(uint addr) { - if((addr & 0x40e000) != 0x0000)return addr; -//8k WRAM mirror -//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff] + if((addr & 0x40e000) != 0x0000) return addr; + //8k WRAM mirror + //$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff] return (0x7e0000 + (addr & 0x1fff)); } @@ -90,8 +90,8 @@ void Cheat::set(uint32 addr) { mask[addr >> 3] |= 1 << (addr & 7); if((addr & 0xffe000) == 0x7e0000) { - //mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff] - uint mirror; + //mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff] + uint mirror; for(int x = 0; x <= 0x3f; x++) { mirror = ((0x00 + x) << 16) + (addr & 0x1fff); mask[mirror >> 3] |= 1 << (mirror & 7); @@ -104,16 +104,16 @@ void Cheat::set(uint32 addr) { void Cheat::clear(uint32 addr) { addr = mirror_address(addr); -//is there more than one cheat code using the same address -//(and likely a different override value) that is enabled? -//if so, do not clear code lookup table entry for this address. -uint8 r; + //is there more than one cheat code using the same address + //(and likely a different override value) that is enabled? + //if so, do not clear code lookup table entry for this address. + uint8 r; if(read(addr, r) == true)return; mask[addr >> 3] &= ~(1 << (addr & 7)); if((addr & 0xffe000) == 0x7e0000) { - //mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff] - uint mirror; + //mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff] + uint mirror; for(int x = 0; x <= 0x3f; x++) { mirror = ((0x00 + x) << 16) + (addr & 0x1fff); mask[mirror >> 3] &= ~(1 << (mirror & 7)); @@ -133,13 +133,13 @@ uint8 r; bool Cheat::read(uint32 addr, uint8 &data) { addr = mirror_address(addr); for(int i = 0; i < cheat_count; i++) { - if(enabled(i) == false)continue; + if(enabled(i) == false) continue; if(addr == mirror_address(index[i].addr)) { data = index[i].data; return true; } } -//code not found, or code is disabled + //code not found, or code is disabled return false; } @@ -147,9 +147,10 @@ bool Cheat::read(uint32 addr, uint8 &data) { * update_cheat_status() will scan to see if any codes are * enabled. if any are, make sure the cheat system is on. * otherwise, turn cheat system off to speed up emulation. - *****/ + *****/ + void Cheat::update_cheat_status() { - for(int i = 0; i < cheat_count; i++) { + for(unsigned i = 0; i < cheat_count; i++) { if(index[i].enabled) { cheat_enabled = true; return; @@ -163,11 +164,11 @@ void Cheat::update_cheat_status() { *****/ bool Cheat::add(bool enable, char *code, char *desc) { - if(cheat_count >= CHEAT_LIMIT)return false; + if(cheat_count >= CheatLimit) return false; -uint32 addr, len; -uint8 data, type; - if(decode(code, addr, data, type) == false)return false; + uint32 addr, len; + uint8 data, type; + if(decode(code, addr, data, type) == false) return false; index[cheat_count].enabled = enable; index[cheat_count].addr = addr; @@ -188,17 +189,17 @@ uint8 data, type; } bool Cheat::edit(uint32 n, bool enable, char *code, char *desc) { - if(n >= cheat_count)return false; + if(n >= cheat_count) return false; -uint32 addr, len; -uint8 data, type; - if(decode(code, addr, data, type) == false)return false; + uint32 addr, len; + uint8 data, type; + if(decode(code, addr, data, type) == false) return false; -//disable current code and clear from code lookup table + //disable current code and clear from code lookup table index[n].enabled = false; clear(index[n].addr); -//update code and enable in code lookup table + //update code and enable in code lookup table index[n].enabled = enable; index[n].addr = addr; index[n].data = data; @@ -217,9 +218,9 @@ uint8 data, type; } bool Cheat::remove(uint32 n) { - if(n >= cheat_count)return false; + if(n >= cheat_count) return false; - for(int i = n; i < cheat_count; i++) { + for(unsigned i = n; i < cheat_count; i++) { index[i].enabled = index[i + 1].enabled; index[i].addr = index[i + 1].addr; index[i].data = index[i + 1].data; @@ -233,7 +234,7 @@ bool Cheat::remove(uint32 n) { } bool Cheat::get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc) { - if(n >= cheat_count)return false; + if(n >= cheat_count) return false; enable = index[n].enabled; addr = index[n].addr; data = index[n].data; @@ -247,19 +248,19 @@ bool Cheat::get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, c *****/ bool Cheat::enabled(uint32 n) { - if(n >= cheat_count)return false; + if(n >= cheat_count) return false; return index[n].enabled; } void Cheat::enable(uint32 n) { - if(n >= cheat_count)return; + if(n >= cheat_count) return; index[n].enabled = true; set(index[n].addr); update_cheat_status(); } void Cheat::disable(uint32 n) { - if(n >= cheat_count)return; + if(n >= cheat_count) return; index[n].enabled = false; clear(index[n].addr); update_cheat_status(); @@ -274,16 +275,16 @@ void Cheat::disable(uint32 n) { /* ... */ bool Cheat::load(const char *fn) { -string data; + string data; if(!fread(data, fn)) return false; replace(data, "\r\n", "\n"); qreplace(data, "=", ","); qreplace(data, " ", ""); -lstring line; + lstring line; split(line, "\n", data); - for(int i = 0; i < ::count(line); i++) { - lstring part; + for(unsigned i = 0; i < ::count(line); i++) { + lstring part; split(part, ",", line[i]); if(::count(part) != 3) continue; trim(part[2], "\""); @@ -294,9 +295,9 @@ lstring line; } bool Cheat::save(const char *fn) { -FILE *fp = fopen(fn, "wb"); + FILE *fp = fopen(fn, "wb"); if(!fp) return false; - for(int i = 0; i < cheat_count; i++) { + for(unsigned i = 0; i < cheat_count; i++) { fprintf(fp, "%9s = %8s, \"%s\"\r\n", index[i].code, index[i].enabled ? "enabled" : "disabled", @@ -314,7 +315,7 @@ void Cheat::clear() { cheat_enabled = false; cheat_count = 0; memset(mask, 0, 0x200000); - for(int i = 0; i <= CHEAT_LIMIT; i++) { + for(unsigned i = 0; i <= CheatLimit; i++) { index[i].enabled = false; index[i].addr = 0x000000; index[i].data = 0x00; diff --git a/src/cheat/cheat.h b/src/cheat/cheat.h index 580415376..74ead8ad3 100644 --- a/src/cheat/cheat.h +++ b/src/cheat/cheat.h @@ -1,51 +1,51 @@ -#define CHEAT_LIMIT 1024 - class Cheat { -public: - enum { - CT_PRO_ACTION_REPLAY, - CT_GAME_GENIE +public: + enum { CheatLimit = 1024 }; + + enum Type { + ProActionReplay, + GameGenie, }; struct CheatIndex { - bool enabled; + bool enabled; uint32 addr; - uint8 data; - char code[ 16 + 1]; - char desc[128 + 1]; - } index[CHEAT_LIMIT + 1]; + uint8 data; + char code[ 16 + 1]; + char desc[128 + 1]; + } index[CheatLimit + 1]; - bool cheat_enabled; + bool cheat_enabled; uint32 cheat_count; - uint8 mask[0x200000]; + uint8 mask[0x200000]; inline bool enabled() { return cheat_enabled; } inline uint count() { return cheat_count; } inline bool exists(uint32 addr) { return bool(mask[addr >> 3] & 1 << (addr & 7)); } - bool decode(char *str, uint32 &addr, uint8 &data, uint8 &type); - bool encode(char *str, uint32 addr, uint8 data, uint8 type); + bool decode(char *str, uint32 &addr, uint8 &data, uint8 &type); + bool encode(char *str, uint32 addr, uint8 data, uint8 type); - bool read(uint32 addr, uint8 &data); + bool read(uint32 addr, uint8 &data); - void update_cheat_status(); - bool add(bool enable, char *code, char *desc); - bool edit(uint32 n, bool enable, char *code, char *desc); - bool get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc); - bool remove (uint32 n); - bool enabled(uint32 n); - void enable (uint32 n); - void disable(uint32 n); - bool load(const char *fn); - bool save(const char *fn); - void clear(); + void update_cheat_status(); + bool add(bool enable, char *code, char *desc); + bool edit(uint32 n, bool enable, char *code, char *desc); + bool get(uint32 n, bool &enable, uint32 &addr, uint8 &data, char *code, char *desc); + bool remove(uint32 n); + bool enabled(uint32 n); + void enable(uint32 n); + void disable(uint32 n); + bool load(const char *fn); + bool save(const char *fn); + void clear(); Cheat(); private: - uint mirror_address(uint addr); - void set(uint32 addr); - void clear(uint32 addr); + uint mirror_address(uint addr); + void set(uint32 addr); + void clear(uint32 addr); }; extern Cheat cheat; diff --git a/src/chip/bsx/bsx.cpp b/src/chip/bsx/bsx.cpp index e4f907fe2..1b30ace5f 100644 --- a/src/chip/bsx/bsx.cpp +++ b/src/chip/bsx/bsx.cpp @@ -1,4 +1,5 @@ -#include "../../base.h" +#include "../../base.h" +#define BSX_CPP #include "bsx_base.cpp" #include "bsx_cart.cpp" diff --git a/src/chip/bsx/bsx_base.cpp b/src/chip/bsx/bsx_base.cpp index 6c414935c..090226b6e 100644 --- a/src/chip/bsx/bsx_base.cpp +++ b/src/chip/bsx/bsx_base.cpp @@ -1,3 +1,5 @@ +#ifdef BSX_CPP + void BSXBase::init() { } @@ -131,3 +133,5 @@ void BSXBase::mmio_write(uint addr, uint8 data) { } break; } } + +#endif //ifdef BSX_CPP diff --git a/src/chip/bsx/bsx_cart.cpp b/src/chip/bsx/bsx_cart.cpp index e02ebd4fe..60e84e3bb 100644 --- a/src/chip/bsx/bsx_cart.cpp +++ b/src/chip/bsx/bsx_cart.cpp @@ -1,3 +1,5 @@ +#ifdef BSX_CPP + void BSXCart::init() { } @@ -93,3 +95,5 @@ BSXCart::~BSXCart() { safe_free(sram_data); safe_free(psram_data); } + +#endif //ifdef BSX_CPP diff --git a/src/chip/bsx/bsx_flash.cpp b/src/chip/bsx/bsx_flash.cpp index e89e01918..43f925fdc 100644 --- a/src/chip/bsx/bsx_flash.cpp +++ b/src/chip/bsx/bsx_flash.cpp @@ -1,3 +1,5 @@ +#ifdef BSX_CPP + void BSXFlash::init() {} void BSXFlash::enable() {} @@ -107,3 +109,5 @@ void BSXFlash::write(uint addr, uint8 data) { } } } + +#endif //ifdef BSX_CPP diff --git a/src/chip/cx4/cx4.cpp b/src/chip/cx4/cx4.cpp index efe96f77f..a0f323589 100644 --- a/src/chip/cx4/cx4.cpp +++ b/src/chip/cx4/cx4.cpp @@ -5,7 +5,8 @@ Portions (c) anomie, Overload, zsKnight, Nach, byuu */ -#include "../../base.h" +#include "../../base.h" +#define CX4_CPP #include "cx4data.cpp" #include "cx4fn.cpp" diff --git a/src/chip/cx4/cx4data.cpp b/src/chip/cx4/cx4data.cpp index 57bc48e7f..0308c833a 100644 --- a/src/chip/cx4/cx4data.cpp +++ b/src/chip/cx4/cx4data.cpp @@ -1,3 +1,5 @@ +#ifdef CX4_CPP + const uint8 Cx4::immediate_data[48] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, @@ -181,3 +183,5 @@ const int16 Cx4::CosTable[512] = { 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 }; + +#endif //ifdef CX4_CPP diff --git a/src/chip/cx4/cx4fn.cpp b/src/chip/cx4/cx4fn.cpp index ec358b515..ca0f8dd78 100644 --- a/src/chip/cx4/cx4fn.cpp +++ b/src/chip/cx4/cx4fn.cpp @@ -1,3 +1,5 @@ +#ifdef CX4_CPP + #include #define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000) #define sar(b, n) ((b) >> (n)) @@ -240,3 +242,5 @@ uint8 bit = 0x80; LineY += D; } } + +#endif //ifdef CX4_CPP diff --git a/src/chip/cx4/cx4oam.cpp b/src/chip/cx4/cx4oam.cpp index feb45b637..6173cb05e 100644 --- a/src/chip/cx4/cx4oam.cpp +++ b/src/chip/cx4/cx4oam.cpp @@ -1,3 +1,5 @@ +#ifdef CX4_CPP + //Build OAM void Cx4::op00_00() { uint32 oamptr = ram[0x626] << 2; @@ -217,3 +219,5 @@ uint16 mask2 = 0x3f3f; destptr += 16; } } + +#endif //ifdef CX4_CPP diff --git a/src/chip/cx4/cx4ops.cpp b/src/chip/cx4/cx4ops.cpp index 6af839ee9..8cc509eee 100644 --- a/src/chip/cx4/cx4ops.cpp +++ b/src/chip/cx4/cx4ops.cpp @@ -1,3 +1,5 @@ +#ifdef CX4_CPP + //Sprite Functions void Cx4::op00() { switch(reg[0x4d]) { @@ -220,3 +222,5 @@ void Cx4::op89() { str(0, 0x054336); str(1, 0xffffff); } + +#endif //ifdef CX4_CPP diff --git a/src/chip/dsp1/dsp1.cpp b/src/chip/dsp1/dsp1.cpp index da4377686..aa3751067 100644 --- a/src/chip/dsp1/dsp1.cpp +++ b/src/chip/dsp1/dsp1.cpp @@ -1,4 +1,5 @@ -#include "../../base.h" +#include "../../base.h" +#define DSP1_CPP #include "dsp1emu.cpp" diff --git a/src/chip/dsp1/dsp1emu.cpp b/src/chip/dsp1/dsp1emu.cpp index 61bd44285..58dd2dead 100644 --- a/src/chip/dsp1/dsp1emu.cpp +++ b/src/chip/dsp1/dsp1emu.cpp @@ -1,3 +1,5 @@ +#ifdef DSP1_CPP + // DSP-1's emulation code // // Based on research by Overload, The Dumper, Neviksti and Andreas Naive @@ -1620,3 +1622,4 @@ const int16 Dsp1::SinTable[256] = { ////////////////////////////////////////////////////////////////// +#endif //ifdef DSP1_CPP diff --git a/src/chip/dsp2/dsp2.cpp b/src/chip/dsp2/dsp2.cpp index e8bc6679d..54c0a2525 100644 --- a/src/chip/dsp2/dsp2.cpp +++ b/src/chip/dsp2/dsp2.cpp @@ -1,4 +1,5 @@ -#include "../../base.h" +#include "../../base.h" +#define DSP2_CPP #include "dsp2_op.cpp" diff --git a/src/chip/dsp2/dsp2_op.cpp b/src/chip/dsp2/dsp2_op.cpp index 15a51529e..fec67bd64 100644 --- a/src/chip/dsp2/dsp2_op.cpp +++ b/src/chip/dsp2/dsp2_op.cpp @@ -1,3 +1,5 @@ +#ifdef DSP2_CPP + //convert bitmap to bitplane tile void DSP2::op01() { //op01 size is always 32 bytes input and output @@ -171,3 +173,5 @@ uint8 pixelarray[512]; status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1]; } } + +#endif //ifdef DSP2_CPP diff --git a/src/chip/dsp3/dsp3.cpp b/src/chip/dsp3/dsp3.cpp index 139b1b7df..28d7c0a91 100644 --- a/src/chip/dsp3/dsp3.cpp +++ b/src/chip/dsp3/dsp3.cpp @@ -1,4 +1,5 @@ -#include "../../base.h" +#include "../../base.h" +#define DSP3_CPP namespace DSP3i { #define bool8 uint8 diff --git a/src/chip/dsp3/dsp3emu.c b/src/chip/dsp3/dsp3emu.c index ab5577184..7ce0d81ed 100644 --- a/src/chip/dsp3/dsp3emu.c +++ b/src/chip/dsp3/dsp3emu.c @@ -1,3 +1,5 @@ +#ifdef DSP3_CPP + //DSP-3 emulator code //Copyright (c) 2003-2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden @@ -1140,3 +1142,5 @@ void InitDSP3() { DSP3_Reset(); } + +#endif //ifdef DSP3_CPP diff --git a/src/chip/dsp4/dsp4.cpp b/src/chip/dsp4/dsp4.cpp index a27bf8d38..3f6535710 100644 --- a/src/chip/dsp4/dsp4.cpp +++ b/src/chip/dsp4/dsp4.cpp @@ -1,4 +1,5 @@ -#include "../../base.h" +#include "../../base.h" +#define DSP4_CPP namespace DSP4i { inline uint16 READ_WORD(uint8 *addr) { diff --git a/src/chip/dsp4/dsp4emu.c b/src/chip/dsp4/dsp4emu.c index 668f58670..50785775a 100644 --- a/src/chip/dsp4/dsp4emu.c +++ b/src/chip/dsp4/dsp4emu.c @@ -1,3 +1,5 @@ +#ifdef DSP4_CPP + //DSP-4 emulator code //Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden @@ -2144,3 +2146,5 @@ void DSP4GetByte() dsp4_byte = 0xff; } } + +#endif //ifdef DSP4_CPP diff --git a/src/chip/sdd1/sdd1.cpp b/src/chip/sdd1/sdd1.cpp index 3e345ea4f..b69d022a8 100644 --- a/src/chip/sdd1/sdd1.cpp +++ b/src/chip/sdd1/sdd1.cpp @@ -1,4 +1,5 @@ -#include "../../base.h" +#include "../../base.h" +#define SDD1_CPP #include "sdd1emu.cpp" diff --git a/src/chip/sdd1/sdd1emu.cpp b/src/chip/sdd1/sdd1emu.cpp index 5f53fa7ae..30f821c94 100644 --- a/src/chip/sdd1/sdd1emu.cpp +++ b/src/chip/sdd1/sdd1emu.cpp @@ -1,3 +1,5 @@ +#ifdef SDD1_CPP + /************************************************************************ S-DD1'algorithm emulation code @@ -445,3 +447,5 @@ SDD1emu::SDD1emu() : } /////////////////////////////////////////////////////////// + +#endif //ifdef SDD1_CPP diff --git a/src/chip/st010/st010.cpp b/src/chip/st010/st010.cpp index d8b956ded..38a5e1c7a 100644 --- a/src/chip/st010/st010.cpp +++ b/src/chip/st010/st010.cpp @@ -1,4 +1,6 @@ -#include "../../base.h" +#include "../../base.h" +#define ST010_CPP + #include "st010_data.h" #include "st010_op.cpp" diff --git a/src/chip/st010/st010_op.cpp b/src/chip/st010/st010_op.cpp index 4219edb6c..1eb9c55c9 100644 --- a/src/chip/st010/st010_op.cpp +++ b/src/chip/st010/st010_op.cpp @@ -1,3 +1,5 @@ +#ifdef ST010_CPP + //ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather //bsnes port - Copyright (C) 2007 byuu @@ -255,3 +257,5 @@ int16 x1, y1; writew(0x0010, x1); writew(0x0012, y1); } + +#endif //ifdef ST010_CPP diff --git a/src/config/config.cpp b/src/config/config.cpp index a48a84455..4eb9b8e1b 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -1,28 +1,36 @@ namespace config { configuration& config() { -static configuration config; + static configuration config; return config; -} +} + +integral_setting File::autodetect_type(config(), "file.autodetect_type", + "Auto-detect file type by inspecting file header, rather than by file extension.\n" + "In other words, if a .zip file is renamed to .smc, it will still be correctly\n" + "identified as a .zip file. However, there is an infinitesimal (1:~500,000,000)\n" + "chance of a false detection when loading an uncompressed image file, if this\n" + "option is enabled.", + integral_setting::boolean, false); string file_updatepath(const char *req_file, const char *req_path) { -string file(req_file); + string file(req_file); replace(file, "\\", "/"); if(!req_path || strlen(req_path) == 0) { return file; } -string path(req_path); + string path(req_path); replace(path, "\\", "/"); if(!strend(path, "/")) { strcat(path, "/"); } if(strbegin(path, "./")) { ltrim(path(), "./"); - string temp; + string temp; strcpy(temp, config::path.base); strcat(temp, path); strcpy(path, temp); } -lstring part; + lstring part; split(part, "/", file); strcat(path, part[count(part) - 1]); return path; @@ -32,35 +40,17 @@ string_setting Path::base("path.base", "Path that bsnes resides in", ""); string_setting Path::rom(config(), "path.rom", "Default path to look for ROM files in (\"\" = use default directory)", ""); -string_setting Path::save(config(), "path.save", - "Default path for all save RAM and cheat files (\"\" = use current directory)", ""); +string_setting Path::save(config(), "path.save", + "Default path for all save RAM files (\"\" = use current directory)", ""); +string_setting Path::cheat(config(), "path.cheat", + "Default path for all cheat files (\"\" = use current directory)", ""); string_setting Path::bsx(config(), "path.bsx", "", ""); string_setting Path::st(config(), "path.st", "", ""); -integral_setting SNES::gamma_ramp(config(), "snes.colorfilter.gamma_ramp", - "Use precalculated TV-style gamma ramp", integral_setting::boolean, true); -integral_setting SNES::sepia(config(), "snes.colorfilter.sepia", - "Convert color to sepia tone", integral_setting::boolean, false); -integral_setting SNES::grayscale(config(), "snes.colorfilter.grayscale", - "Convert color to grayscale tone", integral_setting::boolean, false); -integral_setting SNES::invert(config(), "snes.colorfilter.invert", - "Invert output image colors", integral_setting::boolean, false); -integral_setting SNES::contrast(config(), "snes.colorfilter.contrast", - "Contrast", integral_setting::decimal, 0); -integral_setting SNES::brightness(config(), "snes.colorfilter.brightness", - "Brightness", integral_setting::decimal, 0); -integral_setting SNES::gamma(config(), "snes.colorfilter.gamma", - "Gamma", integral_setting::decimal, 80); - -integral_setting SNES::ntsc_merge_fields(config(), "snes.ntsc_merge_fields", - "Merge fields in NTSC video filter\n" - "Set to true if using filter at any refresh rate other than 60hz\n" - "", integral_setting::boolean, true); - integral_setting SNES::controller_port0(config(), "snes.controller_port_1", - "Controller attached to SNES port 1", integral_setting::decimal, ::SNES::DEVICEID_JOYPAD1); + "Controller attached to SNES port 1", integral_setting::decimal, ::SNES::Input::DeviceIDJoypad1); integral_setting SNES::controller_port1(config(), "snes.controller_port_2", - "Controller attached to SNES port 2", integral_setting::decimal, ::SNES::DEVICEID_JOYPAD2); + "Controller attached to SNES port 2", integral_setting::decimal, ::SNES::Input::DeviceIDJoypad2); integral_setting CPU::ntsc_clock_rate(config(), "cpu.ntsc_clock_rate", "NTSC S-CPU clock rate (in hz)", integral_setting::decimal, 21477272); @@ -126,4 +116,4 @@ integral_setting PPU::oam_pri1_enable("ppu.oam_pri1_enable", "Enable OAM Priorit integral_setting PPU::oam_pri2_enable("ppu.oam_pri2_enable", "Enable OAM Priority 2", integral_setting::boolean, true); integral_setting PPU::oam_pri3_enable("ppu.oam_pri3_enable", "Enable OAM Priority 3", integral_setting::boolean, true); -}; +} //namespace config diff --git a/src/config/config.h b/src/config/config.h index 7e44de366..9cfcea634 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -2,16 +2,18 @@ namespace config { extern configuration& config(); -string file_updatepath(const char *, const char *); +string file_updatepath(const char*, const char*); + +extern struct File { + static integral_setting autodetect_type; +} file; extern struct Path { - static string_setting base, rom, save; + static string_setting base, rom, save, cheat; static string_setting bsx, st; } path; extern struct SNES { - static integral_setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma; - static integral_setting ntsc_merge_fields; static integral_setting controller_port0; static integral_setting controller_port1; } snes; diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index f1a851469..0122057ae 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -1,4 +1,6 @@ -#include "../base.h" +#include "../base.h" +#define CPU_CPP + #include "dcpu.cpp" CPU::CPU() { diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index ae8fa24eb..18b246400 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -4,81 +4,75 @@ class CPU : public MMIO { public: virtual void enter() = 0; -public: -//CPU version number -//* 1 and 2 are known -//* reported by $4210 -//* affects DRAM refresh behavior -uint8 cpu_version; + //CPU version number + //* 1 and 2 are known + //* reported by $4210 + //* affects DRAM refresh behavior + uint8 cpu_version; -//timing + //timing virtual uint16 vcounter() = 0; virtual uint16 hcounter() = 0; - virtual uint16 hclock() = 0; - virtual bool interlace() = 0; - virtual bool interlace_field() = 0; - virtual bool overscan() = 0; - virtual uint16 region_scanlines() = 0; - virtual void set_interlace(bool r) = 0; - virtual void set_overscan (bool r) = 0; - -CPURegs regs; - virtual uint8 port_read (uint8 port) = 0; - virtual void port_write(uint8 port, uint8 value) = 0; + virtual uint16 hdot() = 0; + virtual uint8 pio_status() = 0; + virtual uint8 port_read(uint8 port) = 0; + virtual void port_write(uint8 port, uint8 value) = 0; + + CPURegs regs; enum { FLAG_N = 0x80, FLAG_V = 0x40, FLAG_M = 0x20, FLAG_X = 0x10, FLAG_D = 0x08, FLAG_I = 0x04, FLAG_Z = 0x02, FLAG_C = 0x01 }; - virtual uint8 pio_status() = 0; - virtual void scanline() = 0; - virtual void frame() = 0; - virtual void power() = 0; - virtual void reset() = 0; + + virtual void scanline() = 0; + virtual void frame() = 0; + virtual void power() = 0; + virtual void reset() = 0; -/***** - * in opcode-based CPU emulators, the main emulation routine - * will only be able to call the disassemble_opcode() function - * on clean opcode edges. but with cycle-based CPU emulators, - * the CPU may be in the middle of executing an opcode when the - * emulator (e.g. debugger) wants to disassemble an opcode. this - * would mean that important registers may not reflect what they - * did at the start of the opcode (especially regs.pc), so in - * cycle-based emulators, this function should be overridden to - * reflect whether or not an opcode has only been partially - * executed. if not, the debugger should abort attempts to skip, - * disable, or disassemble the current opcode. - *****/ + /***** + * in opcode-based CPU emulators, the main emulation routine + * will only be able to call the disassemble_opcode() function + * on clean opcode edges. but with cycle-based CPU emulators, + * the CPU may be in the middle of executing an opcode when the + * emulator (e.g. debugger) wants to disassemble an opcode. this + * would mean that important registers may not reflect what they + * did at the start of the opcode (especially regs.pc), so in + * cycle-based emulators, this function should be overridden to + * reflect whether or not an opcode has only been partially + * executed. if not, the debugger should abort attempts to skip, + * disable, or disassemble the current opcode. + *****/ virtual bool in_opcode() { return false; } -/***** - * opcode disassembler - *****/ -enum { - OPTYPE_DP = 0, //dp - OPTYPE_DPX, //dp,x - OPTYPE_DPY, //dp,y - OPTYPE_IDP, //(dp) - OPTYPE_IDPX, //(dp,x) - OPTYPE_IDPY, //(dp),y - OPTYPE_ILDP, //[dp] - OPTYPE_ILDPY, //[dp],y - OPTYPE_ADDR, //addr - OPTYPE_ADDRX, //addr,x - OPTYPE_ADDRY, //addr,y - OPTYPE_IADDRX, //(addr,x) - OPTYPE_ILADDR, //[addr] - OPTYPE_LONG, //long - OPTYPE_LONGX, //long, x - OPTYPE_SR, //sr,s - OPTYPE_ISRY, //(sr,s),y - OPTYPE_ADDR_PC, //pbr:addr - OPTYPE_IADDR_PC, //pbr:(addr) - OPTYPE_RELB, //relb - OPTYPE_RELW, //relw -}; + /***** + * opcode disassembler + *****/ + enum { + OPTYPE_DP = 0, //dp + OPTYPE_DPX, //dp,x + OPTYPE_DPY, //dp,y + OPTYPE_IDP, //(dp) + OPTYPE_IDPX, //(dp,x) + OPTYPE_IDPY, //(dp),y + OPTYPE_ILDP, //[dp] + OPTYPE_ILDPY, //[dp],y + OPTYPE_ADDR, //addr + OPTYPE_ADDRX, //addr,x + OPTYPE_ADDRY, //addr,y + OPTYPE_IADDRX, //(addr,x) + OPTYPE_ILADDR, //[addr] + OPTYPE_LONG, //long + OPTYPE_LONGX, //long, x + OPTYPE_SR, //sr,s + OPTYPE_ISRY, //(sr,s),y + OPTYPE_ADDR_PC, //pbr:addr + OPTYPE_IADDR_PC, //pbr:(addr) + OPTYPE_RELB, //relb + OPTYPE_RELW, //relw + }; void disassemble_opcode(char *output); uint8 dreadb(uint32 addr); diff --git a/src/cpu/cpuregs.h b/src/cpu/cpuregs.h index 5b502044f..4c6195ee0 100644 --- a/src/cpu/cpuregs.h +++ b/src/cpu/cpuregs.h @@ -1,11 +1,11 @@ class CPURegFlags { public: -union { - uint8 data; - struct { - bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1); + union { + uint8 data; + struct { + bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1); + }; }; -}; inline operator unsigned() const { return data; } template inline unsigned operator = (const T i) { data = i; return data; } @@ -18,10 +18,10 @@ union { class CPUReg16 { public: -union { - uint16 w; - struct { uint8 order_lsb2(l, h); }; -}; + union { + uint16 w; + struct { uint8 order_lsb2(l, h); }; + }; inline operator unsigned() const { return w; } template inline unsigned operator = (const T i) { w = i; return w; } @@ -41,11 +41,11 @@ union { class CPUReg24 { public: -union { - uint32 d; - struct { uint16 order_lsb2(w, wh); }; - struct { uint8 order_lsb4(l, h, b, bh); }; -}; + union { + uint32 d; + struct { uint16 order_lsb2(w, wh); }; + struct { uint8 order_lsb4(l, h, b, bh); }; + }; inline operator unsigned() const { return d; } template inline unsigned operator = (const T i) { d = uclip<24>(i); return d; } @@ -65,11 +65,11 @@ union { class CPURegs { public: -CPUReg24 pc; -CPUReg16 a, x, y, s, d; -CPURegFlags p; -uint8 db; -uint8 mdr; -bool e; + CPUReg24 pc; + CPUReg16 a, x, y, s, d; + CPURegFlags p; + uint8 db; + uint8 mdr; + bool e; CPURegs() : db(0), mdr(0x00), e(false) {} }; diff --git a/src/cpu/dcpu.cpp b/src/cpu/dcpu.cpp index 8d781bbc4..98c4b38ce 100644 --- a/src/cpu/dcpu.cpp +++ b/src/cpu/dcpu.cpp @@ -1,3 +1,5 @@ +#ifdef CPU_CPP + uint8 CPU::dreadb(uint32 addr) { if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) { //$[00-3f|80-bf]:[2000-5fff] @@ -423,7 +425,7 @@ uint8 op2 = dreadb(pc.d); strcat(s, t); strcat(s, " "); - sprintf(t, "V:%3d H:%4d", vcounter(), hclock()); + sprintf(t, "V:%3d H:%4d", vcounter(), hcounter()); strcat(s, t); } @@ -473,3 +475,5 @@ static uint8 op_len_tbl[256] = { if(len == 6)return (regs.e || regs.p.x) ? 2 : 3; return len; } + +#endif //ifdef CPU_CPP diff --git a/src/cpu/scpu/core/core.cpp b/src/cpu/scpu/core/core.cpp index aea39dd13..bba72e9a6 100644 --- a/src/cpu/scpu/core/core.cpp +++ b/src/cpu/scpu/core/core.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + #include "opfn.cpp" #include "op_read.cpp" @@ -43,8 +45,6 @@ void sCPU::op_irq() { regs.pc.w = rd.w; } -// - alwaysinline void sCPU::op_io_cond2() { if(regs.d.l != 0x00) { op_io(); @@ -62,3 +62,5 @@ alwaysinline void sCPU::op_io_cond6(uint16 addr) { op_io(); } } + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/core/core.h b/src/cpu/scpu/core/core.h index 9097197f7..1ab5f209e 100644 --- a/src/cpu/scpu/core/core.h +++ b/src/cpu/scpu/core/core.h @@ -1,57 +1,57 @@ -void (sCPU::*optbl[256])(); + void (sCPU::*optbl[256])(); -CPUReg24 aa, rd; -uint8 dp, sp; + CPUReg24 aa, rd; + uint8_t dp, sp; - void op_irq(); + void op_irq(); inline bool in_opcode() { return status.in_opcode; } -//op_read - void op_adc_b(); - void op_adc_w(); - void op_and_b(); - void op_and_w(); - void op_bit_b(); - void op_bit_w(); - void op_cmp_b(); - void op_cmp_w(); - void op_cpx_b(); - void op_cpx_w(); - void op_cpy_b(); - void op_cpy_w(); - void op_eor_b(); - void op_eor_w(); - void op_lda_b(); - void op_lda_w(); - void op_ldx_b(); - void op_ldx_w(); - void op_ldy_b(); - void op_ldy_w(); - void op_ora_b(); - void op_ora_w(); - void op_sbc_b(); - void op_sbc_w(); -//op_rmw - void op_inc_b(); - void op_inc_w(); - void op_dec_b(); - void op_dec_w(); - void op_asl_b(); - void op_asl_w(); - void op_lsr_b(); - void op_lsr_w(); - void op_rol_b(); - void op_rol_w(); - void op_ror_b(); - void op_ror_w(); - void op_trb_b(); - void op_trb_w(); - void op_tsb_b(); - void op_tsb_w(); + //op_read + void op_adc_b(); + void op_adc_w(); + void op_and_b(); + void op_and_w(); + void op_bit_b(); + void op_bit_w(); + void op_cmp_b(); + void op_cmp_w(); + void op_cpx_b(); + void op_cpx_w(); + void op_cpy_b(); + void op_cpy_w(); + void op_eor_b(); + void op_eor_w(); + void op_lda_b(); + void op_lda_w(); + void op_ldx_b(); + void op_ldx_w(); + void op_ldy_b(); + void op_ldy_w(); + void op_ora_b(); + void op_ora_w(); + void op_sbc_b(); + void op_sbc_w(); + //op_rmw + void op_inc_b(); + void op_inc_w(); + void op_dec_b(); + void op_dec_w(); + void op_asl_b(); + void op_asl_w(); + void op_lsr_b(); + void op_lsr_w(); + void op_rol_b(); + void op_rol_w(); + void op_ror_b(); + void op_ror_w(); + void op_trb_b(); + void op_trb_w(); + void op_tsb_b(); + void op_tsb_w(); - void op_io_cond2(); - void op_io_cond4(uint16 x, uint16 y); - void op_io_cond6(uint16 addr); + void op_io_cond2(); + void op_io_cond4(uint16 x, uint16 y); + void op_io_cond6(uint16 addr); -#include "op.h" + #include "op.h" diff --git a/src/cpu/scpu/core/opfn.cpp b/src/cpu/scpu/core/opfn.cpp index 9527d983e..23d9372fd 100644 --- a/src/cpu/scpu/core/opfn.cpp +++ b/src/cpu/scpu/core/opfn.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + //op_read inline void sCPU::op_adc_b() { int32 r = regs.a.l + rd.l + regs.p.c; @@ -371,3 +373,5 @@ inline void sCPU::op_tsb_w() { regs.p.z = ((rd.w & regs.a.w) == 0); rd.w |= regs.a.w; } + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/dma/dma.cpp b/src/cpu/scpu/dma/dma.cpp index f3cb27d63..c7697e12f 100644 --- a/src/cpu/scpu/dma/dma.cpp +++ b/src/cpu/scpu/dma/dma.cpp @@ -1,273 +1,289 @@ -void sCPU::dma_add_clocks(uint clocks) { - status.dma_clocks += clocks; - add_clocks(clocks); -} - -/***** - * used by both DMA and HDMA - * - * DMA address bus A cannot read from or write to the following addresses : - * $[00-3f|80-bf]:43[00-7f] - * $[00-3f|80-bf]:420b - * $[00-3f|80-bf]:420c - * WRAM<>WRAM transfers via $2180 - *****/ -void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) { -uint8 r; - if(direction == 0) { //a->b - if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 || - (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) { - r = regs.mdr; - } else { - r = bus.read(abus); - } - bus.write(0x2100 | bbus, r); - } else { //b->a - if(bbus == 0x80 && ((abus & 0x7e0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) { - //prevent WRAM->WRAM transfers - r = regs.mdr; - } else { - r = bus.read(0x2100 | bbus); - } - if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 || - (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c)return; - bus.write(abus, r); - } - - dma_add_clocks(8); - cycle_edge(); -} - -/***** - * address calculation functions - *****/ - -uint8 sCPU::dma_bbus(uint8 i, uint8 index) { - switch(channel[i].xfermode) { - default: - case 0: return (channel[i].destaddr); break; //0 - case 1: return (channel[i].destaddr + (index & 1)); break; //0,1 - case 2: return (channel[i].destaddr); break; //0,0 - case 3: return (channel[i].destaddr + ((index >> 1) & 1)); break; //0,0,1,1 - case 4: return (channel[i].destaddr + (index & 3)); break; //0,1,2,3 - case 5: return (channel[i].destaddr + (index & 1)); break; //0,1,0,1 - case 6: return (channel[i].destaddr); break; //0,0 [2] - case 7: return (channel[i].destaddr + ((index >> 1) & 1)); break; //0,0,1,1 [3] - } -} - -inline uint32 sCPU::dma_addr(uint8 i) { -uint32 r = (channel[i].srcbank << 16) | (channel[i].srcaddr); - - if(channel[i].fixedxfer == false) { - if(channel[i].reversexfer == false) { - channel[i].srcaddr++; - } else { - channel[i].srcaddr--; - } - } - - return r; -} - -inline uint32 sCPU::hdma_addr(uint8 i) { - return (channel[i].srcbank << 16) | (channel[i].hdma_addr++); -} - -inline uint32 sCPU::hdma_iaddr(uint8 i) { - return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++); -} - -/***** - * DMA functions - *****/ - -void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) { - if(cartridge.info.sdd1 == true && sdd1.dma_active() == true) { - bus.write(0x2100 | bbus, sdd1.dma_read()); - } else { - dma_transfer(0, bbus, dma_addr(i)); - } - channel[i].xfersize--; -} - -void sCPU::dma_transfertobusa(uint8 i, uint8 bbus) { - dma_transfer(1, bbus, dma_addr(i)); - channel[i].xfersize--; -} - -inline void sCPU::dma_write(uint8 i, uint8 index) { -//cannot use dma_transfer() directly, due to current S-DD1 implementation - if(channel[i].direction == 0) { - dma_transfertobusb(i, index); - } else { - dma_transfertobusa(i, index); - } -} - -void sCPU::dma_run() { - for(int i = 0; i < 8; i++) { - if(channel[i].dma_enabled == false)continue; - dma_add_clocks(8); - - if(cartridge.info.sdd1 == true) { - sdd1.dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), channel[i].xfersize); - } - - if(tracer.enabled() == true && tracer.cpudma_enabled() == true) { - tprintf("[DMA] channel:%d direction:%s reverse:%c fixed:%c mode:%d b_addr:$21%0.2x " - "a_addr:$%0.2x%0.4x length:$%0.4x (%5d)", - i, channel[i].direction ? "b->a" : "a->b", channel[i].reversexfer ? '1' : '0', - channel[i].fixedxfer ? '1' : '0', channel[i].xfermode, channel[i].destaddr, - channel[i].srcbank, channel[i].srcaddr, - channel[i].xfersize, channel[i].xfersize ? channel[i].xfersize : 65536); - } - - uint index = 0; - do { - dma_write(i, dma_bbus(i, index++)); - } while(channel[i].dma_enabled && channel[i].xfersize); - - channel[i].dma_enabled = false; - } - - counter.set(counter.irq_delay, 2); -} - -/***** - * HDMA functions - *****/ - -inline bool sCPU::hdma_active(uint8 i) { - return (channel[i].hdma_enabled && !channel[i].hdma_completed); -} - -inline bool sCPU::hdma_active_after(uint8 i) { - for(int n = i + 1; n < 8; n++) { - if(hdma_active(n) == true) { return true; } - } - - return false; -} - -inline uint8 sCPU::hdma_enabled_channels() { -uint8 r = 0; - for(int i = 0; i < 8; i++) { - if(channel[i].hdma_enabled)r++; - } - return r; -} - -inline uint8 sCPU::hdma_active_channels() { -uint8 r = 0; - for(int i = 0; i < 8; i++) { - if(hdma_active(i) == true)r++; - } - return r; -} - -void sCPU::hdma_update(uint8 i) { - channel[i].hdma_line_counter = bus.read(hdma_addr(i)); - dma_add_clocks(8); - - channel[i].hdma_completed = (channel[i].hdma_line_counter == 0); - channel[i].hdma_do_transfer = !channel[i].hdma_completed; - - if(channel[i].hdma_indirect) { - channel[i].hdma_iaddr = bus.read(hdma_addr(i)) << 8; - dma_add_clocks(8); - - if(!channel[i].hdma_completed || hdma_active_after(i)) { - channel[i].hdma_iaddr >>= 8; - channel[i].hdma_iaddr |= bus.read(hdma_addr(i)) << 8; - dma_add_clocks(8); - } - } -} - -void sCPU::hdma_run() { -static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; - for(int i = 0; i < 8; i++) { - if(hdma_active(i) == false)continue; - channel[i].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer - dma_add_clocks(8); - - if(channel[i].hdma_do_transfer) { - int xferlen = hdma_xferlen[channel[i].xfermode]; - for(int index = 0; index < xferlen; index++) { - if(bool(config::cpu.hdma_enable) == true) { - dma_transfer(channel[i].direction, dma_bbus(i, index), - !channel[i].hdma_indirect ? hdma_addr(i) : hdma_iaddr(i)); - } else { - dma_add_clocks(8); - cycle_edge(); - } - } - } - - channel[i].hdma_line_counter--; - channel[i].hdma_do_transfer = bool(channel[i].hdma_line_counter & 0x80); - if((channel[i].hdma_line_counter & 0x7f) == 0) { - hdma_update(i); - } - } - - counter.set(counter.irq_delay, 2); -} - -void sCPU::hdma_init_reset() { - for(int i = 0; i < 8; i++) { - channel[i].hdma_completed = false; - channel[i].hdma_do_transfer = false; - } -} - -void sCPU::hdma_init() { - for(int i = 0; i < 8; i++) { - if(!channel[i].hdma_enabled)continue; - channel[i].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer - - channel[i].hdma_addr = channel[i].srcaddr; - hdma_update(i); - } - - counter.set(counter.irq_delay, 2); -} - -/***** - * power / reset functions - *****/ - -void sCPU::dma_power() { - for(int i = 0; i < 8; i++) { - channel[i].dmap = 0xff; - channel[i].direction = 1; - channel[i].hdma_indirect = true; - channel[i].reversexfer = true; - channel[i].fixedxfer = true; - channel[i].xfermode = 7; - - channel[i].destaddr = 0xff; - - channel[i].srcaddr = 0xffff; - channel[i].srcbank = 0xff; - - channel[i].xfersize = 0xffff; - //channel[i].hdma_iaddr = 0xffff; //union with xfersize - channel[i].hdma_ibank = 0xff; - - channel[i].hdma_addr = 0xffff; - channel[i].hdma_line_counter = 0xff; - channel[i].unknown = 0xff; - } -} - -void sCPU::dma_reset() { - for(int i = 0; i < 8; i++) { - channel[i].dma_enabled = false; - channel[i].hdma_enabled = false; - - channel[i].hdma_completed = false; - channel[i].hdma_do_transfer = false; - } -} +#ifdef SCPU_CPP + +void sCPU::dma_add_clocks(uint clocks) { + status.dma_clocks += clocks; + add_clocks(clocks); +} + +/***** + * used by both DMA and HDMA + * + * DMA address bus A cannot read from or write to the following addresses : + * $[00-3f|80-bf]:43[00-7f] + * $[00-3f|80-bf]:420b + * $[00-3f|80-bf]:420c + * + * WRAM<>WRAM transfers via $2180 are also illegal + *****/ + +void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) { + if(direction == 0) { + //a->b transfer (to $21xx) + if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) { + //illegal WRAM->WRAM transfer + //read most likely occurs; no write occurs + //read is irrelevant, as it has no observable effect on emulation + } else if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 + || (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) { + //illegal register access + bus.write(0x2100 | bbus, regs.mdr); //TODO: verify if MDR is written here + } else { + //valid transfer + bus.write(0x2100 | bbus, bus.read(abus)); + } + } else { + //b->a transfer (from $21xx) + if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) { + //illegal WRAM->WRAM transfer + //no read occurs; write does occur + //does not write MDR as expected + //TODO: 0x00 was observed on hardware; verify if other values are possible + bus.write(abus, 0x00); + } else if((abus & 0x40ff00) == 0x2100 || (abus & 0x40ff80) == 0x4300 + || (abus & 0x40ffff) == 0x420b || (abus & 0x40ffff) == 0x420c) { + //illegal register access + bus.write(abus, regs.mdr); //TODO: verify if MDR is written here + } else { + //valid transfer + bus.write(abus, bus.read(0x2100 | bbus)); + } + } + + //each byte *always* consumes 8 clocks, even if transfer is invalid and no read and/or write occurs + dma_add_clocks(8); + cycle_edge(); +} + +/***** + * address calculation functions + *****/ + +uint8 sCPU::dma_bbus(uint8 i, uint8 index) { + switch(channel[i].xfermode) { default: + case 0: return (channel[i].destaddr); //0 + case 1: return (channel[i].destaddr + (index & 1)); //0,1 + case 2: return (channel[i].destaddr); //0,0 + case 3: return (channel[i].destaddr + ((index >> 1) & 1)); //0,0,1,1 + case 4: return (channel[i].destaddr + (index & 3)); //0,1,2,3 + case 5: return (channel[i].destaddr + (index & 1)); //0,1,0,1 + case 6: return (channel[i].destaddr); //0,0 [2] + case 7: return (channel[i].destaddr + ((index >> 1) & 1)); //0,0,1,1 [3] + } +} + +inline uint32 sCPU::dma_addr(uint8 i) { + uint32 r = (channel[i].srcbank << 16) | (channel[i].srcaddr); + + if(channel[i].fixedxfer == false) { + if(channel[i].reversexfer == false) { + channel[i].srcaddr++; + } else { + channel[i].srcaddr--; + } + } + + return r; +} + +inline uint32 sCPU::hdma_addr(uint8 i) { + return (channel[i].srcbank << 16) | (channel[i].hdma_addr++); +} + +inline uint32 sCPU::hdma_iaddr(uint8 i) { + return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++); +} + +/***** + * DMA functions + *****/ + +void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) { + if(cartridge.info.sdd1 == true && sdd1.dma_active() == true) { + bus.write(0x2100 | bbus, sdd1.dma_read()); + } else { + dma_transfer(0, bbus, dma_addr(i)); + } + channel[i].xfersize--; +} + +void sCPU::dma_transfertobusa(uint8 i, uint8 bbus) { + dma_transfer(1, bbus, dma_addr(i)); + channel[i].xfersize--; +} + +inline void sCPU::dma_write(uint8 i, uint8 index) { + //cannot use dma_transfer() directly, due to current S-DD1 implementation + if(channel[i].direction == 0) { + dma_transfertobusb(i, index); + } else { + dma_transfertobusa(i, index); + } +} + +void sCPU::dma_run() { + for(int i = 0; i < 8; i++) { + if(channel[i].dma_enabled == false) continue; + dma_add_clocks(8); + + if(cartridge.info.sdd1 == true) { + sdd1.dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), channel[i].xfersize); + } + + if(tracer.enabled() == true && tracer.cpudma_enabled() == true) { + tprintf("[DMA] channel:%d direction:%s reverse:%c fixed:%c mode:%d b_addr:$21%0.2x " + "a_addr:$%0.2x%0.4x length:$%0.4x (%5d)", + i, channel[i].direction ? "b->a" : "a->b", channel[i].reversexfer ? '1' : '0', + channel[i].fixedxfer ? '1' : '0', channel[i].xfermode, channel[i].destaddr, + channel[i].srcbank, channel[i].srcaddr, + channel[i].xfersize, channel[i].xfersize ? channel[i].xfersize : 65536); + } + + uint index = 0; + do { + dma_write(i, dma_bbus(i, index++)); + } while(channel[i].dma_enabled && channel[i].xfersize); + + channel[i].dma_enabled = false; + } + + counter.set(counter.irq_delay, 2); +} + +/***** + * HDMA functions + *****/ + +inline bool sCPU::hdma_active(uint8 i) { + return (channel[i].hdma_enabled && !channel[i].hdma_completed); +} + +inline bool sCPU::hdma_active_after(uint8 i) { + for(int n = i + 1; n < 8; n++) { + if(hdma_active(n) == true) return true; + } + return false; +} + +inline uint8 sCPU::hdma_enabled_channels() { + uint8 r = 0; + for(int i = 0; i < 8; i++) { + if(channel[i].hdma_enabled) r++; + } + return r; +} + +inline uint8 sCPU::hdma_active_channels() { + uint8 r = 0; + for(int i = 0; i < 8; i++) { + if(hdma_active(i) == true) r++; + } + return r; +} + +void sCPU::hdma_update(uint8 i) { + channel[i].hdma_line_counter = bus.read(hdma_addr(i)); + dma_add_clocks(8); + + channel[i].hdma_completed = (channel[i].hdma_line_counter == 0); + channel[i].hdma_do_transfer = !channel[i].hdma_completed; + + if(channel[i].hdma_indirect) { + channel[i].hdma_iaddr = bus.read(hdma_addr(i)) << 8; + dma_add_clocks(8); + + if(!channel[i].hdma_completed || hdma_active_after(i)) { + channel[i].hdma_iaddr >>= 8; + channel[i].hdma_iaddr |= bus.read(hdma_addr(i)) << 8; + dma_add_clocks(8); + } + } +} + +void sCPU::hdma_run() { + static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; + for(int i = 0; i < 8; i++) { + if(hdma_active(i) == false) continue; + channel[i].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer + dma_add_clocks(8); + + if(channel[i].hdma_do_transfer) { + int xferlen = hdma_xferlen[channel[i].xfermode]; + for(int index = 0; index < xferlen; index++) { + if(bool(config::cpu.hdma_enable) == true) { + dma_transfer(channel[i].direction, dma_bbus(i, index), + !channel[i].hdma_indirect ? hdma_addr(i) : hdma_iaddr(i)); + } else { + dma_add_clocks(8); + cycle_edge(); + } + } + } + + channel[i].hdma_line_counter--; + channel[i].hdma_do_transfer = bool(channel[i].hdma_line_counter & 0x80); + if((channel[i].hdma_line_counter & 0x7f) == 0) { + hdma_update(i); + } + } + + counter.set(counter.irq_delay, 2); +} + +void sCPU::hdma_init_reset() { + for(int i = 0; i < 8; i++) { + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + } +} + +void sCPU::hdma_init() { + for(int i = 0; i < 8; i++) { + if(!channel[i].hdma_enabled)continue; + channel[i].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer + + channel[i].hdma_addr = channel[i].srcaddr; + hdma_update(i); + } + + counter.set(counter.irq_delay, 2); +} + +/***** + * power / reset functions + *****/ + +void sCPU::dma_power() { + for(int i = 0; i < 8; i++) { + channel[i].dmap = 0xff; + channel[i].direction = 1; + channel[i].hdma_indirect = true; + channel[i].reversexfer = true; + channel[i].fixedxfer = true; + channel[i].xfermode = 7; + + channel[i].destaddr = 0xff; + + channel[i].srcaddr = 0xffff; + channel[i].srcbank = 0xff; + + channel[i].xfersize = 0xffff; + //channel[i].hdma_iaddr = 0xffff; //union with xfersize + channel[i].hdma_ibank = 0xff; + + channel[i].hdma_addr = 0xffff; + channel[i].hdma_line_counter = 0xff; + channel[i].unknown = 0xff; + } +} + +void sCPU::dma_reset() { + for(int i = 0; i < 8; i++) { + channel[i].dma_enabled = false; + channel[i].hdma_enabled = false; + + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + } +} + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/dma/dma.h b/src/cpu/scpu/dma/dma.h index 845e2f8d0..3ad1651b1 100644 --- a/src/cpu/scpu/dma/dma.h +++ b/src/cpu/scpu/dma/dma.h @@ -1,71 +1,71 @@ -struct { -//$420b - bool dma_enabled; + struct { + //$420b + bool dma_enabled; -//$420c - bool hdma_enabled; + //$420c + bool hdma_enabled; -//$43x0 - uint8 dmap; - bool direction; - bool hdma_indirect; - bool reversexfer; - bool fixedxfer; - uint8 xfermode; + //$43x0 + uint8 dmap; + bool direction; + bool hdma_indirect; + bool reversexfer; + bool fixedxfer; + uint8 xfermode; -//$43x1 - uint8 destaddr; + //$43x1 + uint8 destaddr; -//$43x2-$43x3 - uint16 srcaddr; + //$43x2-$43x3 + uint16 srcaddr; -//$43x4 - uint8 srcbank; + //$43x4 + uint8 srcbank; -//$43x5-$43x6 - union { - uint16 xfersize; - uint16 hdma_iaddr; - }; + //$43x5-$43x6 + union { + uint16 xfersize; + uint16 hdma_iaddr; + }; -//$43x7 - uint8 hdma_ibank; + //$43x7 + uint8 hdma_ibank; -//$43x8-$43x9 - uint16 hdma_addr; + //$43x8-$43x9 + uint16 hdma_addr; -//$43xa - uint8 hdma_line_counter; + //$43xa + uint8 hdma_line_counter; -//$43xb/$43xf - uint8 unknown; + //$43xb/$43xf + uint8 unknown; -//internal variables - bool hdma_completed; - bool hdma_do_transfer; -} channel[8]; + //internal variables + bool hdma_completed; + bool hdma_do_transfer; + } channel[8]; - void dma_add_clocks(uint clocks); - void dma_transfer(bool direction, uint8 bbus, uint32 abus); + void dma_add_clocks(uint clocks); + void dma_transfer(bool direction, uint8 bbus, uint32 abus); - uint8 dma_bbus(uint8 i, uint8 index); + uint8 dma_bbus(uint8 i, uint8 index); uint32 dma_addr(uint8 i); uint32 hdma_addr(uint8 i); uint32 hdma_iaddr(uint8 i); - void dma_transfertobusb(uint8 i, uint8 bbus); - void dma_transfertobusa(uint8 i, uint8 bbus); - void dma_write(uint8 i, uint8 index); - void dma_run(); + void dma_transfertobusb(uint8 i, uint8 bbus); + void dma_transfertobusa(uint8 i, uint8 bbus); + void dma_write(uint8 i, uint8 index); + void dma_run(); - bool hdma_active(uint8 i); - bool hdma_active_after(uint8 i); - uint8 hdma_enabled_channels(); - uint8 hdma_active_channels(); - void hdma_update(uint8 i); - void hdma_run(); - void hdma_init_reset(); - void hdma_init(); + bool hdma_active(uint8 i); + bool hdma_active_after(uint8 i); + uint8 hdma_enabled_channels(); + uint8 hdma_active_channels(); + void hdma_update(uint8 i); + void hdma_run(); + void hdma_init_reset(); + void hdma_init(); - void dma_power(); - void dma_reset(); + void dma_power(); + void dma_reset(); diff --git a/src/cpu/scpu/memory/memory.cpp b/src/cpu/scpu/memory/memory.cpp index 36cd1ec5c..16faf7796 100644 --- a/src/cpu/scpu/memory/memory.cpp +++ b/src/cpu/scpu/memory/memory.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + /***** * These 3 functions control bus timing for the CPU. * cpu_io is an I/O cycle, and always 6 clock cycles long. @@ -119,3 +121,5 @@ alwaysinline void sCPU::op_writedp(uint32 addr, uint8 data) { alwaysinline void sCPU::op_writesp(uint32 addr, uint8 data) { op_write((regs.s + (addr & 0xffff)) & 0xffff, data); } + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/memory/memory.h b/src/cpu/scpu/memory/memory.h index 545c6c645..50c3b212b 100644 --- a/src/cpu/scpu/memory/memory.h +++ b/src/cpu/scpu/memory/memory.h @@ -1,35 +1,35 @@ -/***** - * CPU<>APU communication ports - *****/ -uint8 apu_port[4]; - uint8 port_read (uint8 port) { return apu_port[port & 3]; } - void port_write(uint8 port, uint8 data) { apu_port[port & 3] = data; } + /***** + * CPU<>APU communication ports + *****/ + uint8 apu_port[4]; + uint8 port_read(uint8 port) { return apu_port[port & 3]; } + void port_write(uint8 port, uint8 data) { apu_port[port & 3] = data; } -/***** - * core CPU bus functions - *****/ - void op_io(); - uint8 op_read (uint32 addr); - void op_write(uint32 addr, uint8 data); + /***** + * core CPU bus functions + *****/ + void op_io(); + uint8 op_read(uint32 addr); + void op_write(uint32 addr, uint8 data); -/***** - * helper memory addressing functions used by CPU core - *****/ - uint8 op_readpc (); - uint8 op_readstack (); - uint8 op_readstackn(); - uint8 op_readaddr (uint32 addr); - uint8 op_readlong (uint32 addr); - uint8 op_readdbr (uint32 addr); - uint8 op_readpbr (uint32 addr); - uint8 op_readdp (uint32 addr); - uint8 op_readsp (uint32 addr); + /***** + * helper memory addressing functions used by CPU core + *****/ + uint8 op_readpc (); + uint8 op_readstack (); + uint8 op_readstackn(); + uint8 op_readaddr (uint32 addr); + uint8 op_readlong (uint32 addr); + uint8 op_readdbr (uint32 addr); + uint8 op_readpbr (uint32 addr); + uint8 op_readdp (uint32 addr); + uint8 op_readsp (uint32 addr); - void op_writestack (uint8 data); - void op_writestackn(uint8 data); - void op_writeaddr (uint32 addr, uint8 data); - void op_writelong (uint32 addr, uint8 data); - void op_writedbr (uint32 addr, uint8 data); - void op_writepbr (uint32 addr, uint8 data); - void op_writedp (uint32 addr, uint8 data); - void op_writesp (uint32 addr, uint8 data); + void op_writestack (uint8 data); + void op_writestackn(uint8 data); + void op_writeaddr (uint32 addr, uint8 data); + void op_writelong (uint32 addr, uint8 data); + void op_writedbr (uint32 addr, uint8 data); + void op_writepbr (uint32 addr, uint8 data); + void op_writedp (uint32 addr, uint8 data); + void op_writesp (uint32 addr, uint8 data); diff --git a/src/cpu/scpu/mmio/mmio.cpp b/src/cpu/scpu/mmio/mmio.cpp index 13e12f257..e511c1098 100644 --- a/src/cpu/scpu/mmio/mmio.cpp +++ b/src/cpu/scpu/mmio/mmio.cpp @@ -1,10 +1,12 @@ +#ifdef SCPU_CPP + uint8 sCPU::pio_status() { return status.pio; } //WMDATA uint8 sCPU::mmio_r2180() { -uint8 r = bus.read(0x7e0000 | status.wram_addr); + uint8 r = bus.read(0x7e0000 | status.wram_addr); status.wram_addr = (status.wram_addr + 1) & 0x01ffff; return r; } @@ -41,7 +43,7 @@ void sCPU::mmio_w4016(uint8 data) { status.joypad_strobe_latch = !!(data & 1); if(status.joypad_strobe_latch == 1) { - snes.poll_input(); + snes.input.poll(); } } @@ -52,8 +54,8 @@ void sCPU::mmio_w4016(uint8 data) { //TODO: test whether strobe latch of zero returns //realtime or buffered status of joypadN.b uint8 sCPU::mmio_r4016() { -uint8 r = regs.mdr & 0xfc; - r |= (uint8)snes.port_read(0); + uint8 r = regs.mdr & 0xfc; + r |= (uint8)snes.input.port_read(0); return r; } @@ -62,8 +64,8 @@ uint8 r = regs.mdr & 0xfc; //4-2 = Always 1 (pins are connected to GND) //1-0 = Joypad serial data uint8 sCPU::mmio_r4017() { -uint8 r = (regs.mdr & 0xe0) | 0x1c; - r |= (uint8)snes.port_read(1); + uint8 r = (regs.mdr & 0xe0) | 0x1c; + r |= (uint8)snes.input.port_read(1); return r; } @@ -167,7 +169,7 @@ void sCPU::mmio_w420d(uint8 data) { //6-4 = MDR //3-0 = CPU (5a22) version uint8 sCPU::mmio_r4210() { -uint8 r = (regs.mdr & 0x70); + uint8 r = (regs.mdr & 0x70); r |= (uint8)(rdnmi()) << 7; r |= (cpu_version & 0x0f); return r; @@ -177,7 +179,7 @@ uint8 r = (regs.mdr & 0x70); //7 = IRQ acknowledge //6-0 = MDR uint8 sCPU::mmio_r4211() { -uint8 r = (regs.mdr & 0x7f); + uint8 r = (regs.mdr & 0x7f); r |= (uint8)(timeup()) << 7; return r; } @@ -188,16 +190,16 @@ uint8 r = (regs.mdr & 0x7f); //5-1 = MDR //0 = JOYPAD acknowledge uint8 sCPU::mmio_r4212() { -uint8 r = (regs.mdr & 0x3e); -uint16 vs = !overscan() ? 225 : 240; + uint8 r = (regs.mdr & 0x3e); + uint16 vs = ppu.overscan() == false ? 225 : 240; -//auto joypad polling + //auto joypad polling if(status.vcounter >= vs && status.vcounter <= (vs + 2))r |= 0x01; -//hblank - if(status.hclock <= 2 || status.hclock >= 1096)r |= 0x40; + //hblank + if(status.hcounter <= 2 || status.hcounter >= 1096)r |= 0x40; -//vblank + //vblank if(status.vcounter >= vs)r |= 0x80; return r; @@ -375,40 +377,40 @@ void sCPU::mmio_power() { } void sCPU::mmio_reset() { -//$2181-$2183 + //$2181-$2183 status.wram_addr = 0x000000; -//$4016-$4017 + //$4016-$4017 status.joypad_strobe_latch = 0; status.joypad1_bits = ~0; status.joypad2_bits = ~0; -//$4200 + //$4200 status.nmi_enabled = false; status.hirq_enabled = false; status.virq_enabled = false; status.auto_joypad_poll = false; -//$4201 + //$4201 status.pio = 0xff; -//$4202-$4203 + //$4202-$4203 status.mul_a = 0xff; status.mul_b = 0xff; -//$4204-$4206 + //$4204-$4206 status.div_a = 0xffff; status.div_b = 0xff; -//$4207-$420a + //$4207-$420a status.hirq_pos = 0x01ff; status.virq_pos = 0x01ff; -//$4214-$4217 + //$4214-$4217 status.r4214 = 0x0000; status.r4216 = 0x0000; -//$4218-$421f + //$4218-$421f status.joy1l = 0x00; status.joy1h = 0x00; status.joy2l = 0x00; @@ -422,55 +424,55 @@ void sCPU::mmio_reset() { uint8 sCPU::mmio_read(uint addr) { addr &= 0xffff; -//APU + //APU if((addr & 0xffc0) == 0x2140) { //$2140-$217f scheduler.sync_cpusmp(); return smp.port_read(addr & 3); } -//DMA + //DMA if((addr & 0xff80) == 0x4300) { //$4300-$437f - uint i = (addr >> 4) & 7; + uint i = (addr >> 4) & 7; switch(addr & 0xf) { - case 0x0: return mmio_r43x0(i); - case 0x1: return mmio_r43x1(i); - case 0x2: return mmio_r43x2(i); - case 0x3: return mmio_r43x3(i); - case 0x4: return mmio_r43x4(i); - case 0x5: return mmio_r43x5(i); - case 0x6: return mmio_r43x6(i); - case 0x7: return mmio_r43x7(i); - case 0x8: return mmio_r43x8(i); - case 0x9: return mmio_r43x9(i); - case 0xa: return mmio_r43xa(i); - case 0xb: return mmio_r43xb(i); - case 0xc: return regs.mdr; //unmapped - case 0xd: return regs.mdr; //unmapped - case 0xe: return regs.mdr; //unmapped - case 0xf: return mmio_r43xb(i); //mirror of $43xb + case 0x0: return mmio_r43x0(i); + case 0x1: return mmio_r43x1(i); + case 0x2: return mmio_r43x2(i); + case 0x3: return mmio_r43x3(i); + case 0x4: return mmio_r43x4(i); + case 0x5: return mmio_r43x5(i); + case 0x6: return mmio_r43x6(i); + case 0x7: return mmio_r43x7(i); + case 0x8: return mmio_r43x8(i); + case 0x9: return mmio_r43x9(i); + case 0xa: return mmio_r43xa(i); + case 0xb: return mmio_r43xb(i); + case 0xc: return regs.mdr; //unmapped + case 0xd: return regs.mdr; //unmapped + case 0xe: return regs.mdr; //unmapped + case 0xf: return mmio_r43xb(i); //mirror of $43xb } } switch(addr) { - case 0x2180: return mmio_r2180(); - case 0x4016: return mmio_r4016(); - case 0x4017: return mmio_r4017(); - case 0x4210: return mmio_r4210(); - case 0x4211: return mmio_r4211(); - case 0x4212: return mmio_r4212(); - case 0x4213: return mmio_r4213(); - case 0x4214: return mmio_r4214(); - case 0x4215: return mmio_r4215(); - case 0x4216: return mmio_r4216(); - case 0x4217: return mmio_r4217(); - case 0x4218: return mmio_r4218(); - case 0x4219: return mmio_r4219(); - case 0x421a: return mmio_r421a(); - case 0x421b: return mmio_r421b(); - case 0x421c: return mmio_r421c(); - case 0x421d: return mmio_r421d(); - case 0x421e: return mmio_r421e(); - case 0x421f: return mmio_r421f(); + case 0x2180: return mmio_r2180(); + case 0x4016: return mmio_r4016(); + case 0x4017: return mmio_r4017(); + case 0x4210: return mmio_r4210(); + case 0x4211: return mmio_r4211(); + case 0x4212: return mmio_r4212(); + case 0x4213: return mmio_r4213(); + case 0x4214: return mmio_r4214(); + case 0x4215: return mmio_r4215(); + case 0x4216: return mmio_r4216(); + case 0x4217: return mmio_r4217(); + case 0x4218: return mmio_r4218(); + case 0x4219: return mmio_r4219(); + case 0x421a: return mmio_r421a(); + case 0x421b: return mmio_r421b(); + case 0x421c: return mmio_r421c(); + case 0x421d: return mmio_r421d(); + case 0x421e: return mmio_r421e(); + case 0x421f: return mmio_r421f(); } return regs.mdr; @@ -479,56 +481,58 @@ uint8 sCPU::mmio_read(uint addr) { void sCPU::mmio_write(uint addr, uint8 data) { addr &= 0xffff; -//APU + //APU if((addr & 0xffc0) == 0x2140) { //$2140-$217f scheduler.sync_cpusmp(); port_write(addr & 3, data); return; } -//DMA + //DMA if((addr & 0xff80) == 0x4300) { //$4300-$437f uint i = (addr >> 4) & 7; switch(addr & 0xf) { - case 0x0: mmio_w43x0(i, data); return; - case 0x1: mmio_w43x1(i, data); return; - case 0x2: mmio_w43x2(i, data); return; - case 0x3: mmio_w43x3(i, data); return; - case 0x4: mmio_w43x4(i, data); return; - case 0x5: mmio_w43x5(i, data); return; - case 0x6: mmio_w43x6(i, data); return; - case 0x7: mmio_w43x7(i, data); return; - case 0x8: mmio_w43x8(i, data); return; - case 0x9: mmio_w43x9(i, data); return; - case 0xa: mmio_w43xa(i, data); return; - case 0xb: mmio_w43xb(i, data); return; - case 0xc: return; //unmapped - case 0xd: return; //unmapped - case 0xe: return; //unmapped - case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb + case 0x0: mmio_w43x0(i, data); return; + case 0x1: mmio_w43x1(i, data); return; + case 0x2: mmio_w43x2(i, data); return; + case 0x3: mmio_w43x3(i, data); return; + case 0x4: mmio_w43x4(i, data); return; + case 0x5: mmio_w43x5(i, data); return; + case 0x6: mmio_w43x6(i, data); return; + case 0x7: mmio_w43x7(i, data); return; + case 0x8: mmio_w43x8(i, data); return; + case 0x9: mmio_w43x9(i, data); return; + case 0xa: mmio_w43xa(i, data); return; + case 0xb: mmio_w43xb(i, data); return; + case 0xc: return; //unmapped + case 0xd: return; //unmapped + case 0xe: return; //unmapped + case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb } } switch(addr) { - case 0x2180: mmio_w2180(data); return; - case 0x2181: mmio_w2181(data); return; - case 0x2182: mmio_w2182(data); return; - case 0x2183: mmio_w2183(data); return; - case 0x4016: mmio_w4016(data); return; - case 0x4017: return; //unmapped - case 0x4200: mmio_w4200(data); return; - case 0x4201: mmio_w4201(data); return; - case 0x4202: mmio_w4202(data); return; - case 0x4203: mmio_w4203(data); return; - case 0x4204: mmio_w4204(data); return; - case 0x4205: mmio_w4205(data); return; - case 0x4206: mmio_w4206(data); return; - case 0x4207: mmio_w4207(data); return; - case 0x4208: mmio_w4208(data); return; - case 0x4209: mmio_w4209(data); return; - case 0x420a: mmio_w420a(data); return; - case 0x420b: mmio_w420b(data); return; - case 0x420c: mmio_w420c(data); return; - case 0x420d: mmio_w420d(data); return; + case 0x2180: mmio_w2180(data); return; + case 0x2181: mmio_w2181(data); return; + case 0x2182: mmio_w2182(data); return; + case 0x2183: mmio_w2183(data); return; + case 0x4016: mmio_w4016(data); return; + case 0x4017: return; //unmapped + case 0x4200: mmio_w4200(data); return; + case 0x4201: mmio_w4201(data); return; + case 0x4202: mmio_w4202(data); return; + case 0x4203: mmio_w4203(data); return; + case 0x4204: mmio_w4204(data); return; + case 0x4205: mmio_w4205(data); return; + case 0x4206: mmio_w4206(data); return; + case 0x4207: mmio_w4207(data); return; + case 0x4208: mmio_w4208(data); return; + case 0x4209: mmio_w4209(data); return; + case 0x420a: mmio_w420a(data); return; + case 0x420b: mmio_w420b(data); return; + case 0x420c: mmio_w420c(data); return; + case 0x420d: mmio_w420d(data); return; } } + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/mmio/mmio.h b/src/cpu/scpu/mmio/mmio.h index 74cdcebf3..33d92d12f 100644 --- a/src/cpu/scpu/mmio/mmio.h +++ b/src/cpu/scpu/mmio/mmio.h @@ -1,70 +1,70 @@ - void mmio_power(); - void mmio_reset(); - uint8 mmio_read (uint addr); - void mmio_write(uint addr, uint8 data); + void mmio_power(); + void mmio_reset(); + uint8 mmio_read(uint addr); + void mmio_write(uint addr, uint8 data); - uint8 pio_status(); + uint8 pio_status(); - uint8 mmio_r2180(); - uint8 mmio_r4016(); - uint8 mmio_r4017(); - uint8 mmio_r4210(); - uint8 mmio_r4211(); - uint8 mmio_r4212(); - uint8 mmio_r4213(); - uint8 mmio_r4214(); - uint8 mmio_r4215(); - uint8 mmio_r4216(); - uint8 mmio_r4217(); - uint8 mmio_r4218(); - uint8 mmio_r4219(); - uint8 mmio_r421a(); - uint8 mmio_r421b(); - uint8 mmio_r421c(); - uint8 mmio_r421d(); - uint8 mmio_r421e(); - uint8 mmio_r421f(); - uint8 mmio_r43x0(uint8 i); - uint8 mmio_r43x1(uint8 i); - uint8 mmio_r43x2(uint8 i); - uint8 mmio_r43x3(uint8 i); - uint8 mmio_r43x4(uint8 i); - uint8 mmio_r43x5(uint8 i); - uint8 mmio_r43x6(uint8 i); - uint8 mmio_r43x7(uint8 i); - uint8 mmio_r43x8(uint8 i); - uint8 mmio_r43x9(uint8 i); - uint8 mmio_r43xa(uint8 i); - uint8 mmio_r43xb(uint8 i); + uint8 mmio_r2180(); + uint8 mmio_r4016(); + uint8 mmio_r4017(); + uint8 mmio_r4210(); + uint8 mmio_r4211(); + uint8 mmio_r4212(); + uint8 mmio_r4213(); + uint8 mmio_r4214(); + uint8 mmio_r4215(); + uint8 mmio_r4216(); + uint8 mmio_r4217(); + uint8 mmio_r4218(); + uint8 mmio_r4219(); + uint8 mmio_r421a(); + uint8 mmio_r421b(); + uint8 mmio_r421c(); + uint8 mmio_r421d(); + uint8 mmio_r421e(); + uint8 mmio_r421f(); + uint8 mmio_r43x0(uint8 i); + uint8 mmio_r43x1(uint8 i); + uint8 mmio_r43x2(uint8 i); + uint8 mmio_r43x3(uint8 i); + uint8 mmio_r43x4(uint8 i); + uint8 mmio_r43x5(uint8 i); + uint8 mmio_r43x6(uint8 i); + uint8 mmio_r43x7(uint8 i); + uint8 mmio_r43x8(uint8 i); + uint8 mmio_r43x9(uint8 i); + uint8 mmio_r43xa(uint8 i); + uint8 mmio_r43xb(uint8 i); - void mmio_w2180(uint8 data); - void mmio_w2181(uint8 data); - void mmio_w2182(uint8 data); - void mmio_w2183(uint8 data); - void mmio_w4016(uint8 data); - void mmio_w4200(uint8 data); - void mmio_w4201(uint8 data); - void mmio_w4202(uint8 data); - void mmio_w4203(uint8 data); - void mmio_w4204(uint8 data); - void mmio_w4205(uint8 data); - void mmio_w4206(uint8 data); - void mmio_w4207(uint8 data); - void mmio_w4208(uint8 data); - void mmio_w4209(uint8 data); - void mmio_w420a(uint8 data); - void mmio_w420b(uint8 data); - void mmio_w420c(uint8 data); - void mmio_w420d(uint8 data); - void mmio_w43x0(uint8 i, uint8 data); - void mmio_w43x1(uint8 i, uint8 data); - void mmio_w43x2(uint8 i, uint8 data); - void mmio_w43x3(uint8 i, uint8 data); - void mmio_w43x4(uint8 i, uint8 data); - void mmio_w43x5(uint8 i, uint8 data); - void mmio_w43x6(uint8 i, uint8 data); - void mmio_w43x7(uint8 i, uint8 data); - void mmio_w43x8(uint8 i, uint8 data); - void mmio_w43x9(uint8 i, uint8 data); - void mmio_w43xa(uint8 i, uint8 data); - void mmio_w43xb(uint8 i, uint8 data); + void mmio_w2180(uint8 data); + void mmio_w2181(uint8 data); + void mmio_w2182(uint8 data); + void mmio_w2183(uint8 data); + void mmio_w4016(uint8 data); + void mmio_w4200(uint8 data); + void mmio_w4201(uint8 data); + void mmio_w4202(uint8 data); + void mmio_w4203(uint8 data); + void mmio_w4204(uint8 data); + void mmio_w4205(uint8 data); + void mmio_w4206(uint8 data); + void mmio_w4207(uint8 data); + void mmio_w4208(uint8 data); + void mmio_w4209(uint8 data); + void mmio_w420a(uint8 data); + void mmio_w420b(uint8 data); + void mmio_w420c(uint8 data); + void mmio_w420d(uint8 data); + void mmio_w43x0(uint8 i, uint8 data); + void mmio_w43x1(uint8 i, uint8 data); + void mmio_w43x2(uint8 i, uint8 data); + void mmio_w43x3(uint8 i, uint8 data); + void mmio_w43x4(uint8 i, uint8 data); + void mmio_w43x5(uint8 i, uint8 data); + void mmio_w43x6(uint8 i, uint8 data); + void mmio_w43x7(uint8 i, uint8 data); + void mmio_w43x8(uint8 i, uint8 data); + void mmio_w43x9(uint8 i, uint8 data); + void mmio_w43xa(uint8 i, uint8 data); + void mmio_w43xb(uint8 i, uint8 data); diff --git a/src/cpu/scpu/scpu.cpp b/src/cpu/scpu/scpu.cpp index 924d3dc37..53f7415d8 100644 --- a/src/cpu/scpu/scpu.cpp +++ b/src/cpu/scpu/scpu.cpp @@ -1,4 +1,5 @@ -#include "../../base.h" +#include "../../base.h" +#define SCPU_CPP #include "core/core.cpp" #include "dma/dma.cpp" @@ -7,8 +8,6 @@ #include "timing/timing.cpp" void sCPU::power() { - status.region = (bool)snes.region(); - regs.a = regs.x = regs.y = 0x0000; regs.s = 0x01ff; @@ -24,7 +23,7 @@ void sCPU::reset() { regs.pc.l = bus.read(0xfffc); regs.pc.h = bus.read(0xfffd); -//note: some registers are not fully reset by SNES + //note: some registers are not fully reset by SNES regs.x.h = 0x00; regs.y.h = 0x00; regs.s.h = 0x01; diff --git a/src/cpu/scpu/scpu.h b/src/cpu/scpu/scpu.h index dc90a0c58..6dedfcff2 100644 --- a/src/cpu/scpu/scpu.h +++ b/src/cpu/scpu/scpu.h @@ -1,138 +1,132 @@ -class sCPU : public CPU { public: +class sCPU : public CPU { +public: void enter(); -#include "core/core.h" -#include "dma/dma.h" -#include "memory/memory.h" -#include "mmio/mmio.h" -#include "timing/timing.h" + #include "core/core.h" + #include "dma/dma.h" + #include "memory/memory.h" + #include "mmio/mmio.h" + #include "timing/timing.h" -struct { - bool wai; - bool irq; - uint16 irq_vector; -} event; + struct { + bool wai; + bool irq; + uint16 irq_vector; + } event; -struct { - uint nmi_hold; - uint irq_hold; + struct { + uint nmi_hold; + uint irq_hold; - uint nmi_fire; - uint irq_fire; - uint irq_delay; - uint hw_math; + uint nmi_fire; + uint irq_fire; + uint irq_delay; + uint hw_math; - alwaysinline void set(uint &ctr, uint clocks) { - if(clocks >= ctr) { ctr = clocks; } - } - - alwaysinline void sub(uint &ctr, uint clocks) { - if(ctr >= clocks) { - ctr -= clocks; - } else { - ctr = 0; + alwaysinline void set(uint &ctr, uint clocks) { + if(clocks >= ctr) { ctr = clocks; } } - } -} counter; -enum { - DMASTATE_INACTIVE, - DMASTATE_DMASYNC, - DMASTATE_RUN, - DMASTATE_CPUSYNC, -}; + alwaysinline void sub(uint &ctr, uint clocks) { + if(ctr >= clocks) { + ctr -= clocks; + } else { + ctr = 0; + } + } + } counter; -struct { -//core - uint8 opcode; - bool in_opcode; + enum { + DMASTATE_INACTIVE, + DMASTATE_DMASYNC, + DMASTATE_RUN, + DMASTATE_CPUSYNC, + }; - uint clock_count; + struct { + //core + uint8 opcode; + bool in_opcode; -//timing - bool region; - uint16 region_scanlines; - uint16 vcounter, hcounter, hclock; - bool interlace, interlace_field; - bool overscan; - uint16 field_lines, line_clocks; - uint16 prev_field_lines, prev_line_clocks; - uint16 vblstart; + uint clock_count; - bool line_rendered; - uint16 line_render_position; + //timing + uint16 vcounter, hcounter; + uint16 field_lines, line_clocks; - bool dram_refreshed; - uint16 dram_refresh_position; + bool line_rendered; + uint16 line_render_position; - bool hdmainit_triggered; - uint16 hdmainit_trigger_position; + bool dram_refreshed; + uint16 dram_refresh_position; - bool hdma_triggered; + bool hdmainit_triggered; + uint16 hdmainit_trigger_position; - uint16 irq_delay; + bool hdma_triggered; - uint16 vnmi_trigger_pos; - bool nmi_valid; - bool nmi_line; - bool nmi_transition; - bool nmi_pending; + uint16 irq_delay; - uint16 virq_trigger_pos, hirq_trigger_pos; - bool irq_valid; - bool irq_line; - bool irq_transition; - bool irq_pending; + bool nmi_valid; + bool nmi_line; + bool nmi_transition; + bool nmi_pending; -//dma - uint dma_counter; - uint dma_clocks; - uint dma_state; - bool dma_pending; - bool hdma_pending; - bool hdmainit_pending; + uint16 virq_trigger_pos, hirq_trigger_pos; + bool irq_valid; + bool irq_line; + bool irq_transition; + bool irq_pending; -//mmio + //dma + uint dma_counter; + uint dma_clocks; + uint dma_state; + bool dma_pending; + bool hdma_pending; + bool hdmainit_pending; -//$2181-$2183 - uint32 wram_addr; + //mmio -//$4016-$4017 - bool joypad_strobe_latch; - uint32 joypad1_bits; - uint32 joypad2_bits; + //$2181-$2183 + uint32 wram_addr; -//$4200 - bool nmi_enabled; - bool hirq_enabled, virq_enabled; - bool auto_joypad_poll; + //$4016-$4017 + bool joypad_strobe_latch; + uint32 joypad1_bits; + uint32 joypad2_bits; -//$4201 - uint8 pio; + //$4200 + bool nmi_enabled; + bool hirq_enabled, virq_enabled; + bool auto_joypad_poll; -//$4202-$4203 - uint8 mul_a, mul_b; + //$4201 + uint8 pio; -//$4204-$4206 - uint16 div_a; - uint8 div_b; + //$4202-$4203 + uint8 mul_a, mul_b; -//$4207-$420a - uint16 hirq_pos, virq_pos; + //$4204-$4206 + uint16 div_a; + uint8 div_b; -//$4214-$4217 - uint16 r4214; - uint16 r4216; + //$4207-$420a + uint16 hirq_pos, virq_pos; -//$4218-$421f - uint8 joy1l, joy1h; - uint8 joy2l, joy2h; - uint8 joy3l, joy3h; - uint8 joy4l, joy4h; -} status; + //$4214-$4217 + uint16 r4214; + uint16 r4216; - void power(); - void reset(); + //$4218-$421f + uint8 joy1l, joy1h; + uint8 joy2l, joy2h; + uint8 joy3l, joy3h; + uint8 joy4l, joy4h; + } status; + + void power(); + void reset(); sCPU(); ~sCPU(); diff --git a/src/cpu/scpu/timing/irq.cpp b/src/cpu/scpu/timing/irq.cpp index 0765ee938..5b1514743 100644 --- a/src/cpu/scpu/timing/irq.cpp +++ b/src/cpu/scpu/timing/irq.cpp @@ -1,60 +1,137 @@ -#include "irqtiming.cpp" - -bool sCPU::irq_pos_valid() { -uint vpos = status.virq_pos; -uint hpos = (status.hirq_enabled) ? status.hirq_pos : 0; -uint vlimit = region_scanlines() >> 1; -//positions that can never be latched -//vlimit = 262/NTSC, 312/PAL -//PAL results are unverified on hardware - if(vpos == 240 && hpos == 339 && interlace() == false && interlace_field() == 1)return false; - if(vpos == (vlimit - 1) && hpos == 339 && interlace() == false)return false; - if(vpos == vlimit && interlace() == false)return false; - if(vpos == vlimit && hpos == 339)return false; - if(vpos > vlimit)return false; - if(hpos > 339)return false; - - return true; +#ifdef SCPU_CPP + +void sCPU::update_interrupts() { + if(irq_pos_valid() == true) { + status.virq_trigger_pos = status.virq_pos; + status.hirq_trigger_pos = 4 * ((status.hirq_enabled) ? (status.hirq_pos + 1) : 0); + } else { + status.virq_trigger_pos = IRQ_TRIGGER_NEVER; + status.hirq_trigger_pos = IRQ_TRIGGER_NEVER; + } } -alwaysinline -bool sCPU::nmi_test() { - if(status.nmi_transition == false) { return false; } - status.nmi_transition = false; +alwaysinline void sCPU::poll_interrupts() { + uint16_t vpos, hpos; - event.wai = false; - return true; -} - -alwaysinline -bool sCPU::irq_test() { - if(status.irq_transition == false) { return false; } - status.irq_transition = false; - - event.wai = false; - return (regs.p.i) ? false : true; -} - -/* - if(status.irq_transition == 1)goto irq_trigger; - - if(status.irq_read == 0) { - if(status.irq_line == 1 && irq_edge()) { - return false; + //NMI hold + if(counter.nmi_hold) { + counter.nmi_hold -= 2; + if(counter.nmi_hold == 0) { + if(status.nmi_enabled == true) status.nmi_transition = true; } - goto irq_trigger; } - if(status.irq_line == 0) { - status.irq_line = 1; - goto irq_trigger; + //NMI test + history.query(2, vpos, hpos); + bool nmi_valid = (vpos >= (!ppu.overscan() ? 225 : 240)); + if(status.nmi_valid == false && nmi_valid == true) { + //0->1 edge sensitive transition + status.nmi_line = true; + counter.nmi_hold = 4; + } else if(status.nmi_valid == true && nmi_valid == false) { + //1->0 edge sensitive transition + status.nmi_line = false; + } + status.nmi_valid = nmi_valid; + + //IRQ hold + if(counter.irq_hold) counter.irq_hold -= 2; + if(status.irq_line == true && counter.irq_hold == 0) { + if(status.virq_enabled == true || status.hirq_enabled == true) status.irq_transition = true; } - return false; - -irq_trigger: - status.irq_transition = 0; - event.wai = false; - return (regs.p.i) ? false : true; + //IRQ test + history.query(10, vpos, hpos); + bool irq_valid = (status.virq_enabled == true || status.hirq_enabled == true); + if(irq_valid == true) { + if(status.virq_enabled == true && vpos != status.virq_trigger_pos) irq_valid = false; + if(status.hirq_enabled == true && hpos != status.hirq_trigger_pos) irq_valid = false; + } + if(status.irq_valid == false && irq_valid == true) { + //0->1 edge sensitive transition + status.irq_line = true; + counter.irq_hold = 4; + } + status.irq_valid = irq_valid; } -*/ + +void sCPU::nmitimen_update(uint8 data) { + bool nmi_enabled = status.nmi_enabled; + bool virq_enabled = status.virq_enabled; + bool hirq_enabled = status.hirq_enabled; + status.nmi_enabled = !!(data & 0x80); + status.virq_enabled = !!(data & 0x20); + status.hirq_enabled = !!(data & 0x10); + + //0->1 edge sensitive transition + if(nmi_enabled == false && status.nmi_enabled == true && status.nmi_line == true) { + status.nmi_transition = true; + } + + //?->1 level sensitive transition + if(status.virq_enabled == true && status.hirq_enabled == false && status.irq_line == true) { + status.irq_transition = true; + } + + if(status.virq_enabled == false && status.hirq_enabled == false) { + status.irq_line = false; + status.irq_transition = false; + } + + update_interrupts(); + counter.set(counter.irq_delay, 2); +} + +void sCPU::hvtime_update(uint16 addr) { + update_interrupts(); +} + +bool sCPU::rdnmi() { + bool result = status.nmi_line; + if(counter.nmi_hold == 0) { + status.nmi_line = false; + } + return result; +} + +bool sCPU::timeup() { + bool result = status.irq_line; + if(counter.irq_hold == 0) { + status.irq_line = false; + status.irq_transition = false; + } + return result; +} + +bool sCPU::irq_pos_valid() { + uint vpos = status.virq_pos; + uint hpos = (status.hirq_enabled) ? status.hirq_pos : 0; + uint vlimit = (snes.region() == SNES::NTSC ? 525 : 625) >> 1; + //positions that can never be latched + //vlimit = 262/NTSC, 312/PAL + //PAL results are unverified on hardware + if(vpos == 240 && hpos == 339 && ppu.interlace() == false && ppu.field() == 1) return false; + if(vpos == (vlimit - 1) && hpos == 339 && ppu.interlace() == false) return false; + if(vpos == vlimit && ppu.interlace() == false) return false; + if(vpos == vlimit && hpos == 339) return false; + if(vpos > vlimit) return false; + if(hpos > 339) return false; + + return true; +} + +alwaysinline bool sCPU::nmi_test() { + if(status.nmi_transition == false) return false; + status.nmi_transition = false; + event.wai = false; + return true; +} + +alwaysinline bool sCPU::irq_test() { + if(status.irq_transition == false) return false; + status.irq_transition = false; + event.wai = false; + return regs.p.i ? false : true; +} + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/timing/irqtiming.cpp b/src/cpu/scpu/timing/irqtiming.cpp deleted file mode 100644 index f29e6d5d9..000000000 --- a/src/cpu/scpu/timing/irqtiming.cpp +++ /dev/null @@ -1,105 +0,0 @@ -void sCPU::update_interrupts() { - status.vnmi_trigger_pos = status.vblstart; - - if(irq_pos_valid() == true) { - status.virq_trigger_pos = status.virq_pos; - status.hirq_trigger_pos = 4 * ((status.hirq_enabled) ? (status.hirq_pos + 1) : 0); - } else { - status.virq_trigger_pos = IRQ_TRIGGER_NEVER; - status.hirq_trigger_pos = IRQ_TRIGGER_NEVER; - } -} - -alwaysinline -void sCPU::poll_interrupts() { -uint vpos = status.vcounter, hpos = status.hclock; - -//NMI test - timeshift_backward(2, vpos, hpos); -bool nmi_valid = (vpos >= status.vnmi_trigger_pos); - if(status.nmi_valid == false && nmi_valid == true) { - //0->1 edge sensitive transition - status.nmi_line = true; - counter.nmi_hold = 6; - } else if(status.nmi_valid == true && nmi_valid == false) { - //1->0 edge sensitive transition - status.nmi_line = false; - } - status.nmi_valid = nmi_valid; - -//NMI hold - if(counter.nmi_hold) { - counter.nmi_hold -= 2; - if(counter.nmi_hold == 0) { - if(status.nmi_enabled == true) { status.nmi_transition = true; } - } - } - -//IRQ test - timeshift_backward(8, vpos, hpos); -bool irq_valid = (status.virq_enabled == true || status.hirq_enabled == true); - if(irq_valid == true) { - if(status.virq_enabled == true && vpos != status.virq_trigger_pos) { irq_valid = false; } - if(status.hirq_enabled == true && hpos != status.hirq_trigger_pos) { irq_valid = false; } - } - if(status.irq_valid == false && irq_valid == true) { - //0->1 edge sensitive transition - status.irq_line = true; - counter.irq_hold = 6; - } - status.irq_valid = irq_valid; - -//IRQ hold - if(counter.irq_hold) { counter.irq_hold -= 2; } - if(status.irq_line == true && counter.irq_hold == 0) { - if(status.virq_enabled == true || status.hirq_enabled == true) { status.irq_transition = true; } - } -} - -void sCPU::nmitimen_update(uint8 data) { -bool nmi_enabled = status.nmi_enabled; -bool virq_enabled = status.virq_enabled; -bool hirq_enabled = status.hirq_enabled; - status.nmi_enabled = !!(data & 0x80); - status.virq_enabled = !!(data & 0x20); - status.hirq_enabled = !!(data & 0x10); - -//0->1 edge sensitive transition - if(nmi_enabled == false && status.nmi_enabled == true && status.nmi_line == true) { - status.nmi_transition = true; - } - -//?->1 level sensitive transition - if(status.virq_enabled == true && status.hirq_enabled == false && status.irq_line == true) { - status.irq_transition = true; - } - - if(status.virq_enabled == false && status.hirq_enabled == false) { - status.irq_line = false; - status.irq_transition = false; - } - - update_interrupts(); - counter.set(counter.irq_delay, 2); -} - -void sCPU::hvtime_update(uint16 addr) { - update_interrupts(); -} - -bool sCPU::rdnmi() { -bool result = status.nmi_line; - if(counter.nmi_hold == 0) { - status.nmi_line = false; - } - return result; -} - -bool sCPU::timeup() { -bool result = status.irq_line; - if(counter.irq_hold == 0) { - status.irq_line = false; - status.irq_transition = false; - } - return result; -} diff --git a/src/cpu/scpu/timing/joypad.cpp b/src/cpu/scpu/timing/joypad.cpp index 3cd1924a6..50e1cce26 100644 --- a/src/cpu/scpu/timing/joypad.cpp +++ b/src/cpu/scpu/timing/joypad.cpp @@ -1,8 +1,10 @@ +#ifdef SCPU_CPP + void sCPU::run_auto_joypad_poll() { -uint16 joy1 = 0, joy2 = 0; - for(int i = 0; i < 16; i++) { - joy1 |= (uint16)snes.port_read(0) ? (0x8000 >> i) : 0; - joy2 |= (uint16)snes.port_read(1) ? (0x8000 >> i) : 0; + uint16_t joy1 = 0, joy2 = 0; + for(unsigned i = 0; i < 16; i++) { + joy1 |= (uint16_t)snes.input.port_read(0) ? (0x8000 >> i) : 0; + joy2 |= (uint16_t)snes.input.port_read(1) ? (0x8000 >> i) : 0; } status.joy1l = joy1; @@ -17,3 +19,5 @@ uint16 joy1 = 0, joy2 = 0; status.joy4l = 0x00; status.joy4h = 0x00; } + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/timing/timeshift.cpp b/src/cpu/scpu/timing/timeshift.cpp deleted file mode 100644 index 1f1408fbd..000000000 --- a/src/cpu/scpu/timing/timeshift.cpp +++ /dev/null @@ -1,22 +0,0 @@ -alwaysinline void sCPU::timeshift_forward(uint clocks, uint &vtime, uint &htime) { - htime += clocks; - if(htime >= status.line_clocks) { - htime -= status.line_clocks; - if(++vtime >= status.field_lines) { - vtime = 0; - } - } -} - -alwaysinline void sCPU::timeshift_backward(uint clocks, uint &vtime, uint &htime) { - if(htime >= clocks) { - htime -= clocks; - } else { - htime += status.prev_line_clocks - clocks; - if(vtime > 0) { - vtime--; - } else { - vtime = status.prev_field_lines - 1; - } - } -} diff --git a/src/cpu/scpu/timing/timing.cpp b/src/cpu/scpu/timing/timing.cpp index 3be22721f..2453a9063 100644 --- a/src/cpu/scpu/timing/timing.cpp +++ b/src/cpu/scpu/timing/timing.cpp @@ -1,31 +1,16 @@ -#define ntsc_color_burst_phase_shift_scanline() \ - (status.region == SNES::NTSC && status.vcounter == 240 && \ - status.interlace == false && status.interlace_field == 1) +#ifdef SCPU_CPP + +#define ntsc_color_burst_phase_shift_scanline() ( \ + snes.region() == SNES::NTSC && status.vcounter == 240 && \ + ppu.interlace() == false && ppu.field() == 1 \ +) -#include "timeshift.cpp" #include "irq.cpp" #include "joypad.cpp" -uint16 sCPU::vcounter() { return status.vcounter; } -uint16 sCPU::hclock() { return status.hclock; } - -bool sCPU::interlace() { return status.interlace; } -bool sCPU::interlace_field() { return status.interlace_field; } -bool sCPU::overscan() { return status.overscan; } -uint16 sCPU::region_scanlines() { return status.region_scanlines; } - -uint sCPU::dma_counter() { return (status.dma_counter + status.hclock) & 7; } - -void sCPU::set_interlace(bool r) { - status.interlace = r; - update_interrupts(); -} - -void sCPU::set_overscan (bool r) { - status.overscan = r; - status.vblstart = (status.overscan == false) ? 225 : 240; - update_interrupts(); -} +uint16 sCPU::vcounter() { return status.vcounter; } +uint16 sCPU::hcounter() { return status.hcounter; } +uint sCPU::dma_counter() { return (status.dma_counter + status.hcounter) & 7; } /***** * One PPU dot = 4 CPU clocks @@ -37,16 +22,14 @@ void sCPU::set_overscan (bool r) { * Dot 323 range = { 1292, 1294, 1296 } * Dot 327 range = { 1310, 1312, 1314 } *****/ -uint16 sCPU::hcounter() { - if(ntsc_color_burst_phase_shift_scanline() == true) { - return (status.hclock >> 2); - } - return (status.hclock - ((status.hclock > 1292) << 1) - ((status.hclock > 1310) << 1)) >> 2; +uint16 sCPU::hdot() { + if(ntsc_color_burst_phase_shift_scanline() == true) return (status.hcounter >> 2); + return (status.hcounter - ((status.hcounter > 1292) << 1) - ((status.hcounter > 1310) << 1)) >> 2; } void sCPU::add_clocks(uint clocks) { if(status.dram_refreshed == false) { - if(status.hclock + clocks >= status.dram_refresh_position) { + if(status.hcounter + clocks >= status.dram_refresh_position) { status.dram_refreshed = true; clocks += 40; } @@ -56,25 +39,21 @@ void sCPU::add_clocks(uint clocks) { scheduler.addclocks_cpu(clocks); clocks >>= 1; - while(clocks--) { - status.hclock += 2; - if(status.hclock >= status.line_clocks) { scanline(); } + while(clocks--) { + history.enqueue(status.vcounter, status.hcounter); + status.hcounter += 2; + if(status.hcounter >= status.line_clocks) scanline(); poll_interrupts(); } } void sCPU::scanline() { - status.hclock = 0; + status.hcounter = 0; status.dma_counter = (status.dma_counter + status.line_clocks) & 7; - - if(++status.vcounter >= status.field_lines) { - frame(); - } - - status.prev_line_clocks = status.line_clocks; + if(++status.vcounter >= status.field_lines) frame(); status.line_clocks = (ntsc_color_burst_phase_shift_scanline() == false) ? 1364 : 1360; -//dram refresh occurs once every scanline + //dram refresh occurs once every scanline status.dram_refreshed = false; if(cpu_version == 2) { if(ntsc_color_burst_phase_shift_scanline() == false) { @@ -86,29 +65,30 @@ void sCPU::scanline() { } } -//hdma triggers once every visible scanline + //hdma triggers once every visible scanline status.line_rendered = false; - status.hdma_triggered = (status.vcounter <= (!overscan() ? 224 : 239)) ? false : true; + status.hdma_triggered = (status.vcounter <= (ppu.overscan() == false ? 224 : 239)) ? false : true; ppu.scanline(); snes.scanline(); update_interrupts(); - if(status.auto_joypad_poll == true && status.vcounter == (!overscan() ? 227 : 242)) { - snes.poll_input(); + if(status.auto_joypad_poll == true && status.vcounter == (ppu.overscan() == false ? 227 : 242)) { + snes.input.poll(); run_auto_joypad_poll(); } } -void sCPU::frame() { +void sCPU::frame() { + ppu.frame(); + snes.frame(); + status.vcounter = 0; - status.interlace_field ^= 1; - status.prev_field_lines = status.field_lines; - status.field_lines = (status.region_scanlines >> 1); -//interlaced even fields have one extra scanline -//(263+262=525 NTSC, 313+312=625 PAL) - if(status.interlace == true && status.interlace_field == 0)status.field_lines++; + status.field_lines = (snes.region() == SNES::NTSC ? 525 : 625) >> 1; + //interlaced even fields have one extra scanline + //(263+262=525 NTSC, 313+312=625 PAL) + if(ppu.interlace() == true && ppu.field() == 0) status.field_lines++; status.hdmainit_triggered = false; if(cpu_version == 1) { @@ -116,9 +96,6 @@ void sCPU::frame() { } else { status.hdmainit_trigger_position = 12 + dma_counter(); } - - ppu.frame(); - snes.frame(); } /***** @@ -129,7 +106,7 @@ void sCPU::frame() { alwaysinline void sCPU::precycle_edge() { if(status.dma_state == DMASTATE_CPUSYNC) { status.dma_state = DMASTATE_INACTIVE; - uint n = status.clock_count - (status.dma_clocks % status.clock_count); + uint n = status.clock_count - (status.dma_clocks % status.clock_count); add_clocks(n ? n : status.clock_count); } } @@ -141,34 +118,33 @@ alwaysinline void sCPU::precycle_edge() { *****/ void sCPU::cycle_edge() { if(status.line_rendered == false) { - if(status.hclock >= status.line_render_position) { + if(status.hcounter >= status.line_render_position) { status.line_rendered = true; ppu.render_scanline(); } } switch(status.dma_state) { - case DMASTATE_INACTIVE: - break; + case DMASTATE_INACTIVE: break; - case DMASTATE_DMASYNC: - status.dma_state = DMASTATE_RUN; - break; + case DMASTATE_DMASYNC: { + status.dma_state = DMASTATE_RUN; + } break; - case DMASTATE_RUN: - status.dma_state = DMASTATE_CPUSYNC; - status.dma_clocks = 8 - dma_counter() + 8; - add_clocks(status.dma_clocks); + case DMASTATE_RUN: { + status.dma_state = DMASTATE_CPUSYNC; + status.dma_clocks = 8 - dma_counter() + 8; + add_clocks(status.dma_clocks); - if(status.hdmainit_pending) { hdma_init(); status.hdmainit_pending = false; } - if(status.hdma_pending) { hdma_run(); status.hdma_pending = false; } - if(status.dma_pending) { dma_run(); status.dma_pending = false; } + if(status.hdmainit_pending) { hdma_init(); status.hdmainit_pending = false; } + if(status.hdma_pending) { hdma_run(); status.hdma_pending = false; } + if(status.dma_pending) { dma_run(); status.dma_pending = false; } - break; + } break; } if(status.hdmainit_triggered == false) { - if(status.hclock >= status.hdmainit_trigger_position || status.vcounter) { + if(status.hcounter >= status.hdmainit_trigger_position || status.vcounter) { status.hdmainit_triggered = true; hdma_init_reset(); if(hdma_enabled_channels()) { @@ -185,7 +161,7 @@ void sCPU::cycle_edge() { } if(status.hdma_triggered == false) { - if(status.hclock >= 1106) { + if(status.hcounter >= 1106) { status.hdma_triggered = true; if(hdma_active_channels()) { add_clocks(18); @@ -211,7 +187,7 @@ void sCPU::cycle_edge() { * trigger during certain events (immediately after DMA, writes to $4200, etc) *****/ void sCPU::last_cycle() { - if(counter.irq_delay) { return; } + if(counter.irq_delay) return; status.nmi_pending |= nmi_test(); status.irq_pending |= irq_test(); @@ -235,27 +211,17 @@ void sCPU::timing_reset() { status.vcounter = 0; status.hcounter = 0; - status.hclock = 0; - status.interlace = 0; - status.interlace_field = 0; - status.overscan = false; - status.region_scanlines = (status.region == SNES::NTSC) ? 525 : 625; - status.vblstart = 225; - - status.field_lines = status.region_scanlines >> 1; + status.field_lines = (snes.region() == SNES::NTSC ? 525 : 625) >> 1; status.line_clocks = 1364; - status.prev_field_lines = status.region_scanlines >> 1; - status.prev_line_clocks = 1364; - - status.line_rendered = false; + status.line_rendered = false; status.line_render_position = min(1112U, (uint)config::ppu.hack.render_scanline_position); - status.dram_refreshed = false; + status.dram_refreshed = false; status.dram_refresh_position = (cpu_version == 1) ? 530 : 538; - status.hdmainit_triggered = false; + status.hdmainit_triggered = false; status.hdmainit_trigger_position = 0; status.hdma_triggered = false; @@ -278,12 +244,16 @@ void sCPU::timing_reset() { status.dma_state = DMASTATE_INACTIVE; status.dma_pending = false; status.hdma_pending = false; - status.hdmainit_pending = false; + status.hdmainit_pending = false; + + history.reset(); -//initial latch values for $213c/$213d -//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137] -//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137] -//add_clocks(186); + //initial latch values for $213c/$213d + //[x]0035 : [y]0000 (53.0 -> 212) [lda $2137] + //[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137] + add_clocks(186); } #undef ntsc_color_burst_phase_shift_scanline + +#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/timing/timing.h b/src/cpu/scpu/timing/timing.h index 975aa1b5a..12185d572 100644 --- a/src/cpu/scpu/timing/timing.h +++ b/src/cpu/scpu/timing/timing.h @@ -1,45 +1,57 @@ uint16 vcounter(); uint16 hcounter(); - uint16 hclock(); + uint16 hdot(); + uint dma_counter(); - bool interlace(); - bool interlace_field(); - bool overscan(); - uint16 region_scanlines(); + void add_clocks(uint clocks); + void scanline(); + void frame(); - void set_interlace(bool r); - void set_overscan(bool r); - - uint dma_counter(); - - void add_clocks(uint clocks); - void scanline(); - void frame(); - - void precycle_edge(); - void cycle_edge(); - void last_cycle(); + void precycle_edge(); + void cycle_edge(); + void last_cycle(); uint32 clocks_executed(); - void timing_power(); - void timing_reset(); + void timing_power(); + void timing_reset(); + + //timeshifting -- needed by NMI and IRQ timing + struct History { + struct Time { + uint16 vcounter; + uint16 hcounter; + } time[32]; + unsigned index; + alwaysinline void enqueue(uint16 vcounter, uint16 hcounter) { + Time &t = time[index++]; + index &= 31; + t.vcounter = vcounter; + t.hcounter = hcounter; + } + alwaysinline void query(unsigned offset, uint16 &vcounter, uint16 &hcounter) { + Time &t = time[(index - (offset >> 1)) & 31]; + vcounter = t.vcounter; + hcounter = t.hcounter; + } + void reset() { + index = 0; + for(unsigned i = 0; i < 32; i++) time[i].vcounter = time[i].hcounter = 0; + } + History() { reset(); } + } history; -//timeshift.cpp - void timeshift_forward (uint clocks, uint &v, uint &h); - void timeshift_backward(uint clocks, uint &v, uint &h); + //irq.cpp + enum { IRQ_TRIGGER_NEVER = 0x3fff }; + void update_interrupts(); + void poll_interrupts(); + void nmitimen_update(uint8 data); + void hvtime_update(uint16 addr); + bool rdnmi(); + bool timeup(); -//irq.cpp -enum { IRQ_TRIGGER_NEVER = 0x3fff }; - void update_interrupts(); - void poll_interrupts(); - void nmitimen_update(uint8 data); - void hvtime_update(uint16 addr); - bool rdnmi(); - bool timeup(); + bool irq_pos_valid(); + bool nmi_test(); + bool irq_test(); - bool irq_pos_valid(); - bool nmi_test(); - bool irq_test(); - -//joypad.cpp - void run_auto_joypad_poll(); + //joypad.cpp + void run_auto_joypad_poll(); diff --git a/src/data/controller.h b/src/data/controller.h new file mode 100644 index 000000000..6b7175e33 --- /dev/null +++ b/src/data/controller.h @@ -0,0 +1,1013 @@ +static char enc_controller[] = { + "_v8B8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw" + "AfB_AfAB8AHwAfAB8AHwAeD9AP396OjomJiZAHBwcG5ubmpqAGpYWFhLS0tBAEFB" + "Ojo6MzMz8QYAy8vLOfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHw" + "AfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfABwAD8_PzU" + "1NR8fAB8cXFxb29vaQBpaVtbW05OTgBEREQ8PDw3N4A3UlJS3t7eOfD_AfAB8AHw" + "AfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB" + "8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_" + "AfAB8AHwAfAB8AHwAfAB8AcB8AHwAcD-_v7FxCTFcwEAcnK7CGZmAGZZWVlPT09J" + "AEhIPz4-PT0-wHh4eO_v7znwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHw" + "AfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8AMB8Fz0" + "r7Gwd3d3CHZ1drsIZWVmWQBaWVNSUUtLSghCQUIaDZ2dnPP88_M58AHwAfAB8AHw" + "AfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB" + "8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHw" + "AfAB8AHwAfA_AfAB8AHwAfAB8AHA-_wA_JiYmXt8e3oMeXm7CLgIW1tZUSBQTkpK" + "SFwERUXwRbGxsTbwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB" + "8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfAA9fb2hYaH" + "fX0AfHl3eHJycWcAZ2hbXFlPUlEAR0dJQUBASkrwSsLCwjbwAfAB8AHw_wHwAfAB" + "8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHw" + "AfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw" + "_wHwAfAB8AHwAfAB8AHwEf0A6erqgYCAfn4AfnZ3dnFycmkAaGlaWlhSUVAAR0ZG" + "QkJCTEzwTMrKyjnwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB" + "8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAcAA_f392tra" + "gYAAgoCBgXh3eW8Ab29laGdYWFUATk1ORkVDREOAQ1JSUtbW1jnw_wHwAfAB8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB" + "8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHw" + "AfAB8AHwAfAB8AHwAfAHAfAB8Lj42NjYgYEAgYKCgnp6em8Abm5iZGJUVVUATUtO" + "RkZGRUSARFZWVuPj4znw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfAHAfAB8AHw09PT" + "g4NihAMAent-uAhcBFWAV1VNTEtHSAIAgEddXV3v7-828P8B8AHwAfAB8AHwAfAB" + "8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHw" + "AfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHwBwHwAfAB8MzMzIWFAIWEg4R9fHxyAHJxZGNjV1VVAE9OTUhJSEpL" + "gEtoaGj29vY28P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB" + "8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_" + "AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwBwHwAfAB8MrJyoWFAIaF" + "hIV-fX1yAHJzZWRlWVlXAFBOT0xMTE5PgE9ra2v4-Pg28P8B8AHwAfAB8AHwAfAB" + "8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHw" + "AfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHwBwHwAfAB8MbGxoeHAodfBH9-gHN0dABlZWZaWFdRUABQTk1NT05O" + "cuBycvn5-TbwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_" + "AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw" + "AfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwAwHwXASJiImFhoYA" + "f39_dHR0Z2cAZ1pbWVJRUE4ATk5QUFB3d3f_XPQB8AHwAfAB8AHwAfAB8P8B8AHw" + "AfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B" + "8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB" + "8B8B8AHwAfAB8Fw0jY2NAImJiYB_gHZ3CHZpaVwEWFJSUgBOT05QUVGAgPB--_v7" + "NvAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB" + "8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_QFg" + "_gHwAfAB8AHwAfAB8P8BUIfwAfAB8AHwAfAB8AHwBwHwAfBcBI6OjomIAIiBgIB3" + "dndpAGpqWFtaVFJSCE9PT1wEgYCB9_z39zbwAfAB8AHwAfAB8P8B8AHwAfDg8QHw" + "AfAB8AHw_wHw3fEB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHwvwHwAfAB8AHwXvIBYP0BgP78AeCMBwHwAfAB8AHwAcD_acCEYJHy" + "AfAB8AHwAfAB8AcB8AHwAWDPz8-KigCKi4uLgYGBdwB2eGlra1xbXRhVVVQRDQEA" + "e3t7-Pb29jbwAfAB8AHwAfD_AfAB8AHw7JHm8ePxAfAB8P8B8AHw4PHjkeaR6fEB" + "8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHw" + "AfBhwlWS6voBUPkBIPgBgIkHAfD_ATBIAwHwAfABkELAZmB4MP-BAJRiZfQB8AHw" + "AfAB8AHwRwHwAfABMNjY2FkEjACMjIKDgnh4eQBrbWxfYF9YWQJYXDR1dXT19fX_" + "NvAB8AHwAfAB8AHwAfDy8f_yke9h6cHa8QHwAfDX8QHw_0yS5mEBMICU7_EB8AHw" + "AfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwW_Je" + "MkdkVWJXHwIVAwEA9AEg8wEg8sUBUPEB8PHx8AHwAfD_AeBCkF0waQB1MH4ApjJl" + "9P9w8gHwAfAB8AHwAfAB8FzECIiIiFwUgYJ5eSB6bW9tYVwEWFeIUlFTXARpaWnS" + "AP828AHwAfAB8AHwAfAB8P7B_1P072HsYebxufEB8NrxAfD_Q2JSMulh7GF9NHFk" + "a_T78f8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB" + "8FPEUJRNZAdbYlgyTDLv7-_t7VTt7AEg6wEg6gEg6T0BUOcB8AHwAfAB8OfnfugB" + "IFQAYABpAHIAewDu_O7uozKWAGj0zZgB8AHwHwHwAfAB8AHwAcDj4-MohISEXBSC" + "XBRvbQBtYWJiWFhZUwBSU09QUFtcXP-9ADbwAfAB8AHwAfAB8AHw_6P4UJSfAO8x" + "bgHvMekxjAH_lTGt8QHwAfAB8E4w5jEBAP9SMl4y7DFwAu9hWpZrZGiU_2X0AfAB" + "8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwqMZbwlCU_01k" + "SjRYYvgx8gF5MmY2ATD_7zEr-wHwAfAB8AHwAQBbAuOTMIcA5ubmmQAMAGWU_9vG" + "AfAB8AHwAfAB8AHwAZCDVgFcZICAgHp6XAQAbmVlZVpaWlMAU1RSUlJVVVX_wAA5" + "8AHwAfAB8AHwAfAB8P-YylOU9TGiAGgBYjF6AY_x_wHwAfAB8CP9MTK7mFA0eWL_" + "YGZ8Mms0KgBolFr2ZfQB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw" + "AfD_AfAB8Kb4o8igOLABqzbFAf_UMV4yvTN4_ymdL80B8AHwPwHwAfABYPdinACZ" + "AMrK_sr9AqIwhQK3AJcycJIB8H8B8AHwAfAB8AHwAcBcZIMghIN-gX5cBGhpAGhZ" + "WFhTUlRQAFBPVFRU3t7e_zbwAfAB8AHwAfAB8AHwS_bHz2NWAVwByMjICQBuAf_B" + "ZZXxAfAB8AHwAfA3Yr8x_330GwCfAJcynADnNl2WIQD_zfjK-AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwVvSpmKZoU5T_WGK5AV8EFQCqMVNk" + "i2Ipnf8BYIHP9QEB8AHwAfAB8AEwB5MAnwCcAOXl5dDQANCpqanc3Nzg4ODg5OTk" + "WwsYANWW_wnzAfAB8AHwAfAB8AHwAQABXGSBgIF5eXlyAHJyZ2hnW1xb_7IIFw1c" + "NDbwAfAB8AHwAfD_AfAB8K9lTmbQPlABVgFcAfikpKRoAW4ByTOfPAHw_wHwAfAB" + "8AGQMTJAMgFgEGv_cWR3ZAkAYzauAGg0TGtllP9ilMf4AfAB8AHwAfAB8AHw_wHw" + "AfAB8AHwAfAB8AHwAfD_AfAB8AHwVvSp-CM0UzT-Ov8MBp8zngFQlJdoi2IZOAEA" + "_xswgWwJACSWAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8H8B8AHwAQBWAR0ByyUD" + "8P34_Pv8mgH6MjzwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwMQFMMgNv" + "wDb_gDQybYIyazQkAFYEvgIEBf9mOWA2wmrH-GL0AfAB8AHw_wHwAfAB8AHwAfAB" + "8AHwAfD_AfAB8AHwAfAB8Fb0VvSpOP-uNqY4lQEBAAwAGwAjnStr_2k_FQBFAGL6" + "AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfABYPsHXAF6AYkx_VAU_dwS" + "ODFKAQYA8Ts88P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8MTydJT_SjQT" + "O-g4awTWOAEADAB0Af96AWlpLz3BMmL0xPIB8AHw_wHwAfAB8AHwAfAB8AHwAfD_" + "AfAB8AHwAfAB8AHwVvT_nP8DNv46TQoJAHoBUzTQaBVm_1DEafAB8AHwAfAB8AHw" + "AfD_AfAB8AHwAfAB8AHwAfAB8AMB8AGQ2NjY3d3d53IH4UlbAfj5hAFTAesy_9w4" + "-gI88AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHw2fKRApcCRAHNMgZv" + "j1s7cQEPAMEI4uLi4gL_kQshMHcxQTdi9AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw" + "_wHwAfAB8AHwAfCAYV4-PgH_rJhWZHcBdAGpyFM0qT4VAP968Uj2ZmABYLMBAfAB" + "8AHw_wHwAfAB8AHwAfAB8AHwAfCPAfAB8AHwAZDT09NfBA87B8QF3wIBEOvs6uv5" + "CCDr630BawEbAJIBPPD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfD2MwEw" + "_2EyKPuFkicAwQJeC2WUzTjjFQBiAePj4-4CCQB0Af8pPYU75WJjMEjzAfAB8AHw" + "_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfBZZOczNWR6Mf9WNC8KZQEYAFPEBgAS" + "AFOU_wbPPmQ4neiYNjbUMQHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AEw" + "6AIB8AEA_yrwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfABwP95aAEAZDip" + "MmpooPKgki0A_z4EuwUObfw_xDgpPf0C4jj_XTDBmE7zAfAB8AHwAfAB8P8B8AHw" + "AfAB8AHwAfAB8AHw_wHwWfRZlK84SgHTAgI9dAH_UzERNN8FxzUjylP9U207NP85" + "AFcAAQDLAf0-ATBL8wHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AEATGL_WzKFOHc0Xj5zOLJi" + "tZKyYv8wACAKET1TB1cABgAPAMQI-Ofn53o0JAD2P6abVPP_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfCL_g5k_48BmwGpBVkEuwUMAB00CQD_1jW4leScQmCD" + "NE00RGQQ8v8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw" + "AfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfBxZGs02Tho9MSSJAAA5OTk" + "3Nzc4eGO4QkAWQQJAODg4MEI_3QETgBLACCdes0B8AHwAfD_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfBc9FYxKQFkODsB_1k0rAWLPsE1VgFTAXCe7vj_UPQB8AHwAfAB" + "8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw" + "AfAB8AHwAfAB8P8B8AHwAfAB8AHwaPTQOLsCD2XEDDNNB18Ezc3N0YEBIMzMzNra" + "2l80_0sAXzQ8kFrzAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwXJQjAXA4" + "NQELPa8F_7UFTQG7CBcKGABKkabIU5T_1PEB8AHwAfAB8AHwAfAB8P8B8AHwAfAB" + "MNIAfwIBAMk5_w8AkQLkMIVlHz5YNTMw-T__AQCXNZc7_DkgwRswxztaMP8JMDmQ" + "VjE8MBIzATBvMCQw_7lhGzCHMBsAUTMzYOg-ATD_PwDYADkAbDAB8AHwAfAB8D8B" + "8AHwAfAB8AFgiALX1wLX2wO-vr63t7dCrgFQpqamngFQqwSrqxhgvLy8wcH-wRQE" + "GgQdNwHwFzFlZMr4AzJnJADKysq5ubkAqampvb2939_-3774KgAa_QHwAfAB8AHw" + "_wHwAfAB8AHwAfAB8AHwAfD_AfAB8FnERwEpAcEyOwFWBP9HAakFsgVcBP9pATAw" + "kKb4_wHwAfAB8AHwAfAB8AHwQ_IfmfAB8AHwnDZVBbOzsxi0tLQOAYUC3t7eOMDA" + "wBEBUwTBAtbWItYkANDQ0NACv7_-vw8AEQHQAiQAEgABAN8C8R0BycnJDAAVACoA" + "jWD_CQBFABsAOQCvAkIDUQBaABE_MN3d3TkAx8fH4x4wNQrGxsbwDzMD4gIRYDDL" + "y8tCAMXFxYEMALu7u9XV1VcAwMPDw8LCwjAAUQD_MwAJAAEAEgA2ABsAxgBfNPGo" + "ANTU1IoDrgN1AF_0_wHwAfAB8AHwAfAB8AHAfALjKQHPA62trT5kAfAB8AMB8AEA" + "oqKir6-v_wIBngEyBx_yZWQUAYuYATAHPjc4AUsArKys2Nj-2B0NFgJfNKA1MwCS" + "NB39_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwCwEsNP9BAVwBZQGLAjsB" + "QQEYAwkA_zWaqcimAqn4AfAB8AHwAfD_AfAB8AHwE8i6ANc3gTYk8AcB8LKYcAJ3" + "d3c1NYA1MTExb29vPQJxYQIyMjIdAfwDCQCZRJmZFAFmZmYMADbgNjY_Pz8sBNID" + "DwDANzc3OTk5lQRIAAhDQ0NFADQ0NDo8OjoXBD4BYDBHBEhIEEgwMDA2ALa2tvEz" + "AOLi4gYDPwA5ACQA-EBAQHsAaQNUACoAeADHbAAnAGAweXl5hwN1AIF7ADg4OJqa" + "mgMDMWkAOzs7LwQ1BFZWRlakAbMEMzMzNjBd_F1dYAPUAWkDlgA2ABUA-ImJiY1p" + "AfAB8AHwAfCPAfAB8AGQCwHS0tIlBfinp6cg9AHwAfAB8AHw4wEAaATExMQJCZcF" + "x_gfLwHH-PNv5QXBBdnZ2f9fNOsFHTokY1_0AfAB8AHw_wHwAfAB8AHwAfAB8AHw" + "AfD_AfAB8Fn0tZjiO5cC4gI7Af9lAWJhVmSLO1b0AfAB8AHwfwHwAfAB8AHwjfbv" + "AZMDjwCPj3R0dHp6en-9BlQDLTwB8AHwAQDtAJ8En597A87Ozm5uEG5LS0tGAn9_" + "f_hCQkL_AAcIFATAAwgBODw8POcDIAQSAJCQPpANCCQAYQjBAioAuLj-uEUAUwSE" + "ACEAPANuAZM8B-EDFwT5A9PT05SU_pTtA2MAJzASAGwDWQT_A4EyBIqKilJSUvcF" + "gU0EkZGRSUlJ3gD_0gCLCMIEjwRQBx4A7Ac8AAg-Pj6WAJWVlWhEaGjjAY2NjWYA" + "z2DPz5OTk1owZgBbIFtbY2Nj7AGBgfCBUFBQPAB89QHwAfD_AfAB8AHwAWB4AJAA" + "WAUF9D8B8AHwAfAB8AHwATCkpH6kIDpi9GI0LgIA8xgA4fzh4V8EBgA-AcAALQAq" + "AP9wAtk7UQNi9AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfBZZLU4FAEaATUB" + "Dj1WBP9lAR06WTGs-Fb0AfAB8AHwPwHwAfAB8AHwH8I8A5ubjptjA0sDAWBgYGDt" + "Ax8bADPwAfDkAO0AZ2dnCFRUVHMFWVlZYYxhYQkAkwNlZWU9AvidnZ1UADQOyQaR" + "CGsEB_YDNAhuBIiIiF5ejl5wAmwAOwGAgICvCPEMALW1tTMAwwyEMFABOLq6ujMA" + "2wNHBHJyxnKUCFoAg4ODMACBADixsbEUBIEAAANkZPBkdnZ2hgEhAA4EKgDHswEM" + "AIkETExMEgZvAEcPAEgJjwROTk53BGr8amqKAOMBYgTBCAkALQA_UQB9B28AigBd" + "AwcChob-hs0IbwBc9AHwAfAB8AHwxwHwAQA7Ab6-vpMA9vN_AfAB8AHwAfAB8AHw" + "AQCq_KqqFwr3MmL0xJgGAIY3_1MEHg-DBx4_XzTrmF_0AfD_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfAB8PkwtTgOPSAB_-QJXAQJAFlkTTHHAiEAWgP_VvQB8AHwAfAB" + "8AHwAfAB8McB8AEA5gHKysorCFmU_wEw8wM4NENiP_BcZEAC2AMfCw09AqgDhQIw" + "AD09Pcf8A0EBMgRBQUEUATIEI8UEOwG7u7ufDOPj4uMIBHt7e4Y9TQGMBIhYWFho" + "AZKSkoQAj_AGFQBjACEAoKCgRQDHKQSFCCQAhYWFkgHRBMcLBB4AZwhcXFwaBN8I" + "H0EEEgkeAJYADACEhISPxzLINBo0MwB-fn4zCccsBLoDjQClpaW8AbwE-HBwcDwA" + "4A3xCMsB1ATHigCxAB4AU1NTrjAO8T8B8AHwAfAB8AHAjgWtrf6t5PMB8AHwAfAB" + "8AHwAfD_AfABAJINLwRixOMBMgESw_8PAMUB7AEBAF80JwBfNB09_1_0AfAB8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8Fn0ujkCAf8OnVABPW5WZDIBVvQB8AHw_wHwAfAB" + "8AHwAfAB8BCS4AGPBQ1Z9AEA1AfBwcHwAH_VAN4ACjLkANvw8ABnBUh8SEgODRQB" + "HQEGAMM8s_yzszYA0gNACE0BzAyuDANLAJ0CVVVV5-fnwE1NTZqamkEBRQDjdATP" + "A3V1dXQB2wNRAI-lP3IARQBiDXFxcR4AeMzMzBsAGwxmAAkAc4xzcws0wgRra2tf" + "DfHUBK-vr7ABewnGAK0NP8ECLQD1BMhkAQBWBGJi4mIQBcTExCwNBgDBCD90DZgE" + "kACzBLkEWgCcnP6cDgHZC24NTgCuME3xAfAfAfAB8AHwAWAwCampqf_V8wHwAfAB" + "8AHwAfAB8AHw_wHAeQWUCGL0-Twbk4ABXwH_sAoGACoAJMAgnYTzAfAB8P8B8AHw" + "AfAB8AHwAfAB8AHw_wHwr_hWNOQ5IzFBAUs8GjH_eDMFbR4wK_IB8AHwAfAB8B8B" + "8AHwAfAB8ApioaGhx0IMGwxf9KenpwIBdQOIkZGR_geMjIzSA48S_A8ADgHkAzs7" + "O4ED_wwAEQHwDGcITAIgBAIEJwMfSwAkAAEAXAE0CG1tbeOXCMcIycnJEgA2ADwA" + "j0IJoAgqAGUEbGxsbjEjXzSyCJaWlj8AubkQuUtLS64M4ODgR-0D0Q1vAF9fX3oN" + "aeBpabS0tCYNgAS2AR8qAMYAYgekAf4ET09PH9IAbADWAj8AlgCKioo_bgQVADMA" + "EgCKADAAsLD-sNUAGQXoCC0AIQCtBIQA45YMHgC4uLj4AU3xAfD_AfAB8AHwVjST" + "AMnzAfAB8P8B8AHwAfAB8AHwAfABYHQB_8sBVWIBACOdJGPOAUoKaAH_X2RFMyD9" + "YvQB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8Fn0_1k0AgGUAjUBSzM1YQX9AfD_AfAB" + "8AHwAfAB8AHwAfAB8D8BkMU6QwjMA1zESAOxsfCxNDQ0FZBoBDAA6sDxGgHFxcUe" + "AEQEFzHvBwdgDCcA2AY8PDzDww7DKQG3DKsD1NTURgBGRpWVldHR0T9dAC8EuQSZ" + "DHMIQgBhYcZhEgB-DMjIyFcAvDT_nwASAI4IGwkNBXMIuwJXCfg3NzeKA6wCbgTO" + "BB4A8aYIQEBAfwu8AfcCUQB_QgmxAP0ChwChBKcNWgDdRN3dvwSysrKQAI38jY1o" + "BAgBYAAwACUOMwCPCQAmDfgBbABaWloJAIijo6MVANPT0yoAP0fxAfAB8AHwAcBm" + "DK6u_q698wHwAfAB8AHwAfAB8I8B8AHwAfB3AcLCwsEF_yP9g5c7Mc4BKjBOA38y" + "X_T_X_QB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8FnEFzFZNLI4_1k0r8gr8gHwAfAB" + "8AHwAfD_AfAB8AHwasi9APgByz0GAMdhCEgDRGQ_Pz9sA5ADfyNtAQAMMAADvMdR" + "AE4AZOBkZGBgYBEBNQHDDOPJAzECwMDAnQiUCLQG4wIE3AhCQkIbAHsPYAB_GwDe" + "A88MDgTbM94MRA1X4FdX5ubmWQHhNnoEf_8DWAiaCIkEyQyeAe0DRwRHRyEA0NDQ" + "TEziTDIEcHBweAAaDd4AP6EBVwBgAMoCrgAeADg4AjiiCXx8fM_Pz_i_v78yBD0F" + "yAQ2AJAA__IBNwWvCKgApwSKALEJ2ADxCAF4eHgWApUEvQBOAD-3yQHwAfAB8AHA" + "dQC9vf69tPMB8AHwAfAB8AHwAfAfAfAB8AHwAZBvCdXV1f8Zm8HIX5QSBj8PTQEh" + "AIIC_yEwX_QB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8Fn0WTR-M__oMsZpbjQXAa_4" + "AfAB8AHw_wHwAfAB8AHwAfABwLcAygL4y8vLWgNFAwYADADqA__8APMMPjSTAxsM" + "5wMp_QEA-FVVVUIAY8MRAR0EgATHTgBMAqcEhoaGVACrDPhNTU0jAXYCnANCAzUE" + "4w8AYgGCgoKmCGUBAQD_DwCEDHgASAAkAJEIUARWBDGxMLu7u24EQgBlZeJlXwSO" + "jo5aADsEPwCBvwStra1iYmI5CYhqamohAJqamk4A_58ApATsBAkAJAD3Ap4EDACP" + "1wHgAV8NUwS6urquCX_PAB0NUQD3CLYEHgBUCTMcMzPvBIQApw2qqqr_ogBsAHoN" + "E_4B8AHwAfABkPHYAKKioqvzAfAB8AHw_wHwAfAB8AHwAfAB8AHwAQD4tbW14wHB" + "mD5kAQDoO_8bAHMCAQBJAiQA6QHhNl_0_6LzAfAB8AHwAfAB8AHwAfD_AfAB8AHw" + "WfRZZCABZAVZZP8I_QHwAfAB8AHwAfAB8AHwHwHwAfABMPYDSQhWVlZ4NTU1LGQM" + "APgH3wLc_NzcVAMMACII9gB1A1n0gQEAOTk54ODgbTUftTgpAREBeAwUBKurq48S" + "APYMzwNTAX19ffAD41ABcwI9PT2xA1oAOwHxJwlFRUVfBPkDfzInAPh5eXkzAPkD" + "UA2_ZF0Ax6EEUwSrDGNjY1kNOQn_ngFQBF8EMADVDJEIiwgeAB-0AC4FMwC4AnMI" + "fn5-f68yuQTvBBo0EgBpABIAvny-vlwEHQ0UAcAAPACYxJiYUQB0dHQtACcAj9QE" + "EAXXDf4BQ0NDFQn_FQDy8QHwAfAB8AEAVwDQBf-f8wHwAfAB8AHwAfAB8AHw_wHw" + "AfAB8AGQUwqtASD9P5P__AC-CAEACgJf9F_0AfAB8P8B8AHwAfAB8AHwAfAB8AHw" + "_1n0WcT5AAs9GjGfAwwAWgP_WfQB8AHwAfAB8AHwAfAB8H8B8AHAwAB4A_cLL_QB" + "MKg8qKhmA2IEKgD7AczMgMysrKxoaGgnwI9vA0cEXDQFAeTk5E8CB4EDOAQbALm5" + "ueLifuJNDYEPRAECBE4MXwGZYJmZT09PSQJKNNfE19dLAJycnFw0SgTAU1NTm5ub" + "KgC3DP-lDCQAXzGMAYMEpATgBzoI-E5OTuEMfgBOAKMIMAAfWQRfBHgA5wydCNPT" + "0_GnAdvb2ygF5QI_AGAAeFhYWNsM2ABfNGAApfylpbgInwDIBLoA5QKtDQiysrI8" + "AFlZWYkEiYlaAJ-fn0pK_koLAUwFOAEzANIAWfEB8P8B8AHwaAGv-AHwAfAB8AHw" + "_wHwAfAB8AHwAfAB8AHwATD_VQ7XAV9kswGKP19kGABfZP_9PmYzX_Su8wHwAfAB" + "8AHw_wHwAfAB8AHwAfBZ9FmUvTn_C20BAFlkVvQB8AHwAfAB8P8B8AHwAfAB8AHw" + "1QDyAVP0_wFgDAwLAVg4AQAEAg4B8wB4kZGRJ5DhAzEyCTm8RLy8OQzd3d3zAzrE" + "OjoJAMHBwd4MkAOBlgNLS0umpqZXAP9iDbQMUjLmNEsAPABCAFAB8a0EQUFBDg11" + "AMwMUA1fdAS0b7UIhwOtBEcBIOX85eVdAL8EWAiuADAAjw0_GQWpCCkEkQtFAHM4" + "2Nj-2AwARAdsALkEAgHlAiEAeFFRUZwJ-A11AMg0zsTOzjAA1NTU6AJlBP9oDRAC" + "0QR9BDYAcwXSAKdtjwHwAfAB8AGQw8PDjQn_AfAB8AHwAfAB8AHwAfAB8P8B8AHw" + "AfAB8AFgmAF7BsFoH19kTjMNMo8BAQDq6ur_JAAhMF_0X_QB8AHwAfAB8P8B8AHw" + "AfAB8AHwWfRZlPkA__MATwIOMQYAhQJZ9AHwAfD_AfAB8AHwAfAB8AHwAfDdYYHP" + "AJCQkDQ0NFn0-G9vb3gD9gANAvUHSAP_JgQwABQB8wCNAypg3QcOAeNUMAIEl5eX" + "Rw1HAUQEH5YDLwHvN0cBQgA4ODgIxcXFMABbW1uHHIeHMjQGALIIMTEx_1UCegF1" + "AJgEMg11AOoGfAiPcAgUBBg53gxUVFSNAz_wA34ASACGAWgEmw3Z2cbZHgAwANDQ" + "0DsEHgD4ZGRk6zgPAIQAwABIAP-gCBsARwelADwAcQSzDXsAf7EAGABBBPsBaA2k" + "DS0A0fzR0SUOUQDvAQkJtAA2AP8hCTAJnAD78QHwAfABkLwE_2wAh_MB8AHwAfAB" + "8AHwAfD_AfAB8AHwAfAB8AHwywGiCf9flIMBUZOBBnMCX_Rf9Lrz_wHwAfAB8AHw" + "AfAB8AHwAfDHAfBZ9Fk06enp6gAaB_8FAc436wInPwHwAfAB8AHw_wHwAfAB8AHw" + "AfAB8AEAzwARzADHx8eLCHBwcAhra2sGAIqKirUMtbXbAMgHbGxsRBxERLcDATCo" + "DIuLi4HwDHp6ei8vL3UDf34MXjVRMCYE7Qx-DGIETTxNTXgMSgFcBC0AkpLwkmNj" + "Y7oMRwECBDsExxgAVDw2AH5-fiQA2AP4lJSUYQJ2CIgIXgJfBP8YAA4EqACxMBIA" + "PABoDVcJcRsAbW1tYzAkCe0Dz_zPz3AIOQDGAB4AIA05AIFgAHV1dVdXVz8AB9QB" + "GgQbAHFxcYyM_owqAC0JdwTjAVEwqAABAviOjo5zBTAJUAS_BHsA_5YAqgTAAKcE" + "dwRgAFoA_vGPAfAB8AFgRQOkpKSB8_8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHw" + "ATCtATsKAjH_MDZLA1djpAEiApcOX_RfxP-68wHwAfAB8AHwAfAB8AHw_wHwWfRZ" + "xPAACj4GAMM5WfT_AfAB8AHwAfAB8AHwAfAB8P8B8AHw3WHVAOoAwgEGP4oD_wIB" + "bgRpAwHwAQDYDE0NogP_lQRyAzYATmAMAKIMeAO3DB9CACg4KwKxA6cEhYWFf1sI" + "YABcBBIAMQi4NVMBscSxseoDgICAlQQVAI-XCOEGCQDkBpOTk1QA_3QB4Tb_DOUI" + "DwBrDTMAnwz_rgAgBNw4tQKcACcAUA0eAMfQCMgBDwCqqqoxBecAEX4Av7-_EwWC" + "goL4iIiIsQCUCB4AGABRAPEYANLS0v4BUQDGAJAAH-wEoQ2KAF0AGwB7e3v_ggVA" + "BTkAkzD_kAHwAfABYP-jBWYDe_MB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAZD_" + "pAEGBl_0qgHIN28DPwZf9P9f9AHwAfAB8AHwAfAB8AHw_wHwAfBZ9Flk2ADqALo2" + "DwD_WfQB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8CydDwDmB1b08QFgp6enLAERAQXB" + "DwBx-QzU1NR3BLQDUQzMYMzMxsbGDAABANcc19cPYFkE-QzKysqIzc3NFQDJyck2" + "AD96BAYAWQR5AiYEGDDV1f7VSDAwAC0AGwA_ABgA6gMPRQAYMAYAXWDT09PO_M7O" + "MwAnAC0AFQA2AAEA_w8AGAAJAGkwPAAeMCoAYwD_sQAbABgAJwAvDRsADAAPMOM_" + "MCoAy8vLdQAwAAYA_7oA3Q0VAEgJCvIB8AHArgD_YAMlBQHwAfAB8AHwAfAB8A8B" + "8AHwAfABwLCvr9Yj4CEPMLq5uQ8Av73-vSrwAfABwMUBX_SyNRIA_9UJ1gVfZB4w" + "X_TG8wHwAfD_AfAB8AHwAfAB8AHwWTRcNP-6AMYGqAZHNN4AbQtZZKs2_0_yAfAB" + "8AHwAfAB8AHwAfA_AfAB8AHwAfABMOQAmJjGmFP0ATBMTEyfAxoBIznwOQB5eXlO" + "DHR0cHRoaGgJAKsM8AxcfFxcUw1EDfUHxgwJADfENzcJAFJSUiQAYwxHfgx7DBgA" + "RkZGdw1VjFVVGABcDWFhYR4AjxgAIw2fDBUAODg4OQDAXV1dNjY2DwAPCY9dAPwM" + "VDCtDVhYWBgA_zAACD0MABgAhAA_MAEwLQCPOw2zDeQMDwA_Pz9-AI-zDSoAsQAY" + "AF9fXzlg_2wADACJDRgAIg54AHIAMADxewBAQEBGDn4GEPIB8P8BYJsEvAds8wHw" + "AfAB8AHwPwHwAfAB8AHwAfABMNHPAM_p5-e-vb2rBKqqCQDg3d2hof6hJ_AB8AHw" + "DAZfxKAIeDP_dQO7CF_0mQOfA6UDXDRf9P8B8AHwAfAB8AHwAfAB8AHw_1lkEAVZ" + "lNALwQs9AjYD9gD_EgDXN_kAAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AEAAd48" + "urq6f39_UQxRUYcDqwNCQkJn4GdnoqKiqAz7MTbwASYBcnJyLi4urTytreQDCQA_" + "AKQHgYHGgQwAAQB3d3erAwkAcasDlpaWVwAMAMkDuIy4uF0ADABBQUHXBP_VAwwA" + "XATdB1wEDAB0BOcDAwkA_AO7u7t8fHyPDAAjBM8Mng2oqKgkMMdIAEIADABiYmJ_" + "COMEgXgwiYmJR0dHDDB_ATAPADkA1QAMAIcAsQBeBF5eDABKSkqwsHCwTU1NJzDI" + "DTkwVMRUVGUNMTExDABNDfigoKBsAHQE_g1cNBHx_wHwAQA8CWPzAfAB8AHwAfB_" + "AfAB8AHwAfAB8AGQSgTf_N3dVgQGMGIEJPAB8AHw_wEwDgpAYl0DXzTCN3sDAw_x" + "XzTr6-seMF9ku2hf9P8B8AHwAfAB8AHwAfAB8Fz0_1mU-A3eAM8A1QA3AllkXT__" + "MfIB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8CaUAQCoORAO490BQgbj4-MLAZUKBQHH" + "M_BclFsIk5OT4weHA_8NCPkDlwirMyAEGDAxCKID40Q0EAilpaU1BAwA1QMfEWQD" + "CdgG5zMrCGpqahEJAEtLS1xkPj4-cRQEtra2QgAPAOcDn4yfnyEJDACKiooYAP-w" + "NH84qgRclH8IOARcNEgAPy0JGDCwBP0IbwAkMHt7hns5MF0Abm5uMAEg-IeHh3kF" + "YwAYAL4IyDr_EfEB8LANXfMB8AHwAfAB8H8B8AHwAfAB8AHwAfDTBenE5uYDAL68" + "vB7wAfD_AfABYMMJBwvVll80BgBWAfGBA97e3n8CiAJfNGQC_58DX8TS8wHwAfAB" + "8AHwAfD_AfAB8Fn0aQnODT8D2wDGAP9OA88AtThZNPs6NPIB8AHw_wHwAfAB8AHw" + "AfAB8AHwAfD_AfAB8K06CwEBMELzLcAmAQMCBM4Hg4ODMjIyH3sDlgyTA0YIujNl" + "ZWV_CTAHCLQMDDAxCCQADDBJ4ElJUFBQDDBlBCQAH4g4Jg1AOAYAlQRWVlbjDABR" + "CX19feoDCQDINP_FZDkAOwT0OIoAgWABYFcJx4gIKQRENGBgYBgwCQAxNQRDQ0MM" + "AKYIZGQeZBgwzg1xNFA0jo6O_4MEDAAhAFz0AfABAMAJWvP_AfAB8AHwAfAB8AHw" + "AfAB8B8B8AHwAQBTBFw00M_P_x7wAfAB8AGQngodAXBiXzSPdQN7A4ED2wbd3d2N" + "A_9fBCQAHgCfA18EqwOxA1_0_wHwAfAB8AHwAfAB8AHwDv3HnwBZlNUA5OTkkwnJ" + "AP_kAOcwWfQB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfAfAfAB8Pgx0gZZBJGR" + "kYECBIKCgoSEhOQDfwYADAAYAPwDCQABAAkAkPyQkBIAJGAYMC1gBjCVDf8JMBgA" + "LWABMC1gDDABAGUEf3gADwBpMFRgYJABYJ8AjfyNja0NVGAYYEUAGGBIAON4MBgA" + "j4-PDAABAHgw4xsAJwCmpqZZ9AHwfQf9QgObAfAB8AHwAfAB8AHwHwHwAfAB8AHw" + "AeCqqakA6Obm39zc0M7izgkAvby8JPAB8AHw4wGQZA7f399flHgzGj3_GwBBAZMz" + "IQCNA6UDqwNfNP8a_QHwAfAB8AHwAfAB8AHwH7X4Dj0GDDQFwwDl5eX_5ADGALJo" + "-QBGBQHwAfAB8B8B8AHwAfAB8AEw2traAaYOwcHBs7OzrMcBsKwLGADS0tKpDjnw" + "_wHwAfAB8AHwAfABYBI_FgL_Uz0EAgEwD2AJYCTADDABkP8VkAzAujY8wFTwP_AS" + "kC1g_5nwGPBd8BswPD8B8AGQjAH4oaGhUfMB8AHwAfAB8AcB8AHwHwirq6vExIDE" + "2NjY29vbYzz_sQMMAEwCSQKcDDbwAfAFBPje3NxTBGIEDJAq8AHwxwHwAZA8D-np" + "6ZYAaQPHvmjUN40D3NzcYgQJAP8kABIAZzIa_QHwAfAB8AHw_wHwAfAB8Fn0Dj2o" + "AK8CKwLjGQUNAurq6t6QWfQB8D8B8AHwAfAB8AHwdg7MzCLMAQKWlpY4B5SUAJSk" + "pKStra27iLu7wwGwtbW1GAD_SQK1C1kH_gFuBNAOVPAB8P8B8AHwAfAB8AHwAfAB" + "8AHw_wHwAfAB8AHwAfAB8AHwAfCPAfAB8AHwDAOnp6dL838B8AHwAfAB8AHwAcAw" + "CcLIwcHk4Q_q6p_wqJAxZAKioqJC8AGQvbuAu9TT07i3tw8wiKmoqA8AysnJKvDH" + "AfAB8AHAuLi4jTBfNP_aZ40DBzWZAwwDIQCiD6sD_7EDtwMa_QHwAfAB8AHwAfAf" + "AfAB8A79Dj3JAOLi4v-1aAEAxgBuBIzxAfAB8AHwBwHwAfDvkcnJyaOjEKOJiYkG" + "AL29vT-yCJkAAfAB8AEAkgHQ0MbQbgS2AYuLi9YI0Aj_ZvAB8AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8AHwHwHwAfAB8AHwAWC3t7f-mgHwAfAB8AHwAfAB8AGA" + "IfgBurm53VsI5-f9XgjprAhf9AGwsgvcCJwGf07wAfAB8AHwAfAB8AGQzfzNzYow" + "dQN7A4Qzu2gBAP-fA3UJgT8a_V_0AfAB8AHw_wHwAfAB8LX4Dm3GAFwBtTj_2AC9" + "AAYAsjgSAAHwAfAB8AcB8AHwAfDZ2dmwsPCwh4eH8wZuAYg-AfCPAfAB8AEw7gXF" + "xcXDBviTk5OkBOcAdfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHw" + "AfAB8P8BwLwBP_MB8AHwAfAB8AHwAwGQhg3Z19fk4eGQ6ebm5wMA5eVfBADg1MvI" + "nn--hoBeuX1QtXNCCQBAxJRx2cW2t8DX_NfXwQhU8AHwAfAB8AHwxwHwAWDXBN3d" + "3YQAvjgfh2MSAJkDGAPBCOPj4__BAtYCsQMa_erzAfAB8AHw_wHwAfAB8LVoDj34" + "BA49wwDx2ADk5OQWNQEAsjg08n8B8AHwAfAB8AHw1wHVDJDgkJDBwcGgBSb0AfAP" + "AfAB8AFgtQ6urq6I_IiIgApxBIHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB" + "8AHwAfAB8AHwAfABMP9MAgH4AfAB8AHwAfAB8AGQALGwsOXj4-fkBuQDMFYEz6yU" + "t3QAQtGlhObPvfU86-QGMwkADwAVALBmgC_Gmnnn5OK9YMDi4eGqqqr6CF3w_wHw" + "AfAB8AHwAfABMFAH_Db_vjiKM5MDmQO4C18ExALHCP8BOBo9uzjPA7v4AfAB8AHw" + "_wHwAfAB8LWYDs29ALU4hAn_DwAGANIANPIB8AHwAfAB8IEBwOHh4bKyslgI_5UK" + "VjEB8AHwAfAB8AHw-gUAtLS0ioqKu7v-u4rwAfAB8AHwAfAB8AHw_wHwAfAB8AHw" + "AfAB8AHwAfAfAfAB8AHwAfAeA6ampv6ZAfAB8AHwAfAB8AHwAVBAwL-_5uTkA2De" + "ANDGvH1P4MGpOPv17wPwA2AhALVvUDrVu6i9AOm-AOby5l8UqakfBWPwAfAB8I8B" + "8AHwAfABMMLCwkcxj4EDjWO7OH0H29vbLQP_Gv0abfDzAfAB8AHwAfAB8ONZ9A7N" + "8vLyqAC0AF8E99gDyQBZZOkB8AHwAfAB8CMB8AGAvLy86gO6uv66UDEB8AHwAfAB" + "8AHwAZADqgEAA6SkpMzMzP-T8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw" + "AfDHAfAB8AGQwMDAM_MB8B8B8AHwAfAB8AEwn56eCNHPz1mU1r-vuQB1QfLfzvbn" + "2AcD8APAJwC2bjjJo8aGWQQ_MN3b2x0NafB_AfAB8AHwAfAB8AEwMAnc_NzcRwFf" + "ZAEAmQOfA7gI_18EFAoabb0DGv328wHwAfAfAfAB8AHwXPQOzeLi4v9sCa4wyQAG" + "AFn0AfAB8AHwBwHwAZDRBLCwsKWl_qV-AP_zAfAB8AHwAfAB8BEBYM7Ozi0Jtra2" + "_5zwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8McB8AHwATDe3t7cCzPz" + "PwHwAfAB8AHwAfABAKmogKjd2trm4-MDMADn5eXczMCyZIAo7tK58NW9A_ADA_AD" + "AO3QtrFfIRjKpotKDUUww8PD_-oDb_AB8AHwAfAB8AHwATA_ug9NMYcDk2OfAycD" + "1dX-1WIEGgfVPxrNXPQB8AHwHwHwAfAB8Fn0tcjx8fH_YwOuAAoFET3GACUFXPQB" + "8B8B8AHwAfABYP8Mi4uL-L-_v_PzAfAB8AHwAfD_AfAB8KQB5Q7jBOkEpfAB8P8B" + "8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD9SgGYAfAB8AHwAfAB8AHw" + "AJiYt7a25OHhGOXj4wMwFATk3dkArVsbzpBe6sIenwPwA_ADYDMApUsFCNS9rEsw" + "5OLiqfypqV8EdfAB8AHwAfAB8OMB8AEw0dHRXDSNA1804wwApQPW1tZfBNkIEAj_" + "Gj3DA7v4_PMB8AHwAfAB8P8B8LX4tTi0AKUAVwNjA8Yw_wYA1QAlBQHwAfAB8AHw" + "AfABAQC5ubmWlpbY_NjYbwAB8AHwAfAB8AHwDwHwAfABMMcLjIyMyvzKyqvwAfAB" + "8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwjwHwAfAB8AGQzc3NJ_M_AfAB8AHwAfAB" + "8PYDycgGyFZkWRTm5ujn5wDBjGKqTADTkvBa46-AA_AD8ANgMwAAqEsAq14g498C" + "3lEw0M7Onp6ef3vwAfAB8AHwAfAB8AEwo_yjozsEUwGNA5ljpQOrAxjS0tIaDSAK" + "5eXl_xA4u_j88wHwAfAB8AHwAfABtcj39_f09PTwjPDw-AThA-Hh4cYA_8g3sjg3" + "8gHwAfAB8AHwAQD_hAywAdQE5PMB8AHwAfAB8A8B8AHwAcAqBo6OjsX8xcWx8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8A8B8AHwAfABMOTk5KD8oKAn8wHwAfAB" + "8AHwAcAApKSk2dfX5eIO4gMwuxgJAOPj3NAAxqxQBbBPAMfgdjLbm2AD8APwA2BA" + "x3czr04AXwTLxKiNVzDh4ODV8AHwHwHwAfAB8AHwAZDLy8s_XDSTA5wzDwCrA7gI" + "09Pw09ra2gwAuzjJA88D_9UDu_gB8AHwAfAB8AHwXPTxtWjy8vLyBJ8AEQ0WAn_A" + "MLX4AfAB8AHwAfABYLT8tLSUBSc5AfAB8AFgNgD9QQ24AfAB4CcALQBC8AHw4wHA" + "DwaSkpLECLfwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AEA8MPD" + "w5cB8AHwAfAB8McB8AGweg3i39-0DAPwAMORaLFRALVTAAC5WAbShD3VfIhCA_AD" + "8AMALQAzALUAUgCtTwCxajDjTjCtBKysrIHwAfAB8P8B8AHwAfABYD0Fu5j4N6sD" + "_7EDCAe7OA8AHgDJA88Du_j_AfAB8AHwAfAB8Fn0tTibDeO1aKIA3d3d6gPaPVk0" + "P9IAAfAB8AHwAfABwLW18LWoqKhjAG8AAfAB8IEBYFRUVH5-fnML_7UFAfABwCcA" + "LQAzAKAOOAofeAD9NQHwAfDKDpWVlf--CL3wAfAB8AHwAfAB8AHw_wHwAfAB8AHw" + "AfAB8AHwAfDHAfABwGsBnJycIfMB8B8B8AHwAfABYNEHwL-_B6YIA_ADMLdqKLdV" + "AAC7VwC8VwDAAF0IzXIiz3YnHwPwA8AnAC0AMwC7VgAAs1MAqE4A3dP-zAw5qwZ1" + "AIrwAfAB8AHwxwHwAfABYMzMzF-UoAL_qwOxA1wEu2gSALv4X_QB8P8B8AHwAfAB" + "8LX47ASWAIoD_1o5ujBZ9AHwAfAB8AHwAQDAurq6oqKiCQDS8wMB8AHATU1NWVlZ" + "fb4CxAHwAeAnAC0AMwDUxNTU8g3f39_qAF_0xwHwATBwBZGRkZIKw_D_AfAB8AHw" + "AfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AGQ8MHBwZYB8AHwAfAB8McB8AFQSw_P" + "zs5Q9ANgAOHa1rJTAL5ZIADCWwDDAzBcAQDHYgjKZw_KaOYQA_ADEGcPIQAnADAw" + "AMFaALlWAK5READQs5xUEOLiyvzJyecDjfAB8AHwAfAB8OMB8AFgp6enXzGPN6UD" + "AwwAFz3Pz8_W1tb_aAS7-Lv4AfAB8AHwAfAB8CNcNLWY8fHx7ATb2-LbSAPi4uLw" + "M6IACQB_hwMB8AHwAfAB8AGQaQydfJ2dbABmAAHwAfABwEogSkpSUlIyBGNj_GNb" + "AfABgCEAJwAtADMA-Ly8vGsE5QVfZAHwAfD_AQAzAB0NGAbJ8AHwAfAB8P8B8AHw" + "AfAB8AHwAfAB8AHw_wHwAfAB8AHwATAdCt0BG_MfAfAB8AHwAfBpY9vZ2Rjj4eED" + "8ANg2ci5ALdXAMJdAMhghADJA7DIXwDHAzAeXgMgDCAVACfAxl4AAL9bALFUAMii" + "_oBRAFwEzgRc9AHwAfAB8P8B8AHwAcBEBGIBfGsJAEUDgbcDzs7O0tLSu5j_1QPb" + "A-EDuzhc9AHwAfAB8A8B8LX4bwC1OPPz8-_87--rAFcJAwz4BHU5BgD_N_IB8AHw" + "AfABwAUBaQxsAI_G8wHwAfBcNFFRUTUE_030AfAnAC0AMwAqD4YNXwQfvgjfNQHw" + "AfABMMLCwvi0tLTM8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfCPAfAB8AHwATDI" + "yMjgAT8B8AHwAfAB8AHwAQC3toC24d_f4-DgA_BBA5DWv6u7WlkUznBjANBkA_AD" + "8AOgzwBkAM1iAMNeAEC0VwDGnHdUEOHw4dLQ0OQDk_AB8AHw_wHwAfAB8AGQxAJl" + "MaVjygLHSwN0BLs43t7e3DLVA__bA7s4F_0B8AHwAfAB8Fz04xE91AT19fW1OP4E" + "XAT_0QdcNFk0gQYB8AHwAfAB8IEBkK-vr8rKymYwHwHwAfAB8Fz0AQBVVVUePQEg" + "CQBc9DMAo6Oj-Kurq74I3QTfBVfwAfD_AZDXAcgNz_AB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHwjwHwAfAB8AEApqamFfMPAfAB8AHwAfCYmJjI4MfH4uDgAzBiBAxg" + "AQPw18SzvFwAy4BkANNnANZpA_ADA_ADoNVpANBmAADFYQC0WQDGnuJ5VDDQ0NC4" + "CJnwAfD_AfAB8AHwAfABkNcEYAxlAY9fNFw0twO9A8zMzAYA_7s40Ai7OOED5wMX" + "_QHwAfCPAfAB8Fn0ET339_e1OP9dCVcJ9QRRObEADj038gHwxwHwAfABkLm5uT0I" + "uvMPAfAB8Fz0QZRAQEBNDwEgCQAbwFw0oaGhqoyqqoEAHwLg4OBX8I8B8AGQfwXr" + "C8vLy9Xw_wHwAfAB8AHwAfAB8AHwAfB_AfAB8AHwAfAB8AHwAcDZfNnZEvMB8AHw" + "AfAB8KHAoKDV09PiUAQDIDjg3t4MYAPwAwDc0ADHvF0AzWUA2MBqANxtAN0D8APw" + "AQOA22wA1GkAxgBiALNYAM2vk_FUMM3MzLj4AfAB8AHwxwHwAfAB8L29vVw0pQP_" + "BDi3A70DmgK7CMkDuwghAP_VA7s45wMXPV_0AfAB8AHwBwHwtcgRPfLy8u3t_u2i" + "ALAN8mS1-AHwAfAB8OMB8DEInp6eG2kB8AHwRwHwXPQBAExMTFYEWP8BIAkADwBc" + "9Fz0AfAB8AGQ_8AA-gjY8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8MMB8AHA" + "u7u7lAHwAfAHAfAB8AGwrq2t3tzm3KkIA0De3gxwA_ADUAC8aBXMZQDabcAA4HAA" + "43ED8APwAQNA4nEA328A1QBqAMViAK9XAPjZzsVRMDYJXASf8AHwHwHwAfAB8AHw" + "AcCgoKA_azEHaPYGvQO4CAEA1NT-1NkIEgAbANsD4QMXPbv4fwHwAfAB8AHwXJS1" + "OCoJ9AD09PDw8Ovr6_9pA28DkzAQNboAAgQB8AHwxwHwAfABYLKysl4FYAAfAfAB" + "8AHwAWBc9EhISH9WBBIAAQAJAA8AXPRcBKngqam4uLjtAEcKV_ADAfAB8LOzs7-_" + "v__b8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAZB_PAYP8wHwAfAB8AFg" + "zAO_HL29OPQD8APwxItUAMdkANltAORy4ADodQDpA_AD8AMgBOZ0jxTSagC_YJAA" + "tG0nrXS7u1z0fwHwAfAB8AHwAfAB8AEA1fzV1WsBpQNgPLcDvQPWAgDKysrR0dHY" + "2P7Y0gMYANsD4QPnA-0Duzj_XPQB8AHwAfAB8BFtyAQRPcDu7u7p6elRCZIH8UsJ" + "4-PjkwABADTyAfDHAfAB8AGQx8fHNwiu848B8AHwXPRclFRUVKwI_loBgA8AFQBc" + "9Fz0AfAB8OMBkDkAm5ubvAHh8AHw_wHwAfAB8AHwAfAB8AHwAfB_AfAB8AHwAfAB" + "8AEwlAuTHwHwAfAB8AHwAVCcnJx4z87OphgD8APwA-DUAL6qvmAA1GsAAONzAOt3" + "AO55HADvA_AD4CcA6HYAAN1wAMxnALZcMADCmXBOMIYNqqn-qd4DqPAB8AHwAfAB" + "8AHw8QHwurq6cTGuM7cDvQOBwwPIyMjNzc16BPjd3d0eANsD4QMXPfMDPxf9AfAB" + "8AHwAfARzfX18PXx8fE2CTADEwJLCf9cNLI4CQAB8AHwAfAB8AFg_9gDxQQOMQHw" + "AfAB8AFgXMT4VlZWWZQBMBUAXMRNCsCoqKi3t7fwAO0AH1fwAfAB8AEA9wu-vr7_" + "4fAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AEw-LS0tAnzAfAB8AHwAQDh" + "wwOop6fahgfVIwPwBwPwA_ADAMCBQchmAADccADpdwDwwHoA83wA9APwA4ADIQBc" + "BOV0ANRsAAC_YQCuYhLd1-LUSzDZ19eZCavwAfD_AfAB8AHwAfAB8AEAJgdxMR--" + "OFw0wwO_BxgM09PT8SMN4eHh2wPhA-cD7QP_F_0B8AHwAfAB8BH9EW2fAMDJycnX" + "19eSB1z0HwHwAfAB8AHwrgmvr6_fqPMB8AHwAfBclFwBIAJt_wFgGGBc9Fz0AfAB" + "8AFgKQH_TQe8AefwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwfwHwAQAXAQnz" + "AfAB8AHwlwCXl7e2tt_d3R7gA_AD8APwA4DVw7MAuGEFzmoA4HMAAOx5APN9APco" + "fwD4A_B_GBD1fgAA8XwA6HcA2QBvAMVlAK5ZABjGpYVLYJMAlZWVP67wAfAB8AHw" + "AfABwMPBIsF1ANbU1Bvw2dn-2VyUlALDA8kDuwiXCxcN_xIAGwAX_Vz0AfAB8AHw" + "XPTjXDQRndzc3OwEmQC4OH-uAL8NAfAB8AHwAfABYK38ra1PBe0AAfAB8AHwAcAB" + "XJRkZGRfX19gfQEgYQEgDDAVABsAXJSfxJ-fXDTOzs41ClfwjwHwAfABMJUKw8PD" + "5_D_AfAB8AHwAfAB8AHwAfAB8H8B8AHwAfAB8AHwAfCLC5J_AfAB8AHwAbCvCKQE" + "VwPefNzcXAQD8APwA_ADwMgAp4W5XwDPawAG318Euwh9APiAABD6gQD7A4D5gAAE" + "9n9ZFOd3ANhwAADGZgCxWwC0BIBJRWDPzc2dnf6dsfAB8AHwAfAB8AHAXgURdQDV" + "09MGAKqqqvEewMTExHcxCji9A8MD8ckDxsbGF20YABedXPT_AfAB8AHwAfAR_RE9" + "SwmNAP8HBbg4AQA38gHwAfAB8AFg8WMAq6urovMB8AHwAfABXJRmZmZ0dHRpAGlp" + "ampqa2tr_mwBIAkADwAVABsAIQBc9P9c9AHwAfABkHQKSwDq8AHw_wHwAfAB8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8CgOIfMB8McB8AGQkgeioaHGA1kUHwPwA_AD8APw" + "AyDCnncgtF0AyGg4FOV3AADtewDyfQD1B6wIUyQJAPF9AOp5AADgdADSbQDAAGMA" + "rVoAsXxGON3Z1zwAPQiDB5ubjpufALTwwMCjo6N7BnEcC9LS0vMDADMMAMJ8wsIj" + "BDoFNvAB8AEAuBy3t3sAbQsWDsvKyvEewLCwsHcxtDO9A8MD_8kDdAQkDG8AF_0X" + "_QHwAfD_AfAB8FxkEZ3iC2kDCAGKAPjg4OBc9AHwAfAB8AHA-Ly8vE8FovMB8AHw" + "AfABXJRycnJ6enpzAHNzdXV1dnZ2_ncBIAkADwAVABsAIQBc9I9c9AHwAfABwK6u" + "rjQC_-3wAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAcA5Ax6RAfAB8AHwAYCj" + "oqL419bWWQQD8APwA_AD8AkDENvbCTDHrpSrAF0KuWAAx2cAINNtANtxShTidQkD" + "EN5zdBTOawDCAGQAslwAoVMACLeQaEJg3Nrapgympq7wAZCWlpa8xLu7SAPi4eEd" + "8QFgYwUE8gqZmZlC8AHA2uDX19DOzgkAPwOEAIign58ekJ6enlyU_70DewDJA1wE" + "F53hAxedXPQfAfAB8AHwXPQRne_v78cwCVEJigDR0dFcNK4wf-8EAfAB8AHwAfAB" + "AFcAofyhocEFbAAB8AHwAfAB8AFcZF1dXX5-fonAiYmLi4uMAYAPAA8VABsAIQBc" + "lKenp7b8trbfBVwEV_AB8AHwAWD4x8fH9QHw8AHwAfAB8P8B8AHwAfAB8AHwAfAB" + "8AHw_wHwAfABwF0DIfMB8AHwAWDAt7a229jYCxQD8A8D8APwA_AD4NbNxrUAiVql" + "VwOuWgAAt18AvWIAv2MRAxC7YQDWCKpYAACeUgCnczvOvwKyM2DZ19esq6sHrvAB" + "YKwIwcDA2Nf-1zsd5Sj1AiDxAZD2A9wIx38ITvABMK6trXsA7whAysnJz87ODADB" + "xL-_JMDb29tLALQzR1w0yQNcBMXFxeIC1vzW1uUy5wPtAxf9AfAB8A8B8AHwXGQY" + "Cfb29vLE8vIqCejo6JwAigD409PTqABcNAjxAfAB8McB8AFgTAW1tbVeNQHw7wHw" + "AfAB8FxkWwHwAeBcZMfrBX4GjQDMzMyMBlfw_wHwAfABYB8C_go1AfPwAfD_AfAB" + "8AHwAfAB8AHwAfAB8L8B8AHwAfAB8AFg4Q-QAfDHAfAB8AFQube3_QsIdADc3MHS" + "wHi5dwBZrlhMqks_pQI-CQBrtGqsyqoPMvQD8APwYsS9oIOoAHZApWosmVEDAJhP" + "AKFkJKJtgDS0km_QxLonYMDd2trY1tYaB67wcQFgmpqatzBZBCRpwwDC1Xp6vFpa" + "sEBNTaxAQKcJAG1gbbevr881wQIEmAyYmFTwAQDU0dHZ4NbWysjIAzAPAFoA_2wA" + "JJDHAkgwXDTDA8kDzwPxGAnLy8vVMxsA5wPtA__zA_kD_wNc9AHwAfAB8AGQjxE9" + "XQB6DYAN7OzsMAn_7ASuDJ49LQNnOAHwAfAB8P8B8AEwhw_jB5zzAfAB8AHw_1z0" + "AfBc9Fz0XPQB8AHwAcD4sbGxOwHz8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHw" + "AfABYNMCIfMB8AHwATCAuLi429ra3c8DAZwjkcOQQalAhADJhL3iveTz5A_BMgkA" + "DwAVAC6iLnLgt3HV2NMwMAPwA_D_A2DeDBXwA_AqMJMMjQmu8A8BYAcLUZC6AJCO" + "wUAAQKmEhMm9veLI5OTzukDk8w8AFQAALi6jdHS52NhG3ThhXgibm5tXwKjEp6dO" + "ALu6uhLwJ5A_NwtFMAk5wwOOAs8DwMAQwMnJycQI2dnZ_x4A5wPtA_MD-QP_Axc9" + "IPT_AfAB8AHwtThcNHQNeg2ADfGGDeXl5W8GjQDjNFz0DwHwAfAB8AHAr6-v13zX" + "13n-AfAB8AHwATBVAFVVVFRUWlpaP0r0AfAnAC0AMwBcNLS0frTWBdM1AfAB8AHw" + "AWDC_MLCgwrz8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfDDAfABYLe3t48B8AHw" + "OQHwj4-SAesFRQDd3ADcv9K-Ta9NqeDcqe_77wPwA2AhAMA5pzmfxZxbCAPw4wPw" + "A2Dc2dkDMBvwA8D4urm5wAOu8AFgXQ8wkAC_vtJNTa-pqQ7cr_ADkCEAOTmooSCg" + "yeDf3zsx1NQw1JSUlFqQSgS2tRC1mZmZb6C1tbLEsLASkK6urlyUuDjxzwO_v7_O" + "BzAMeAMYAP_nA-0D8wP5A_8DXDS7-AHwfwHwAfBcZG4NdA16DYAN6vzq6owNgQBc" + "NLg4qAAGAB8B8AHwAfAB8PAwq6ur_5bzAWBXDAsBtwYB8AHwATAR1AF5eXk1BG9v" + "b_9K9AHwJzAzADkATvAB8AFg_5kAnwC08AFgJwZUAPbwAfD_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfAB8AFg5gF-8wHwIwHwIQPe3t5FMKjLAKhCrULQ79DaHPTaA_AD" + "wCcAOKk4OH-6fjoIA_AD8NvZHtkDABjwA_DkDLGwsBiRkZGu8AEwlZSUCMfFxTOQ" + "p6fLQQBBrc7O8NjY9QcD8APAJwA4OKqAf368-QD8MGcIyPQB8AHAohyiojgxtzNc" + "ZL29vcdHCnENFQnd3d3nA-0D__MD-QP_AwUEXPQB8AHwAfAfXGRoDVcAdA1jAO7u" + "7peGDdYLwgfIzg3U1Lg4H1z0AfAB8AHwAWDOzs44urq6n_8BME8Ifn7-fgUBPwkB" + "8AHwAWBSDkoK-Ht7e0r0AfAnAC0AMwD_SPAB8AGQmQCfAKUAbwJZB48HAiQ2AWAS" + "AKmpqRtj_wHwAfAB8AHwAfAB8AHwAfA_AfAB8AHwAfAB8AHwn5-On_3yAfABwJqa" + "mv0CAUIwuNG4KaUpvODrvMDtwAPwA_ADAAC56rkjoyOEu96DjmgD8AMwLwTbAyAb" + "8IEDwNXT06WkpFn0gQFgn56e09DQM3AA29u4uNEoKKbAubnrvb3tA_AD8AEDALa2" + "6iEhpISMg7yrCUAyrKysbPD_AfABkNkIXMTJA88DXATuAv_5Dw8A_D_tA_MD-QP_" + "AwUE_wsEXPQB8AHwAfBcZG4NXQAA8vLy7e3t5-f-5x4DPAkBABQ95DBMNQHwfwHw" + "AfAB8EAFAQBW9AEwTQBNTVlZWZycnD9aDAHwAfABME8O6A6Dg_CDY2NjSvQB8CcA" + "LQD_MwA5AE7wAfABYJkAnwClAHGnAdDQ0GIKCQNfxLL8srIeBvnwAfAB8AHwAfD_" + "AfAB8AHwAfAB8AHwAfAB8PcB8AEw1guOAfAB8AGwAwMBPzDO2M4bnRxg4MRho-Wj" + "A_AD8ANggTMABpQHpcaklzjjA_ADANnX11wUG_AD4MDFxMSWlpa3A6vwMQEwrays" + "TgAwYN3bANvOztgaGp5e4F7Fn5_lA_AD8ANggTMABQWWpaPGRQD_AgFGArsIcvAB" + "8AFgqAD6aAcGALg4zwO8vLzBwfDBysrKWAsXB6YC7QP_8wP5A_8DBQRc9AHwAfAB" + "8A8BMAYJaA1XAPX19fEA8fHs7Ozm5ub_JwNCA5AJXGQB8AHwAfAB8HEBYL6-vv4H" + "n_8BMErgSkpSUlLAAyb0AWBx2wNISEgkABvwJ8A_AD8_Nzc3NTU1ADw8PEZGRlhY" + "_lgn8AFgUQBXADYAG_CSZP8kAJ8ApQD5DAwGKQFlOsOQ-Lu7u1gO-fAB8AHwAfD_" + "AfAB8AHwAfAB8AHwAfAB8P8B8AHwAQDBAvryAfABwHcHA00BQjBfs2ACmQPAXslf" + "hNyFA_AD8AMDYDMAApgDIZsheNbW05o4A_AD8APw2jzX1wgNpfABYMoIv70GvTOQ" + "yxrd3V5etQAAAJxaWsqAgB7dA_AD8ANgMwAAAJtAHx6e19TXSzCx_LGxePAB8AGQ" + "8AaGYVw0j6YClALPD8EI0dHRWgX_pgLtA_MD-QP_AwUECwQRBB8m9AHwAfAB8Fw0" + "-Pj4APT09PDw8Ovr_utvAO8EyweEAOA06QEB8I8B8AHwAfABYLi4uPAAx0P7ATC3" + "A1FRUTj0L2QAQEBAPj4-SUlwSURERCHwATBEBEOIQ0M6AeA9PT1dAP8w8AEwUQBX" + "AF0AYwBi9IBkA0IApQClpaWurq6PDwZHBCkBw5DCwsJBAf_58AHwAfAB8AHwAfAB" + "8AHw_wHwAfAB8AHwAfAB8AEA4wE-jQHwAfABsLIFPzDB0wDBCJsJA54ENuC6N2XT" + "ZwPwA_ADYAA3uzgDnQQDl_AEib2InQgD8APwA_DA09HRoaCgovABYDEHBc7MzDBg" + "CTna2QDZv73QBQWeAAAAojIyvGBg1AcD8APwA2AzM70AACKhXwSIh74DGdzc_xwL" + "e_AB8AGQMwCGYZoCyQP_jgJcBNQHwQivAn0EpgLtA__zA_kD_wMFBFz0AfAB8AHw" + "AxE9XJTv7-_q6ur45eXl7ASPB1z0AfAB8AcB8AHwAQC1tbXY2A7YVvRc9AGQTExM" + "QcRBQfwDVlZWHgABAP8FBPzz_zNZBLIIAfABMF_0_wEwUQBaMGMAaQBvAHUAXfAx" + "XDSdnZ1fBMwAy8vGy8_AwgHGxsb58AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw" + "AfABAJsK9_IB8BEBwM7Ozj8waLdoAASfBQSjBQqogAtCyERIy0oD8B8D8AMALQAz" + "ADkABJwFeDGhMXwIA_AD8APAyBzGxtENn_ABYKalpRjX1dU58AMAZGO3AAAApQAA" + "qQYGgK09PclCQswD8D8D8AMALQAzADkAXwQuLo6lSwBfBL4ImJiYgfCPAfABYPkM" + "XPS5ubkIB_jFxcViAbE_7QPzA_kDP1yUF_0B8AHwXPRLAPr6gPr39_fz8_NjAMDp" + "6enk5OSQAIQAfzxp2wAB8AHwAfAB8AFgsxyzs279AWBcxFpaWsfhA1IILwRXV1f8" + "MwEwGEJCQiD0AQBOTk7GRQHwAYBHR0e89AEA_1EAYJBvAHUAewCBAIcAXMTAm5ub" + "o6OjswosAf-GmgEAbgS7CPnwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfDvAfAB8AEA" + "YQWMAfAB8AGACJCQkD9gK6YsBQCkBwWoBwWpBwANrg8pwSsuxH4wA_ADwCcALQAz" + "ADkQoYAHBJcGxdDDUgjHA_AD8ANgtbOzogOf8GMBMBsAtbS0NvADYCYAJqsAAKwA" + "ALAAAACxCAi1IiLwwicnxAPwA8AnAC0AhzMAOSBfBJ7Fw9FOAMDb2tqsrKyH8AHw" + "PwFgQQRHYcMDyQOjArq6Irq7CMTExPQF1dX-1ecD7QPzA_kD_wMFBAsEH1z0AfAB" + "8AHwRQD8_PwRXGTu7u5pAOPj4_-QAIcAGQJc9AHwAfAB8AHw-LS0tEweAfBc5N4D" + "QAg4UFBQ7TPhAwGQSEj-SCD0GADPDA4EAWAPABLA8QEAVFRUPPBRAGPAeDB_gQCH" + "AI0AXPRc9AEAGwbB_MHB-fAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfB_AQDi" + "AvfyAfABkFMBPDDSANnSBZ8HBqkIIAatCAauAxAHrwAJELYSGLwaGfy9GwPwAwAb" + "ACEAJwAwMAAGrAgGpQgFm4AHmMGX2dbWA_ADA_ADANbT06OiogOZ8AFgk5OTxcPD" + "IznwA2DPzNMaJLQAIAC4AAC5AwABAQC5CAi8Dw--EH4QA_ADEBsAIQAnADAwAMYA" + "9whfBKWXlWkQaA3_cwiK8AHwXPRcZM8DRQDYAwDDw8PMzMzU1P7UGwDtA_MD-QNc" + "ZBEEXPQPAfAB8Fz0XDT29vbyBPLyYwDo6Oji4uLiUgi4uLjTC5MA6wv_NPIB8AHw" + "AfBcxFP0XPTJA_hPT0-fDAX0ATAeABXw0FhYWFIBIFMB8AEg8R4wVVVVPPBR8AFg" + "hwD_HjBc9Fz00w64-AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw7wHwAfABMAIBiwHw" + "AfABgANQATwwttC3BqQJAAeuCgezCge0gQOgCLYKCLcLAwA8CbgDEAwwFQAnwAex" + "AAoHqwkGngl9YLh82NbWA_AD8MxgysqXlpaW8AFgnGCcnNDOzjnwA5CyILDNAACv" + "IyS_AAQAwAOwvgAAvQDgALwAALsDIAkADwAXFQAnwBUAtqEEenm941EAuwi_v7-N" + "8AHwAWD4wMDAhmHDA8kDzwPVA8cBAJUBVQvT09PnA-0D__MD-QP_AwUEXPQB8AHw" + "AfARXGT5-flcNO3t7UDn5-fh4eGhDbf8t7eNACEDMwMPAIcAAfD_AfAB8AHwATBg" + "APYAov8BMAdclNIDPQhdXV1eXuBeX19fYAFQDwABAP9JOLj45Wge8I6YHvBRAFow" + "P2lgdQAPAIEANgC4-KKi_qJcBBUG8gbDkDsBIQb58P8B8AHwAfAB8AEARQ8oAkYC" + "_wYA5goh8AHwAfAB8GbwZvA_AfAB8AEAEvMB8AHAp6cCpzwwqcuqCKcKAAmzCwm5" + "Cwm6HwPwA_ADsDYAcQSuCggAoQp2tnXY1dUDA_ADwL68vI6OjgOT8AFgrKur1tTU" + "YznwA8Clo8m1KCMExjgAAMgD8APwA7DHAIQAxXokrXJxu1EA_1wETAKQ8AHwAWB6" + "AUcxvQM_wwOOAs8DdQNcBE8Lysr-ytcBGwDtA_MD-QNcNAsE_1z0AfAB8AHwXPRc" + "ZIQAVwn_2QszA1z0AfAB8AHwAZD4DQ-rCVb0XPTVA2hoaGnhASBqamprAVAMABUw" + "QyD0MwBhYWFiAVBlDGVlQgABAGZmZmP8Y2MVMCEANQQ88GnwaWD_QgBaAFz0XPQB" + "AIcDQQH58B8B8AHwAfABwCgCs7OzCKSkpKALh4eHj_yPj5MD8gqQBi3wAfAB8L8B" + "8GbwZvAB8AHAxwKKAfAPAfABgFABPDCxzrEJAKkLCbYMCr0NHArAA_AD8AOwvw0K" + "ALsNCbEMCKILwHi3eNfV1QPwA2AxCA2rqqqN8AFgjY2Qjb28vDNw1NRF8HEDYKyq" + "zNUsIATBCNCHA_AD8AOwzwAAypskMK90c71RALsIwcD-wJbwAfABYNhmvQOaAskD" + "j44CXAQBACcGycnJXPQfXPQB8AHwAfBc9PHx8QDs7Ozm5ubg4P7g9gOEAKgGmD0P" + "AIcAAfCPAfAB8AHwATC-vr5PBQ9G-wEwXJQsNG1tbXgAeHh6enp2dnYCdQEgc3Nz" + "cnJyiHd3dyD0XFxcFAQIcXFxLQB7e3t_CH9_ggEggYGBffx9fUgAOQBRAGIEPPAe" + "MP9dAGYwQgB1ABUAMABZNFyUiJqamgwDsLCwhwP41dXVw5A7ASkN-fAB8I8B8AHw" + "AZAcAqurq8MwMfMDlZWVTAL4BHx8_ny2AfkDM_AB8AHwZvBm8H9m8AHwAZBDAvfy" + "AfABkJkEmZk8MMTTxAmoAAwKtg0LwA4LcMQOC8UD8APwA4DDBA4LlQSxDQmgCziQ" + "vY8OFAPwAyDPzA7MJAaK8AFglpWVymP0DjBQ1dPTRfADkMAOvh0EXAR_CNIAANa4" + "AADXA_AD8AOA1V8kIsFcBI6MwlQwvbv-u5nwAfABYHoBRzG9A8MDA44CEgC1tbW2" + "trb_0whcBCYNGwDtA_MD-QP_Ax9c9AHwAfAB8FzE9fX1_1z0XgKYPbANEgAB8AHw" + "AfD_AfABMF0AjQPq9gEwXMQBYIEvBISEhIODgyMEfzUE9gMMACD0AQAXBBIDjACM" + "jJKSkpaWlmOyAgEAl5eXgweAB4n8iYlrBPAMOfBRAFcAXQD4fn5-DABvAHUAJMBc" + "ZIFUAKGhoa-vrxUG_8IBw5C_AT4B-fAB8AHwAfBHATCBBpQFqKiogQls_GxsXAp-" + "BiUCAQCEALkN-HBwcCsINzIB8AHwAfAfZvBm8GbwAfABMMTExD9rAQHwAfABYCII" + "P2AdqgAgC7YODMMPDHDJEAzLA_AD8ANQygAQDMcQC74PCgCwDgmdDL7MvAfMDAPw" + "AwDDwcGQkAaQh_ABYKKhodPRHtEwYFkERfAD8BQUuMPeLFkE3AAA3wPwA_ABA1De" + "AADbAADRYVwkrL27zk4Auwi1_LS0MgSf8AHwATBJC0Qx_70DwwOLAnIDhgpcNPYG" + "XPT_BQRc9AHwAfAB8Fz0XGSQAP9SAmECPDlc9AHwAfAB8AGQ8ekH0NDQVvRc9JT4" + "OAQ_NQQbDz4EIwQk8AEAZGQCZGsHnp6eo6OjgcoLqampqqqqMAPApaWloKCgqAaL" + "CD828AEAUQBXAF0AYwB0dP50IfBc9Fz0UTzhAPnwAfCPAfAB8AEADQK6urpvAOPb" + "ABYFpqamKwX4BA8AGG5ubkAFBgBUVFT_8AABCz_wAfAB8GbwZvBm8D8B8AFgQAL3" + "8gHwAcDKygLKPzBYtVoLsg8ADMEQDcsRDc84EQ3QA_AD8AMgzhEADMgQDLwPC6pw" + "Di2iL_MMA_ADALMMsrKx8wFgi4uLtByysjbwA_AD8FFPvQMULVwE4QAA5QAADuYD" + "8APwAyDjAADdIbgovSYlsFFgpKP-o6vwAfABYKkIXGTDA4kB_88DXAS7CAkAXASd" + "AhsAXPQfXPQB8AHwAfBFAPv7-8dc9HUAVw-8vLz-BIQA_8kGEgAB8AHwAfAB8AEw" + "SQWP_wBG-wEwXDRXV1fY8_8BYPkDWwhHBxvwATB0B7EM-LGxsVABhwkuBbUFXwH4" + "ra2t7vgBYFEAVwBW9P8BkJkAXGSqBFwEoQceBg_M_24E-fAB8AHwAfBvA8YA5wPx" + "8ANpaWnYAAEFWAgPAAMBMK4MampqU1NT__wDNzIB8AHwZvBm8GbwZvD3AfABMIAE" + "iAHwAfABsLMBET8wqMmoHQQMvRAADcoRDtISDtQ4Eg7VA_AD4CcAzxIADcURDLYP" + "C6IwDnGycW0IA8DT0DDQpKKie_ABYJGR8JHEw8M58APwA_ADAECjockAALx_KOAA" + "AADoAADrAAAe7APwA-AnAF8E2gAAgMoAALRsa7quYP9_C6XwAfABYBM4AQC9A6oB" + "_00EzwMMM1z0XJQRBFz0AfCPAfBc9Fz0XDS7u7vABv-PB4QAvQw38gHwAfAB8AFg" + "OM_Pz-EAVvRcZE9P_E9OAfAB8AGAMwD3ApKU-F9fX5UB4D3HCwYAuAj4b29vJpQz" + "AGzwAfBs8Mdc9MBg9T3X19f58AHwPwHwAcADCRYCSAn4BHl5PnlMCBwF85MBMO0A" + "UFD-UCQAePAB8AHwZvBm8Gbw_wHwAZBeBffyAfABwLgOXWAAR7BJDLMQDsUAEQ7R" + "Eg_XEw9w2RMP2gPwA4AhANUAEw7MEg2-EQwAqw8bnR3Lz8kI1dLSA5DQzc2fDJ6e" + "ePABYJ2cnM88zc02wAPwA_ADkD8-MLsAAMYpJFwE7gDgAPEAAPID8AOAIQADXwS4" + "CNMAAL4SERCsy8jPSzC-vb3_iwio8AHwAWBBYb0DwwPJAxHPA7CwsFzE39_f8fMD" + "6-vrXPQB8AHwAfDjXPRc9L29vekHkwB7Bv9c9AHwAfAB8HbCXQBG-wEwAkEBIERE" + "REBAQB4_AfAB8AEgMwBGRkbx-gJYWFhqyG4H2QvlyP8nAC0AMwA5AE7wAfABMJMA" + "I5kAojCYmJhcBK6u8K7Dw8MqBsBgMgGrAz_28AHwAfABwFoAYAB_fwB_XV1dhoaG" + "pACkpHt7e2NjYwfzwwEA0gBISEhnZ_5nkg1I8AHwZvBm8GbwZvDjAfABkI2Njf0I" + "AfAB8AcBkH8CPzCxy7IRpAAUDbgRDscTDwDTFBDZFRDcFQwQ3QPwGCDaFRDXABQP" + "zxQOwRINALARC5sPg7aDiNTS0gOQwL6-vAQHcvABMAgNrKur09Ee0TbAA_AD8APA" + "rKrJAAUFtwAAzQAAht-RKD4E9gAA9wPwoRgg9AAA8IYk2E0tEK1_fr1IMNHPz_6U" + "sfAB8AGAUAeAYYsCwwP_bAPPAwUHXPRc9Fz0AfAB8P9c9Fz0XDR3B4cA2Qu6DAgE" + "_1oJCgUB8AHwAfAB8AEw8AAHVwBZ9AEwNTU1NDQcNDEB8AHwAVA4ODj__ANVCE39" + "AfC1OC0AMwA5AP9O8AHwAWCZAJ8AWQRc9AEwf7kB9Q3z8AHwAfABYB0BvwC_v6mp" + "qXNzcyMWBaYLn5-frQ1iYo5i8_MUBCgFPj4-Swn43NzcTvAB8GbwZvBm8P9m8AHw" + "AZBiDf3yAfAe8xUDAUIwhbyHDKUPDkC4EQ_HExBfFBQAEd0VEd8VEeARA4DeFRFc" + "BNcUEAjOEw9ZFBAMng9wTaRO1CYEA1BaDK0crKzUB2_wATCQkJD4t7a2JwA2kAPw" + "A_AD8AEDMH99vwAAuQAMAM9fJJQI8wAA-EAAAPoAAPsDgPkbXCS1COdZJOsIsUZF" + "Pq-0YF4Cq_AB8AGQmpr-mt1hvQPDA8kDzwNLABT9HxT9XPQB8AHwXPT8_PzHXPR1" + "APkDs7OzdgKED382A1z0AfAB8AHwAZB-A9H80dHq9gEwdQBpDMYJvQOPygLJMwHw" + "AcBFRUW4-P8B8LiYMwBI8AHwAfABABQ9_6UAqwDibgEAzgHbAPPwAfAfAfABMBMC" + "xQpACGlpaRGHDJubm28Abm5ueGFhYfPzFATaDfMDTeBNTeHh4VIIUfAB8D9m8Gbw" + "ZvBm8AHwAZCioh6iCQkB8AHwAcCoqKgBRWB5tnsMoBANALIRDsATD8wULWIU16Yo" + "UATbrzgVEATQFH0EDrsSDasAEQyaD0qhS84cz8yCCAMw5AyenZ0PeANp8AEAcQSW" + "lpbD_MLCzAMzYAPwA_AD8APAhHJxGg20AADIOCTQ5QAA7cEo9a9YCQABVgTqAADg" + "AADSCAAAwLIIQ0KszgLMhxDSz8_CwcH_Dg2x8AHwAZD5D1xklwLDA__JA88DXPRc" + "9BEEXPQB8AHwj1z0XPRvAHoHycnJfg__mwqHMEUGqAAB8AHwAfAB8OMBMFcAzc3N" + "VvQ1bXsA-Le3t1MHwANNBwHwAfAASkpKUVFRWVn-WUr0AfAnAC0AMwAmNO4FwJ2d" + "nZ6enlfwAfB_ATCZAJ8ApQCrALEAvWDHfMfHMvEB8AHwATAXAbYctraNAD0IAQCh" + "oaGPUwfXDfDzAQBcXFwiBYg8PDxOCePj4-YK_1HwAfBm8GbwZvBm8AHwAcD4ra2t" + "_fIB8AHwAQCfAAFIYJO8lBWZFwwApRANsREOvBJID8MTSgQPyQMgxgITdAQOtxIN" + "rRGBrwgLjw5pqWomFHEDUMXDwwkJYPABYJjgl5fLysozkAPwA_ALA_ADkNIJUI2L" + "vgoECqrBKMcAANMAVADbSiTiAyDedCTOAAAAwgAAsgAAEKFjYrA2MNDOzji8urpZ" + "9AHwAfCysv6yNTGFAkoAnQLJA88DjAH_UwFoBBIA_AbnA1z0XPQB8EcB8AHwXGT2" + "9vZcxM_Ez8_mBLm5uZIHhQL409PTqAAB8AHwAfAB8P8BMD406vZTZygOzAkOASgO" + "5qwB8AHwrKxc9AHwXPSPuAtZBCwE8QWqqqpX8P8B8AEwmQCfAKUAqwCxALow_yoG" + "kwnw8AHwAfABADIKBwJjnAxJCHBwcJMAVgdnDGdn8PMhAFpaWkv8S0vUDU8IewC8" + "AVHwAfA_ZvBm8GbwZvAB8AHwu7ucu4UB8AHwAfCFhWcIAwkDS2DCzcJep18ADZMQ" + "DJsPDKNAEA2oEA2qAxAMBKYQ1ggLlw8LjYAOQZlDr8Sv9Rc_3iMDAOcMSABd8AFg" + "q6r-qtYIMGAD8APwA_AD8AOQAL68ylZWrwICAKUAAK4AALcA8AC9AAAvDQMA1jh6" + "BICeOTikqqnDMDAA0c_Pv729iYiOiK7wAfAB8MDAwDIx_7cDvQPDA8kDzwMBAFw0" + "Ogg_XPRc9AHwAfAB8Fz08vKA8u3t7efn5-8K-Nra2iED6ws5M-ILDwD_PAM68gHw" + "AfAB8AFgWgD_AA_t9nM1dQAaAcbGxsOYw8PBAfAB8MHBXGTxDwNEREQMAwHwAQAb" + "AD8hAFxkEAsPDGADOAq8vP68V_AB8AEwmQCfAKUAqwD_qWhoBOo5AfAB8AHABwKw" + "BAMMA4EMf39_pqamwICAgGRkZPPz8wOB1A1HR0c1NTUoBf-2ASgCODEB8GbwZvBm" + "8Gbw_2bwAfABwJEL_fIB8AHwATADvjhRkMLMwoOyhQBGmkgzljUMiAAPCocNK5Iu" + "OoCUO3CpcrbGKkADrAJRDNHOzqSjo9NU8AGQrayBDMwtAANAAYwEyMhysrJUqYCp" + "SKWlO6KiCQDAZa6uo8HBJHAD8AMD8APwz8--vMh-AHy0Pj2kKimiAAICmQAAmCMi" + "AJ8xMZ9qaa2yjK_EJ2CyCL27uxD1nwHwAfABMIICBUHS0mMD8aE3q6ur9QFkC3oE" + "XAT_GwDnA9EB8wP5A_8DBQRc9P8B8AHwAfBc9FzEmw1sA-Y0_1z0AfAB8AHwAcBX" + "ACEJWfR_X2QgMasDJwAB8AHwXGRI_EhIDAAJAAHwAQAbACEA_1yUGwzeDFkE7QBX" + "8AHwATD_mQAaYbdgtQgs8QHwAfDGCQFxAX19fV1dXYoAioqjo6N5eXkHrgzz8xQE" + "VlZWQ0MCQ6IMeHh45OTk_6UMUfAB8GbwZvBm8GbwAfD3AfABYGYAhAHwAfAB8AFQ" + "j3wOC_oB8FiSu7q64w3HS_ABkHoKz87OJQgDAAFlAoq8vECoqIQAycm94uLk8_MP" + "JDMJAA8AFQAtoaFs4LGxys3NMDAD8APwHwNgLwQS8BXwAwDPzMz4tbS0q_AB8AHw" + "ATD2APlhddLS3AXDA_IBkQtcNP8UBxUAXPRc9AHwAfAB8FyUCPr6-lw07u7u6ADo" + "6OLi4tvb2zFPCLq6uo0A1ArHx_7HCgUSAK4AAfAB8AHwAfD_AWBYBYrzAfAB8AHw" + "AQBcZPhQUFAVA50IAfABABsA_yEAXMTZBdMF9DUB8AHwAfB_AQBrCiEC5_AB8AHw" + "2gSMHIyMlgD5A0gJcXFxGGFhYfPzFARUVFRAQEBAMzMzzg3j_OPjsAFO8AHwZvBm" + "8Gbwj2bwAfAB8AGQnJycA_OPAfAB8AGQjwenp6cuMj8B8AFgFDfhAELwAcCoqAao" + "GwYzENDQtMnJAEqtrafb2-36DvoD8ANgIQA4pqaWPLy8EgkD8APwA2DQzY7NAzAb" + "8CfAoqGhq_DHAfAB8AFgoqKiCzGxAz_NAr0DwwPJA_AAigy4uP64xwipBR4A0QHt" + "A_MD-QN_XDQLBFz0AfAB8AHwXGT3IPf38_PzYwDp6eLpRgLc3NycAPEL2QX_jQAJ" + "APc7y_EB8AHwAfABkP-NAwEApfMB8AHwAfBcZMEL_7g4CQABwLg4CTBc9Fz0AfD_" + "AfABYFkEhfUB8AHwSwZUBghXV1fVA5OTk2yMbGzw8wEAXFxctAAAPT09Nzc3srL-" + "shwCNg9O8AHwZvBm8GbwD2bwAfAB8AHAra2tgw8B8AHwAfAB8IODlZX-lVEAIQOX" + "ApQyPwMMAPcLP8UERA0z8AHwgQPQYqDDAMM_rKzJ7e3THPLyA_ADwCcANqmp-Hiz" + "s3k4A_AD0FY0GPCBA-DMysqamZmr8P8B8AHwAZBbBWdltwMaAcMDA8kDlwuxsbG5" + "ubn_EgCjNecD7QPzA_kD_wMFBB9c9AHwAfAB8Fw0_f39MVxk7-_vaQD7Ct3djt0n" + "A4EAkAC0tLRUCf-UAgA8OQMB8AHwAfAB8AFgP-n3AfAB8AHwAQBclFVV_lV6BycD" + "AQBLAwEADDAVAP8bAFyUrwJcBDUK6gCPAVfwfwHwAfC_beHwAfAB8KsMmSCZmU5O" + "TooMc3Mec0z4AQC0ACEAOjo6iD8_PzAA4ODggw3_S_AB8GbwZvBm8GbwAfAB8DEB" + "8MXFxQPzAQCIiICIqaiopaOjEmCIm5qaEgCRkJAt8B8B8AHwAfAB8AEAjo6OA88G" + "nDCux8cmpKTAsejoterqA_AD8AEDAK_n5yCion0ctLSOaAPwAzDOzMw4z83NAwAb" + "8APAwsDwwI6NjavwAfAB8AHA_9UP2ACLMhE9wwPJA98CJwbxxAjExMTlAuED5wPt" + "A__zA_kDXGQRBFz0AfAB8Fz0AUsA-_v7-Pj49AT09GMA6urq5eXw5d7e3k8Cwgch" + "Bhc9-MbGxg8AkgG0AAHwAfD_AfAB8AFguzir8wHwAfBc9IdcZAEAKgNmZmZnAYD_" + "DwA_M1z0XPQB8AHwAZDOAT8j8QHwAfABAMoF9wtJSSJJBAViYmLww19fjl_LDasA" + "SQhNTU1GCP-kAc40AfAB8GbwZvBm8GbwXwHwAfAB8AEApQyCAfCCEIK3tbV7A5qa" + "mgMMACQAysjIxcPD-IeHhyrwAfAB8AHwAfAZdRC3t5YwjwsZnZ3AVsLCk-DgA_AD" + "8AMDYDMABZWVnL29xzs0A_ADAM7Ly1xkA_DxA5C0s7OVAajwAfAB8PEBwJCQkFRj" + "sQO3AxE9-KamppcLZQQSD-sFGwD_4QPdAe0D8wP5A_8DBQQLBD9c9AHwAfAB8AEA" + "XJTw8BDw6-vrbwDf39_419fXTwhoCpMAjAGDCv-XArs4AfAB8AHwAfBfxPD2DwHw" + "AfABwFzEZWVlb_hvb3ABgA8AFQBc9E8L8dwFvr6-5wBX8AHwAfA_AQBZ9AHwAfAB" + "YIcAQ0MOQ7EM5APzw1hYWEYARkY0NDRjY2P_yApyBpw2AfAB8GbwZvBm8B9m8AHw" + "AfAB8AEwoKCgPwnzAQBHBE0EUwQJALu68LrPzMweAyfwAfAB8EcB8AHwAQCNjY2n" + "YVkAsLAAnJxPxcV4cNbWA_AD8ANgMwAAAJubHZycysvLH7QAA_AD8APwAwDNy8v4" + "o6KipfAB8AHwAfABAPioqKjbMKsDygK3A70D_8MDXAQoCC8N4gJDDtsD4QP_5wPt" + "A_MD-QNclCb0AfAB8AMB8Fw0-fn59fX1APHx8ezs7ObmDuYHC7QGgwHAwMCn4Ken" + "s7OzkwBsCZMA_z_zAfAB8AHwAcCo8wHwAfCHAfBcxAEAenp6dwGA_w8AG2Bc9Fz0" + "AfAB8AFg2PAPAfAB8AEwHwjLy8s94D09SEhImQD5Y2EIA8INDgQzMzOBgYHA4uLi" + "29vbP_AB8P8B8GbwZvBm8AHwAfAB8AHAjy8HVwAB8AEAlZSU4Af4wL6-BgBtAiHw" + "AfAB8B8B8AHwATCeCpMwt8rKAAWengCioii4cLhOzMwD8APwA2ApILm5AKGhXwSA" + "th62twAD8APwA_DFxMT4kZGRovAB8AHwAfABMPjBwcGqN6sDsQPQAr0D41YBXASu" + "rq4rCJoL6A7_IQDhA-cD7QPzA_kD_wMFBB9c9AHwAfAB8Bdt_Pz8AVcA9vb28vLy" + "7QDt7efn5-Hh4Tja2tqlALANljC5uf65SwkwDPc7AfAB8AHwAfA_AZCf8wHwAfAB" + "wFz0dnZ6doUOfgEgCQAPAFz0lCCUlJubm1wEvb3-vXsDV_AB8LTzuDgB8AHwjwHw" + "sjVLBqIANjY25AMjmQDtA1RUVJ8AOjqAOjAwMJ6enpgB-NjY2DzwAfAB8GbwZvA_" + "ZvAB8AHwAfAB8DcCiooeigzzATD7AkIMurm5_xvwAfAB8AHwAfABYMsHkzAAYLS0" + "AKWlAKkAqQSsrCvBwS_8w8MD8APwAwAtADMAOQDxXwQso6P8HAPwA_ADsP_tAKsJ" + "n_AB8AHwAfABMFUOH25hqwOxA7cDvQOkpKSB0AiwsLC4uLh9BP_VAwcC4QPpAe0D" + "8wP5A_8DfwUECwQR_QHwAfAB8Fxk-gT6-lw07u7u6Oji6BAL3NzcMAPFB60N_5kA" + "TgmWMLs4AfAB8AHwAfB_98IEDl_0AfAB8Fz0QWRewF5ej4-PiAEgCQD_DwBc9Fz0" + "AfAB8FmUAQDS8B8B8AHwAZD_AC4Ic3NzAC4uLjExMTU14jVGCC0tLWQI0QpmBvjV" + "1dU28AHwAfBm8Gbwf2bwAfAB8AHwAfABMD4HgOMB8AEglJOTHgzGBhvwHwHwAfAB" + "8AHwATCEhIRhHWclqqoAIwQXDbEAsQSzsxO7uxX8vLwD8APAJwAtADMAORDBXwSe" + "nrrGxr0AA_D7A_ADYKifKZ_wAfAB8AHw_wFgqAPbMKUDqwOxA7cDFQAIoqKirgmy" + "srK64Lq6w8PD1QOvAuED_-cD7QPzA1w0BQRc9AHwAfAPAfBcZAYJVwD39_fzAPPz" + "7-_v6enpeOTk5GwPhQL-BM4KpSylpWIECQDGRwHNzf-6AKEBAfAB8AHwAfABkFkE" + "f3UAl_IB8AHwATBc9AEAZYhlZZMBIGZmZhiQ_1xkGwBcBIYB5ACVAVfwAfD_Csgt" + "NgHwAfAB8AGQSwB6AQHjBHV1dVNTU2fgZ2eZmZmPMRACMPD_AfAB8AHwZvBm8AHw" + "AfAB8GMB8AFgxMTED_MBMJPIkpLNIgulpRvwAfA_AfAB8AHwATBdBo0wxs4gzgCo" + "qAAmBLe3CAC4uAMwAbe3Ajy2tgPwA2AhAC1gALYAtgCvrwCkpI48u7u9AAPwA_AD" + "AMrH8MeXlpaZ8AHwAfAB8P8BwKkI2wCfA6UDqwPNArcD470DuAirq6sdDRIAfjz_" + "ZgPsAfIB7QPzA_kD_wMFBH8LBFz0AfAB8AHwXGRoDfgA-Pj09PTw8PAA6-vr5eXl" + "39_G34ICqADHx8dRBvgE-Le3t_UEuzg68gHwAfD_AfAB8DUHOPcB8AHwXPQB8P8B" + "wFz0XPQB8FnEPwwTBcnw_wHwAfAB8AEAsDqAAbMKAQD43t7eEQEn8AHwAfAB8H9m" + "8GbwAfAB8AHwAfAB8JBIkJB_AfB_f1wEzPzKygYDG_AB8AHwAfAB8BEBMJeXl4ow" + "q8jIARoUubkAv78AwALAA6C9vQC7uwD8urpERAkADwAVACfwXwTgqalztra9AAPw" + "A_DAwL6-i4qKlvAB8McB8AHwAcCVlZXbMLU4f6sDsQO3A7UIwAOSCsQIvvy-vs8D" + "IQDbA_sB5wPtA__zA_kD_wMFBFz0AfAB8AHwBwFgXDRuDfX19fHxgPHs7Ozm5uYc" + "C4jZ2dk_A8nJyaoNcZ8AsbGx6gacAPgEzvzOzqIAAfAB8AHwAfABwI9f9AHwAfBc" + "lFdXV0r0_wHwJwBc9Fz0AfABYFkE6Qf_w_AB8AHwo_UB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfDNMgHw_wHwAQBJAhXzAfAB8AHwAfAPAfAB8OYBijCexcUAxLS0IxTGxgBo" + "BAPwYwPwA5DHxwBCAHQErYCtbLW1zMnJA_CBA8CysLCCgoKT8P8B8AHwAfAB8EoE" + "2ACZA58Dj6UDqwOxA7cDoKCg2QLjwQghAMDAwM8DuALbA__hA-cD7QPzA_kD_wNc" + "NCD0_wHwAfAB8LtoaA1dAHQNeg2I7e3thg3i4uKWD_GSB8vLy-8E_gRXCbs4_xIA" + "XPQB8AHwAfAB8HIztAkPnfsB8AHwKQRPT09OHwHwAfABIC0AXDSampr4p6enXAR9" + "AVfwAfABAP9ZBAQFwPAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfAPAfAB8AGQ" + "9wKFhYV-fwHwAfAB8AHwAfAB8AGwljSWloowph0EdgjExMAAzMwAz88D8APwEwOg" + "Uw3JyfQYr69u4La2y8nJA_ADYAgN-J-eno3wAfAB8AHwAfDxAQCKioqTMwYAnwO1" + "OA-xA7cDAQC-CLKysrr8urq9M9UD2wPhA-cD7QP_8wP5A_8DBQS1-AHwAfAB8P9c" + "xG4NdA16DYANhg1-P-QDjxACpA2wCruYzMzMxgD_AfAB8AHwAfAB8F80pvsB8AUB" + "wEEBIEREREBA_EA_AfABgCEAJwAwMFz0_wHwWfSiALrwAfAB8AFgfvP_AfAB8AHw" + "AcBp8HKQePAB8P8B8AHwb_AB8AHwZQEb8wHwHwHwAfAB8AHwAcCNjY2BhzC4ysoA" + "t7d_GADS0gDW1gDX1ycD8APwA3DV1WIUwcGBXASGurrLyMgD8IEDMMPAwI-Pj4rw" + "HwHwAfAB8AHwATCurq5H2DCZA7WYnp6eugOs4KystLS03ALJA88D_7gC2wPhA-cD" + "7QPzA_kD_wP_XPQB8AHwAfBcxBc9dA16DT-ADYYNMAmSDUIDSAPIyPDIs7OzXQkB" + "Bbs4OQz_Gj0B8AHwAfAB8AHweAAWDg-BMNDyAfABYDU1NTR4NDQxAfAB4CcALQCS" + "EQEgmZmZjAG7u7vH7QBU8FfJ2traWfQB8P8B8AHwAfAB8AHwAfAB8KEB_wHwJ_AB" + "8AHwAfAB8AHwAfDDAQA6AoODg30B8AHwHwHwAfAB8AHwAYCBgYEdBWETuAhcBCYE" + "29sAHN7eA_AD8ANA3d0AINraANDQUx2srJKyDwPIyANAx8cDEPEPULe1tagJh_AB" + "8AHw_wHwAfABMGMA7DfbAF8BtThjqwOxA5-fn80FEQ224La2v7-_3AIXN9sD_-ED" + "5wPtA_MD-QMRPVz0AfB_AfAB8Fz0GAl6DYANKgnnIOfn4eHhRQPS0gLSsQDBwcGh" + "oaEYpKSkMw8WBcbGxv9dCbvyAfAB8AHwAfABYMMDP8AJX_QB8AFgeQiiAKmp_qld" + "D5EIOzQB8AGQJwAtAP8zADkAPwBU8AFgrA6QAM85_wHwAfAB8AHwgfMB8AHwAfD_" + "XPQB8BgwLfAB8AHwAfBp8P8B8AHw7gIh8wHwAfAB8AHwjwHwAcDhD4cwTbq6FB0B" + "XATg4ADk5ADlDuUD8APwAxDi4gDcgty4GLy8JK2tSmQYycfHAwAPYKempn9SCIHw" + "AfAB8AHwAfABYK38ra3SMJMDmQPEAqUDqwMPtQgRDdYCxAi5ubnC_MLCyQPPA9UD" + "2wPhA-cD_-0D8wP5A1z0AfAB8AHwAfARF83u7u4wCePj4_88CZkMFz14Ca4AEAUE" + "BRwF_4QDLgU68gHwAfAB8AHwX5Q_hwAUAerzAfABAGIBwMD-wKwFWQEyBJEIAfAB" + "wCcAPy0AMwA5AD8AVPABMNTU8NTe3t4RMQHwAfAB8B8B8PaTGQJvNgQCxMTE_wwA" + "iD59ARwCnDZ-BuMKJADHYwnpBAYAo6Oj8goKC-NkAgAGqKioDwAvATAA_wHwszEJ" + "MM8AywH5AJUKbwD_OQBCMH4DPwCLAnUACzchAP8eAC0AHQG3D5kAhDDG8AHwwwHw" + "OgKEhIR8AfAB8H8B8AHwAfAB8AGAJAyHMJ1BWQS8vADR0VwU6IDoAOvrAOzsA_Az" + "A9AnAObmuBhWDbS0iGa0tFM0ycbGCUAAx8fGxMSVlZU_e_AB8AHwAfAB8AGQiIj-" + "iOY30QFZAZkDpwGhAasDGJ2dnRH9vgLc3Nz_2wPhA-cDEf0B8AHwAfAB8ONc9Bed" + "5eXlF51zAgo1_4QDqzB2AtgAvvIB8AHwAfD_AfABYAYDigAXATX3AfAwAP-cAAMD" + "qAASA58DAfABwCcAPy0AMwA5AMMzAcBZBNnZ_tnxBc8Dn_AB8AHwAfDtkwjT09Md" + "BHV1dWkgaWk8PDxICZSUAJRERERtbW2OYI6OkJCQ-AqIPokAiYlVVVVlZWUBtwCX" + "l5dzc3NgIGBgWlpanwZjYxBjLCwsQgCRkZF_LARp8AEARQAGMNQBJwBqAGpqSEhI" + "W1tbAz0LRQA4ODhfX18_UwTmBBUAAQByAM4ESUkASVxcXFNTU4YAhoaamppNTU3A" + "Pj4-eXl5tQJRMP8B8AHwAZBZByfzAfAB8AHwRwHwAfABkIeHh7ViPGC5uQDGxikU" + "XATugO4A8fEA8vID8AcDcCEAXwTj4wDT0wAAvr4Rq6vAxcbFU2QDMLy6uiYBePD_" + "AfAB8AHwAfABwIMByQDSAP-JAb4CmQNWZ_0FET0jDRHN_9sDEZ1c9AHwAfAB8AHw" + "F_3_F836Ar0AyQYEBV8EwzYmDf-uAFz0AfAB8AHwAfABwBcB_94DwTj886PLaDFQ" + "AWsBMgT_AfABwCcALQAuNTP8OQmPAfjX19eW8AHwAfAB8AHwP3UALATeA2wAEAIx" + "AmhoHmj8A1UFEgC2DXJycuMJANoEWVlZnAYOAQEAH3oEGwAVAKIGugCysrL4V1dX" + "pAQ2AMA5AfBcZPHYAFBQUHkC7QZlB10A8QAJUlJS7AGNAOkBDABHwgTjAVcAVFRU" + "_wB34Hd3enp6XQD7BO4LvxIAUWAB8AHwAcC6AHsB8P8B8AHwAfAB8AHwAYALCoQw" + "AKbExAW3twDNMM0A39-RGD4E9vYYAPf3A_AYEPT0AATw8IYU2NgAxcWAAK2teLa2" + "ySEBIMfHyMbGAzCurfCtf39_cvAB8AHwAfD_AfABwHgGyTCJAYkAkwOZA_-fA6UD" + "XATRAcEIvwHiAr0D_yQA3QER_RH9AfAB8AHwAfBHXJS8BGkA9vb2F23kHOTkF23M" + "BoILnJyc_zcLPQveBho9vjgB8AHwAfD_AfAB8AGQHQHSCQEAUQNt-_8BYG4xnABp" + "AwHwAfABAC0Axyg1SJD5AODg4OsFigP_jfAB8AHwAfAB8M46agg0CBhFRUUlAm8A" + "SkpKfy4I3gNoAZ0IhAZVBYMBRgBGRlFRUYCAgMC1tbVWVlaGBEcExw4BMwBqAnFx" + "cavwAfDHAQCbBF8HOzs7iALhAPGEAIODgzsESwBpAHgAMVsIXl5ecgA2CTY2_jYM" + "AG4EAQIeACEJCgViMY_-8QHwAfC4Pn19fTDz_wHwAfAB8AHwAfABYPkAt2BmehcN" + "vgjPz18UlAjzAPMA-PgA-voAZPv7A3D5-VwUtQjnBudZFOsIsbFCrKwDU2QDAMbD" + "w5ybm_9s8AHwAfAB8AHwAfA-AUsM_981Dj0rAtY-XAqJCqQBDwDxKAK9vb2hANAy" + "zwPVA_8Rbe0D8wP5A1z0AfAB8AHwxwHwF_0XPebm5l0zcwL_wAAQAnwLEwXIDRAF" + "2wDsB_-WMwHwAfAB8AHwAfAB8CMBwN7e3tvb21cDWfT_AfAB8AHwAcDFBGMA5QWE" + "A_-B8AHwAfAB8AHwAWARBDk58YsIYmJiWQeBDHUGFQAPcgaQDHoBMQiZmZlw4HBw" + "uLi4GACJAWc4xyEAOQAUAWtra34PqgE_cDIB8AEwzjQ2MFYNNzfGN6EE5wBkZGRH" + "BFYBR7kE0wiaCD8_PwsHbwBvb4GBgY2NjceTAPgEOQBOTk6EAGUE_w8AXPQB8AHw" + "ATAGA84EAfD_AfAB8AHwAfAB8AFgIweHYABuuLgAtLQAyILIOBTl5QDt7cEYHPX1" + "r0gJAFYE6uoAAODgANLSAMDAAbIIQKiow8TEyAzFxQMAVgS8u7uK_IqKZvAB8AHw" + "AfAB8AHw_wEA-QzAMIEDywGNA5MDUAT_nwNcBB4AIgIhBqoBPQIkAP8ZAskDzwPV" + "AxH9WfQB8AHwjwHwAfAXzc4E8vLyNgnA6Ojo4uLicALZAv-RAlwHuzjtBvoCgQm3" + "APU3_8TyAfAB8AHwAfAB8AEwxwv44-PjxAjHO3b7AfAB8P8BwAJtVwA8A3XwAfAB" + "8AHw_wHw7cO2CsMDmw0dBDIEdQM4SEhIigZfATECT08GT2sBnACHh4dubo5ucQFM" + "AoMBXV1dCQDHdQ_rBa4AW1tbWwJwBUdj8AHAJAB0dHTIAbMcs7NpANUGhABNTU1H" + "cgC2BBsJeXl5LQM9_D09owIYAIQA7wSvCDkA_9Q0EDWKAF3wAfAB8AEwmwT_0gA2" + "8wHwAfAB8AHwAfABkAPBAopgh7q6CqqqAcEYx8cA09MA25LbShTi4gMQ3t50FADO" + "zgDCwgCyssAAoaFfrKyBAQMwwMTBwainp0MIYPD_AfAB8AHwAfAB8AEAOAF1Mx-d" + "OygCIgLSABYCmJiY_wYAEwLZDjYGVQK3A9wCwwP_yQPPA9UD2wPhA7U4Ef0B8B8B" + "8AHwAfAX_cgE9_f3ATAJ7-_v6urq5fzl5cIHXQ9YAg0CfAK0AONBBwADrq6uawSR" + "AhgA_1_0AfAB8AHwAfAB8JaTVAP_CAQBZfECMvQB8AHAtgfhAOMvCq0E2dnZn_MB" + "8AHwHwHwAfAB8AEwhABycnJxOghqamp1BssKwANg4GBghYWFewYxCAwAgVUIiYmJ" + "WVlZDwA4p6enjwS6DAUEdnb-dl4ChgHrC2cISwBUMJIBYwHwcmCLi4shCdEEgoyC" + "gr8BXwR4eHgIAf_aAbgICQBZAbsI2QiGBGAA-K-vryoAJwCSBAkABQf_sgIh-QHw" + "AfABkK8LHAU88_8B8AHwAfAB8AHwAWBXDFsFAYpgt8TEU62tAgCkpACurgC3t0AA" + "vb0Av78DELsGu9YYegSenjeiooikvr6sCMfExAMAwMG_v5aVlVrwAfD_AfAB8AHw" + "AfABMDIBOAHjMf-8AfsBhwONA5MDvwFAAgkAiKioqDoCt7e3sQP_JADTAuICyQPP" + "A9UD2wPhA__nA7U4XPQB8AHwAfAB8Lv4ASoJ9fX18fHx7ADs7Ofn5-Hh4Y8eDB8I" + "TALJMJ2dncYA_xwFzwbnAGcCvjgB8AHwAfD_AfAB8AHwAZCZAJdlrgAJAP__CScM" + "AwMBANaYZQEVMB4A_9UAUAQzAPg9qThd8AHwAfD_AfAB8AHw8GOZABcEYzxoAf_g" + "ClMBAQAJAL0AhwxRPx4A_6IGCQBuARgw2TVsCSoARgL_3gAlO8nwATBpAB4wPwBy" + "AP8BAPkAeDBLAFMEGADOMQkA_1EATgAPACEwCQAhADMACQB_QQEkAMg0ZvAB8AHw" + "AWCr_KurIgUB8AHwAfAB8AHwHwHwAWBfBH4AjZC2w8MAebGxO6KiKKEAoQKZmQCY" + "mCHAnp4vnZ1moS4nYMDFwsK6uLj6BVTw_wHwAfAB8AHwAfABYLRggwEfjAGBA4cD" + "jQOTA5aWlvG1CKSkpAEIOgX7N8UB_1UC7gIbA88D1QPbA-ED5wP_tfgB8AHwAfAB" + "8Fz0uzgXPQHaBO7u7unp6eT85OTyBMECuwLPAHMCJQvHxgDDBiILtbW18QLSBv--" + "OAHwAfAB8AHwAfAB8AHw_wEAFQNKAaYFYgQ1BAEAwAD_ZA4BMEo09gxrAV8EUASN" + "M_8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AGQjwEB8CfwAfD_AfAB8AHwAfAB8AHw" + "ATBMAn9C8wHwAfAB8AHwAfABwJT8lJTTApbwAfDPM8cFeAz_QAhL8AHwAfAB8AHw" + "AfABYH8sAeBhdQN7A4EDhwONA5X8lZW1aGgKtTixALcDvQP_wwMJA88D1QPbAxE9" + "tfgB8H8B8AHwAfAB8GYAFz3UBPT89PS7OJMDuziKM7s4HAXjJTVGBbi4uOQA_A_J" + "AP_Q8gHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfDB8gHwAfAB8Fz0" + "AfAYMP8t8AHwAfAB8GnwAfAB8AHw_30HBAiVDQHwAfAB8AHwAfDHAfABkCkEm5ub" + "xAKc8P8BANYCAQDfAogOwAMtAELwPwHwAfAB8AHwAfABkISE_oRHOpAwsQB7A4ED" + "hwONA_-QM8EItci3A7U4yQO1ONsD_-EDET1Z9AHwAfAB8AHwXPTjFz27OPLy8rto" + "Pwz-BHjOzs67OBYFhAmQD6L8oqIlBckwSQVf9AHwAfD_AfAB8AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfA_AfAB8AHwAfABYNkL" + "fn7-fk7zAfAB8AHwAfAB8AHwEQEAioqKLzenp6cAra2trq6upqYQpqOjo-gCg4OD" + "_zcIM_AB8AHwAfAB8AHwAcD4fX19ZgNZNGkD4zd7A-OBA58Ak5OTHwUMALUI-LCw" + "sLVosQO3A70DtWj_1QO1OBH9AfAB8AHwAfAB8CMXndQE9_f34ATw8P7wu_jYMMMA" + "UAogCsQIJg34vLy8XzQ68gHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8B8B8AHwAfABYIMHfHx8XncB8AHwAfAB" + "4IsmBJ3inQOQgYGBJ_AB8AHw_wHwAfAB8AHwAfAB8AHwATD_1wSLCCkxWTSOBXUD" + "pgiBA4iSkpLpB5-fn7U4-LS0tLX4tTjPA9UD2wP_tThc9AHwAfAB8AHwAfC7-P-7" + "-L8N4QCQOcwA2ADmDd8F__wA8AC-aAHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AEwLQNFA1rz" + "AfAB8IEBwJ2cnMTCwgOQwL-9vYaFhSrwAfD_AfAB8AHwAfAB8AHwAfAB8P-1CKAI" + "IzFZZG8DdQN7A4EDEaoNnZ2dYAmpqan4sbGxmQPgPasDtfi1-P8B8AHwAfAB8AHw" + "XPS7-PIECOfn57s409PTzIzMzPgNqQi1tbWKCceQOY0JDwC-vr5f9AHw_wHwAfAB" + "8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwPwHw" + "AfAB8AHwAfABwKqq-qpOA3YB8AHwAfABgFwUIMHBiomJDzCUk_6TDwAVACrwAfAB" + "8AHwAfD_AfAB8AHwAfAB8EQEWWR4AxFjA7a2tkcEnJycx3sDXAR-A6CgoMgNxQ3_" + "hAOZAycApQOrA7U4vQO1-P9c9AHwAfAB8AHwAfC7-Ls4iPPz8_IE6urq_gQA3t7e" + "19fX0NAA0MnJycHBwbn8ubkoBTcF5ADqAPAAX2T4xcXFCwEB8AHwAfAB8P8B8AHw" + "AfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B" + "8AHwAfABMKUGX_QB8AHwAQGQnJubw8HBpgykpAkAAwC1s7O-4Ly8gICAKvAB8AHw" + "_wHwAfAB8AHwAfAB8AHA6gw_FzFRA1cDWWSpCHUDkJACkA4Nnp6epKSk-Kurq_kJ" + "kwOZA58DpQP_qwOxA7cDvQPDA8kDtfgB8D8B8AHwAfAB8AHwu8j4-ID49fX18fHx" + "uzgA4uLi29vb1NQw1M3NzfAA6gC3t_634w3kAOoA5ADhAPwAX_T_AfAB8AHwAfAB" + "8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw" + "AfAB8AHwAfCAB58JDGnzAfAB8Fx0wMADkMCvrq6Eg4Mq8AHw_wHwAfAB8AHwAfAB" + "8AHwAZB4oqKiWcRvM2kDbwOP4I-PlpaW1AcnAG4E-LCwsB4AJAAwAJ8DpQP_qwOx" + "A7U4wwPJA88DtfgB8H8B8AHwAfAB8AHwu_jyBO8E7-_-BObm5t_fAN_Z2dnS0tLL" + "jMvL8ACBCbS0tJAJ_-oAXzT8AOQwX_QB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B" + "8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfAPAfAB8AHwAcCzs7N7OHt7" + "dQHwAfAB8HV1gScMwsDAiYiIDzDjVgQPAKqoqCrwAfAB8P8B8AHwAfAB8AHwAfAB" + "MFkED8AJWfRdA8oIlJSUjoyOjgYADm2tra2HAz-NAyoAmQOfA6UDqwPl5f7ltwO9" + "A7X49vMB8AHwAfAPAfAB8Fz0u5jy8vLtAO3t6Ojo4-PjAN3d3dbW1s_PMM_IyMga" + "PY0Jo6MGo_Awvmi9vb3Cwv7C-w0dAQHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfCPAfAB8AEwSwN9fX14" + "8yMB8AHwm5qaTQSlo_6jCQADAAkADzAq8AHwAfD_AfAB8AHwAfAB8AHwAQATDv-6" + "CQUxPwNFA0sDUQNXA10DgVk0kpKSmpqaaAT4paWlDp2TA5kDnwOlA_-rA7EDtwO1" + "-Fz0AfAB8AHwDwHwAfAB8LuY9_f39GD09PDw8F0JuwjhROHhGp2_v78HArEAsbGh" + "oaGMjIz_HZ1f9AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8IEB8Lu7u4WFhX7zIwHwXPTCv78DkKmo" + "8Kh5eXkq8AHwAfAB8B8B8AHwAfAB8AHwenp6HykEWfRZNF0DYwOQkJBAmZmZnZ2d" + "0Qeq_KqqDv2fA6UDqwOxA7cD_70DwwO1-AHwAfAB8AHwAfD_AfBc9OYEkADyBFEJ" + "uwgaPQ9pCRqdAgH_ALW1ta_Er6_-DYuLi1UFCAH_9gAVAF_0AfAB8AHwAfAB8P8B" + "8AHwAfAB8AHwAfAB8AHwvwHwNGIBAL8KGgEBAMABgP-pBQHwAfAB8AHwAfAB8AHw" + "_wHwAfAB8AHwAfABYPCQAjHfCwEUMSjyHgBRA3QB8AHw_wHwAfAB8AHwAfAB8AHw" + "AfAHAfAB8AGwhoaGurp-ulnERQNLA1EDVwNdA48gj4-YmJhpA6KiPqI4DXUDZjMw" + "AA797u7-7rcDvQPDA8kDtfgB8AHw_wHwAfAB8AHwX_QanV0JGp0A19fX0NDQycl-" + "yQUBYwbyDcwJUgUCAZH8kZH_APwAOQ8bAEYyQ5L_AfAB8AHwAfAB8AHwAfAB8P8B" + "8AHwAfAB8AHwSmRNNLkKx2ADGw9GAri4uBkCIwH_9gl-BigCQQEB8AHwAfAB8P8B" + "8AHwAfAB8AHwAfAB8AHw_wFg5wDtAPMA-QD_AHQH0Av_EQF6ByhiK8JJAioMjfMB" + "8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfABMDIE9jAoMgsBOQM_IwH8AEsDUQNXAw4N" + "l5cGlw8AJAynp6etrf6tdQMnADAAhwONA5MDDv3_Dv0B8AHwAfAB8AHwAfAB8Adc" + "NBr9Gj3n5-fi4gDi3Nzc1dXVzjzOzuYNMwMtAwsBrKxirAoOioqKugkJAKb8pqbk" + "CRsAUQNf9AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwVvRTZFAEJgFjA-YK8TcC" + "pKSkgQYrApkGAQD_6QoBAD0CAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfABwN4w8eow" + "oKCg9gD_ACQDmAf_EQEXAWgEKgMpAS8BLsKABPCHh4dzAfAB8AHwAfD_AfAB8AHw" + "AfAB8AHwAfABsP-tDTYDzpoCATMDOQM_A0UDj0sDUQOyCFkEm5ubOwH_GAAzADIB" + "FwEsAYEDhwONA_-TA5kDnwMO_Vk0XPQB8AHwfwHwAfAB8AHwu_i7aF0J8wzz8xo9" + "zg3g4ODa_Nra4A3mDewNEQE5AxEB__YASQIOAWc1Fg46AjcCugn_mZYB8AHwAfAB" + "8AHwAfAB8P8B8AHwAfAB8AHwAZCBNpIH4ysC2DmpqalNBF0D4QnYlJSU6Qo6Ao0B" + "IJkG_wEAOAEB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAQDkMPiMjIzwAC0DjwcF" + "AYyXHyMBKQEzAy5iMZKlpaX4eHh4n_MB8AHwAfAB8H8B8AHwAfAB8AHwAfABMIn8" + "iYkcAi6S-QAtAwgBOQOPGgFFAyQALAGWlpZZNP8FAZkGaQNvA3UDewOBA4cD_40D" + "kwOZA58DpQOrAw49tfj_AfAB8AHwAfAB8AHwAfBf9McabcINyA3p6enUDdoNgeAN" + "09PTzMzMJQ7_RQPwAO8K_AA_AxQBRgI9Av8RARIAwDkx8gHwAfAB8AHw_wHwAfAB" + "8AHwAfAB8AHwVvR_UQZWlGwGFAEuAuA6hgeEQISEgoKCfwEgfeEBIHx8fHsB8AHw" + "AfD_AfAB8AHwAfAB8AHwAfAB8B8B8AEg4QDqMPYwgYGB_wUBCwERAWQFPwMjAc0I" + "7jv_YgQpzQEAEgCRBaXzAfAB8P8B8AHwAfAB8AHwAfAB8AHA_wsBuQouYght-QAt" + "AzMDOQMxPwOIiIgaMVkEn59-n1k0YwOABAsBdQN7A9L80tKHA40DkwOZA58DpQP_" + "Dv3e8wHwAfAB8AHwAfAB8D8B8Br9aQnIDc4N1A3k5ADk3t7e2NjY0eDR0cvLy180" + "9gBfNP8LARoBrgYNAg0LSgFtBTEy__VqAfAB8AHwAfAB8AHwAfB_AfAB8AHwAfBW" + "9OQAKAK1_LW1VgSPBzMDKwKtB1M08VQDgICABgABAF8EEgD9ATCFAVAS8AHwAfAB" + "8AHw9wHwAfABkIYBILcAAQDOAf8BADMGAQCCmFwHWQcDAwEA_zoFATD1AQHwGAAk" + "AC0AMwDHGQJIABExg4ODBgAPAP9OACkBxwhiBMQ4nQUx8kkC_TgBcgHwAfAB8AHw" + "AfAB8A8B8AHwAfAB8HJydHT-dGMGcwgxwhsD2AAnAy0D_ywBIAEdATIBCz1ZxN8I" + "RA3_dQN7A4EDhwONA5MDmQOfA_8O_Vz0AfAB8AHwAfAB8AHw_wHwu8hfNGkJugDO" + "DdQN2g0A4-Pj3d3d19f-11808ADVOV806Qp_AiMBMUwCmJiY5wmTBra2_rZXbzQy" + "AfAB8AHwAfAB8P8B8AHwAfAB8AHwAfDMAAJt8eQAr6-vrAgoAoE2RTP_AQCrA5xj" + "n2MBAKhjATCBM_8B8AHwAfAB8AHwAfABwIEAjwHAPjRBNCw0k5OT3gD-lQFQXwcB" + "MA8DAfABMCRg_zMwPwBFAF0AzDnOBAYACwH_FQBiBE4DxDhTASY9MZJiAf_9CL3z" + "AfAB8AHwAfAB8AHw_wHwAfABkPsBcgYxYgEACQP_DwMxAuoAIQMnA30ByjViAXFZ" + "lKqqqlcDKgBZNMr8ysp1A3sDgQOHA40DkwP_mQMOPVk0tfgB8AHwAfAB8P8B8AHw" + "AfAB8BrNugDAANQNCOvr69IA4uLi3ADc3NbW1tDQ0P_wAF80AgFfNBQBIwFRAz0C" + "_0kCwgeaBRsAPg0u8gHwAfD_AfAB8AHwAfAB8AHwAfAB8OMlwlgFsLCw5AAQAkID" + "_6xoAjEPAKUzy2efY3VjnGP_q_MB8AHwAfAB8AHwAfDlAsUBkJkBsJqamvQCATD_" + "BQQBkE8FAcAhwDlgRQBOMP9gAOcACAEaAbAHKjlRPz8A_6MFRwRSAsQ4NMJuAQUK" + "xvP_AfAB8AHwAfAB8AHwAfAB8P8yBJcIisYDAwkDDwMxAt06_yUC_wAFAQwAWTQg" + "DbJoWTQ_7ghpA28DdQN7A4ED5ub-5o0DkwNZNA79AfAB8AHw_wHwAfAB8AHwAfAa" + "_V9kzg3H1A1fNNgA4eHhX5T8AP--mBwCPQJYO1oDwWjyamL0_wHwAfAB8AHwAfAB" + "8AHwAfDjAfBWxLy8vCUyXQauCf8WAn427guMBzEC-QDvB0o0_0gDrmOcM0IDWwIB" + "MJUEAQD_UgIB8AHwAfAB8AHwAfAB8PcBwNUAAZCiAeDUAQHwAfD_MGBFAFcA6gDz" + "AIA0CwERAf87AXMF4AeRBUEBjgUvAScAP5M2VQJrAfX6twOQA3Nz_HNxAfAB8AHw" + "AfAB8AHw_wHwAeBWBPsBFATg-v0CAwP_r2gnAPAAWQQZPhIAFAFZ9P9ZxHsDWWST" + "A5kDWcRc9AHw_wHwAfAB8AHwAfAB8AHwX2QDaQlflO7u7urq6uNf9B2drKysXwRD" + "AjEy_wQCPQI4ARUAVA8jCmI0MQL_ZTQB8AHwAfAB8AHwAfAB8P8B8AHwHzKxALcA" + "rDhWNAoC_1Y00QoCPVYEjAdTBJoIGwCPTTRKNLEzWAKkpKRAArEOAaenp0IDAQCp" + "AVD_VAAB8AHwAfAB8AHwAfAB8P8B8AEw7gIB8AHwAZA8YNsw_-cA8AD2APwAAgFu" + "NEQEHQH_IwFaAyUCRwGdBVQ_PgEyAT85AKkIVz-WNjTCPAB8fP585PMB8AHwAfAB" + "8AHwAfDHATCHAJkJubm5NPLxAv_3Av0C_wAJA-oAFQPdOoEG_ysCKAIIAREBIQA_" + "A1U1WcT429vbWTSBA4cDWZSlA_9Z9AHwAfAB8AHwAfAB8AHwHwHwGv0QBboAzg33" + "9_f_X_TwAF-URwHOB1QGnQVJAv9AAkcBkDbyCkQBIz0ukmL0_wHwAfAB8AHwAfAB" + "8AHwAfB_VpS3AL0ArDgQAkcEVjSC_IKC4QBWZCoDZwJGAvAA_1A0UQMRASoDdQMd" + "AWcC9wvfSwBGAgEAMgEBALMB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfABgNgwAQDk" + "AO0A8wD5AP__AHo0CgJLA2gEZTQvATgB_8IH-QliBFkB2gdiNC0APwAfbwNi9AEw" + "0gM5AHl5eX_z8wHwAfAB8AHwAfABMHb8dnb1AdsANPI0kgU9HAL_KAI2P18EOQCl" + "CSsCGwAtA_8iAh0BLwFFAzwAUQNZ9FmU_5MDmQOfAw79AfAB8AHwAfA_AfAB8AHw" + "AfAB8F_09PQw9PHx8b74AgHLy_DLxcXFUwHpAVgCRgL_SwM6AjQCzgeQ9mI00wWg" + "Bf9i9AHwAfAB8AHwAfAB8AHw_yKSnwClAFbEbwaWOVYEJQL__zxWNKk45AAuAlME" + "VQI2AP80An8CYwMaARkLTgAqA0MC_ywBXQABAIUCATADDAHwAfD_AfAB8AHwAfAB" + "8AHwAfAB8P8BwM9g3jDnAO0A8wD5AMIH_wIBQgNQAWg0ZTSCBTUBOwH_bAOTNgEA" + "YgSyBVYBdwFiNB80Mpb2ATAbAKgDgYGB8HR0dHAB8AHwAfAB8PkB8HBwYwDvAccC" + "sG008v80MiQA4Go2PwYA1QAIPS4C_1gFJwMFATMDHwIsAd4ASwP_UQNZ9HsDgQOH" + "A1n0wPMB8P8B8AHwAfAB8AHwAfAB8F_0R1_0X_QCAdHR0Q4BxvzGxl8BWz5OAxAC" + "YAMZAv-gBQIKxDhiZKkFUAEqAHkC_4gCZTQ0MgHwAfAB8AHwAfD_AfABwIQwjQCT" + "AJkAnwClAP-rACIyTQesOF4CBgCsmFZk_ycDLQNTNF4CMQJRA1oDFwH_eAMYM4gC" + "jQ_1CgEAogZMAv8BkEcBAfAB8AHwAfAB8AHw_wHwAfAB8AHwAQDJwNsAAQD_5ADt" + "APMAzjcFAQsBXAEXAf8dAWU0LwFlAcc4IARNAbUF_7sFYjTEaDTyNPIBMNsDMADx" + "cAJ6enod9AHwAfABkMBycnKAgIARBIEA_3gANPI08jRiVjQuNbgIrzj_CG0hA_wA" + "LQM2ABcBTgBZNP9RA1cDXQNZ9Fn0uvMB8AHw_wHwAfAB8AHwAfAB8AHwxT0DX_Rf" + "9NfX19LS0sDMzMzHx8dGAg46_6oHQA4gPUoBIgIuMmI0YgH_FQBcAb0GKgBqArUF" + "fmMu8v8B8AHwAfAB8AHwImL6MocA_40AkwCZAJ8ApQCrACJiwwD_KAXMAFb0GwPt" + "ACsCWwI_AH8uAso7dgJgAGMDNwIgAchcyMjvCkACLwHNAYDO_wHwAfAB8AHwAfAB" + "8AHwAfD_AfAB8AHwAVDYYOcA7QDzAPjJycn_AAUBCwElAjY8_2U0ygg1AXEBYpTE" + "CI0DYmT_ljY08jTyAfDFBEMIPAAPBse_ASkEATB1dXVBZIYE_xhgbQs_CdQBlgBj" + "AFHwNPL_NPI0kukKUQAxYghtIQM2AP8tAwsBFAEgAS8BSwNRA1n0_1n0ojO68wHw" + "AfAB8AHwAfB_AfAB8AHwAfBf9F_0_ADiAOLi3d3d2NjY-NPT00wCPAOoBlEDWgOP" + "IG1xAaoBVgGNjY31B_-iMzoCDAZDAkwCcG5oAaoB_10_lvYB8AHwAfAB8HKW5TL_" + "dQB7AIEAhwCNAJMAmQCfAP-lAKsAsQC3AFbEIQBWlFgC_-0AQgD0MlNk0QdXA2AD" + "HQE4z8_P7Ao9AiwB1NT81NUBIKIGAfABMGQCAfD_AfAB8AHwAfAB8AHwAfABwP-0" + "8AFg3jDnAO0A8wCMB_8A_240aDTWCCMBRWwuAsIHKT3_YjRfAeMHxAg0YkACNPI0" + "8v_s8QHwAfAB8AHwNPI08jSS_wVtGQUxYg8DFQMIPScDAgH_MwM5Ax0BLAFLA1ED" + "VwNZ9P9Z9LTzAfAB8AHwAfAB8AHwHwHwAfAB8F_0X8Ty8vIB9gDr6-vn5-fjAOPj" + "3t7e2dnZ_0kCQAKlBjcCgwEgPfgKkzb_MAxhDpA2dwFaPNMFfQHoBficnJzNlfs6" + "S5w08gHw_wHwHPKdy2kAY5mHAI0AkwD_mQD_PMkGIjJW9NIAVpRqAv9UACsChAah" + "By4CUwTFB1cDjzQCaQONAzoC2traSA__mQYBAEYCATBBAQHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHw_wEA1WDkMO0A8wAfAv8ABQH_CwERARcBZTQpAVoDkgFixP_EOGUB" + "YpQ08jTyNPIB8AHw_wHwNPI08jTyNPIFPSQA_QL_MWIVAwg9WgAtAzMDOQM_A_8m" + "AUEBUQNXA10DYwNpA1n0_1n0AfAB8AHwAfAB8AHwAfAfAfAB8AHwX_RfNPX19RH2" + "AO_v71805OTk-N_f30MCPQKbBzcCsAf_YwOPAcFoMAyyBYwB8joECECDg4N_f3-M" + "AYX8hYU9AhIAvQMbAIYBWAL_wAa_AYYBPwANCDcyMAZUAP8BAMMD7wEBYAEyAWAb" + "kDAw_zkA6s9dAD8GwTJ1AHsAgQA_hwCNAJMAmQB7Bo4LkZH-kVb0JTICPVZkbAAn" + "A6k4f4QGCAFIA8IHUARgA0E04Pzg4OwKlgZAAgEAOAEBYP7lAfAB8AHwAfAB8AHw" + "AfDPAfAB8AHwAfDl5dJg5DD_7QDzAPkAIgIFAQsBQgMXAf8dASMBKQFaAzUBYvST" + "ZmI0_30BaQw08jQyQTrRATTyNDL_MfIx8gEwKgA08jTyNPI0wv9WNAVt_QIxMq84" + "YAAhA_kA_y0DCAE5Az8DIwE4AVk0XQP_YwNpA1n0WfQB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfBf9F_0wOzs7Ojo6FUCQwL_qAafBgQLNAJjAxUMMTKRPv-bATIEZQFUP3cB" + "ngHuBes1fzEyDwBDApsBRwohAO41pvympjcycwJIAM8DPTIBAP-LAv4BAfAYAB4A" + "HgYtADMA_zkAGTJLAEI5XQBjAGkAbwD_dQAfMnI_fzskD84KIgInP_9W9AI9VpQn" + "A_kAmAeEBlNkf1cDTTQjAekKOgIvAQEA6f8BIPgKAfAB8AHwAfAB8AHw_wHwAfAB" + "8AHwAfABwN4wAQD_6gDzAPkAdzQLAREBZwUdAf8jAVQDxzhi9F8BZQFixIkB_5UB" + "NPI08jTyDQIxMtsDMfL_MTJHNDTyNPI08jSSVmTrAv_xAik3VAAxYhsDhDYtAzMD" + "_zkDPwMjAS8BUQNZ9Fn0AfD_AfAB8AHwAfAB8AHwAfAB8I8B8AHwX_TwAPj4-PwA" + "APPz8_Dw8O3t_u1GAkACOgIgnRUMwTgMBv9NOv01VG9iNIkB6wWeAfoF-H5-fmBv" + "EgbFARsANzj_4WM5AOwBswH1AQEATgABAP8EAgEwDzAbMCcAMwaXYkUA_0sAUQBX" + "AF0AGG91AAEAFAf4i4uLqWhGAiKSsQBWxP9yDy0_VpQtAzMDKwKEBi4C_04DUDRH" + "NDcCLAEBAO8KAQD_QwIBkEoBAfAB8AHwAfAB8P8B8AHwAfAB8AHwAWDPwOQw__Aw" + "-QCMB2s0EQFlNCMBKQH_LgI1AWMDYvRixDTyNPI08v8wAAECBwJxNAEASwAx8hsw" + "_1UCJwBmADTyNPI08jTyf2v_sz0zP-QAGwMInQ4BFwEgAf8sAUoBVwNdA2MDWfSc" + "8wHw_wHwAfAB8AHwAfAB8AHwAfBHAfBf9F-U-vr6_AD2xPb2EA7x8fFGAiCd_5YG" + "wZhVDrsOZQojPRI2xDj_9QESBpEOZQrIAacBwgGzAT-8MRIGDAAhBsEOGACMjP6M" + "OjIBACEGJDYBANQBAQD_PwABAAwwFQAeAEgGFjI5AP8_AEUASwBRAFcAYDAlAi4C" + "_x4AH2KpOI0AJD9WZN8CVsTxJQLFxcVWlCgCVjQrAv-EBlM0FwFNNDQCKQEBAJMG" + "_z0CATA-AQHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAcDhYP_tAAEA9gB9NGg0ZwXN" + "OM8J_8cI3gli9GI0awFxAWJklmb_NPI08jQyTwi6DOAxEwLjMf8lMgFgRjJSMl4y" + "NPI08l4C_zTymQACPVY06wIFPf0CAwP_CQOvmCcDCJ0lAikBPgFXA_9dA2MDWfQB" + "8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwX_R_AgG3CQ4BIP0xYk8OVQ7I_MjICArc" + "DmLEdGoqBu4FPzFi8gETAr4OJwacBnx88Hx9fX3aAQwA5gEVAPiEhITjAQEA_gEn" + "AAGQ_xIAHgAQAicALQDbNj8ARQD_rm9vNsU6cjYfYuo25zYiYv_fAkcHVpQlMlaU" + "JwMtAzMD_wUBPwNIA444TTQmAY0GNwL_AQA1AQEwQQEB8AHwAfAB8P8B8AHwAfAB" + "8AHwAfAB8AHA_-Fg8DD5AHE0aDRlNE4Dxzj_YsRTAVkBxPiWljTyNPLyAf80Ytk4" + "EwIZAv4BAfAYAAEA_yQANPI08jTyNJKMbVZk9wL__QIDAwkDDwMxMvAACP0mAf8W" + "Mln0kPMB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8GLE8AD_YjQCAbcJDgEgnZY2MTJy" + "AxGgBdPT0yM9x8fH42KUJj2tra1sDBwIxzj_MWL7Or8BVDY3Akg2ODRFNv0BMHoB" + "4BgwKzKABHACwAb4kJCQbDbAZl0AxTofYv91Nv88mQCfACIC2QInPwL9_wI9VpSp" + "OCsCRQPdOk00dTP_LwE1AQFgQAIB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHA_-SQ" + "8wBFP2s0KzJIAy4C7zr_UT8xYmL0YsQ08jTyNMLJnPEyBHt7ey7yNPI0Ak00_zTy" + "NPI0ktkCVpT3AgU9CQP_DwMxYicDhDYIbSMBIjJWNP9ZNITzAfAB8AHwAfAB8AHw" + "_wHwAfAB8AHwAfAB8MH4OjIfIG3BODEyHgxPDtra2vjW1tbyOmLEhQ71Osdo_zEy" + "9z5iCvcONDIhBjcyxTr_6QEBAMg6AQD-AQHwGzAqMP8KOxkySwAcMl0A-TxvAB8y" + "_3VmkwAkPyIyVvRWNNQKVsT_qTimOFM0LjJ1MzIBATA6Mv8B8AHwAfAB8AHwAfAB" + "8AHw_wHwAfAB8AHwfmYBMHFkZZT_7zpi9GL0YmQ0YpsBNPI08v808jRiLvIxYjTy" + "NPI08jQy_80CNGJWZPcC_QIDAwkDDwP_FQPqAPAArzgInSABr_gB8P8B8AHwAfAB" + "8AHwAfAB8AHw_wHwAfAB8AHwX_Q3YsH4mgX_I21ixCMKfw6FDmYMkwbHOPixsbEx" + "MgMG-zpgDxgG_zQyJwY3YjoyPTIBYAcCCjL_AWAkMDAwGTJFABwyVwBdAP_5PG8A" + "HzKBAIcAqTiZACQ__yJiAp1W9FZkqThTZE2UODH_AWBZ8QHwAfAB8AHwAfAB8P8B" + "8AHwAfAB8AHw58BrlC6S_2L0Jp1iZJaWNJKnATTyNPL_NPI08jTyNPI08jSSwQI0" + "kv_fAlbEBW2v-C7CWfQB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwX8TB-DEy" + "wThiNDjk5ORilCY9fw7JyRDJxcXFkza8vLz4ubm5MTIDBvs6NGKcNv_aATAGOjKP" + "CgEA9QFDMgHAfxgwJDAWMjkAPwBFABxiq_yrq8U6pjh7AIEAhwCpOP-ZAJ8ApQCr" + "ACIyVjQC_Vb0_yiSK_IB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAu8v-Q9mL0" + "YvSWNjTyNPLRAdcB_2hkNPI08jGSNPI0Mn8CNPL_NPI0kuUCVpQDA1Y0rzgxYv-v" + "yC7yAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwNPJ_wfjBaPAJLgIjbWKUeQ7U" + "_NTU9TrHODGSAwYvPTRi-K6urmtkhgrpAXE0QAL_QzIBwBgwIQAWMjMAGWJLAD8c" + "YmMAcjYfknU2mQDQ0P7QpQCrACIyVvRW9Fb0KPL_AfAB8AHwAfAB8AHwAfAB8P8B" + "8AHwAfAB8AHwLvJi9GL0_1kBYsQ0kpUBNPI08jRiazT_NDIQMjTyMWI0Ml4yNDJz" + "Av808mkANPI0MtMCNJJWNAVt_w8DFQOv-K_4AfAB8AHwAfD_AfAB8AHwAfAB8AHw" + "AfAB8H8B8AHwMfLB-CNtYvR5Dtvg29vY2Nj1CuIFMcLjrA5cCr6-vjRiIQY3Mviz" + "s7OGCukBjwoBAPUB_0MyAfAYACQwLQAzABliSwD_HGJjAGkAbwBTxCYHmQCfAP-l" + "AKsAImJW9CXyVvQB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8DHyYvRi" + "ZP808jQyoQE08jTya2Q08jHy_xgwNJJtAjTyNPI0MscCNPL_VpQFba_4MfIB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAx8sH4I51ilB0KeQ744uLik2Yxwvs6" + "YA80MhjBwcEhBjcyu7u7_-MBiQrsAXMI9QFDMgHAGDD_IQAnABYyOQAZMksAUQAc" + "Mo9jAMU6U8R1Nt_f36UA_yQ_twDrAiIyVpTkAFb0JfL_AfAB8AHwAfAB8AHwAfAB" + "8P8B8AHwAfAB8AHwAfAB8GL0_2L0Jp00kpUBNPI08jTyCjL_NPI08icAYQI08jTy" + "NPLTAv80klZkBc2v-CPxAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwLvJi" + "9C7yYjR5Dn_1OpM2MZKmDi89tQ40MsoEyso3MsbGxsTE_sTjAYkK7AE_BvUBQzIB" + "wP8YMCEAJwAtADMAOQAZMmwG_1EAHDJjAMU6dQBTlKmYJD__IsJW9CXyAfAB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8GL0NDJZATTyNPL_NPI0wukBazQ0" + "8jTyFTA08v9zAk00NPI08jTyNv9W9DTy_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw" + "AfAB8AHwAfAu8o9i9C4yFwpzDu_v7_Vqj5M2Wg8xYlYK2dnZNGLjGwY3Ms7Ozjoy" + "iQrsAf90NEMCAfABABsAEzItABYy_z8AGTJRABwyGA9pAG8AH2L_hwCpmKUAqwAk" + "PyLyVvQB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_NPI08jTy" + "NPI0MtEBNPI08v8u8jGSNPI0kpcCNPI08jTy_zTyNPIB8AHwAfAB8AHwAfD_AfAB" + "8AHwAfAB8AHwAfAB8P8B8AHwLvImzU4MdwGTZjGSx5Y2Vgo0Ytzc3BsGa2T_gArj" + "AdwOAQBAMgEAmwoBwP8YMCEAAQAqADMAOQBNZFEA_1cAHGJvAHI2H5J1ZiTPIvL_" + "IvIB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfA08jTyNPI08jTC" + "azT_NGIQMjTyNMJeMjRiTTQ08v808jTyNPI08gHwAfAB8AHw_wHwAfAB8AHwAfAB" + "8AHwAfD_AfAB8AHwAfAB8C7yLpKTxj8xkvtqNDKcNscO1AHe3v7eOjI2BuwBQDIB" + "MAECAZD_FTAkMC0AFjI_AEUASwBsNv9dAG8GxWofknXGIvIi8gHw_wHwAfAB8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8DTyNPI08jSS0QE08jTy_zHySWI0" + "8jTCmjI08jTyNPL_NPIB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHw" + "AfAu8i6SMcLiBTGS-zr_rw40Ypw2OpI2Bqg2QzIB8P8BMCEwKgBKlGw2HGJpAMU6" + "_x-SkwAfwiLy6vAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB" + "8DTy_zTyNPI08jTyMfIB8DFiNPL_NPI08jTyNPIB8AHwAfAB8P8B8AHwAfAB8AHw" + "AfAB8AHw_wHwAfAB8AHwAfAB8C7yMfL_gwGW9vs6NGKcNjdigAoBAP89MgEw-zEB" + "8BAyEzI2MBmS_1cAHGLFOh_CdfbDYN7wAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHw" + "AfAB8AHwAfAB8AHw_wHwAfA08mJkZfQ08jTyMfL_MfI08jTyNPJTZDTyNPIB8P8B" + "8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8JP2ZfRlNDRiN8I6" + "Mv89MkAyAfABYCQwMDA8MBmS_xxixcofYnX2AfAB8AHwAfD_AfAB8AHwAfAB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfAB8AHw_zTyNPI08jTyNPI08jTyNPL_NPI08jTyNPIB" + "8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwLvL_MfL7mjRi" + "N2I6wgEw9QEB8P8BYCdgFpIZYqP4H_Ii8gHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB" + "8AHwAfAB8AHwAfAB8P8B8AHwAfAB8DTyNPI08jTy_yjyNPI08jTyNPI08gHwAfD_" + "AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8DTyNPI3kjqS" + "AWD_-zEB8CSQFmIZkhzyHPIB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB" + "8AHwAfD_AfAB8AHwAfAB8DTyNPI08v808jTyNPI08jTyNPKo8AHw_wHwAfAB8AHw" + "AfAB8AHwAfABAcA" +}; diff --git a/src/data/icon48.h b/src/data/icon48.h new file mode 100644 index 000000000..b9cfaa8a8 --- /dev/null +++ b/src/data/icon48.h @@ -0,0 +1,40 @@ +static char enc_icon48[] = { + "_gAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw" + "AfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB" + "8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHw" + "AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfABgFD_oRYPBAA1BABWVQQAWwQAQQQAGgQA" + "Av8u8AHwAfAB8AHwAfAB8AHwVbSAAQQALQQAsAQA9FUEAP8EwPsEAM4EAFP9BAAE" + "QvAB8AHwAfAB8AHwqwHwvOAEBACFBAD5uPDVBOD-BAC9BAAUSvAB8L8B8AHwAfAB" + "8AHwvGADBACuoqjwBPAEwNsEABZS8H8B8AHwAfAB8AHwAfDAIHuvnPAE8ATwBCDH" + "BAAFVvC_AfAB8AHwAfAB8LzAIAQA3vaY8ATwBPAEYGZa8AHw3wHwAfAB8AHwwMCX" + "kPAE8OsE8ASg3wQABl7wAfAB8K8B8AHwAfC8QAYEAOeQ8PcE8ATw0OMvYvAB8AHw" + "AfDXAfAB8MBAHAQA_JDwBPALBPAE4GRi8AAAPz9U_wEEAA0EAB0EAB59BAAPBABE" + "9gHwAfDA8BVVBABxBAB3BAChUET9p5zwBPAE8BaGuMALBACqbAQAzgQA9AQA-wQA" + "qvwEAPYEANYEAHoEAL4SlvAB8AHwAfAEhjIEAF68FEKo8ATwBFCBcIFHtQQA5AQA" + "_wTwBKDuBAB-XDQQjvAB8AHwAfAQhmhHzPYE8ARgpQ5YwEBor2xBsPAE8AQQ_QQA" + "hFTyfwHwAfAB8MjA-Bgg8wTQowAQ-_-rACMuNrz_SrzwBPAE8MQgZ4LwbwHwAfAB" + "8BDJkbTwBMCnAAfLfV-0ETU6fP_mnPAE8ATwBCAkExxfhvAB8AHwAfDEgBEEAO0D" + "uPAEQKQO_f-tAIBCLDX_cTw-mPA3BPAE8ASAlYLwAUDNAKoBBAAFBAAUBAAiBAB-" + "JQhAEBAYEETz5PYE8KgABZxKRfIENju8_9eQ8ATwBPAEoOq0wKoDBAAsBACGBADM" + "BADq7AQA_AQA_gSAEBAYEOrKBACDBAAqBABMo6gAFkC88AQgrvgCBy83wP8VPj7_" + "-JDwBPCvBPAIs7yAuBDEoED_BPBXBPAEQDAQwAQAKcCAHRf8S7hQMBl_uFk4O_--" + "KYzwBPAE8ATwvEBhBABe95zwBPAE8ARg9gQAW1HAIJ8XFKwA8uhIkFUEAB-sxhkE" + "AH0EAJL1BADDBADznPAE8ATwwADozQBIBAD5kPAE8ATwAQTg-ADQACn_nrwYAshD" + "pPUB8NAQEQQA3nGgRqjwBPDAkOKI8ATw9wTwBPAEIM8UAwHwAfAB8HvIEPQYzKjw" + "BPAEQDQS0t-I8ATwBPAE8ARAeprwAfB3AfDEYLAZyqzwBPAEAMX1cAAvBADxiPAE" + "8ATwBOB68AQAGZbwAfAB8MSgHK0EAPGw8ASg_gQAScBDvj4URZTwBPAE8AQw6gQA" + "RjwN9mwJ__8IBAAT_QQAGgRADBAUEET2xHDgE6u48ARwuwQAA0CFGQQAup0EAPOc" + "8ATwBIDyBACgmADLABe0gAkEAKpFBACaBADSBADsBABa-QQA-wRADBDtBADTVQQA" + "nQQASAQACsDAGK0EAPW48AQg3QQAFfbwVcggEQQAUwQAoRxD6b0EAPRcJNwwEBAY" + "EJ8EAKpRBAAQuIAGBABuBAC66AQA_wTwBPAEgOoEAEpzBAAHSxBBOFgryF-88BQg" + "LHEB8NDQBgQAC10EAA0IQLj-vDAQBADFr5jwBPAE8ASgywQAFMRA6pm4gOcEAHAE" + "AOAgAfCvAfAB8AHwvEACBAC1jPAvBPAE8ATwBAC_VBBDMtT_TrAAeQQAPAQAYKLf" + "AfAB8AHwAfDAQBnYQozw1wTwBPAE8P0EAB1p8AHwrwHwAfAB8MDgGAQA-ojw7wTw" + "BPAE8AQA_AQA3PsB8N8B8AHwAfDA8CQVsYjwBPD3BPAE8AQAulz1AfAB8AHw1wHw" + "AfDEQA0EAL2M8ATw9wTwBKAEFBFh8AHwAfAB8FcB8AHwxIAFBABoBADjXQQA_pzw" + "BPAEgOUEAG3_hCUB8AHwAfAB8AHwAfAB8KvIEFwXPQQAkgQAz8BGXveYQwQQDBAU" + "ENAEAJT9BABB9CYB8AHwAfAB8AHwrwHwAfAB8NBwBAQADtgl_QQwDxRA5PIB8AHw" + "AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB" + "8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw" + "AfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwfwHwAfAB8AHwAfAB8AGA" +}; diff --git a/src/dsp/adsp/adsp.cpp b/src/dsp/adsp/adsp.cpp index 1a102662d..5a3879d5b 100644 --- a/src/dsp/adsp/adsp.cpp +++ b/src/dsp/adsp/adsp.cpp @@ -1,4 +1,6 @@ -#include "../../base.h" +#include "../../base.h" +#define ADSP_CPP + #include "adsp_tables.cpp" void aDSP::enter() { loop: @@ -579,7 +581,7 @@ int32 fir_samplel, fir_sampler; } snes.audio_update(msamplel, msampler); - scheduler.addclocks_dsp(32 * 3); + scheduler.addclocks_dsp(32 * 3 * 8); } aDSP::aDSP() {} diff --git a/src/dsp/adsp/adsp_tables.cpp b/src/dsp/adsp/adsp_tables.cpp index bb72e5875..e9f1b7ebe 100644 --- a/src/dsp/adsp/adsp_tables.cpp +++ b/src/dsp/adsp/adsp_tables.cpp @@ -1,3 +1,5 @@ +#ifdef ADSP_CPP + const uint16 aDSP::rate_table[32] = { 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, @@ -71,3 +73,5 @@ const int16 aDSP::gaussian_table[512] = { 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519 }; + +#endif //ifdef ADSP_CPP diff --git a/src/dsp/bdsp/bdsp.cpp b/src/dsp/bdsp/bdsp.cpp index bb3e3fd70..6e984dc97 100644 --- a/src/dsp/bdsp/bdsp.cpp +++ b/src/dsp/bdsp/bdsp.cpp @@ -469,7 +469,7 @@ void bDSP::enter() { // n is currently ignored #define NEXT_CLOCK( n ) \ - scheduler.addclocks_dsp( 3 ); + scheduler.addclocks_dsp( 3 * 8 ); // Execute clock for a particular voice #define V( clock, voice ) voice_##clock( &m.voices [voice] ); @@ -563,7 +563,7 @@ void bDSP::enter() } // Output sample to DAC - snes.audio_update( main_out_l, main_out_r ); + snes.audio.update( main_out_l, main_out_r ); m.t_main_out [0] = 0; m.t_main_out [1] = 0; diff --git a/src/dsp/dsp.h b/src/dsp/dsp.h index abb2ed569..1e36b51b3 100644 --- a/src/dsp/dsp.h +++ b/src/dsp/dsp.h @@ -1,11 +1,12 @@ -class DSP { public: - virtual void enter() = 0; +class DSP { +public: + virtual void enter() = 0; - virtual uint8 read (uint8 addr) = 0; - virtual void write(uint8 addr, uint8 data) = 0; + virtual uint8 read(uint8 addr) = 0; + virtual void write(uint8 addr, uint8 data) = 0; - virtual void power() = 0; - virtual void reset() = 0; + virtual void power() = 0; + virtual void reset() = 0; DSP() {} virtual ~DSP() {} diff --git a/src/lib/hiro_gtk/button.cpp b/src/lib/hiro/gtk/button.cpp similarity index 100% rename from src/lib/hiro_gtk/button.cpp rename to src/lib/hiro/gtk/button.cpp diff --git a/src/lib/hiro_gtk/button.h b/src/lib/hiro/gtk/button.h similarity index 100% rename from src/lib/hiro_gtk/button.h rename to src/lib/hiro/gtk/button.h diff --git a/src/lib/hiro_gtk/canvas.cpp b/src/lib/hiro/gtk/canvas.cpp similarity index 94% rename from src/lib/hiro_gtk/canvas.cpp rename to src/lib/hiro/gtk/canvas.cpp index 5351bab46..e6f7e4bbe 100644 --- a/src/lib/hiro_gtk/canvas.cpp +++ b/src/lib/hiro/gtk/canvas.cpp @@ -1,9 +1,9 @@ void hiro_pcanvas_expose(pCanvas *p) { -uint32_t *f = p->fbuffer; -uint32_t *r = p->rbuffer; + uint32_t *f = p->fbuffer; + uint32_t *r = p->rbuffer; for(uint y = p->canvas->allocation.height; y; y--) { for(uint x = p->canvas->allocation.width; x; x--) { - uint32_t p = *f++; + uint32_t p = *f++; *r++ = ((p << 16) & 0xff0000) + (p & 0x00ff00) + ((p >> 16) & 0x0000ff); } } @@ -28,7 +28,7 @@ void pCanvas::create(uint style, uint width, uint height) { void pCanvas::redraw() { if(!canvas || !canvas->window) return; -GdkRectangle rect; + GdkRectangle rect; rect.x = 0; rect.y = 0; rect.width = canvas->allocation.width; diff --git a/src/lib/hiro_gtk/canvas.h b/src/lib/hiro/gtk/canvas.h similarity index 100% rename from src/lib/hiro_gtk/canvas.h rename to src/lib/hiro/gtk/canvas.h diff --git a/src/lib/hiro_gtk/checkbox.cpp b/src/lib/hiro/gtk/checkbox.cpp similarity index 100% rename from src/lib/hiro_gtk/checkbox.cpp rename to src/lib/hiro/gtk/checkbox.cpp diff --git a/src/lib/hiro_gtk/checkbox.h b/src/lib/hiro/gtk/checkbox.h similarity index 100% rename from src/lib/hiro_gtk/checkbox.h rename to src/lib/hiro/gtk/checkbox.h diff --git a/src/lib/hiro_gtk/combobox.cpp b/src/lib/hiro/gtk/combobox.cpp similarity index 100% rename from src/lib/hiro_gtk/combobox.cpp rename to src/lib/hiro/gtk/combobox.cpp diff --git a/src/lib/hiro_gtk/combobox.h b/src/lib/hiro/gtk/combobox.h similarity index 100% rename from src/lib/hiro_gtk/combobox.h rename to src/lib/hiro/gtk/combobox.h diff --git a/src/lib/hiro_gtk/editbox.cpp b/src/lib/hiro/gtk/editbox.cpp similarity index 100% rename from src/lib/hiro_gtk/editbox.cpp rename to src/lib/hiro/gtk/editbox.cpp diff --git a/src/lib/hiro_gtk/editbox.h b/src/lib/hiro/gtk/editbox.h similarity index 100% rename from src/lib/hiro_gtk/editbox.h rename to src/lib/hiro/gtk/editbox.h diff --git a/src/lib/hiro_gtk/formcontrol.cpp b/src/lib/hiro/gtk/formcontrol.cpp similarity index 100% rename from src/lib/hiro_gtk/formcontrol.cpp rename to src/lib/hiro/gtk/formcontrol.cpp diff --git a/src/lib/hiro_gtk/formcontrol.h b/src/lib/hiro/gtk/formcontrol.h similarity index 100% rename from src/lib/hiro_gtk/formcontrol.h rename to src/lib/hiro/gtk/formcontrol.h diff --git a/src/lib/hiro_gtk/frame.cpp b/src/lib/hiro/gtk/frame.cpp similarity index 100% rename from src/lib/hiro_gtk/frame.cpp rename to src/lib/hiro/gtk/frame.cpp diff --git a/src/lib/hiro_gtk/frame.h b/src/lib/hiro/gtk/frame.h similarity index 100% rename from src/lib/hiro_gtk/frame.h rename to src/lib/hiro/gtk/frame.h diff --git a/src/lib/hiro_gtk/hiro.cpp b/src/lib/hiro/gtk/hiro.cpp similarity index 54% rename from src/lib/hiro_gtk/hiro.cpp rename to src/lib/hiro/gtk/hiro.cpp index 3b64799e0..8f4fd280e 100644 --- a/src/lib/hiro_gtk/hiro.cpp +++ b/src/lib/hiro/gtk/hiro.cpp @@ -38,12 +38,24 @@ void pHiro::init() { gtk_init(&argc, &argv); free(argv[0]); free(argv); + + is_composited = false; + screen = gdk_screen_get_default(); + if(gdk_screen_is_composited(screen)) { + colormap = gdk_screen_get_rgba_colormap(screen); + if(colormap) is_composited = true; + else colormap = gdk_screen_get_rgb_colormap(screen); //fallback + } else { + colormap = gdk_screen_get_rgb_colormap(screen); + } } void pHiro::term() { + enable_screensaver(); } bool pHiro::run() { + if(is_screensaver_enabled == false) screensaver_tick(); gtk_main_iteration_do(false); return pending(); } @@ -52,11 +64,34 @@ bool pHiro::pending() { return gtk_events_pending(); } -bool pHiro::file_load(Window *focus, char *filename, const char *filter, const char *path) { +bool pHiro::folder_select(Window *focus, char *filename, const char *path) { if(!filename) return false; strcpy(filename, ""); - GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File", + GtkWidget *dialog = gtk_file_chooser_dialog_new("Select Folder", + focus ? GTK_WINDOW(focus->p.gtk_handle()) : (GtkWindow*)0, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)0); + + if(path && *path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + strcpy(filename, fn); + g_free(fn); + } + + gtk_widget_destroy(dialog); + return strcmp(filename, ""); //return true if filename exists +} + +bool pHiro::file_open(Window *focus, char *filename, const char *path, const char *filter) { + if(!filename) return false; + strcpy(filename, ""); + + GtkWidget *dialog = gtk_file_chooser_dialog_new("Open File", focus ? GTK_WINDOW(focus->p.gtk_handle()) : (GtkWindow*)0, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, @@ -75,7 +110,7 @@ bool pHiro::file_load(Window *focus, char *filename, const char *filter, const c return strcmp(filename, ""); //return true if filename exists } -bool pHiro::file_save(Window *focus, char *filename, const char *filter, const char *path) { +bool pHiro::file_save(Window *focus, char *filename, const char *path, const char *filter) { if(!filename) return false; strcpy(filename, ""); @@ -107,15 +142,50 @@ uint pHiro::screen_height() { return gdk_screen_height(); } +void pHiro::enable_screensaver() { + if(is_screensaver_enabled == true) return; + is_screensaver_enabled = true; + DPMSDisable(GDK_DISPLAY()); +} + +void pHiro::disable_screensaver() { + if(is_screensaver_enabled == false) return; + is_screensaver_enabled = false; + DPMSEnable(GDK_DISPLAY()); +} + pHiro& pHiro::handle() { return hiro().p; } pHiro::pHiro(Hiro &self_) : self(self_) { + is_screensaver_enabled = true; } pHiro& phiro() { return pHiro::handle(); } +/* internal */ + +void pHiro::screensaver_tick() { + static clock_t delta_x = 0, delta_y = 0; + + delta_y = clock(); + if(delta_y - delta_x < CLOCKS_PER_SEC * 20) return; + + //XSetScreenSaver(timeout = 0) does not work + //XResetScreenSaver() does not work + //XScreenSaverSuspend() does not work + //DPMSDisable() does not work + //XSendEvent(KeyPressMask) does not work + //use XTest extension to send fake keypress every ~20 seconds. + //keycode of 255 does not map to any actual key, but it will block screensaver. + delta_x = delta_y; + XTestFakeKeyEvent(GDK_DISPLAY(), 255, True, 0); + XSync(GDK_DISPLAY(), False); + XTestFakeKeyEvent(GDK_DISPLAY(), 255, False, 0); + XSync(GDK_DISPLAY(), False); +} + } //namespace libhiro diff --git a/src/lib/hiro_gtk/hiro.h b/src/lib/hiro/gtk/hiro.h similarity index 63% rename from src/lib/hiro_gtk/hiro.h rename to src/lib/hiro/gtk/hiro.h index 79160626a..6d2c6b5a0 100644 --- a/src/lib/hiro_gtk/hiro.h +++ b/src/lib/hiro/gtk/hiro.h @@ -3,7 +3,10 @@ #include #include +#include #include +#include +#include namespace libhiro { @@ -36,16 +39,26 @@ public: bool run(); bool pending(); - bool file_load(Window *focus, char *filename, const char *filter, const char *path); - bool file_save(Window *focus, char *filename, const char *filter, const char *path); + bool folder_select(Window *focus, char *filename, const char *path = ""); + bool file_open(Window *focus, char *filename, const char *path = "", const char *filter = ""); + bool file_save(Window *focus, char *filename, const char *path = "", const char *filter = ""); uint screen_width(); uint screen_height(); + void enable_screensaver(); + void disable_screensaver(); + static pHiro& handle(); pHiro(Hiro&); /* internal */ + GdkScreen *screen; + GdkColormap *colormap; + bool is_composited; + + bool is_screensaver_enabled; + void screensaver_tick(); uint16_t translate_key(uint key); }; diff --git a/src/lib/hiro_gtk/keymap.cpp b/src/lib/hiro/gtk/keymap.cpp similarity index 100% rename from src/lib/hiro_gtk/keymap.cpp rename to src/lib/hiro/gtk/keymap.cpp diff --git a/src/lib/hiro_gtk/label.cpp b/src/lib/hiro/gtk/label.cpp similarity index 100% rename from src/lib/hiro_gtk/label.cpp rename to src/lib/hiro/gtk/label.cpp diff --git a/src/lib/hiro_gtk/label.h b/src/lib/hiro/gtk/label.h similarity index 100% rename from src/lib/hiro_gtk/label.h rename to src/lib/hiro/gtk/label.h diff --git a/src/lib/hiro_gtk/listbox.cpp b/src/lib/hiro/gtk/listbox.cpp similarity index 100% rename from src/lib/hiro_gtk/listbox.cpp rename to src/lib/hiro/gtk/listbox.cpp diff --git a/src/lib/hiro_gtk/listbox.h b/src/lib/hiro/gtk/listbox.h similarity index 100% rename from src/lib/hiro_gtk/listbox.h rename to src/lib/hiro/gtk/listbox.h diff --git a/src/lib/hiro_gtk/menucheckitem.cpp b/src/lib/hiro/gtk/menucheckitem.cpp similarity index 100% rename from src/lib/hiro_gtk/menucheckitem.cpp rename to src/lib/hiro/gtk/menucheckitem.cpp diff --git a/src/lib/hiro_gtk/menucheckitem.h b/src/lib/hiro/gtk/menucheckitem.h similarity index 100% rename from src/lib/hiro_gtk/menucheckitem.h rename to src/lib/hiro/gtk/menucheckitem.h diff --git a/src/lib/hiro_gtk/menucontrol.cpp b/src/lib/hiro/gtk/menucontrol.cpp similarity index 100% rename from src/lib/hiro_gtk/menucontrol.cpp rename to src/lib/hiro/gtk/menucontrol.cpp diff --git a/src/lib/hiro_gtk/menucontrol.h b/src/lib/hiro/gtk/menucontrol.h similarity index 100% rename from src/lib/hiro_gtk/menucontrol.h rename to src/lib/hiro/gtk/menucontrol.h diff --git a/src/lib/hiro_gtk/menugroup.cpp b/src/lib/hiro/gtk/menugroup.cpp similarity index 100% rename from src/lib/hiro_gtk/menugroup.cpp rename to src/lib/hiro/gtk/menugroup.cpp diff --git a/src/lib/hiro_gtk/menugroup.h b/src/lib/hiro/gtk/menugroup.h similarity index 100% rename from src/lib/hiro_gtk/menugroup.h rename to src/lib/hiro/gtk/menugroup.h diff --git a/src/lib/hiro_gtk/menuitem.cpp b/src/lib/hiro/gtk/menuitem.cpp similarity index 100% rename from src/lib/hiro_gtk/menuitem.cpp rename to src/lib/hiro/gtk/menuitem.cpp diff --git a/src/lib/hiro_gtk/menuitem.h b/src/lib/hiro/gtk/menuitem.h similarity index 100% rename from src/lib/hiro_gtk/menuitem.h rename to src/lib/hiro/gtk/menuitem.h diff --git a/src/lib/hiro_gtk/menuradioitem.cpp b/src/lib/hiro/gtk/menuradioitem.cpp similarity index 100% rename from src/lib/hiro_gtk/menuradioitem.cpp rename to src/lib/hiro/gtk/menuradioitem.cpp diff --git a/src/lib/hiro_gtk/menuradioitem.h b/src/lib/hiro/gtk/menuradioitem.h similarity index 100% rename from src/lib/hiro_gtk/menuradioitem.h rename to src/lib/hiro/gtk/menuradioitem.h diff --git a/src/lib/hiro_gtk/menuseparator.cpp b/src/lib/hiro/gtk/menuseparator.cpp similarity index 100% rename from src/lib/hiro_gtk/menuseparator.cpp rename to src/lib/hiro/gtk/menuseparator.cpp diff --git a/src/lib/hiro_gtk/menuseparator.h b/src/lib/hiro/gtk/menuseparator.h similarity index 100% rename from src/lib/hiro_gtk/menuseparator.h rename to src/lib/hiro/gtk/menuseparator.h diff --git a/src/lib/hiro_gtk/progressbar.cpp b/src/lib/hiro/gtk/progressbar.cpp similarity index 100% rename from src/lib/hiro_gtk/progressbar.cpp rename to src/lib/hiro/gtk/progressbar.cpp diff --git a/src/lib/hiro_gtk/progressbar.h b/src/lib/hiro/gtk/progressbar.h similarity index 100% rename from src/lib/hiro_gtk/progressbar.h rename to src/lib/hiro/gtk/progressbar.h diff --git a/src/lib/hiro_gtk/radiobox.cpp b/src/lib/hiro/gtk/radiobox.cpp similarity index 100% rename from src/lib/hiro_gtk/radiobox.cpp rename to src/lib/hiro/gtk/radiobox.cpp diff --git a/src/lib/hiro_gtk/radiobox.h b/src/lib/hiro/gtk/radiobox.h similarity index 100% rename from src/lib/hiro_gtk/radiobox.h rename to src/lib/hiro/gtk/radiobox.h diff --git a/src/lib/hiro_gtk/slider.cpp b/src/lib/hiro/gtk/slider.cpp similarity index 100% rename from src/lib/hiro_gtk/slider.cpp rename to src/lib/hiro/gtk/slider.cpp diff --git a/src/lib/hiro_gtk/slider.h b/src/lib/hiro/gtk/slider.h similarity index 100% rename from src/lib/hiro_gtk/slider.h rename to src/lib/hiro/gtk/slider.h diff --git a/src/lib/hiro_gtk/widget.cpp b/src/lib/hiro/gtk/widget.cpp similarity index 100% rename from src/lib/hiro_gtk/widget.cpp rename to src/lib/hiro/gtk/widget.cpp diff --git a/src/lib/hiro_gtk/widget.h b/src/lib/hiro/gtk/widget.h similarity index 100% rename from src/lib/hiro_gtk/widget.h rename to src/lib/hiro/gtk/widget.h diff --git a/src/lib/hiro_gtk/window.cpp b/src/lib/hiro/gtk/window.cpp similarity index 78% rename from src/lib/hiro_gtk/window.cpp rename to src/lib/hiro/gtk/window.cpp index 930e4586d..a1e9bd319 100644 --- a/src/lib/hiro_gtk/window.cpp +++ b/src/lib/hiro/gtk/window.cpp @@ -1,24 +1,49 @@ -gint hiro_pwindow_close(pWindow *p) { -uintptr_t r = p->self.on_close ? p->self.on_close(Event(Event::Close, 0, &p->self)) : true; +static gint hiro_pwindow_close(pWindow *p) { + uintptr_t r = p->self.on_close ? p->self.on_close(Event(Event::Close, 0, &p->self)) : true; return !bool(r); } -gint hiro_pwindow_keydown(GtkWidget *w, GdkEventKey *key, pWindow *p) { +static gboolean hiro_pwindow_expose(pWindow *p) { + cairo_t *context = gdk_cairo_create(p->window->window); + GtkStyle *style = gtk_widget_get_style(p->window); + + double red = double(style->bg[GTK_STATE_NORMAL].red) / 65536.0; + double green = double(style->bg[GTK_STATE_NORMAL].green) / 65536.0; + double blue = double(style->bg[GTK_STATE_NORMAL].blue) / 65536.0; + double alpha = double(p->state.alpha) / 256.0; + + if(phiro().is_composited == true) { + cairo_set_source_rgba(context, red, green, blue, alpha); + } else { + cairo_set_source_rgb(context, red, green, blue); + } + + cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); + cairo_paint(context); + cairo_destroy(context); + return FALSE; +} + +static gint hiro_pwindow_keydown(GtkWidget *w, GdkEventKey *key, pWindow *p) { if(p && p->self.on_keydown) p->self.on_keydown(Event(Event::KeyDown, phiro().translate_key(key->keyval), &p->self)); return FALSE; } -gint hiro_pwindow_keyup(GtkWidget *w, GdkEventKey *key, pWindow *p) { +static gint hiro_pwindow_keyup(GtkWidget *w, GdkEventKey *key, pWindow *p) { if(p && p->self.on_keyup) p->self.on_keyup(Event(Event::KeyUp, phiro().translate_key(key->keyval), &p->self)); return FALSE; } void pWindow::create(uint style, uint width, uint height, const char *text) { window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_colormap(window, phiro().colormap); + gtk_window_set_title(GTK_WINDOW(window), text ? text : ""); gtk_window_set_resizable(GTK_WINDOW(window), false); + gtk_widget_set_app_paintable(window, true); if(style & Window::AutoCenter) gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS); g_signal_connect_swapped(G_OBJECT(window), "delete_event", G_CALLBACK(hiro_pwindow_close), (gpointer)this); + g_signal_connect_swapped(G_OBJECT(window), "expose_event", G_CALLBACK(hiro_pwindow_expose), (gpointer)this); g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(hiro_pwindow_keydown), (gpointer)this); g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(hiro_pwindow_keyup), (gpointer)this); @@ -45,6 +70,7 @@ void pWindow::create(uint style, uint width, uint height, const char *text) { gtk_box_pack_start(GTK_BOX(menucontainer), statuscontainer, false, false, 0); gtk_widget_show(statuscontainer); + gtk_widget_realize(window); state.is_fullscreen = false; state.width = width; state.height = height; @@ -131,8 +157,13 @@ uint pWindow::get_height() { return height; } +void pWindow::set_opacity(uint8_t opacity) { + state.alpha = opacity; + if(window) gtk_widget_queue_draw(window); +} + void pWindow::set_background_color(uint8_t r, uint8_t g, uint8_t b) { -GdkColor color; + GdkColor color; color.pixel = (r << 16) | (g << 8) | b; color.red = (r << 8) | r; color.green = (g << 8) | g; @@ -140,6 +171,28 @@ GdkColor color; gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); } +void pWindow::set_icon(unsigned width, unsigned height, const uint32_t *data) { + uint8_t *temp = (uint8_t*)malloc(width * height * 4); + memcpy(temp, data, width * height * 4); + for(unsigned i = 0; i < width * height; i++) { + //ABGR -> ARGB + uint8_t t = temp[i * 4 + 0]; + temp[i * 4 + 0] = temp[i * 4 + 2]; + temp[i * 4 + 2] = t; + } + + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( + (const guchar*)temp, GDK_COLORSPACE_RGB, + /* has_alpha = */ TRUE, /* bits_per_sample = */ 8, + width, height, /* rowstride = */ width * 4, + /* destroy_fn = */ NULL, /* destroy_fn_data = */ NULL + ); + gtk_window_set_icon(GTK_WINDOW(window), pixbuf); + + g_object_unref(pixbuf); + free(temp); +} + void pWindow::set_text(const char *text) { gtk_window_set_title(GTK_WINDOW(window), text ? text : ""); } @@ -224,6 +277,7 @@ pWindow::pWindow(Window &self_) : pWidget(self_), self(self_), menu(*this), stat state.is_fullscreen = false; state.width = 0; state.height = 0; + state.alpha = 255; } /* internal */ diff --git a/src/lib/hiro_gtk/window.h b/src/lib/hiro/gtk/window.h similarity index 92% rename from src/lib/hiro_gtk/window.h rename to src/lib/hiro/gtk/window.h index d1e5663ac..1a2d09add 100644 --- a/src/lib/hiro_gtk/window.h +++ b/src/lib/hiro/gtk/window.h @@ -10,7 +10,9 @@ public: void unfullscreen(); uint get_width(); uint get_height(); + void set_opacity(uint8_t opacity); void set_background_color(uint8_t r, uint8_t g, uint8_t b); + void set_icon(unsigned width, unsigned height, const uint32_t *data); void set_text(const char *text = ""); void attach(Window &window, uint x, uint y); void attach(MenuGroup &menugroup); @@ -55,6 +57,7 @@ public: bool is_fullscreen; uint width; uint height; + uint alpha; } state; void menu_show(bool = true); diff --git a/src/lib/hiro.cpp b/src/lib/hiro/hiro.cpp similarity index 94% rename from src/lib/hiro.cpp rename to src/lib/hiro/hiro.cpp index 7dca8509e..30d096bf1 100644 --- a/src/lib/hiro.cpp +++ b/src/lib/hiro/hiro.cpp @@ -1,10 +1,10 @@ -#include +#include "hiro.h" using namespace nall; #if defined(_WIN32) - #include + #include "win/hiro.cpp" #else - #include + #include "gtk/hiro.cpp" #endif namespace libhiro { @@ -15,10 +15,13 @@ void Hiro::init() { p.init(); } void Hiro::term() { p.term(); } bool Hiro::run() { return p.run(); } bool Hiro::pending() { return p.pending(); } -bool Hiro::file_load(Window *focus, char *filename, const char *filter, const char *path) { return p.file_load(focus, filename, filter, path); } -bool Hiro::file_save(Window *focus, char *filename, const char *filter, const char *path) { return p.file_save(focus, filename, filter, path); } +bool Hiro::folder_select(Window *focus, char *filename, const char *path) { return p.folder_select(focus, filename, path); } +bool Hiro::file_open(Window *focus, char *filename, const char *path, const char *filter) { return p.file_open(focus, filename, path, filter); } +bool Hiro::file_save(Window *focus, char *filename, const char *path, const char *filter) { return p.file_save(focus, filename, path, filter); } uint Hiro::screen_width() { return p.screen_width(); } uint Hiro::screen_height() { return p.screen_height(); } +void Hiro::enable_screensaver() { p.enable_screensaver(); } +void Hiro::disable_screensaver() { p.disable_screensaver(); } Hiro& Hiro::handle() { static Hiro hiro; return hiro; } Hiro::Hiro() : p(*new pHiro(*this)) {} Hiro::~Hiro() { delete &p; } @@ -46,7 +49,9 @@ void Window::fullscreen() { p.fullscreen(); } void Window::unfullscreen() { p.unfullscreen(); } uint Window::get_width() { return p.get_width(); } uint Window::get_height() { return p.get_height(); } +void Window::set_opacity(uint8_t opacity) { p.set_opacity(opacity); } void Window::set_background_color(uint8_t r, uint8_t g, uint8_t b) { p.set_background_color(r, g, b); } +void Window::set_icon(unsigned width, unsigned height, const uint32_t *data) { p.set_icon(width, height, data); } void Window::set_text(const char *text) { p.set_text(text); } void Window::attach(Window &window, uint x, uint y) { p.attach(window, x, y); } void Window::attach(MenuGroup &menugroup) { p.attach(menugroup); } diff --git a/src/lib/hiro.h b/src/lib/hiro/hiro.h similarity index 95% rename from src/lib/hiro.h rename to src/lib/hiro/hiro.h index 069797fce..0d1962f8e 100644 --- a/src/lib/hiro.h +++ b/src/lib/hiro/hiro.h @@ -1,6 +1,6 @@ /* hiro - version: 0.001 (2008-02-03) + version: 0.002 (2008-02-19) author: byuu license: public domain */ @@ -112,12 +112,16 @@ public: bool run(); bool pending(); - bool file_load(Window *focus, char *filename, const char *filter, const char *path); - bool file_save(Window *focus, char *filename, const char *filter, const char *path); + bool folder_select(Window *focus, char *filename, const char *path = ""); + bool file_open(Window *focus, char *filename, const char *path = "", const char *filter = ""); + bool file_save(Window *focus, char *filename, const char *path = "", const char *filter = ""); uint screen_width(); uint screen_height(); + void enable_screensaver(); + void disable_screensaver(); + static Hiro& handle(); Hiro(); ~Hiro(); @@ -187,7 +191,9 @@ public: void unfullscreen(); uint get_width(); uint get_height(); + void set_opacity(uint8_t opacity); void set_background_color(uint8_t r, uint8_t g, uint8_t b); + void set_icon(unsigned width, unsigned height, const uint32_t *data); void set_status_text(const char *text = ""); void set_text(const char *text = ""); void attach(Window &window, uint x, uint y); diff --git a/src/lib/hiro_win/button.cpp b/src/lib/hiro/win/button.cpp similarity index 95% rename from src/lib/hiro_win/button.cpp rename to src/lib/hiro/win/button.cpp index 8347f1b5c..ac0cfb1bc 100644 --- a/src/lib/hiro_win/button.cpp +++ b/src/lib/hiro/win/button.cpp @@ -1,5 +1,5 @@ void pButton::create(uint style, uint width, uint height, const char *text) { - hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE, + hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); diff --git a/src/lib/hiro_win/button.h b/src/lib/hiro/win/button.h similarity index 100% rename from src/lib/hiro_win/button.h rename to src/lib/hiro/win/button.h diff --git a/src/lib/hiro_win/canvas.cpp b/src/lib/hiro/win/canvas.cpp similarity index 98% rename from src/lib/hiro_win/canvas.cpp rename to src/lib/hiro/win/canvas.cpp index 0abf990f1..191604147 100644 --- a/src/lib/hiro_win/canvas.cpp +++ b/src/lib/hiro/win/canvas.cpp @@ -31,7 +31,7 @@ pCanvas::~pCanvas() { /* internal */ void pCanvas::blit() { -PAINTSTRUCT ps; + PAINTSTRUCT ps; BeginPaint(hwnd, &ps); SetDIBitsToDevice(ps.hdc, 0, 0, iwidth, iheight, 0, 0, 0, iheight, (void*)ibuffer, &bmi, DIB_RGB_COLORS); EndPaint(hwnd, &ps); diff --git a/src/lib/hiro_win/canvas.h b/src/lib/hiro/win/canvas.h similarity index 100% rename from src/lib/hiro_win/canvas.h rename to src/lib/hiro/win/canvas.h diff --git a/src/lib/hiro_win/checkbox.cpp b/src/lib/hiro/win/checkbox.cpp similarity index 95% rename from src/lib/hiro_win/checkbox.cpp rename to src/lib/hiro/win/checkbox.cpp index 07d040b26..c11cfe87e 100644 --- a/src/lib/hiro_win/checkbox.cpp +++ b/src/lib/hiro/win/checkbox.cpp @@ -1,5 +1,5 @@ void pCheckbox::create(uint style, uint width, uint height, const char *text) { - hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE | BS_CHECKBOX, + hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX, 0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0); diff --git a/src/lib/hiro_win/checkbox.h b/src/lib/hiro/win/checkbox.h similarity index 100% rename from src/lib/hiro_win/checkbox.h rename to src/lib/hiro/win/checkbox.h diff --git a/src/lib/hiro_win/combobox.cpp b/src/lib/hiro/win/combobox.cpp similarity index 55% rename from src/lib/hiro_win/combobox.cpp rename to src/lib/hiro/win/combobox.cpp index bcd3b0205..acb3858f2 100644 --- a/src/lib/hiro_win/combobox.cpp +++ b/src/lib/hiro/win/combobox.cpp @@ -1,9 +1,19 @@ void pCombobox::create(uint style, uint width, uint height, const char *text) { hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "", - WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS, + WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS, 0, 0, width, 200, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0); + + //fix combobox height + //CreateWindow height parameter represents dropdown window height; auto-sizes control based on current font setting + //GetWindowRect returns true height (~22px), CB_GETITEMHEIGHT returns text height (~16px) + //difference = WindowHeight - CB_GETITEMHEIGHT + //CB_SETITEMHEIGHT to height - difference, so that height matches requested height perfectly + RECT rc; + GetWindowRect(hwnd, &rc); + unsigned adjusted_height = height - ((rc.bottom - rc.top) - SendMessage(hwnd, CB_GETITEMHEIGHT, (WPARAM)-1, 0)); + SendMessage(hwnd, CB_SETITEMHEIGHT, (WPARAM)-1, adjusted_height); } void pCombobox::add_item(const char *text) { diff --git a/src/lib/hiro_win/combobox.h b/src/lib/hiro/win/combobox.h similarity index 100% rename from src/lib/hiro_win/combobox.h rename to src/lib/hiro/win/combobox.h diff --git a/src/lib/hiro_win/editbox.cpp b/src/lib/hiro/win/editbox.cpp similarity index 94% rename from src/lib/hiro_win/editbox.cpp rename to src/lib/hiro/win/editbox.cpp index 079e0761d..d1b8b686b 100644 --- a/src/lib/hiro_win/editbox.cpp +++ b/src/lib/hiro/win/editbox.cpp @@ -10,7 +10,7 @@ void pEditbox::create(uint style, uint width, uint height, const char *text) { hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | vscroll | hscroll | - (multiline == true ? ES_MULTILINE : 0) | + (multiline == true ? ES_MULTILINE | ES_WANTRETURN : WS_TABSTOP) | (readonly == true ? ES_READONLY : 0), 0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); diff --git a/src/lib/hiro_win/editbox.h b/src/lib/hiro/win/editbox.h similarity index 100% rename from src/lib/hiro_win/editbox.h rename to src/lib/hiro/win/editbox.h diff --git a/src/lib/hiro_win/formcontrol.cpp b/src/lib/hiro/win/formcontrol.cpp similarity index 71% rename from src/lib/hiro_win/formcontrol.cpp rename to src/lib/hiro/win/formcontrol.cpp index 3f96e2983..32eb0a321 100644 --- a/src/lib/hiro_win/formcontrol.cpp +++ b/src/lib/hiro/win/formcontrol.cpp @@ -29,3 +29,17 @@ uintptr_t pFormControl::handle() { pFormControl::pFormControl(FormControl &self_) : pWidget(self_), self(self_) { hwnd = 0; } + +/* internal */ + +void pFormControl::show(bool state) { + ShowWindow(hwnd, state ? SW_NORMAL : SW_HIDE); +} + +void pFormControl::hide() { + show(false); +} + +bool pFormControl::visible() { + return GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE; +} diff --git a/src/lib/hiro_win/formcontrol.h b/src/lib/hiro/win/formcontrol.h similarity index 78% rename from src/lib/hiro_win/formcontrol.h rename to src/lib/hiro/win/formcontrol.h index e2faeaf60..c70e93b79 100644 --- a/src/lib/hiro_win/formcontrol.h +++ b/src/lib/hiro/win/formcontrol.h @@ -8,6 +8,10 @@ public: bool enabled(); uintptr_t handle(); + virtual void show(bool = true); + virtual void hide(); + virtual bool visible(); + FormControl &self; pFormControl(FormControl&); diff --git a/src/lib/hiro_win/frame.cpp b/src/lib/hiro/win/frame.cpp similarity index 100% rename from src/lib/hiro_win/frame.cpp rename to src/lib/hiro/win/frame.cpp diff --git a/src/lib/hiro_win/frame.h b/src/lib/hiro/win/frame.h similarity index 100% rename from src/lib/hiro_win/frame.h rename to src/lib/hiro/win/frame.h diff --git a/src/lib/hiro_win/hiro.cpp b/src/lib/hiro/win/hiro.cpp similarity index 84% rename from src/lib/hiro_win/hiro.cpp rename to src/lib/hiro/win/hiro.cpp index 0c677f4c8..98d5e69a2 100644 --- a/src/lib/hiro_win/hiro.cpp +++ b/src/lib/hiro/win/hiro.cpp @@ -31,10 +31,14 @@ LRESULT CALLBACK phiro_wndproc(HWND, UINT, WPARAM, LPARAM); #include "slider.cpp" void pHiro::init() { -WNDCLASS wc; + memset(&osversioninfo, 0, sizeof(OSVERSIONINFO)); + osversioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osversioninfo); + + WNDCLASS wc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); + wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hInstance = GetModuleHandle(0); @@ -55,25 +59,53 @@ void pHiro::term() { } bool pHiro::run() { -MSG msg; + MSG msg; if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); + if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } return pending(); } bool pHiro::pending() { -MSG msg; + MSG msg; return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); } -bool pHiro::file_load(Window *focus, char *filename, const char *filter, const char *path) { -string dir, f; +bool pHiro::folder_select(Window *focus, char *filename, const char *path) { + strcpy(filename, ""); + BROWSEINFO bi; + bi.hwndOwner = focus ? focus->p.hwnd : 0; + bi.pidlRoot = NULL; + bi.pszDisplayName = filename; + bi.lpszTitle = "Select Folder"; + bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; + bi.lpfn = NULL; + bi.lParam = 0; + bi.iImage = 0; + bool result = false; + LPITEMIDLIST pidl = SHBrowseForFolder(&bi); + if(pidl) { + if(SHGetPathFromIDList(pidl, filename)) { + result = true; + IMalloc *imalloc = 0; + if(SUCCEEDED(SHGetMalloc(&imalloc))) { + imalloc->Free(pidl); + imalloc->Release(); + } + } + } + return result; +} + +bool pHiro::file_open(Window *focus, char *filename, const char *path, const char *filter) { + string dir, f; strcpy(dir, path ? path : ""); replace(dir, "/", "\\"); -lstring type, part; + lstring type, part; strcpy(f, ""); split(type, "|", filter); for(int i = 0; i < count(type); i++) { @@ -89,12 +121,12 @@ lstring type, part; strcat(f, "|"); } -char *pf = f(); + char *pf = f(); for(int i = strlen(pf) - 1; i >= 0; i--) { if(pf[i] == '|') pf[i] = '\0'; } -OPENFILENAME ofn; + OPENFILENAME ofn; strcpy(filename, ""); memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); @@ -109,12 +141,12 @@ OPENFILENAME ofn; return GetOpenFileName(&ofn); } -bool pHiro::file_save(Window *focus, char *filename, const char *filter, const char *path) { -string dir, f; +bool pHiro::file_save(Window *focus, char *filename, const char *path, const char *filter) { + string dir, f; strcpy(dir, path ? path : ""); replace(dir, "/", "\\"); -lstring type, part; + lstring type, part; strcpy(f, ""); split(type, "|", filter); for(int i = 0; i < count(type); i++) { @@ -130,12 +162,12 @@ lstring type, part; strcat(f, "|"); } -char *pf = f(); + char *pf = f(); for(int i = strlen(pf) - 1; i >= 0; i--) { if(pf[i] == '|') pf[i] = '\0'; } -OPENFILENAME ofn; + OPENFILENAME ofn; strcpy(filename, ""); memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); @@ -158,11 +190,20 @@ uint pHiro::screen_height() { return GetSystemMetrics(SM_CYSCREEN); } +void pHiro::enable_screensaver() { + is_screensaver_enabled = true; +} + +void pHiro::disable_screensaver() { + is_screensaver_enabled = false; +} + pHiro& pHiro::handle() { return hiro().p; } pHiro::pHiro(Hiro &self_) : self(self_) { + is_screensaver_enabled = true; } pHiro& phiro() { @@ -199,11 +240,11 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch(msg) { case WM_SYSCOMMAND: { switch(wparam) { - //TODO: write hiro API to allow this to be toggled. - //for now, screensaver and monitorpower events are disabled always. case SC_SCREENSAVE: - case SC_MONITORPOWER: - return FALSE; + case SC_MONITORPOWER: { + if(is_screensaver_enabled == false) return FALSE; + //fallthrough to DefWindowProc() + } break; } } break; diff --git a/src/lib/hiro_win/hiro.h b/src/lib/hiro/win/hiro.h similarity index 77% rename from src/lib/hiro_win/hiro.h rename to src/lib/hiro/win/hiro.h index f16c0ab49..8969990df 100644 --- a/src/lib/hiro_win/hiro.h +++ b/src/lib/hiro/win/hiro.h @@ -13,6 +13,7 @@ #include #include +#include namespace libhiro { @@ -45,16 +46,22 @@ public: bool run(); bool pending(); - bool file_load(Window *focus, char *filename, const char *filter, const char *path); - bool file_save(Window *focus, char *filename, const char *filter, const char *path); + bool folder_select(Window *focus, char *filename, const char *path = ""); + bool file_open(Window *focus, char *filename, const char *path = "", const char *filter = ""); + bool file_save(Window *focus, char *filename, const char *path = "", const char *filter = ""); uint screen_width(); uint screen_height(); + void enable_screensaver(); + void disable_screensaver(); + static pHiro& handle(); pHiro(Hiro&); /* internal */ + OSVERSIONINFO osversioninfo; + bool is_screensaver_enabled; HWND default_hwnd; //default parent window for all windowless controls HFONT default_font; //default font for all controls HBRUSH black_brush; //used for Canvas background diff --git a/src/lib/hiro_win/keymap.cpp b/src/lib/hiro/win/keymap.cpp similarity index 100% rename from src/lib/hiro_win/keymap.cpp rename to src/lib/hiro/win/keymap.cpp diff --git a/src/lib/hiro_win/label.cpp b/src/lib/hiro/win/label.cpp similarity index 100% rename from src/lib/hiro_win/label.cpp rename to src/lib/hiro/win/label.cpp diff --git a/src/lib/hiro_win/label.h b/src/lib/hiro/win/label.h similarity index 100% rename from src/lib/hiro_win/label.h rename to src/lib/hiro/win/label.h diff --git a/src/lib/hiro_win/listbox.cpp b/src/lib/hiro/win/listbox.cpp similarity index 95% rename from src/lib/hiro_win/listbox.cpp rename to src/lib/hiro/win/listbox.cpp index 242f858be..f8d72ac4c 100644 --- a/src/lib/hiro_win/listbox.cpp +++ b/src/lib/hiro/win/listbox.cpp @@ -7,7 +7,8 @@ uint vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL : (style & Listbox::VerticalScrollNever) ? 0 : 0; hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "", - WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll | + WS_CHILD | WS_TABSTOP | WS_VISIBLE | + LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll | (header ? 0 : LVS_NOCOLUMNHEADER), 0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); diff --git a/src/lib/hiro_win/listbox.h b/src/lib/hiro/win/listbox.h similarity index 100% rename from src/lib/hiro_win/listbox.h rename to src/lib/hiro/win/listbox.h diff --git a/src/lib/hiro_win/menucheckitem.cpp b/src/lib/hiro/win/menucheckitem.cpp similarity index 100% rename from src/lib/hiro_win/menucheckitem.cpp rename to src/lib/hiro/win/menucheckitem.cpp diff --git a/src/lib/hiro_win/menucheckitem.h b/src/lib/hiro/win/menucheckitem.h similarity index 100% rename from src/lib/hiro_win/menucheckitem.h rename to src/lib/hiro/win/menucheckitem.h diff --git a/src/lib/hiro_win/menucontrol.cpp b/src/lib/hiro/win/menucontrol.cpp similarity index 100% rename from src/lib/hiro_win/menucontrol.cpp rename to src/lib/hiro/win/menucontrol.cpp diff --git a/src/lib/hiro_win/menucontrol.h b/src/lib/hiro/win/menucontrol.h similarity index 100% rename from src/lib/hiro_win/menucontrol.h rename to src/lib/hiro/win/menucontrol.h diff --git a/src/lib/hiro_win/menugroup.cpp b/src/lib/hiro/win/menugroup.cpp similarity index 100% rename from src/lib/hiro_win/menugroup.cpp rename to src/lib/hiro/win/menugroup.cpp diff --git a/src/lib/hiro_win/menugroup.h b/src/lib/hiro/win/menugroup.h similarity index 100% rename from src/lib/hiro_win/menugroup.h rename to src/lib/hiro/win/menugroup.h diff --git a/src/lib/hiro_win/menuitem.cpp b/src/lib/hiro/win/menuitem.cpp similarity index 100% rename from src/lib/hiro_win/menuitem.cpp rename to src/lib/hiro/win/menuitem.cpp diff --git a/src/lib/hiro_win/menuitem.h b/src/lib/hiro/win/menuitem.h similarity index 100% rename from src/lib/hiro_win/menuitem.h rename to src/lib/hiro/win/menuitem.h diff --git a/src/lib/hiro_win/menuradioitem.cpp b/src/lib/hiro/win/menuradioitem.cpp similarity index 100% rename from src/lib/hiro_win/menuradioitem.cpp rename to src/lib/hiro/win/menuradioitem.cpp diff --git a/src/lib/hiro_win/menuradioitem.h b/src/lib/hiro/win/menuradioitem.h similarity index 100% rename from src/lib/hiro_win/menuradioitem.h rename to src/lib/hiro/win/menuradioitem.h diff --git a/src/lib/hiro_win/menuseparator.cpp b/src/lib/hiro/win/menuseparator.cpp similarity index 100% rename from src/lib/hiro_win/menuseparator.cpp rename to src/lib/hiro/win/menuseparator.cpp diff --git a/src/lib/hiro_win/menuseparator.h b/src/lib/hiro/win/menuseparator.h similarity index 100% rename from src/lib/hiro_win/menuseparator.h rename to src/lib/hiro/win/menuseparator.h diff --git a/src/lib/hiro_win/progressbar.cpp b/src/lib/hiro/win/progressbar.cpp similarity index 100% rename from src/lib/hiro_win/progressbar.cpp rename to src/lib/hiro/win/progressbar.cpp diff --git a/src/lib/hiro_win/progressbar.h b/src/lib/hiro/win/progressbar.h similarity index 100% rename from src/lib/hiro_win/progressbar.h rename to src/lib/hiro/win/progressbar.h diff --git a/src/lib/hiro_win/radiobox.cpp b/src/lib/hiro/win/radiobox.cpp similarity index 95% rename from src/lib/hiro_win/radiobox.cpp rename to src/lib/hiro/win/radiobox.cpp index 66233dab9..d776674d4 100644 --- a/src/lib/hiro_win/radiobox.cpp +++ b/src/lib/hiro/win/radiobox.cpp @@ -1,6 +1,6 @@ void pRadiobox::create(RadioboxGroup &group_, uint style, uint width, uint height, const char *text) { group = group_; - hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON, + hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON, 0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0); if(group[0] == &self) check(); diff --git a/src/lib/hiro_win/radiobox.h b/src/lib/hiro/win/radiobox.h similarity index 100% rename from src/lib/hiro_win/radiobox.h rename to src/lib/hiro/win/radiobox.h diff --git a/src/lib/hiro_win/slider.cpp b/src/lib/hiro/win/slider.cpp similarity index 92% rename from src/lib/hiro_win/slider.cpp rename to src/lib/hiro/win/slider.cpp index dca64aea3..81e1eb95c 100644 --- a/src/lib/hiro_win/slider.cpp +++ b/src/lib/hiro/win/slider.cpp @@ -2,7 +2,7 @@ void pSlider::create(uint style, uint width, uint height, uint length) { if(length < 1) length = 1; hwnd = CreateWindow(TRACKBAR_CLASS, "", - WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_BOTH | + WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | (style & Slider::Vertical ? TBS_VERT : TBS_HORZ), 0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); diff --git a/src/lib/hiro_win/slider.h b/src/lib/hiro/win/slider.h similarity index 100% rename from src/lib/hiro_win/slider.h rename to src/lib/hiro/win/slider.h diff --git a/src/lib/hiro_win/widget.cpp b/src/lib/hiro/win/widget.cpp similarity index 100% rename from src/lib/hiro_win/widget.cpp rename to src/lib/hiro/win/widget.cpp diff --git a/src/lib/hiro_win/widget.h b/src/lib/hiro/win/widget.h similarity index 100% rename from src/lib/hiro_win/widget.h rename to src/lib/hiro/win/widget.h diff --git a/src/lib/hiro_win/window.cpp b/src/lib/hiro/win/window.cpp similarity index 59% rename from src/lib/hiro_win/window.cpp rename to src/lib/hiro/win/window.cpp index d6de842fc..d7a70cc62 100644 --- a/src/lib/hiro_win/window.cpp +++ b/src/lib/hiro/win/window.cpp @@ -1,7 +1,7 @@ void pWindow::create(uint style, uint width_, uint height_, const char *text) { auto_center = style & Window::AutoCenter; -RECT rc; + RECT rc; SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); hwnd = CreateWindowEx(0, "hiro_window", text ? text : "", @@ -30,40 +30,51 @@ void pWindow::move(uint x, uint y) { } void pWindow::resize(uint width_, uint height_) { + int screen_width = GetSystemMetrics(SM_CXSCREEN); + int screen_height = GetSystemMetrics(SM_CYSCREEN); + if(is_fullscreen == true) { - width_ = GetSystemMetrics(SM_CXSCREEN); - height_ = GetSystemMetrics(SM_CYSCREEN); - SetWindowPos(hwnd, 0, 0, 0, width_, height_, SWP_NOZORDER | SWP_FRAMECHANGED); + SetWindowPos(hwnd, 0, 0, 0, screen_width, screen_height, SWP_NOZORDER | SWP_FRAMECHANGED); return; } width = width_; height = height_; -//set requested window size to hidden window, calculate the difference between -//requested and actual client size area, and then adjust width so that new -//width, height values will set requested client area size. -//AdjustWindowRect() does not properly calculate the height of multi-line menus, -//and thusly is not used. + //set requested window size to hidden window, calculate the difference between + //requested and actual client size area, and then adjust width so that new + //width, height values will set requested client area size. + //AdjustWindowRect() does not properly calculate the height of multi-line menus, + //and thusly is not used. SetWindowPos(hwndr, 0, 0, 0, width_, height_, SWP_NOMOVE | SWP_NOZORDER); -RECT rc; + RECT rc; GetClientRect(hwndr, &rc); width_ += width_ - (rc.right - rc.left); height_ += height_ - (rc.bottom - rc.top); if(status.visible()) { - //statusbar does not count as part of window client area width, height + //statusbar does not count as part of window client area width, height GetClientRect(hstatus, &rc); height_ += rc.bottom - rc.top; } -int x = (GetSystemMetrics(SM_CXSCREEN) - width_) / 2; -int y = (GetSystemMetrics(SM_CYSCREEN) - height_) / 2; + //if window is larger than the screen size, Windows will hide the window entirely. + //therefore, window must be constrained to fit within the current screen size. -//if window is larger than screen, force window to top-left corner - SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); - if(x < rc.left) x = rc.left; - if(y < rc.top) y = rc.top; + int x, y; + if(width_ <= screen_width) { + x = (screen_width - width_) >> 1; + } else { + x = 0; + width_ = screen_width; + } + + if(height_ <= screen_height) { + y = (screen_height - height_) >> 1; + } else { + y = 0; + height_ = screen_height; + } SetWindowPos(hwnd, 0, x, y, width_, height_, (auto_center ? 0 : SWP_NOMOVE) | SWP_NOZORDER | SWP_FRAMECHANGED); } @@ -124,11 +135,64 @@ uint pWindow::get_height() { return (rc.bottom - rc.top) - (src.bottom - src.top); } +void pWindow::set_opacity(uint8_t opacity_) { + opacity = opacity_; + if(!hwnd) return; + + if(opacity != 255) { + //enable translucency + SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); + SetLayeredWindowAttributes(hwnd, 0, opacity, LWA_ALPHA); + } else { + //disable transluceny + SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); + SetLayeredWindowAttributes(hwnd, 0, 0, 0); + } + + InvalidateRect(hwnd, 0, TRUE); +} + void pWindow::set_background_color(uint8_t r, uint8_t g, uint8_t b) { if(background) DeleteObject(background); background = CreateSolidBrush(RGB(r, g, b)); } +void pWindow::set_icon(unsigned width, unsigned height, const uint32_t *data) { + if(hicon) DestroyIcon(hicon); + + uint8_t *mask = (uint8_t*)malloc(width * height / 8); + memset(mask, 0, width * height / 8); + uint8_t *icon = (uint8_t*)malloc(width * height * 4); + memcpy(icon, data, width * height * 4); + + if((phiro().osversioninfo.dwMajorVersion < 5) + || (phiro().osversioninfo.dwMajorVersion == 5 && phiro().osversioninfo.dwMinorVersion < 1)) { + //5.1 and above represents Windows XP or later, which supports 32-bit icons. + //5.0 and below represents Windows 2000 or earlier, which does not support 32-bit icons. + //if running Win2k or prior, alpha channel will be ignored; + //so scale color intensity by alpha level, which gives icons a black background. + //this is because an alpha of 0 (fully transparent) results in a color of 0 (black). + //without this step and alpha ignored, icons lose appearance of anti-aliasing. + for(unsigned i = 0; i < width * height; i++) { + uint8_t a = icon[i * 4 + 3]; + uint8_t r = uint8_t(1.0 / 256.0 * a * icon[i * 4 + 2]); + uint8_t g = uint8_t(1.0 / 256.0 * a * icon[i * 4 + 1]); + uint8_t b = uint8_t(1.0 / 256.0 * a * icon[i * 4 + 0]); + icon[i * 4 + 3] = 0xff; //ignored anyway, but just to be safe ... + icon[i * 4 + 2] = max(0, min(255, r)); //clamp 0 <= color <= 255 ... + icon[i * 4 + 1] = max(0, min(255, g)); //not required, but again ... + icon[i * 4 + 0] = max(0, min(255, b)); //it's better to be safe. + } + } + + hicon = CreateIcon(GetModuleHandle(0), width, height, 1, 32, (const BYTE*)mask, (const BYTE*)icon); + SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon); + SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hicon); + + free(mask); + free(icon); +} + void pWindow::set_text(const char *text) { SetWindowText(hwnd, text); } @@ -136,13 +200,14 @@ void pWindow::set_text(const char *text) { void pWindow::attach(Window &window, uint x, uint y) { if(!window.p.hwnd) return; -//toplevel window size is larger, because it includes window borders -//read size of window without window borders, and resize upon attach -RECT rc; + //toplevel window size is larger, because it includes window borders + //read size of window without window borders, and resize upon attach + RECT rc; GetClientRect(window.p.hwnd, &rc); ShowWindow(window.p.hwnd, SW_HIDE); SetWindowLong(window.p.hwnd, GWL_STYLE, WS_CHILD); + SetWindowLong(window.p.hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT); SetParent(window.p.hwnd, hwnd); SetWindowPos(window.p.hwnd, 0, x, y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_FRAMECHANGED); ShowWindow(window.p.hwnd, SW_NORMAL); @@ -156,6 +221,10 @@ void pWindow::attach(MenuGroup &menugroup) { void pWindow::attach(FormControl &formcontrol, uint x, uint y) { SetWindowPos(formcontrol.p.hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); SetParent(formcontrol.p.hwnd, hwnd); + //SetParent() sets Z-order to topmost ... + //this causes WS_TABSTOP property to run through controls "backward" + //by inverting this, the later a control is attached, the later the tab key moves to it + SetWindowPos(formcontrol.p.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } void pWindow::move(Window &window, uint x, uint y) { @@ -207,8 +276,10 @@ pWindow::Statusbar::Statusbar(pWindow &p_) : p(p_) { pWindow::pWindow(Window &self_) : pWidget(self_), self(self_), menu(*this), status(*this) { hwnd = 0; hwndr = 0; + hicon = 0; hmenu = 0; background = 0; + opacity = 255; is_fullscreen = false; auto_center = false; width = 0; @@ -216,6 +287,7 @@ pWindow::pWindow(Window &self_) : pWidget(self_), self(self_), menu(*this), stat } pWindow::~pWindow() { + if(hicon) DestroyIcon(hicon); if(background) DeleteObject(background); } diff --git a/src/lib/hiro_win/window.h b/src/lib/hiro/win/window.h similarity index 91% rename from src/lib/hiro_win/window.h rename to src/lib/hiro/win/window.h index 71693fbe2..9a816ef98 100644 --- a/src/lib/hiro_win/window.h +++ b/src/lib/hiro/win/window.h @@ -10,7 +10,9 @@ public: void unfullscreen(); uint get_width(); uint get_height(); + void set_opacity(uint8_t opacity); void set_background_color(uint8_t r, uint8_t g, uint8_t b); + void set_icon(unsigned width, unsigned height, const uint32_t *data); void set_text(const char *text = ""); void attach(Window &window, uint x, uint y); void attach(MenuGroup &menugroup); @@ -46,9 +48,11 @@ public: /* internal */ HWND hwnd; HWND hwndr; //hidden window, used as resize assistant + HICON hicon; HMENU hmenu; HWND hstatus; HBRUSH background; + uint8_t opacity; bool is_fullscreen; bool auto_center; uint width, height; diff --git a/src/lib/libco/fiber.c b/src/lib/libco/fiber.c index d1b39586d..02ef5bc78 100644 --- a/src/lib/libco/fiber.c +++ b/src/lib/libco/fiber.c @@ -5,7 +5,7 @@ */ #define LIBCO_C -#include "../libco.h" +#include "libco.h" #define WINVER 0x0400 #define _WIN32_WINNT 0x0400 #define WIN32_LEAN_AND_MEAN diff --git a/src/lib/libco.c b/src/lib/libco/libco.c similarity index 71% rename from src/lib/libco.c rename to src/lib/libco/libco.c index 0e7d3761f..604b37df4 100644 --- a/src/lib/libco.c +++ b/src/lib/libco/libco.c @@ -5,17 +5,17 @@ */ #if defined(__GNUC__) && defined(__i386__) - #include "libco/x86.c" + #include "x86.c" #elif defined(__GNUC__) && defined(__amd64__) && !defined(__MINGW64__) - #include "libco/x86-64.c" + #include "x86-64.c" #elif defined(__MINGW64__) - #include "libco/fiber.c" + #include "fiber.c" #elif defined(__GNUC__) - #include "libco/sjlj.c" + #include "sjlj.c" #elif defined(_MSC_VER) && defined(_M_IX86) - #include "libco/x86.c" + #include "x86.c" #elif defined(_MSC_VER) && defined(_M_AMD64) - #include "libco/fiber.c" + #include "fiber.c" #else #error "libco: unsupported processor, compiler or operating system" #endif diff --git a/src/lib/libco.h b/src/lib/libco/libco.h similarity index 100% rename from src/lib/libco.h rename to src/lib/libco/libco.h diff --git a/src/lib/libco/sjlj.c b/src/lib/libco/sjlj.c index 86b2ea264..8b72b614e 100644 --- a/src/lib/libco/sjlj.c +++ b/src/lib/libco/sjlj.c @@ -12,7 +12,7 @@ */ #define LIBCO_C -#include "../libco.h" +#include "libco.h" #include #include #include diff --git a/src/lib/libco/ucontext.c b/src/lib/libco/ucontext.c index 47766e645..17472f6bc 100644 --- a/src/lib/libco/ucontext.c +++ b/src/lib/libco/ucontext.c @@ -17,7 +17,7 @@ */ #define LIBCO_C -#include "../libco.h" +#include "libco.h" #include #include diff --git a/src/lib/libco/x86-64.c b/src/lib/libco/x86-64.c index e1e8c7f30..2e2a11310 100644 --- a/src/lib/libco/x86-64.c +++ b/src/lib/libco/x86-64.c @@ -5,7 +5,7 @@ */ #define LIBCO_C -#include "../libco.h" +#include "libco.h" #include #include diff --git a/src/lib/libco/x86.c b/src/lib/libco/x86.c index 18af8ac44..3a5507ffc 100644 --- a/src/lib/libco/x86.c +++ b/src/lib/libco/x86.c @@ -5,7 +5,7 @@ */ #define LIBCO_C -#include "../libco.h" +#include "libco.h" #include #include diff --git a/src/lib/libfilter/colortable.cpp b/src/lib/libfilter/colortable.cpp new file mode 100644 index 000000000..936ab4952 --- /dev/null +++ b/src/lib/libfilter/colortable.cpp @@ -0,0 +1,123 @@ +Colortable colortable; + +void Colortable::set_format(Format format_) { format = format_; } +void Colortable::set_contrast(int32_t contrast_) { contrast = contrast_; } +void Colortable::set_brightness(int32_t brightness_) { brightness = brightness_; } +void Colortable::set_gamma(int32_t gamma_) { gamma = gamma_; } + +void Colortable::enable_gamma_ramp(bool value) { gamma_ramp = value; } +void Colortable::enable_sepia(bool value) { sepia = value; } +void Colortable::enable_grayscale(bool value) { grayscale = value; } +void Colortable::enable_invert(bool value) { invert = value; } + +void Colortable::update() { + int32_t l, r, g, b; + double kr = 0.2126, kb = 0.0722, kg = (1.0 - kr - kb); //luminance + uint32_t col; + for(unsigned i = 0; i < 32768; i++) { + //bgr555->rgb888 + col = ((i & 0x001f) << 19) | ((i & 0x001c) << 14) + | ((i & 0x03e0) << 6) | ((i & 0x0380) << 1) + | ((i & 0x7c00) >> 7) | ((i & 0x7000) >> 12); + + r = (col >> 16) & 0xff; + g = (col >> 8) & 0xff; + b = (col ) & 0xff; + + if(gamma_ramp == true) { + r = gamma_ramp_table[r >> 3]; + g = gamma_ramp_table[g >> 3]; + b = gamma_ramp_table[b >> 3]; + } + + contrast_adjust(r); brightness_adjust(r); gamma_adjust(r); + contrast_adjust(g); brightness_adjust(g); gamma_adjust(g); + contrast_adjust(b); brightness_adjust(b); gamma_adjust(b); + + if(sepia == true) { + l = (int32_t)((double)r * kr + (double)g * kg + (double)b * kb); + l = max(0, min(255, l)); + + r = (int32_t)((double)l * (1.0 + 0.300)); + g = (int32_t)((double)l * (1.0 - 0.055)); + b = (int32_t)((double)l * (1.0 - 0.225)); + + r = max(0, min(255, r)); + g = max(0, min(255, g)); + b = max(0, min(255, b)); + } + + if(grayscale == true) { + l = (int32_t)((double)r * kr + (double)g * kg + (double)b * kb); + l = max(0, min(255, l)); + r = g = b = l; + } + + if(invert == true) { + r ^= 0xff; + g ^= 0xff; + b ^= 0xff; + } + + switch(format) { + case RGB555: { + r >>= 3; + g >>= 3; + b >>= 3; + table[i] = (r << 10) | (g << 5) | (b); + } break; + + case RGB565: { + r >>= 3; + g >>= 2; + b >>= 3; + table[i] = (r << 11) | (g << 5) | (b); + } break; + + case RGB888: { + table[i] = (r << 16) | (g << 8) | (b); + } break; + + default: { + table[i] = -1U; + } break; + } + } +} + +Colortable::Colortable() { + table = new uint32_t[32768]; + contrast = 0; + brightness = 0; + gamma = 100; +} + +Colortable::~Colortable() { + delete[] table; +} + +/* internal */ + +const uint8_t Colortable::gamma_ramp_table[32] = { + 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, + 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, + 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, + 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff, +}; + +void Colortable::contrast_adjust(int32_t &input) { + double lmin = 0.0 - (double)contrast; + double lmax = 255.0 + (double)contrast; + int32_t result = (int32_t)(lmin + (double)input * ((lmax - lmin) / 256.0)); + input = max(0, min(255, result)); +} + +void Colortable::brightness_adjust(int32_t &input) { + int32_t result = input + brightness; + input = max(0, min(255, result)); +} + +void Colortable::gamma_adjust(int32_t &input) { + int32_t result = (int32_t)(pow(((double)(input + 1) / 256.0), (double)gamma / 100.0) * 256.0); + input = max(0, min(255, result)); +} diff --git a/src/lib/libfilter/colortable.h b/src/lib/libfilter/colortable.h new file mode 100644 index 000000000..0fc420173 --- /dev/null +++ b/src/lib/libfilter/colortable.h @@ -0,0 +1,44 @@ +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(int32_t); + void set_brightness(int32_t); + void set_gamma(int32_t); + 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; + + int32_t contrast; + int32_t brightness; + int32_t gamma; + + bool gamma_ramp; + bool sepia; + bool grayscale; + bool invert; + + static const uint8_t gamma_ramp_table[32]; + void contrast_adjust(int32_t &input); + void brightness_adjust(int32_t &input); + void gamma_adjust(int32_t &input); +}; + +extern Colortable colortable; diff --git a/src/lib/libfilter/direct.cpp b/src/lib/libfilter/direct.cpp new file mode 100644 index 000000000..6afe0e388 --- /dev/null +++ b/src/lib/libfilter/direct.cpp @@ -0,0 +1,30 @@ +DirectFilter filter_direct; + +void DirectFilter::render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + 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; + } + + outwidth = width; + outheight = height; +} diff --git a/src/lib/libfilter/direct.h b/src/lib/libfilter/direct.h new file mode 100644 index 000000000..0d339faef --- /dev/null +++ b/src/lib/libfilter/direct.h @@ -0,0 +1,6 @@ +class DirectFilter : public Filter { +public: + void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); +}; + +extern DirectFilter filter_direct; diff --git a/src/lib/libfilter/filter.cpp b/src/lib/libfilter/filter.cpp new file mode 100644 index 000000000..7025ba60a --- /dev/null +++ b/src/lib/libfilter/filter.cpp @@ -0,0 +1,34 @@ +FilterInterface filter; + +void FilterInterface::set(FilterInterface::FilterType type) { + active_filter = type; +} + +void FilterInterface::render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height +) { + switch(active_filter) { default: + case Direct: { + filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); + } break; + + case Scanline: { + filter_scanline.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); + } break; + + case Scale2x: { + filter_scale2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); + } break; + + case HQ2x: { + filter_hq2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); + } break; + + case NTSC: { + filter_ntsc.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); + } break; + } +} + +FilterInterface::FilterInterface() : active_filter(FilterInterface::Direct) {} diff --git a/src/lib/libfilter/filter.h b/src/lib/libfilter/filter.h new file mode 100644 index 000000000..7aaa36b01 --- /dev/null +++ b/src/lib/libfilter/filter.h @@ -0,0 +1,32 @@ +class Filter { +public: + virtual void render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height + ) = 0; +}; + +class FilterInterface : public Filter { +public: + enum FilterType { + Direct, + Scanline, + Scale2x, + HQ2x, + NTSC, + }; + + void set(FilterType type); + + void render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height + ); + + FilterInterface(); + +private: + FilterType active_filter; +}; + +extern FilterInterface filter; diff --git a/src/lib/libfilter/hq2x.cpp b/src/lib/libfilter/hq2x.cpp new file mode 100644 index 000000000..0418fdde5 --- /dev/null +++ b/src/lib/libfilter/hq2x.cpp @@ -0,0 +1,160 @@ +HQ2xFilter filter_hq2x; + +#define diff(x, y) ((yuvtable[x] - yuvtable[y] + diff_offset) & diff_mask) +#define hdiff(x, y) ((x - yuvtable[y]) & diff_mask) +#define expand_rgb(n) { n |= n << 16; n &= 0x03e07c1f; } +#define pack_rgb(n) { n &= 0x03e07c1f; n |= n >> 16; } + +static uint16_t blend1(uint32_t c1, uint32_t c2) { + expand_rgb(c1); + expand_rgb(c2); + c1 = (c1 * 3 + c2) >> 2; + pack_rgb(c1); + return c1; +} + +static uint16_t blend2(uint32_t c1, uint32_t c2, uint32_t c3) { +//c1 = (c1 * 2 + c2 + c3) >> 2; + c2 = (c2 + c3 - ((c2 ^ c3) & 0x0421)) >> 1; + c1 = (c1 + c2 - ((c1 ^ c2) & 0x0421)) >> 1; + return c1; +} + +static uint16_t blend6(uint32_t c1, uint32_t c2, uint32_t c3) { + expand_rgb(c1); + expand_rgb(c2); + expand_rgb(c3); + c1 = (c1 * 5 + c2 * 2 + c3) >> 3; + pack_rgb(c1); + return c1; +} + +static uint16_t blend7(uint32_t c1, uint32_t c2, uint32_t c3) { + expand_rgb(c1); + expand_rgb(c2); + expand_rgb(c3); + c1 = (c1 * 6 + c2 + c3) >> 3; + pack_rgb(c1); + return c1; +} + +static uint16_t blend9(uint32_t c1, uint32_t c2, uint32_t c3) { + expand_rgb(c1); + expand_rgb(c2); + expand_rgb(c3); + c1 = (c1 * 2 + (c2 + c3) * 3) >> 3; + pack_rgb(c1); + return c1; +} + +static uint16_t blend10(uint32_t c1, uint32_t c2, uint32_t c3) { + expand_rgb(c1); + expand_rgb(c2); + expand_rgb(c3); + c1 = (c1 * 14 + c2 + c3) >> 4; + pack_rgb(c1); + return c1; +} + +void HQ2xFilter::render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height +) { + if(width > 256 || height > 240) { + filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); + return; + } + + pitch >>= 1; + outpitch >>= 2; + + uint32_t *out0 = output; + uint32_t *out1 = output + outpitch; + + #define W1 input[-1 - pitch] + #define W2 input[ 0 - pitch] + #define W3 input[+1 - pitch] + #define W4 input[-1] + #define W5 input[ 0] + #define W6 input[+1] + #define W7 input[-1 + pitch] + #define W8 input[ 0 + pitch] + #define W9 input[+1 + pitch] + + input += pitch; + memset(out0, 0, 2048); out0 += outpitch << 1; + memset(out1, 0, 2048); out1 += outpitch << 1; + + for(int y = height - 2; y; --y) { + input++; + *out0++ = 0; *out0++ = 0; + *out1++ = 0; *out1++ = 0; + + int32_t pattern = diff(W5, W4) ? 0x10 : 0x00; + for(int x = 256 - 2; x; --x) { + uint32_t center = yuvtable[W5] + diff_offset; + + //W4 for pixel x+1 is the same as W6 for pixel x + pattern = (pattern & 0x10) >> 1; + pattern |= hdiff(center, W1) ? 0x01 : 0x00; + pattern |= hdiff(center, W2) ? 0x02 : 0x00; + pattern |= hdiff(center, W3) ? 0x04 : 0x00; + //pattern |= hdiff(center, W4) ? 0x08 : 0x00; + pattern |= hdiff(center, W6) ? 0x10 : 0x00; + pattern |= hdiff(center, W7) ? 0x20 : 0x00; + pattern |= hdiff(center, W8) ? 0x40 : 0x00; + pattern |= hdiff(center, W9) ? 0x80 : 0x00; + + switch(pattern) { + #include "hq2x_table.h" + } + + 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; + } + + memset(out0, 0, 2048); + memset(out1, 0, 2048); + + outwidth = width * 2; + outheight = height * 2; +} + +HQ2xFilter::HQ2xFilter() { + yuvtable = new uint32_t[32768]; + + for(int i = 0; i < 32768; i++) { + int ir = (i) & 0x1f; + int ig = (i >> 5) & 0x1f; + int ib = (i >> 10) & 0x1f; + + //bgr555->bgr888 + double r = (ir << 3) | (ir >> 2); + double g = (ig << 3) | (ig >> 2); + double b = (ib << 3) | (ib >> 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] = (int(y) << 21) + (int(u) << 11) + (int(v)); + } + + diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407; + diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0; +} + +HQ2xFilter::~HQ2xFilter() { + delete[] yuvtable; +} diff --git a/src/lib/libfilter/hq2x.h b/src/lib/libfilter/hq2x.h new file mode 100644 index 000000000..227a796ca --- /dev/null +++ b/src/lib/libfilter/hq2x.h @@ -0,0 +1,14 @@ +class HQ2xFilter : public Filter { +public: + void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); + + HQ2xFilter(); + ~HQ2xFilter(); + +private: + uint32_t *yuvtable; + uint32_t diff_offset; + uint32_t diff_mask; +}; + +extern HQ2xFilter filter_hq2x; diff --git a/src/snes/video/filter_hq2x_lookuptbl.h b/src/lib/libfilter/hq2x_table.h similarity index 93% rename from src/snes/video/filter_hq2x_lookuptbl.h rename to src/lib/libfilter/hq2x_table.h index c737d1343..3d93e947f 100644 --- a/src/snes/video/filter_hq2x_lookuptbl.h +++ b/src/lib/libfilter/hq2x_table.h @@ -1,7 +1,14 @@ -#define p00(__color) *(out0 + 0) = (colortbl[__color]) -#define p01(__color) *(out0 + 1) = (colortbl[__color]) -#define p10(__color) *(out1 + 0) = (colortbl[__color]) -#define p11(__color) *(out1 + 1) = (colortbl[__color]) +/***** + * HQ2x Algorithm (C) 2003 Maxim Stepin + * License: LGPL + * + * Optimizations (C) 2006 Shay Green, byuu + *****/ + +#define p00(color) *(out0 + 0) = (colortable[color]) +#define p01(color) *(out0 + 1) = (colortable[color]) +#define p10(color) *(out1 + 0) = (colortable[color]) +#define p11(color) *(out1 + 1) = (colortable[color]) #define PIXEL00_0 p00( W5); #define PIXEL00_10 p00(blend1 (W5, W1)); diff --git a/src/lib/libfilter/libfilter.cpp b/src/lib/libfilter/libfilter.cpp new file mode 100644 index 000000000..0f984efac --- /dev/null +++ b/src/lib/libfilter/libfilter.cpp @@ -0,0 +1,14 @@ +#include "libfilter.h" +using nall::min; +using nall::max; + +namespace libfilter { + #include "colortable.cpp" + #include "filter.cpp" + + #include "direct.cpp" + #include "scanline.cpp" + #include "scale2x.cpp" + #include "hq2x.cpp" + #include "ntsc.cpp" +} //namespace libfilter diff --git a/src/lib/libfilter/libfilter.h b/src/lib/libfilter/libfilter.h new file mode 100644 index 000000000..e06a63d76 --- /dev/null +++ b/src/lib/libfilter/libfilter.h @@ -0,0 +1,22 @@ +#ifndef LIBFILTER_H +#define LIBFILTER_H + +#include +#include +#include +#include +#include +#include + +namespace libfilter { + #include "colortable.h" + #include "filter.h" + + #include "direct.h" + #include "scanline.h" + #include "scale2x.h" + #include "hq2x.h" + #include "ntsc.h" +} //namespace libfilter + +#endif //ifndef LIBFILTER_H diff --git a/src/lib/libfilter/ntsc.cpp b/src/lib/libfilter/ntsc.cpp new file mode 100644 index 000000000..14b8c37a3 --- /dev/null +++ b/src/lib/libfilter/ntsc.cpp @@ -0,0 +1,73 @@ +#include "snes_ntsc/snes_ntsc.c" + +NTSCFilter filter_ntsc; + +void NTSCFilter::render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height +) { + if(!ntsc)return; + + int const out_width = outwidth = SNES_NTSC_OUT_WIDTH(256); + int const out_height = outheight = height; + burst ^= burst_toggle; + + //blit multiple scanlines of same width, rather than one at a time + int run_start = 0; + int run_width = line[0]; + int l = 0; + + while(1) { + if(run_width != line[l] || l >= out_height) { + uint16_t const *in = (uint16_t*)((uint8_t*)input + pitch * run_start); + uint16_t *out = (uint16_t*)((uint8_t*)output + outpitch * run_start); + int height = l - run_start; + int line_burst = (burst + run_start) % 3; + if(run_width == 256) { + snes_ntsc_blit(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, outpitch); + } else { + snes_ntsc_blit_hires(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, outpitch); + } + if(l >= out_height) break; + run_width = line[l]; + run_start = l; + } + l++; + } +} + +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) { + return; //to do: report out of memory error + } + } + + 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, true); +} + +NTSCFilter::~NTSCFilter() { + if(ntsc) free(ntsc); +} diff --git a/src/lib/libfilter/ntsc.h b/src/lib/libfilter/ntsc.h new file mode 100644 index 000000000..953f48852 --- /dev/null +++ b/src/lib/libfilter/ntsc.h @@ -0,0 +1,17 @@ +#include "snes_ntsc/snes_ntsc.h" + +class NTSCFilter : public Filter { +public: + void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); + + NTSCFilter(); + ~NTSCFilter(); + +private: + struct snes_ntsc_t *ntsc; + int burst, burst_toggle; + + void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields); +}; + +extern NTSCFilter filter_ntsc; diff --git a/src/lib/libfilter/scale2x.cpp b/src/lib/libfilter/scale2x.cpp new file mode 100644 index 000000000..687a56839 --- /dev/null +++ b/src/lib/libfilter/scale2x.cpp @@ -0,0 +1,47 @@ +Scale2xFilter filter_scale2x; + +void Scale2xFilter::render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height +) { + if(width > 256 || height > 240) { + filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); + return; + } + + pitch >>= 1; + outpitch >>= 2; + + uint32_t A, B, C, D, P; + int prevline, nextline; + + for(int y = 0; y < height; y++) { + prevline = (y > 0) ? -pitch : 0; + nextline = (y < height - 1) ? pitch : 0; + for(int x = 0; x < 256; x++) { + A = *(input + prevline); + B = (x > 0) ? *(input - 1) : *input; + C = (x < 255) ? *(input + 1) : *input; + D = *(input + nextline); + P = colortable[*input]; + if(A != D && B != C) { + *(output) = A == B ? colortable[A] : P; + *(output + 1) = A == C ? colortable[A] : P; + *(output + outpitch) = D == B ? colortable[D] : P; + *(output + outpitch + 1) = D == C ? colortable[D] : P; + } else { + *(output) = P; + *(output + 1) = P; + *(output + outpitch) = P; + *(output + outpitch + 1) = P; + } + input++; + output += 2; + } + input += pitch - 256; + output += outpitch + outpitch - 512; + } + + outwidth = width * 2; + outheight = height * 2; +} diff --git a/src/lib/libfilter/scale2x.h b/src/lib/libfilter/scale2x.h new file mode 100644 index 000000000..00f52896c --- /dev/null +++ b/src/lib/libfilter/scale2x.h @@ -0,0 +1,6 @@ +class Scale2xFilter : public Filter { +public: + void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); +}; + +extern Scale2xFilter filter_scale2x; diff --git a/src/lib/libfilter/scanline.cpp b/src/lib/libfilter/scanline.cpp new file mode 100644 index 000000000..af402e7eb --- /dev/null +++ b/src/lib/libfilter/scanline.cpp @@ -0,0 +1,40 @@ +ScanlineFilter filter_scanline; + +void ScanlineFilter::render( + uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, + uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height +) { + if(height > 240) { + filter_direct.render(output, outpitch, outwidth, outheight, 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 + pitch; + 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; + } + + outwidth = width; + outheight = height * 2; +} diff --git a/src/lib/libfilter/scanline.h b/src/lib/libfilter/scanline.h new file mode 100644 index 000000000..c1b804ccf --- /dev/null +++ b/src/lib/libfilter/scanline.h @@ -0,0 +1,6 @@ +class ScanlineFilter : public Filter { +public: + void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); +}; + +extern ScanlineFilter filter_scanline; diff --git a/src/snes/video/ntsc/snes_ntsc.c b/src/lib/libfilter/snes_ntsc/snes_ntsc.c similarity index 100% rename from src/snes/video/ntsc/snes_ntsc.c rename to src/lib/libfilter/snes_ntsc/snes_ntsc.c diff --git a/src/snes/video/ntsc/snes_ntsc.h b/src/lib/libfilter/snes_ntsc/snes_ntsc.h similarity index 96% rename from src/snes/video/ntsc/snes_ntsc.h rename to src/lib/libfilter/snes_ntsc/snes_ntsc.h index 5338d1452..37b3c7bc1 100644 --- a/src/snes/video/ntsc/snes_ntsc.h +++ b/src/lib/libfilter/snes_ntsc/snes_ntsc.h @@ -207,15 +207,15 @@ enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count }; if ( bits == 16 ) {\ rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\ - rgb_out = snes.color_lookup_table[rgb_out];\ + 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 = snes.color_lookup_table[rgb_out];\ + 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 = snes.color_lookup_table[rgb_out];\ + rgb_out = colortable[rgb_out];\ } else {\ rgb_out = raw_ << x;\ }\ diff --git a/src/snes/video/ntsc/snes_ntsc_config.h b/src/lib/libfilter/snes_ntsc/snes_ntsc_config.h similarity index 93% rename from src/snes/video/ntsc/snes_ntsc_config.h rename to src/lib/libfilter/snes_ntsc/snes_ntsc_config.h index 58cc92c1d..5c85e26bb 100644 --- a/src/snes/video/ntsc/snes_ntsc_config.h +++ b/src/lib/libfilter/snes_ntsc/snes_ntsc_config.h @@ -11,7 +11,7 @@ handle things however it wants. */ /* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */ -#define SNES_NTSC_OUT_DEPTH 16 +#define SNES_NTSC_OUT_DEPTH 32 /* Type of input pixel values */ #define SNES_NTSC_IN_T unsigned short diff --git a/src/snes/video/ntsc/snes_ntsc_impl.h b/src/lib/libfilter/snes_ntsc/snes_ntsc_impl.h similarity index 100% rename from src/snes/video/ntsc/snes_ntsc_impl.h rename to src/lib/libfilter/snes_ntsc/snes_ntsc_impl.h diff --git a/src/lib/nall/base64.hpp b/src/lib/nall/base64.hpp new file mode 100644 index 000000000..a4f3d07ed --- /dev/null +++ b/src/lib/nall/base64.hpp @@ -0,0 +1,94 @@ +#ifndef NALL_BASE64_HPP +#define NALL_BASE64_HPP + +#include +#include + +#include + +namespace nall { + +class base64 { +public: + static bool encode(char *&output, const uint8_t* input, unsigned inlength) { + output = new(zeromemory) char[inlength * 8 / 6 + 6]; + + unsigned i = 0, o = 0; + while(i < inlength) { + switch(i % 3) { + case 0: { + output[o++] = enc(input[i] >> 2); + output[o] = enc((input[i] & 3) << 4); + } break; + + case 1: { + uint8_t prev = dec(output[o]); + output[o++] = enc(prev + (input[i] >> 4)); + output[o] = enc((input[i] & 15) << 2); + } break; + + case 2: { + uint8_t prev = dec(output[o]); + output[o++] = enc(prev + (input[i] >> 6)); + output[o++] = enc(input[i] & 63); + } break; + } + + i++; + } + + return true; + } + + static bool decode(uint8_t *&output, unsigned &outlength, const char *input) { + unsigned inlength = strlen(input), infix = 0; + output = new(zeromemory) uint8_t[inlength]; + + unsigned i = 0, o = 0; + while(i < inlength) { + uint8_t x = dec(input[i]); + + switch(i++ & 3) { + case 0: { + output[o] = x << 2; + } break; + + case 1: { + output[o++] |= x >> 4; + output[o] = (x & 15) << 4; + } break; + + case 2: { + output[o++] |= x >> 2; + output[o] = (x & 3) << 6; + } break; + + case 3: { + output[o++] |= x; + } break; + } + } + + outlength = o; + return true; + } + +private: + static char enc(uint8_t n) { + static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + return lookup_table[n & 63]; + } + + static uint8_t dec(char n) { + if(n >= 'A' && n <= 'Z') return n - 'A'; + if(n >= 'a' && n <= 'z') return n - 'a' + 26; + if(n >= '0' && n <= '9') return n - '0' + 52; + if(n == '-') return 62; + if(n == '_') return 63; + return 0; + } +}; + +} //namespace nall + +#endif //ifndef NALL_BASE64_HPP diff --git a/src/lib/nall/detect.hpp b/src/lib/nall/detect.hpp new file mode 100644 index 000000000..c196237f3 --- /dev/null +++ b/src/lib/nall/detect.hpp @@ -0,0 +1,30 @@ +#ifndef NALL_DETECT_HPP +#define NALL_DETECT_HPP + +/* Compiler detection */ + +#if defined(__GNUC__) + #define COMPILER_GCC +#elif defined(_MSC_VER) + #define COMPILER_VISUALC +#endif + +/* Platform detection */ + +#if defined(_WIN32) + #define PLATFORM_WIN +#elif defined(__APPLE__) + #define PLATFORM_OSX +#elif defined(linux) || defined(__sun__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define PLATFORM_X +#endif + +/* Endian detection */ + +#if defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64) + #define ARCH_LSB +#elif defined(__powerpc__) || defined(_M_PPC) + #define ARCH_MSB +#endif + +#endif //ifndef NALL_DETECT_HPP diff --git a/src/lib/nall/lzss.hpp b/src/lib/nall/lzss.hpp new file mode 100644 index 000000000..0073460c7 --- /dev/null +++ b/src/lib/nall/lzss.hpp @@ -0,0 +1,83 @@ +#ifndef NALL_LZSS_HPP +#define NALL_LZSS_HPP + +#include +#include +#include + +namespace nall { + +class lzss { +public: + static bool encode(uint8_t *&output, unsigned &outlength, const uint8_t *input, unsigned inlength) { + output = new(zeromemory) uint8_t[inlength * 9 / 8 + 9]; + + unsigned i = 0, o = 0; + while(i < inlength) { + unsigned flagoffset = o++; + uint8_t flag = 0x00; + + for(unsigned b = 0; b < 8 && i < inlength; b++) { + unsigned longest = 0, pointer; + for(unsigned index = 1; index < 4096; index++) { + unsigned count = 0; + while(true) { + if(count >= 15 + 3) break; //verify pattern match is not longer than max length + if(i + count >= inlength) break; //verify pattern match does not read past end of input + if(i + count < index) break; //verify read is not before start of input + if(input[i + count] != input[i + count - index]) break; //verify pattern still matches + count++; + } + + if(count > longest) { + longest = count; + pointer = index; + } + } + + if(longest < 3) output[o++] = input[i++]; + else { + flag |= 1 << b; + uint16_t x = ((longest - 3) << 12) + pointer; + output[o++] = x; + output[o++] = x >> 8; + i += longest; + } + } + + output[flagoffset] = flag; + } + + outlength = o; + return true; + } + + static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) { + output = new(zeromemory) uint8_t[length]; + + unsigned i = 0, o = 0; + while(o < length) { + uint8_t flag = input[i++]; + + for(unsigned b = 0; b < 8 && o < length; b++) { + if(!(flag & (1 << b))) output[o++] = input[i++]; + else { + uint16_t offset = input[i++]; + offset += input[i++] << 8; + uint16_t lookuplength = (offset >> 12) + 3; + offset &= 4095; + for(unsigned index = 0; index < lookuplength && o + index < length; index++) { + output[o + index] = output[o + index - offset]; + } + o += lookuplength; + } + } + } + + return true; + } +}; + +} //namespace nall + +#endif //ifndef NALL_LZSS_HPP diff --git a/src/lib/nall/string.cpp b/src/lib/nall/string.cpp index bdfd33a89..508371e13 100644 --- a/src/lib/nall/string.cpp +++ b/src/lib/nall/string.cpp @@ -1,8 +1,11 @@ #ifndef NALL_STRING_CPP #define NALL_STRING_CPP -#include +#include +#include +#include +#include #include #include #include diff --git a/src/lib/nall/string/class.cpp b/src/lib/nall/string/class.cpp index 000d8fc28..8c167c9c5 100644 --- a/src/lib/nall/string/class.cpp +++ b/src/lib/nall/string/class.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_CLASS_CPP -#define NALL_STRING_CLASS_CPP +#ifdef NALL_STRING_CPP size_t count(nall::lstring &str) { return str.size(); @@ -220,4 +219,4 @@ char *fdata = (char*)malloc(size + 1); return true; } -#endif //ifndef NALL_STRING_CLASS_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/compare.cpp b/src/lib/nall/string/compare.cpp index f7155a3df..72a636678 100644 --- a/src/lib/nall/string/compare.cpp +++ b/src/lib/nall/string/compare.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_COMPARE_CPP -#define NALL_STRING_COMPARE_CPP +#ifdef NALL_STRING_CPP char chrlower(char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; @@ -97,4 +96,4 @@ bool striend(const char *str, const char *key) { return true; } -#endif //ifndef NALL_STRING_COMPARE_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/convert.cpp b/src/lib/nall/string/convert.cpp index 94a1e1754..70551c433 100644 --- a/src/lib/nall/string/convert.cpp +++ b/src/lib/nall/string/convert.cpp @@ -1,9 +1,4 @@ -#ifndef NALL_STRING_CONVERT_CPP -#define NALL_STRING_CONVERT_CPP - -#include -#include -#include +#ifdef NALL_STRING_CPP char* strlower(char *str) { if(!str) return 0; @@ -290,4 +285,4 @@ size_t strdouble(char *str, double value, size_t length /* = 0 */) { return nall::min(initial_length, digits + 1); } -#endif //ifndef NALL_STRING_CONVERT_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/match.cpp b/src/lib/nall/string/match.cpp index 43df1e369..7cee520e1 100644 --- a/src/lib/nall/string/match.cpp +++ b/src/lib/nall/string/match.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_MATCH_CPP -#define NALL_MATCH_CPP +#ifdef NALL_STRING_CPP bool match(const char *p, const char *s) { const char *p_ = 0, *s_ = 0; @@ -69,4 +68,4 @@ bool match(const char *p, const char *s) { } } -#endif //ifndef NALL_MATCH_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/math.cpp b/src/lib/nall/string/math.cpp index 7a7249dbf..812ebd0d9 100644 --- a/src/lib/nall/string/math.cpp +++ b/src/lib/nall/string/math.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_MATH_CPP -#define NALL_MATH_CPP +#ifdef NALL_STRING_CPP static int eval_integer(const char *&s) { if(!*s) throw "nall::bad_eval_integer"; @@ -147,4 +146,4 @@ bool strmath(const char *s, int &result) { } } -#endif //ifndef NALL_MATH_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/replace.cpp b/src/lib/nall/string/replace.cpp index f6f28a1a2..9474c8b06 100644 --- a/src/lib/nall/string/replace.cpp +++ b/src/lib/nall/string/replace.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_REPLACE_CPP -#define NALL_STRING_REPLACE_CPP +#ifdef NALL_STRING_CPP nall::string &replace(nall::string &str, const char *key, const char *token) { int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); @@ -88,4 +87,4 @@ nall::string &qreplace(nall::string &str, const char *key, const char *token) { return str; } -#endif //ifndef NALL_STRING_REPLACE_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/split.cpp b/src/lib/nall/string/split.cpp index 29dd246bd..ebcd9b53e 100644 --- a/src/lib/nall/string/split.cpp +++ b/src/lib/nall/string/split.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_SPLIT_CPP -#define NALL_STRING_SPLIT_CPP +#ifdef NALL_STRING_CPP void split(nall::lstring &dest, const char *key, const char *src, size_t limit) { dest.reset(); @@ -49,4 +48,4 @@ void qsplit(nall::lstring &dest, const char *key, const char *src, size_t limit) strcpy(dest[split_count++], src + lp); } -#endif //ifndef NALL_STRING_SPLIT_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/strl.cpp b/src/lib/nall/string/strl.cpp index d7efa354f..5710b9f26 100644 --- a/src/lib/nall/string/strl.cpp +++ b/src/lib/nall/string/strl.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_STRL_CPP -#define NALL_STRING_STRL_CPP +#ifdef NALL_STRING_CPP //strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller @@ -45,4 +44,4 @@ size_t strlcat(char *dest, const char *src, size_t length) { return dlength + (s - src); //return length of resulting string, sans null terminator } -#endif //ifndef NALL_STRING_STRL_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/nall/string/trim.cpp b/src/lib/nall/string/trim.cpp index 087f4743b..bef5d166b 100644 --- a/src/lib/nall/string/trim.cpp +++ b/src/lib/nall/string/trim.cpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_TRIM_CPP -#define NALL_STRING_TRIM_CPP +#ifdef NALL_STRING_CPP char* ltrim(char *str, const char *key) { if(!key || !*key) return str; @@ -33,4 +32,4 @@ char* trim_once(char *str, const char *key) { return ltrim_once(rtrim_once(str, key), key); } -#endif //ifndef NALL_STRING_TRIM_CPP +#endif //ifdef NALL_STRING_CPP diff --git a/src/lib/ruby/audio/openal.cpp b/src/lib/ruby/audio/openal.cpp index 4aad7c42c..28067b44d 100644 --- a/src/lib/ruby/audio/openal.cpp +++ b/src/lib/ruby/audio/openal.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -172,13 +172,10 @@ public: settings.synchronize = true; settings.frequency = 22050; - - alutInit(0, NULL); } ~pAudioOpenAL() { term(); - alutExit(); } }; diff --git a/src/lib/ruby/input/directinput.cpp b/src/lib/ruby/input/directinput.cpp index 285f4e57f..f655446ba 100644 --- a/src/lib/ruby/input/directinput.cpp +++ b/src/lib/ruby/input/directinput.cpp @@ -1,5 +1,4 @@ #include -#define WIN32_LEAN_AND_MEAN #include #define DIRECTINPUT_VERSION 0x0800 diff --git a/src/lib/ruby/input/sdl.cpp b/src/lib/ruby/input/sdl.cpp index de22c515f..387ba9977 100644 --- a/src/lib/ruby/input/sdl.cpp +++ b/src/lib/ruby/input/sdl.cpp @@ -25,9 +25,6 @@ #include #include #include -#include -#include -#include #endif #include diff --git a/src/lib/ruby/input/x.cpp b/src/lib/ruby/input/x.cpp index e45f15eea..cd259b7ae 100644 --- a/src/lib/ruby/input/x.cpp +++ b/src/lib/ruby/input/x.cpp @@ -3,9 +3,6 @@ #include #include #include -#include -#include -#include #include diff --git a/src/lib/ruby/ruby.cpp b/src/lib/ruby/ruby.cpp index ac0366e6b..679003bd7 100644 --- a/src/lib/ruby/ruby.cpp +++ b/src/lib/ruby/ruby.cpp @@ -1,9 +1,8 @@ #include +#include namespace ruby { -#include - VideoInterface video; AudioInterface audio; InputInterface input; @@ -73,7 +72,7 @@ void VideoInterface::term() { bool VideoInterface::cap(Video::Setting setting) { return p ? p->cap(setting) : false; } uintptr_t VideoInterface::get(Video::Setting setting) { return p ? p->get(setting) : false; } bool VideoInterface::set(Video::Setting setting, uintptr_t param) { return p ? p->set(setting, param) : false; } -bool VideoInterface::lock(uint16_t *&data, unsigned &pitch) { return p ? p->lock(data, pitch) : false; } +bool VideoInterface::lock(uint32_t *&data, unsigned &pitch) { return p ? p->lock(data, pitch) : false; } void VideoInterface::unlock() { if(p) p->unlock(); } void VideoInterface::clear() { if(p) p->clear(); } void VideoInterface::refresh(unsigned width, unsigned height) { if(p) p->refresh(width, height); } diff --git a/src/lib/ruby/ruby.h b/src/lib/ruby/ruby.h index ff401fcba..075ed44f1 100644 --- a/src/lib/ruby/ruby.h +++ b/src/lib/ruby/ruby.h @@ -30,7 +30,7 @@ public: bool cap(Video::Setting setting); uintptr_t get(Video::Setting setting); bool set(Video::Setting setting, uintptr_t param); - bool lock(uint16_t *&data, unsigned &pitch); + bool lock(uint32_t *&data, unsigned &pitch); void unlock(); void clear(); void refresh(unsigned width, unsigned height); diff --git a/src/lib/ruby/ruby.impl.h b/src/lib/ruby/ruby.impl.h deleted file mode 100644 index e5370168a..000000000 --- a/src/lib/ruby/ruby.impl.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Video */ - -#ifdef VIDEO_DIRECT3D - #include -#endif - -#ifdef VIDEO_DIRECTDRAW - #include -#endif - -#ifdef VIDEO_GDI - #include -#endif - -#ifdef VIDEO_GLX - #include -#endif - -#ifdef VIDEO_SDL - #include -#endif - -#ifdef VIDEO_XV - #include -#endif - -/* Audio */ - -#ifdef AUDIO_AO - #include -#endif - -#ifdef AUDIO_DIRECTSOUND - #include -#endif - -#ifdef AUDIO_OPENAL - #include -#endif - -#ifdef AUDIO_OSS - #include -#endif - -/* Input */ - -#ifdef INPUT_DIRECTINPUT - #include -#endif - -#ifdef INPUT_SDL - #include -#endif - -#ifdef INPUT_X - #include -#endif diff --git a/src/lib/ruby/ruby_impl.cpp b/src/lib/ruby/ruby_impl.cpp new file mode 100644 index 000000000..aa2720761 --- /dev/null +++ b/src/lib/ruby/ruby_impl.cpp @@ -0,0 +1,57 @@ +/* Video */ + +#ifdef VIDEO_DIRECT3D + #include +#endif + +#ifdef VIDEO_DIRECTDRAW + #include +#endif + +#ifdef VIDEO_GDI + #include +#endif + +#ifdef VIDEO_GLX + #include +#endif + +#ifdef VIDEO_SDL + #include +#endif + +#ifdef VIDEO_XV + #include +#endif + +/* Audio */ + +#ifdef AUDIO_AO + #include +#endif + +#ifdef AUDIO_DIRECTSOUND + #include +#endif + +#ifdef AUDIO_OPENAL + #include +#endif + +#ifdef AUDIO_OSS + #include +#endif + +/* Input */ + +#ifdef INPUT_DIRECTINPUT + #include +#endif + +#ifdef INPUT_SDL + #include +#endif + +#ifdef INPUT_X + #include +#endif diff --git a/src/lib/ruby/video.h b/src/lib/ruby/video.h index 091e3e203..c23a54bb3 100644 --- a/src/lib/ruby/video.h +++ b/src/lib/ruby/video.h @@ -15,7 +15,7 @@ public: virtual uintptr_t get(Setting) { return false; } virtual bool set(Setting, uintptr_t) { return false; } - virtual bool lock(uint16_t *&data, unsigned &pitch) { return false; } + virtual bool lock(uint32_t *&data, unsigned &pitch) { return false; } virtual void unlock() {} virtual void clear() {} diff --git a/src/lib/ruby/video/direct3d.cpp b/src/lib/ruby/video/direct3d.cpp index a0656ecc6..75d1e828b 100644 --- a/src/lib/ruby/video/direct3d.cpp +++ b/src/lib/ruby/video/direct3d.cpp @@ -1,4 +1,3 @@ -#define WIN32_LEAN_AND_MEAN #include #include @@ -109,7 +108,7 @@ public: uint32_t px, uint32_t py, uint32_t pw, uint32_t ph, uint32_t tw, uint32_t th, uint32_t x, uint32_t y, uint32_t w, uint32_t h - ){ + ) { d3dvertex vertex[4]; vertex[0].x = vertex[2].x = (double)(x ) - 0.5; vertex[1].x = vertex[3].x = (double)(x + w) - 0.5; @@ -157,14 +156,14 @@ public: } } - bool lock(uint16_t *&data, unsigned &pitch) { + bool lock(uint32_t *&data, unsigned &pitch) { if(caps.stretchrect == false) { texture->GetLevelDesc(0, &d3dsd); texture->GetSurfaceLevel(0, &surface); } surface->LockRect(&d3dlr, 0, flags.lock); pitch = d3dlr.Pitch; - return data = (uint16_t*)d3dlr.pBits; + return data = (uint32_t*)d3dlr.pBits; } void unlock() { @@ -279,10 +278,10 @@ public: device->SetFVF(D3DVERTEX); if(caps.stretchrect == true) { - device->CreateOffscreenPlainSurface(1024, 1024, D3DFMT_R5G6B5, + device->CreateOffscreenPlainSurface(1024, 1024, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &surface, NULL); } else { - device->CreateTexture(1024, 1024, 1, flags.t_usage, D3DFMT_R5G6B5, + device->CreateTexture(1024, 1024, 1, flags.t_usage, D3DFMT_X8R8G8B8, static_cast(flags.t_pool), &texture, NULL); } @@ -318,7 +317,7 @@ public: bool VideoD3D::cap(Setting setting) { return p.cap(setting); } uintptr_t VideoD3D::get(Setting setting) { return p.get(setting); } bool VideoD3D::set(Setting setting, uintptr_t param) { return p.set(setting, param); } -bool VideoD3D::lock(uint16_t *&data, unsigned &pitch) { return p.lock(data, pitch); } +bool VideoD3D::lock(uint32_t *&data, unsigned &pitch) { return p.lock(data, pitch); } void VideoD3D::unlock() { p.unlock(); } void VideoD3D::clear() { p.clear(); } void VideoD3D::refresh(unsigned width, unsigned height) { p.refresh(width, height); } diff --git a/src/lib/ruby/video/direct3d.h b/src/lib/ruby/video/direct3d.h index 17c2d66a0..9f2fd0633 100644 --- a/src/lib/ruby/video/direct3d.h +++ b/src/lib/ruby/video/direct3d.h @@ -6,7 +6,7 @@ public: uintptr_t get(Setting); bool set(Setting, uintptr_t); - bool lock(uint16_t *&data, unsigned &pitch); + bool lock(uint32_t *&data, unsigned &pitch); void unlock(); void clear(); diff --git a/src/lib/ruby/video/directdraw.cpp b/src/lib/ruby/video/directdraw.cpp index 4d021d1e1..d7d2f88f0 100644 --- a/src/lib/ruby/video/directdraw.cpp +++ b/src/lib/ruby/video/directdraw.cpp @@ -1,4 +1,3 @@ -#define WIN32_LEAN_AND_MEAN #include #include @@ -49,17 +48,17 @@ public: } void clear() { - DDBLTFX fx; + DDBLTFX fx; fx.dwSize = sizeof(DDBLTFX); fx.dwFillColor = 0x00000000; screen->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); } - bool lock(uint16_t *&data, unsigned &pitch) { + bool lock(uint32_t *&data, unsigned &pitch) { if(raster->Lock(0, &ddsd, DDLOCK_WAIT, 0) != DD_OK) return false; pitch = ddsd.lPitch; - return data = (uint16_t*)ddsd.lpSurface; + return data = (uint32_t*)ddsd.lpSurface; } void unlock() { @@ -69,18 +68,18 @@ public: void refresh(unsigned r_width, unsigned r_height) { if(settings.synchronize) { for(;;) { - BOOL in_vblank; + BOOL in_vblank; lpdd7->GetVerticalBlankStatus(&in_vblank); if(bool(in_vblank) == true) break; //Sleep(1); } } - HRESULT hr; - RECT rd, rs; + HRESULT hr; + RECT rd, rs; SetRect(&rs, 0, 0, r_width, r_height); - POINT p = { 0, 0 }; + POINT p = { 0, 0 }; ClientToScreen(settings.handle, &p); GetClientRect(settings.handle, &rd); OffsetRect(&rd, p.x, p.y); @@ -117,10 +116,9 @@ public: } void create_raster() { - int depth; screen->GetSurfaceDesc(&ddsd); - depth = ddsd.ddpfPixelFormat.dwRGBBitCount; - if(depth == 15 || depth == 16) goto try_native_surface; + int depth = ddsd.ddpfPixelFormat.dwRGBBitCount; + if(depth == 32) goto try_native_surface; memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); ddsd.dwSize = sizeof(DDSURFACEDESC2); @@ -131,14 +129,14 @@ public: ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; - ddsd.ddpfPixelFormat.dwRGBBitCount = 16; - ddsd.ddpfPixelFormat.dwRBitMask = 0xf800; - ddsd.ddpfPixelFormat.dwGBitMask = 0x07e0; - ddsd.ddpfPixelFormat.dwBBitMask = 0x001f; + ddsd.ddpfPixelFormat.dwRGBBitCount = 32; + ddsd.ddpfPixelFormat.dwRBitMask = 0xff0000; + ddsd.ddpfPixelFormat.dwGBitMask = 0x00ff00; + ddsd.ddpfPixelFormat.dwBBitMask = 0x0000ff; if(lpdd7->CreateSurface(&ddsd, &raster, 0) == DD_OK) return; - try_native_surface: + try_native_surface: memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; @@ -146,7 +144,7 @@ public: ddsd.dwWidth = 1024; ddsd.dwHeight = 1024; - lpdd7->CreateSurface(&ddsd, &raster, 0); + if(lpdd7->CreateSurface(&ddsd, &raster, 0) == DD_OK) return; } void term() { @@ -171,7 +169,7 @@ public: bool VideoDD::cap(Setting setting) { return p.cap(setting); } uintptr_t VideoDD::get(Setting setting) { return p.get(setting); } bool VideoDD::set(Setting setting, uintptr_t param) { return p.set(setting, param); } -bool VideoDD::lock(uint16_t *&data, unsigned &pitch) { return p.lock(data, pitch); } +bool VideoDD::lock(uint32_t *&data, unsigned &pitch) { return p.lock(data, pitch); } void VideoDD::unlock() { p.unlock(); } void VideoDD::clear() { p.clear(); } void VideoDD::refresh(unsigned width, unsigned height) { p.refresh(width, height); } diff --git a/src/lib/ruby/video/directdraw.h b/src/lib/ruby/video/directdraw.h index f202121b0..e4e8eb9d7 100644 --- a/src/lib/ruby/video/directdraw.h +++ b/src/lib/ruby/video/directdraw.h @@ -6,7 +6,7 @@ public: uintptr_t get(Setting); bool set(Setting, uintptr_t); - bool lock(uint16_t *&data, unsigned &pitch); + bool lock(uint32_t *&data, unsigned &pitch); void unlock(); void clear(); diff --git a/src/lib/ruby/video/gdi.cpp b/src/lib/ruby/video/gdi.cpp index 4c827a279..7a29c9c13 100644 --- a/src/lib/ruby/video/gdi.cpp +++ b/src/lib/ruby/video/gdi.cpp @@ -1,5 +1,4 @@ #include -#define WIN32_LEAN_AND_MEAN #include #include @@ -12,7 +11,7 @@ class pVideoGDI { public: VideoGDI &self; - uint16_t *buffer; + uint32_t *buffer; HBITMAP bitmap; HDC bitmapdc; BITMAPINFO bmi; @@ -39,8 +38,8 @@ public: return false; } - bool lock(uint16_t *&data, unsigned &pitch) { - pitch = 2048; + bool lock(uint32_t *&data, unsigned &pitch) { + pitch = 1024 * 4; return data = buffer; } @@ -70,9 +69,9 @@ public: bmi.bmiHeader.biWidth = 1024; bmi.bmiHeader.biHeight = -1024; bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 16; //biBitCount of 15 is invalid, biBitCount of 16 is really RGB555 + bmi.bmiHeader.biBitCount = 32; //biBitCount of 15 is invalid, biBitCount of 16 is really RGB555 bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = 1024 * 1024 * sizeof(uint16_t); + bmi.bmiHeader.biSizeImage = 1024 * 1024 * sizeof(uint32_t); return true; } @@ -83,7 +82,7 @@ public: } pVideoGDI(VideoGDI &self_) : self(self_) { - buffer = (uint16_t*)malloc(1024 * 1024 * sizeof(uint16_t)); + buffer = (uint32_t*)malloc(1024 * 1024 * sizeof(uint32_t)); settings.handle = 0; } @@ -95,7 +94,7 @@ public: bool VideoGDI::cap(Setting setting) { return p.cap(setting); } uintptr_t VideoGDI::get(Setting setting) { return p.get(setting); } bool VideoGDI::set(Setting setting, uintptr_t param) { return p.set(setting, param); } -bool VideoGDI::lock(uint16_t *&data, unsigned &pitch) { return p.lock(data, pitch); } +bool VideoGDI::lock(uint32_t *&data, unsigned &pitch) { return p.lock(data, pitch); } void VideoGDI::unlock() { p.unlock(); } void VideoGDI::refresh(unsigned width, unsigned height) { p.refresh(width, height); } bool VideoGDI::init() { return p.init(); } diff --git a/src/lib/ruby/video/gdi.h b/src/lib/ruby/video/gdi.h index 7a2c5735c..e701f70ac 100644 --- a/src/lib/ruby/video/gdi.h +++ b/src/lib/ruby/video/gdi.h @@ -6,7 +6,7 @@ public: uintptr_t get(Setting); bool set(Setting, uintptr_t); - bool lock(uint16_t *&data, unsigned &pitch); + bool lock(uint32_t *&data, unsigned &pitch); void unlock(); void refresh(unsigned width, unsigned height); diff --git a/src/lib/ruby/video/glx.cpp b/src/lib/ruby/video/glx.cpp index 85961eeb9..9aea321b7 100644 --- a/src/lib/ruby/video/glx.cpp +++ b/src/lib/ruby/video/glx.cpp @@ -40,7 +40,7 @@ static Bool x_wait_for_map_notify(Display *d, XEvent *e, char *arg) { class pVideoGLX { public: VideoGLX &self; - uint16_t *buffer; + uint32_t *buffer; Display *display; int screen; @@ -84,8 +84,8 @@ public: return false; } - bool lock(uint16_t *&data, unsigned &pitch) { - pitch = 1024 * 2; + bool lock(uint32_t *&data, unsigned &pitch) { + pitch = 1024 * 4; return data = buffer; } @@ -93,7 +93,7 @@ public: } void clear() { - memset(buffer, 0, 1024 * 1024 * sizeof(uint16_t)); + memset(buffer, 0, 1024 * 1024 * sizeof(uint32_t)); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glFlush(); @@ -129,7 +129,7 @@ public: glPixelStorei(GL_UNPACK_ROW_LENGTH, 1024); //length of buffer in pixels glTexSubImage2D(GL_TEXTURE_2D, /* mip-map level = */ 0, /* x = */ 0, /* y = */ 0, - width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buffer); + width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); //OpenGL projection sets 0,0 as *bottom-left* of screen. //therefore, below vertices flip image to support top-left source. @@ -157,7 +157,7 @@ public: //require GLX 1.2+ API if(glx.version_major < 1 || (glx.version_major == 1 && glx.version_minor < 2)) return false; - buffer = new(zeromemory) uint16_t[1024 * 1024 * sizeof(uint16_t)]; + buffer = new(zeromemory) uint32_t[1024 * 1024 * sizeof(uint32_t)]; XWindowAttributes wa; XGetWindowAttributes(display, settings.handle, &wa); @@ -166,7 +166,7 @@ public: int elements = 0; int attributelist[] = { GLX_RGBA, - GLX_DOUBLEBUFFER, True, + GLX_DOUBLEBUFFER, None }; XVisualInfo *vi = glXChooseVisual(display, screen, attributelist); @@ -216,7 +216,7 @@ public: glTexImage2D(GL_TEXTURE_2D, /* mip-map level = */ 0, /* internal format = */ GL_RGB, /* width = */ 1024, /* height = */ 1024, /* border = */ 0, - /* format = */ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buffer); + /* format = */ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); return true; } @@ -252,7 +252,7 @@ public: bool VideoGLX::cap(Setting setting) { return p.cap(setting); } uintptr_t VideoGLX::get(Setting setting) { return p.get(setting); } bool VideoGLX::set(Setting setting, uintptr_t param) { return p.set(setting, param); } -bool VideoGLX::lock(uint16_t *&data, unsigned &pitch) { return p.lock(data, pitch); } +bool VideoGLX::lock(uint32_t *&data, unsigned &pitch) { return p.lock(data, pitch); } void VideoGLX::unlock() { p.unlock(); } void VideoGLX::clear() { p.clear(); } void VideoGLX::refresh(unsigned width, unsigned height) { p.refresh(width, height); } diff --git a/src/lib/ruby/video/glx.h b/src/lib/ruby/video/glx.h index 444f60e68..f80b20fff 100644 --- a/src/lib/ruby/video/glx.h +++ b/src/lib/ruby/video/glx.h @@ -6,7 +6,7 @@ public: uintptr_t get(Setting); bool set(Setting, uintptr_t); - bool lock(uint16_t *&data, unsigned &pitch); + bool lock(uint32_t *&data, unsigned &pitch); void unlock(); void clear(); diff --git a/src/lib/ruby/video/sdl.cpp b/src/lib/ruby/video/sdl.cpp index ab13c878e..52734570c 100644 --- a/src/lib/ruby/video/sdl.cpp +++ b/src/lib/ruby/video/sdl.cpp @@ -42,10 +42,10 @@ public: return false; } - bool lock(uint16_t *&data, unsigned &pitch) { + bool lock(uint32_t *&data, unsigned &pitch) { if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer); pitch = buffer->pitch; - return data = (uint16_t*)buffer->pixels; + return data = (uint32_t*)buffer->pixels; } void unlock() { @@ -81,10 +81,10 @@ public: sprintf(env, "SDL_WINDOWID=%ld", settings.handle); putenv(env); SDL_InitSubSystem(SDL_INIT_VIDEO); - screen = SDL_SetVideoMode(2560, 1600, 16, SDL_HWSURFACE); + screen = SDL_SetVideoMode(2560, 1600, 32, SDL_HWSURFACE); buffer = SDL_CreateRGBSurface(SDL_HWSURFACE, 1024, 1024, - 16, 0xf800, 0x07e0, 0x001f, 0x0000 + 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 ); return true; } @@ -101,7 +101,7 @@ public: bool VideoSDL::cap(Setting setting) { return p.cap(setting); } uintptr_t VideoSDL::get(Setting setting) { return p.get(setting); } bool VideoSDL::set(Setting setting, uintptr_t param) { return p.set(setting, param); } -bool VideoSDL::lock(uint16_t *&data, unsigned &pitch) { return p.lock(data, pitch); } +bool VideoSDL::lock(uint32_t *&data, unsigned &pitch) { return p.lock(data, pitch); } void VideoSDL::unlock() { p.unlock(); } void VideoSDL::clear() { p.clear(); } void VideoSDL::refresh(unsigned width, unsigned height) { p.refresh(width, height); } diff --git a/src/lib/ruby/video/sdl.h b/src/lib/ruby/video/sdl.h index d3fb9f439..5dcf35069 100644 --- a/src/lib/ruby/video/sdl.h +++ b/src/lib/ruby/video/sdl.h @@ -6,7 +6,7 @@ public: uintptr_t get(Setting); bool set(Setting, uintptr_t); - bool lock(uint16_t *&data, unsigned &pitch); + bool lock(uint32_t *&data, unsigned &pitch); void unlock(); void clear(); diff --git a/src/lib/ruby/video/xv.cpp b/src/lib/ruby/video/xv.cpp index 798097176..83576a9f6 100644 --- a/src/lib/ruby/video/xv.cpp +++ b/src/lib/ruby/video/xv.cpp @@ -18,7 +18,7 @@ namespace ruby { class pVideoXv { public: VideoXv &self; - uint16_t *buffer; + uint32_t *buffer; XvImage *xvimage; GC gc; Display *display; @@ -48,8 +48,8 @@ public: return false; } - bool lock(uint16_t *&data, unsigned &pitch) { - pitch = 1024 * 2; + bool lock(uint32_t *&data, unsigned &pitch) { + pitch = 1024 * 4; return data = buffer; } @@ -57,25 +57,24 @@ public: } void clear() { - memset(buffer, 0, 1024 * 1024 * sizeof(uint16_t)); + memset(buffer, 0, 1024 * 1024 * sizeof(uint32_t)); //clear twice in case video is double buffered ... refresh(1024, 1024); refresh(1024, 1024); } - void refresh(unsigned r_width, unsigned r_height) { - Window dw; - int d0, d1; - unsigned d2, d3; - unsigned width, height; - XGetGeometry(display, settings.handle, &dw, &d0, &d1, &width, &height, &d2, &d3); + void refresh(unsigned width, unsigned height) { + XWindowAttributes attributes; + XGetWindowAttributes(display, settings.handle, &attributes); - uint16_t *input = (uint16_t*)buffer; - uint16_t *output = (uint16_t*)xvimage->data; - for(int y = 0; y < r_height; y++) { - for(int x = 0; x < r_width >> 1; x++) { - uint16_t p0 = *input++; - uint16_t p1 = *input++; + uint32_t *input = (uint32_t*)buffer; + uint16_t *output = (uint16_t*)xvimage->data; + for(int y = 0; y < height; y++) { + for(int x = 0; x < width >> 1; x++) { + uint32_t p0 = *input++; + uint32_t p1 = *input++; + p0 = ((p0 >> 8) & 0xf800) + ((p0 >> 5) & 0x07e0) + ((p0 >> 3) & 0x001f); + p1 = ((p1 >> 8) & 0xf800) + ((p1 >> 5) & 0x07e0) + ((p1 >> 3) & 0x001f); uint8_t u = (utable[p0] + utable[p1]) >> 1; uint8_t v = (vtable[p0] + vtable[p1]) >> 1; @@ -83,35 +82,22 @@ public: *output++ = (u << 8) | ytable[p0]; *output++ = (v << 8) | ytable[p1]; } - input += 1024 - r_width; - output += 1024 - r_width; + input += 1024 - width; + output += 1024 - width; } XvShmPutImage(display, xv_port, settings.handle, gc, xvimage, - 0, 0, r_width, r_height, 0, 0, width, height, + 0, 0, attributes.width, attributes.height, true); } bool init() { - buffer = (uint16_t*)malloc(1024 * 1024 * sizeof(uint16_t)); + buffer = (uint32_t*)malloc(1024 * 1024 * sizeof(uint32_t)); display = XOpenDisplay(0); screen = DefaultScreen(display); gc = XCreateGC(display, settings.handle, 0, 0); - XVisualInfo visual_info; - if(XMatchVisualInfo(display, screen, 24, TrueColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 16, TrueColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 15, TrueColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 8, PseudoColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 8, GrayScale, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 8, StaticGray, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 1, StaticGray, &visual_info)) { - } else { - fprintf(stderr, "VideoXv: unable to find suitable video display.\n"); - return false; - } - if(!XShmQueryExtension(display)) { fprintf(stderr, "VideoXv: XShm extension not found.\n"); return false; @@ -138,8 +124,7 @@ public: const Atom atom = XInternAtom(display, "XV_AUTOPAINT_COLORKEY", true); if(atom != None) XvSetPortAttribute(display, xv_port, atom, 1); - //0x00000003 = 32-bit X8R8G8B8 [xRGB] (few drivers support this mode) - //0x32595559 = 16-bit Y8U8,Y8V8 [YUY2] (most drivers support this mode) + //0x32595559 = 16-bit Y8U8,Y8V8 (YUY2) xvimage = XvShmCreateImage(display, xv_port, 0x32595559, 0, 1024, 1024, &shminfo); if(!xvimage) { fprintf(stderr, "VideoXv: XShmCreateImage failed.\n"); @@ -202,7 +187,7 @@ public: bool VideoXv::cap(Setting setting) { return p.cap(setting); } uintptr_t VideoXv::get(Setting setting) { return p.get(setting); } bool VideoXv::set(Setting setting, uintptr_t param) { return p.set(setting, param); } -bool VideoXv::lock(uint16_t *&data, unsigned &pitch) { return p.lock(data, pitch); } +bool VideoXv::lock(uint32_t *&data, unsigned &pitch) { return p.lock(data, pitch); } void VideoXv::unlock() { p.unlock(); } void VideoXv::clear() { p.clear(); } void VideoXv::refresh(unsigned width, unsigned height) { p.refresh(width, height); } diff --git a/src/lib/ruby/video/xv.h b/src/lib/ruby/video/xv.h index f93b9728c..258fe4e4b 100644 --- a/src/lib/ruby/video/xv.h +++ b/src/lib/ruby/video/xv.h @@ -6,7 +6,7 @@ public: uintptr_t get(Setting); bool set(Setting, uintptr_t); - bool lock(uint16_t *&data, unsigned &pitch); + bool lock(uint32_t *&data, unsigned &pitch); void unlock(); void clear(); diff --git a/src/memory/memory.cpp b/src/memory/memory.cpp index cdc4e27a1..4750d9a24 100644 --- a/src/memory/memory.cpp +++ b/src/memory/memory.cpp @@ -1,4 +1,6 @@ #include "../base.h" +#define MEMORY_CPP + #include "memory_rw.cpp" namespace memory { @@ -16,7 +18,7 @@ uint8 UnmappedMMIO::mmio_read(uint) { return cpu.regs.mdr; } void UnmappedMMIO::mmio_write(uint, uint8) {} void MMIOAccess::map(uint addr, MMIO &access) { -//MMIO: $[00-3f]:[2000-5fff] + //MMIO: $[00-3f]:[2000-5fff] mmio[(addr - 0x2000) & 0x3fff] = &access; } @@ -29,9 +31,9 @@ void MMIOAccess::write(uint addr, uint8 data) { } uint Bus::mirror(uint addr, uint size) { -uint base = 0; + uint base = 0; if(size) { - uint mask = 1 << 23; + uint mask = 1 << 23; while(addr >= size) { while(!(addr & mask)) mask >>= 1; addr -= mask; @@ -62,9 +64,9 @@ void Bus::map( if(access.size() == -1U) return; -uint8 page_lo = addr_lo >> 8; -uint8 page_hi = addr_hi >> 8; -uint index = 0; + uint8 page_lo = addr_lo >> 8; + uint8 page_hi = addr_hi >> 8; + uint index = 0; switch(mode) { case MapDirect: { diff --git a/src/memory/memory.h b/src/memory/memory.h index eb33ff44a..9adaa3246 100644 --- a/src/memory/memory.h +++ b/src/memory/memory.h @@ -3,7 +3,7 @@ struct Memory { virtual uint8 read(uint addr) = 0; virtual void write(uint addr, uint8 data) = 0; -enum { WRAP_NONE = 0, WRAP_BANK = 1, WRAP_PAGE = 2 }; + enum { WRAP_NONE = 0, WRAP_BANK = 1, WRAP_PAGE = 2 }; virtual uint16 read_word(uint addr, uint wrap = WRAP_NONE); virtual void write_word(uint addr, uint16 data, uint wrap = WRAP_NONE); virtual uint32 read_long(uint addr, uint wrap = WRAP_NONE); @@ -69,26 +69,26 @@ class Bus { public: uint mirror(uint addr, uint size); void map(uint addr, Memory &access, uint offset); -enum MapMode { MapDirect, MapLinear, MapShadow }; + enum MapMode { MapDirect, MapLinear, MapShadow }; void map(MapMode mode, uint8 bank_lo, uint8 bank_hi, uint16 addr_lo, uint16 addr_hi, Memory &access, uint offset = 0, uint size = 0); alwaysinline uint8 read(uint addr) { - #if defined(CHEAT_SYSTEM) + #if defined(CHEAT_SYSTEM) if(cheat.enabled() && cheat.exists(addr)) { - uint8 r; + uint8 r; if(cheat.read(addr, r)) return r; } - #endif + #endif - Page &p = page[addr >> 8]; + Page &p = page[addr >> 8]; return p.access->read(p.offset + addr); } alwaysinline void write(uint addr, uint8 data) { - Page &p = page[addr >> 8]; + Page &p = page[addr >> 8]; return p.access->write(p.offset + addr, data); } diff --git a/src/memory/memory_rw.cpp b/src/memory/memory_rw.cpp index fb132cc1a..ad653b0c6 100644 --- a/src/memory/memory_rw.cpp +++ b/src/memory/memory_rw.cpp @@ -1,77 +1,81 @@ +#ifdef MEMORY_CPP + uint16 Memory::read_word(uint addr, uint wrap) { -uint16 r; + uint16 r; switch(wrap) { - case WRAP_NONE: - r = read(addr); - r |= read(addr + 1) << 8; - break; - case WRAP_BANK: - r = read(addr); - r |= read((addr & 0xff0000) | ((addr + 1) & 0xffff)) << 8; - break; - case WRAP_PAGE: - r = read(addr); - r |= read((addr & 0xffff00) | ((addr + 1) & 0xff)) << 8; - break; + case WRAP_NONE: { + r = read(addr); + r |= read(addr + 1) << 8; + } break; + case WRAP_BANK: { + r = read(addr); + r |= read((addr & 0xff0000) | ((addr + 1) & 0xffff)) << 8; + } break; + case WRAP_PAGE: { + r = read(addr); + r |= read((addr & 0xffff00) | ((addr + 1) & 0xff)) << 8; + } break; } return r; } void Memory::write_word(uint addr, uint16 data, uint wrap) { switch(wrap) { - case WRAP_NONE: - write(addr, data); - write(addr + 1, data >> 8); - return; - case WRAP_BANK: - write(addr, data); - write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8); - return; - case WRAP_PAGE: - write(addr, data); - write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8); - return; + case WRAP_NONE: { + write(addr, data); + write(addr + 1, data >> 8); + } return; + case WRAP_BANK: { + write(addr, data); + write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8); + } return; + case WRAP_PAGE: { + write(addr, data); + write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8); + } return; } } uint32 Memory::read_long(uint addr, uint wrap) { -uint32 r; + uint32 r; switch(wrap) { - case WRAP_NONE: - r = read(addr); - r |= read(addr + 1) << 8; - r |= read(addr + 2) << 16; - break; - case WRAP_BANK: - r = read(addr); - r |= read((addr & 0xff0000) | ((addr + 1) & 0xffff)) << 8; - r |= read((addr & 0xff0000) | ((addr + 2) & 0xffff)) << 16; - break; - case WRAP_PAGE: - r = read(addr); - r |= read((addr & 0xffff00) | ((addr + 1) & 0xff)) << 8; - r |= read((addr & 0xffff00) | ((addr + 2) & 0xff)) << 16; - break; + case WRAP_NONE: { + r = read(addr); + r |= read(addr + 1) << 8; + r |= read(addr + 2) << 16; + } break; + case WRAP_BANK: { + r = read(addr); + r |= read((addr & 0xff0000) | ((addr + 1) & 0xffff)) << 8; + r |= read((addr & 0xff0000) | ((addr + 2) & 0xffff)) << 16; + } break; + case WRAP_PAGE: { + r = read(addr); + r |= read((addr & 0xffff00) | ((addr + 1) & 0xff)) << 8; + r |= read((addr & 0xffff00) | ((addr + 2) & 0xff)) << 16; + } break; } return r; } void Memory::write_long(uint addr, uint32 data, uint wrap) { switch(wrap) { - case WRAP_NONE: - write(addr, data); - write(addr + 1, data >> 8); - write(addr + 2, data >> 16); - return; - case WRAP_BANK: - write(addr, data); - write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8); - write((addr & 0xff0000) | ((addr + 2) & 0xffff), data >> 16); - return; - case WRAP_PAGE: - write(addr, data); - write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8); - write((addr & 0xffff00) | ((addr + 2) & 0xff), data >> 16); - return; + case WRAP_NONE: { + write(addr, data); + write(addr + 1, data >> 8); + write(addr + 2, data >> 16); + } return; + case WRAP_BANK: { + write(addr, data); + write((addr & 0xff0000) | ((addr + 1) & 0xffff), data >> 8); + write((addr & 0xff0000) | ((addr + 2) & 0xffff), data >> 16); + } return; + case WRAP_PAGE: { + write(addr, data); + write((addr & 0xffff00) | ((addr + 1) & 0xff), data >> 8); + write((addr & 0xffff00) | ((addr + 2) & 0xff), data >> 16); + } return; } } + +#endif //ifdef MEMORY_CPP diff --git a/src/memory/smemory/mapper/chip.cpp b/src/memory/smemory/mapper/chip.cpp index d49eaf399..9c65cba7c 100644 --- a/src/memory/smemory/mapper/chip.cpp +++ b/src/memory/smemory/mapper/chip.cpp @@ -1,3 +1,5 @@ +#ifdef SMEMORY_CPP + void sBus::map_cx4() { map(MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, cx4); map(MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, cx4); @@ -48,3 +50,5 @@ void sBus::map_st010() { map(MapDirect, 0x68, 0x6f, 0x0000, 0x0fff, st010); map(MapDirect, 0xe8, 0xef, 0x0000, 0x0fff, st010); } + +#endif //ifdef SMEMORY_CPP diff --git a/src/memory/smemory/mapper/generic.cpp b/src/memory/smemory/mapper/generic.cpp index ee0f2b157..30eb76652 100644 --- a/src/memory/smemory/mapper/generic.cpp +++ b/src/memory/smemory/mapper/generic.cpp @@ -1,3 +1,5 @@ +#ifdef SMEMORY_CPP + void sBus::map_generic() { switch(cartridge.mapper()) { case Cartridge::LoROM: { @@ -81,10 +83,12 @@ void sBus::map_generic_sram() { map(MapLinear, 0x20, 0x3f, 0x6000, 0x7fff, memory::cartram); map(MapLinear, 0xa0, 0xbf, 0x6000, 0x7fff, memory::cartram); -//research shows only games with very large ROM/RAM sizes require MAD-1 memory mapping of SRAM -//otherwise, default to safer, larger SRAM address window -uint16 addr_hi = (memory::cartrom.size() > 0x200000 || memory::cartram.size() > 32 * 1024) ? 0x7fff : 0xffff; + //research shows only games with very large ROM/RAM sizes require MAD-1 memory mapping of SRAM + //otherwise, default to safer, larger SRAM address window + uint16 addr_hi = (memory::cartrom.size() > 0x200000 || memory::cartram.size() > 32 * 1024) ? 0x7fff : 0xffff; map(MapLinear, 0x70, 0x7f, 0x0000, addr_hi, memory::cartram); if(cartridge.info.mapper != Cartridge::LoROM) return; map(MapLinear, 0xf0, 0xff, 0x0000, addr_hi, memory::cartram); } + +#endif //ifdef SMEMORY_CPP diff --git a/src/memory/smemory/mapper/system.cpp b/src/memory/smemory/mapper/system.cpp index e26bf8650..ef089f9db 100644 --- a/src/memory/smemory/mapper/system.cpp +++ b/src/memory/smemory/mapper/system.cpp @@ -1,8 +1,10 @@ +#ifdef SMEMORY_CPP + void sBus::map_reset() { - for(uint i = 0x0000; i <= 0xffff; i++) + for(uint32_t i = 0x0000; i <= 0xffff; i++) map(i << 8, memory::memory_unmapped, 0); - for(uint i = 0x2000; i <= 0x5fff; i++) + for(uint16_t i = 0x2000; i <= 0x5fff; i++) memory::mmio.map(i, memory::mmio_unmapped); } @@ -15,3 +17,5 @@ void sBus::map_system() { map(MapLinear, 0x7e, 0x7f, 0x0000, 0xffff, memory::wram); } + +#endif //ifdef SMEMORY_CPP diff --git a/src/memory/smemory/smemory.cpp b/src/memory/smemory/smemory.cpp index 38ffd4b82..411e788a2 100644 --- a/src/memory/smemory/smemory.cpp +++ b/src/memory/smemory/smemory.cpp @@ -1,4 +1,6 @@ #include "../../base.h" +#define SMEMORY_CPP + #include "mapper/system.cpp" #include "mapper/generic.cpp" #include "mapper/chip.cpp" @@ -28,7 +30,7 @@ void sBus::load_cart() { if(cartridge.info.obc1) map_obc1(); if(cartridge.info.st010) map_st010(); - snes.set_region(cartridge.region()); + snes.set_region(cartridge.region() == Cartridge::NTSC ? SNES::NTSC : SNES::PAL); is_cart_loaded = true; } diff --git a/src/ppu/bppu/bppu.cpp b/src/ppu/bppu/bppu.cpp index 135420ec6..a864d66ce 100644 --- a/src/ppu/bppu/bppu.cpp +++ b/src/ppu/bppu/bppu.cpp @@ -1,87 +1,69 @@ -#include "../../base.h" +#include "../../base.h" +#define BPPU_CPP + #include "bppu_mmio.cpp" #include "bppu_render.cpp" -void bPPU::run() {} - void bPPU::scanline() { - line.y = cpu.vcounter(); - line.interlace = cpu.interlace(); - line.interlace_field = cpu.interlace_field(); + line.y = cpu.vcounter(); if(line.y == 0) { - //RTO flag reset + //RTO flag reset regs.time_over = false; regs.range_over = false; } - if(line.y == 1) { - //mosaic reset - for(int bg = BG1; bg <= BG4; bg++) { - regs.bg_y[bg] = 1; - } - + if(line.y == 1) { + //mosaic reset + for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1; regs.mosaic_countdown = regs.mosaic_size + 1; regs.mosaic_countdown--; } else { for(int bg = BG1; bg <= BG4; bg++) { - if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) { - regs.bg_y[bg] = line.y; - } - } - - if(!regs.mosaic_countdown) { - regs.mosaic_countdown = regs.mosaic_size + 1; + if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line.y; } + if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1; regs.mosaic_countdown--; } -//note: this should actually occur at V=225,HC=10. -//this is a limitation of the scanline-based renderer. - if(line.y == (!cpu.overscan() ? 225 : 240)) { + //note: this should actually occur at V=225,HC=10. + //this is a limitation of the scanline-based renderer. + if(line.y == (!overscan() ? 225 : 240)) { if(regs.display_disabled == false) { - //OAM address reset + //OAM address reset regs.oam_addr = regs.oam_baseaddr << 1; regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; } } - - if(line.y == 241 && line.interlace_field == 1) { - if(regs.interlace != cpu.interlace()) { - //clear entire frame so that odd scanlines are empty - //this should be handled better, but one blank frame looks - //better than one improperly interlaced frame... - memset(output, 0, 512 * 480 * sizeof(uint16)); - } - //cpu.set_overscan(regs.overscan); - cpu.set_interlace(regs.interlace); - regs.scanlines = (regs.overscan == false) ? 224 : 239; - } } void bPPU::render_scanline() { -#ifdef FAVOR_SPEED -//bypass RTO status flag calculations - if(status.render_output == false)return; -#endif + #ifdef FAST_FRAMESKIP + //bypass RTO status flag calculations + if(status.render_output == false) return; + #endif - if(line.y >= 0 && line.y < (cpu.overscan() ? 240 : 225)) { + if(line.y >= 0 && line.y < (!overscan() ? 225 : 240)) { if(config::ppu.hack.obj_cache == false) { if(line.y != 0) { render_line_oam_rto(); render_line(); } } else { - if(line.y != 0) { - render_line(); - } + if(line.y != 0) render_line(); render_line_oam_rto(); } } } void bPPU::frame() { - PPU::frame(); + PPU::frame(); + + display.field ^= 1; + if(display.field == 0) { + display.interlace = regs.interlace; + regs.scanlines = (regs.overscan == false) ? 224 : 239; + } } void bPPU::power() { @@ -93,25 +75,25 @@ void bPPU::power() { region = snes.region(); -//$2100 + //$2100 regs.display_disabled = 1; regs.display_brightness = 15; -//$2101 + //$2101 regs.oam_basesize = 0; regs.oam_nameselect = 0; regs.oam_tdaddr = 0x0000; -//$2102-$2103 + //$2102-$2103 regs.oam_baseaddr = 0x0000; regs.oam_addr = 0x0000; regs.oam_priority = false; regs.oam_firstsprite = 0; -//$2104 + //$2104 regs.oam_latchdata = 0x00; -//$2105 + //$2105 regs.bg_tilesize[BG1] = 0; regs.bg_tilesize[BG2] = 0; regs.bg_tilesize[BG3] = 0; @@ -119,7 +101,7 @@ void bPPU::power() { regs.bg3_priority = 0; regs.bg_mode = 0; -//$2106 + //$2106 regs.mosaic_size = 0; regs.mosaic_enabled[BG1] = false; regs.mosaic_enabled[BG2] = false; @@ -127,7 +109,7 @@ void bPPU::power() { regs.mosaic_enabled[BG4] = false; regs.mosaic_countdown = 0; -//$2107-$210a + //$2107-$210a regs.bg_scaddr[BG1] = 0x0000; regs.bg_scaddr[BG2] = 0x0000; regs.bg_scaddr[BG3] = 0x0000; @@ -137,13 +119,13 @@ void bPPU::power() { regs.bg_scsize[BG3] = SC_32x32; regs.bg_scsize[BG4] = SC_32x32; -//$210b-$210c + //$210b-$210c regs.bg_tdaddr[BG1] = 0x0000; regs.bg_tdaddr[BG2] = 0x0000; regs.bg_tdaddr[BG3] = 0x0000; regs.bg_tdaddr[BG4] = 0x0000; -//$210d-$2114 + //$210d-$2114 regs.bg_ofslatch = 0x00; regs.m7_hofs = regs.m7_vofs = 0x0000; regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000; @@ -151,20 +133,20 @@ void bPPU::power() { regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000; regs.bg_hofs[BG4] = regs.bg_vofs[BG4] = 0x0000; -//$2115 + //$2115 regs.vram_incmode = 1; regs.vram_mapping = 0; regs.vram_incsize = 1; -//$2116-$2117 + //$2116-$2117 regs.vram_addr = 0x0000; -//$211a + //$211a regs.mode7_repeat = 0; regs.mode7_vflip = false; regs.mode7_hflip = false; -//$211b-$2120 + //$211b-$2120 regs.m7_latch = 0x00; regs.m7a = 0x0000; regs.m7b = 0x0000; @@ -173,13 +155,13 @@ void bPPU::power() { regs.m7x = 0x0000; regs.m7y = 0x0000; -//$2121 + //$2121 regs.cgram_addr = 0x0000; -//$2122 + //$2122 regs.cgram_latchdata = 0x00; -//$2123-$2125 + //$2123-$2125 regs.window1_enabled[BG1] = false; regs.window1_enabled[BG2] = false; regs.window1_enabled[BG3] = false; @@ -208,13 +190,13 @@ void bPPU::power() { regs.window2_invert [OAM] = false; regs.window2_invert [COL] = false; -//$2126-$2129 + //$2126-$2129 regs.window1_left = 0x00; regs.window1_right = 0x00; regs.window2_left = 0x00; regs.window2_right = 0x00; -//$212a-$212b + //$212a-$212b regs.window_mask[BG1] = 0; regs.window_mask[BG2] = 0; regs.window_mask[BG3] = 0; @@ -222,7 +204,7 @@ void bPPU::power() { regs.window_mask[OAM] = 0; regs.window_mask[COL] = 0; -//$212c-$212d + //$212c-$212d regs.bg_enabled[BG1] = false; regs.bg_enabled[BG2] = false; regs.bg_enabled[BG3] = false; @@ -234,7 +216,7 @@ void bPPU::power() { regs.bgsub_enabled[BG4] = false; regs.bgsub_enabled[OAM] = false; -//$212e-$212f + //$212e-$212f regs.window_enabled[BG1] = false; regs.window_enabled[BG2] = false; regs.window_enabled[BG3] = false; @@ -246,13 +228,13 @@ void bPPU::power() { regs.sub_window_enabled[BG4] = false; regs.sub_window_enabled[OAM] = false; -//$2130 + //$2130 regs.color_mask = 0; regs.colorsub_mask = 0; regs.addsub_mode = false; regs.direct_color = false; -//$2131 + //$2131 regs.color_mode = 0; regs.color_halve = false; regs.color_enabled[BACK] = false; @@ -262,13 +244,13 @@ void bPPU::power() { regs.color_enabled[BG2] = false; regs.color_enabled[BG1] = false; -//$2132 + //$2132 regs.color_r = 0x00; regs.color_g = 0x00; regs.color_b = 0x00; regs.color_rgb = 0x0000; -//$2133 + //$2133 regs.mode7_extbg = false; regs.pseudo_hires = false; regs.overscan = false; @@ -276,17 +258,17 @@ void bPPU::power() { regs.oam_interlace = false; regs.interlace = false; -//$2137 + //$2137 regs.hcounter = 0; regs.vcounter = 0; regs.latch_hcounter = 0; regs.latch_vcounter = 0; regs.counters_latched = false; -//$2139-$213a + //$2139-$213a regs.vram_readbuffer = 0x0000; -//$213e + //$213e regs.time_over = false; regs.range_over = false; @@ -295,15 +277,19 @@ void bPPU::power() { void bPPU::reset() { PPU::reset(); - frame(); + frame(); + + display.field = 0; + display.interlace = false; + display.overscan = false; memset(sprite_list, 0, sizeof(sprite_list)); -//open bus support + //open bus support regs.ppu1_mdr = 0xff; regs.ppu2_mdr = 0xff; -//bg line counters + //bg line counters regs.bg_y[0] = 0; regs.bg_y[1] = 0; regs.bg_y[2] = 0; @@ -313,9 +299,7 @@ void bPPU::reset() { } uint8 bPPU::vram_read(uint16 addr) { -uint8 r; - r = vram[addr]; - return r; + return vram[addr]; } void bPPU::vram_write(uint16 addr, uint8 value) { @@ -323,10 +307,8 @@ void bPPU::vram_write(uint16 addr, uint8 value) { } uint8 bPPU::oam_read(uint16 addr) { -uint8 r; if(addr >= 0x0200) { addr = 0x0200 | (addr & 31); } - r = oam[addr]; - return r; + return oam[addr]; } void bPPU::oam_write(uint16 addr, uint8 value) { @@ -335,9 +317,8 @@ void bPPU::oam_write(uint16 addr, uint8 value) { } uint8 bPPU::cgram_read(uint16 addr) { -uint8 r; addr &= 511; - r = cgram[addr]; + uint8 r = cgram[addr]; if(addr & 1) { r &= 0x7f; } return r; } @@ -365,18 +346,20 @@ bPPU::bPPU() { } for(int l = 0; l < 16; l++) { - double m = (double)l / 15.0; + double m = (double)l / 15.0; for(int i = 0; i < 32 * 32; i++) { - int r = minmax<0, 31>((int)((double)((i) & 31) * m + 0.5)); - int g = minmax<0, 31>((int)((double)((i >> 5) & 31) * m + 0.5)); - if(i < 32)light_table_b[l][i] = (r << 10); + int r = (int)((double)((i) & 31) * m + 0.5); + int g = (int)((double)((i >> 5) & 31) * m + 0.5); + r = max(0, min(31, r)); + g = max(0, min(31, g)); + if(i < 32) light_table_b[l][i] = (r << 10); light_table_gr[l][i] = (g << 5) | (r); } } } bPPU::~bPPU() { - safe_free(vram); - safe_free(oam); - safe_free(cgram); + free(vram); + free(oam); + free(cgram); } diff --git a/src/ppu/bppu/bppu.h b/src/ppu/bppu/bppu.h index 5759ffc9f..c611c4de5 100644 --- a/src/ppu/bppu/bppu.h +++ b/src/ppu/bppu/bppu.h @@ -1,145 +1,155 @@ class bPPU : public PPU { public: -uint8 *vram, *oam, *cgram; -uint8 region; + uint8 *vram, *oam, *cgram; + uint8 region; -enum { NTSC = 0, PAL = 1 }; -enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 }; -enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 }; + enum { NTSC = 0, PAL = 1 }; + enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 }; + enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 }; -struct { - uint y; - bool interlace; - bool interlace_field; -} line; + struct { + uint y; + } line; + + struct { + bool field; + bool interlace; + bool overscan; + } display; -struct { -//open bus support - uint8 ppu1_mdr, ppu2_mdr; + struct { + //open bus support + uint8 ppu1_mdr, ppu2_mdr; -//bg line counters - uint16 bg_y[4]; + //bg line counters + uint16 bg_y[4]; -//$2100 - bool display_disabled; - uint8 display_brightness; + //$2100 + bool display_disabled; + uint8 display_brightness; -//$2101 - uint8 oam_basesize; - uint8 oam_nameselect; - uint16 oam_tdaddr; + //$2101 + uint8 oam_basesize; + uint8 oam_nameselect; + uint16 oam_tdaddr; -//$2102-$2103 - uint16 oam_baseaddr; - uint16 oam_addr; - bool oam_priority; - uint8 oam_firstsprite; + //$2102-$2103 + uint16 oam_baseaddr; + uint16 oam_addr; + bool oam_priority; + uint8 oam_firstsprite; -//$2104 - uint8 oam_latchdata; + //$2104 + uint8 oam_latchdata; -//$2105 - bool bg_tilesize[4]; - bool bg3_priority; - uint8 bg_mode; + //$2105 + bool bg_tilesize[4]; + bool bg3_priority; + uint8 bg_mode; -//$2106 - uint8 mosaic_size; - bool mosaic_enabled[4]; - uint16 mosaic_countdown; + //$2106 + uint8 mosaic_size; + bool mosaic_enabled[4]; + uint16 mosaic_countdown; -//$2107-$210a - uint16 bg_scaddr[4]; - uint8 bg_scsize[4]; + //$2107-$210a + uint16 bg_scaddr[4]; + uint8 bg_scsize[4]; -//$210b-$210c - uint16 bg_tdaddr[4]; + //$210b-$210c + uint16 bg_tdaddr[4]; -//$210d-$2114 - uint8 bg_ofslatch; - uint16 m7_hofs, m7_vofs; - uint16 bg_hofs[4]; - uint16 bg_vofs[4]; + //$210d-$2114 + uint8 bg_ofslatch; + uint16 m7_hofs, m7_vofs; + uint16 bg_hofs[4]; + uint16 bg_vofs[4]; -//$2115 - bool vram_incmode; - uint8 vram_mapping; - uint8 vram_incsize; + //$2115 + bool vram_incmode; + uint8 vram_mapping; + uint8 vram_incsize; -//$2116-$2117 - uint16 vram_addr; + //$2116-$2117 + uint16 vram_addr; -//$211a - uint8 mode7_repeat; - bool mode7_vflip; - bool mode7_hflip; + //$211a + uint8 mode7_repeat; + bool mode7_vflip; + bool mode7_hflip; -//$211b-$2120 - uint8 m7_latch; - uint16 m7a, m7b, m7c, m7d, m7x, m7y; + //$211b-$2120 + uint8 m7_latch; + uint16 m7a, m7b, m7c, m7d, m7x, m7y; -//$2121 - uint16 cgram_addr; + //$2121 + uint16 cgram_addr; -//$2122 - uint8 cgram_latchdata; + //$2122 + uint8 cgram_latchdata; -//$2123-$2125 - bool window1_enabled[6]; - bool window1_invert [6]; - bool window2_enabled[6]; - bool window2_invert [6]; + //$2123-$2125 + bool window1_enabled[6]; + bool window1_invert [6]; + bool window2_enabled[6]; + bool window2_invert [6]; -//$2126-$2129 - uint8 window1_left, window1_right; - uint8 window2_left, window2_right; + //$2126-$2129 + uint8 window1_left, window1_right; + uint8 window2_left, window2_right; -//$212a-$212b - uint8 window_mask[6]; + //$212a-$212b + uint8 window_mask[6]; -//$212c-$212d - bool bg_enabled[5], bgsub_enabled[5]; + //$212c-$212d + bool bg_enabled[5], bgsub_enabled[5]; -//$212e-$212f - bool window_enabled[5], sub_window_enabled[5]; + //$212e-$212f + bool window_enabled[5], sub_window_enabled[5]; -//$2130 - uint8 color_mask, colorsub_mask; - bool addsub_mode; - bool direct_color; + //$2130 + uint8 color_mask, colorsub_mask; + bool addsub_mode; + bool direct_color; -//$2131 - bool color_mode, color_halve; - bool color_enabled[6]; + //$2131 + bool color_mode, color_halve; + bool color_enabled[6]; -//$2132 - uint8 color_r, color_g, color_b; - uint16 color_rgb; + //$2132 + uint8 color_r, color_g, color_b; + uint16 color_rgb; -//$2133 -//overscan and interlace are checked once per frame to -//determine if entire frame should be interlaced/non-interlace -//and overscan adjusted. therefore, the variables act sort of -//like a buffer, but they do still affect internal rendering - bool mode7_extbg; - bool pseudo_hires; - bool overscan; - uint16 scanlines; - bool oam_interlace; - bool interlace; + //$2133 + //overscan and interlace are checked once per frame to + //determine if entire frame should be interlaced/non-interlace + //and overscan adjusted. therefore, the variables act sort of + //like a buffer, but they do still affect internal rendering + bool mode7_extbg; + bool pseudo_hires; + bool overscan; + uint16 scanlines; + bool oam_interlace; + bool interlace; -//$2137 - uint16 hcounter, vcounter; - bool latch_hcounter, latch_vcounter; - bool counters_latched; + //$2137 + uint16 hcounter, vcounter; + bool latch_hcounter, latch_vcounter; + bool counters_latched; -//$2139-$213a - uint16 vram_readbuffer; + //$2139-$213a + uint16 vram_readbuffer; + + //$213e + bool time_over, range_over; + uint16 oam_itemcount, oam_tilecount; + } regs; + + alwaysinline bool field() { return display.field; } + alwaysinline bool interlace() { return display.interlace; } + alwaysinline bool overscan() { return display.overscan; } + alwaysinline bool hires() { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); } -//$213e - bool time_over, range_over; - uint16 oam_itemcount, oam_tilecount; -} regs; uint8 vram_read (uint16 addr); void vram_write (uint16 addr, uint8 value); uint8 oam_read (uint16 addr); @@ -220,37 +230,34 @@ struct { uint8 mmio_r213e(); //STAT77 uint8 mmio_r213f(); //STAT78 - uint8 mmio_read (uint addr); - void mmio_write(uint addr, uint8 data); + uint8 mmio_read(uint addr); + void mmio_write(uint addr, uint8 data); - void latch_counters(); + void latch_counters(); -//PPU render functions + //PPU render functions + #include "bppu_render.h" -#include "bppu_render.h" + uint16 light_table_b[16][32]; + uint16 light_table_gr[16][32 * 32]; + uint16 mosaic_table[16][4096]; + void render_line(); -uint16 light_table_b[16][32]; -uint16 light_table_gr[16][32 * 32]; -uint16 mosaic_table[16][4096]; - void render_line(); - - void update_oam_status(); -//required functions - void run(); - void scanline(); - void render_scanline(); - void frame(); - void power(); - void reset(); - - bool scanline_is_hires() { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); } + void update_oam_status(); + //required functions + void run(); + void scanline(); + void render_scanline(); + void frame(); + void power(); + void reset(); inline uint16 read16(uint8 *addr, uint pos) { - #if defined(ARCH_LSB) + #if defined(ARCH_LSB) return *((uint16*)(addr + pos)); - #else + #else return (addr[pos]) | (addr[pos + 1] << 8); - #endif + #endif } bPPU(); diff --git a/src/ppu/bppu/bppu_mmio.cpp b/src/ppu/bppu/bppu_mmio.cpp index 177846368..a8c1af4ea 100644 --- a/src/ppu/bppu/bppu_mmio.cpp +++ b/src/ppu/bppu/bppu_mmio.cpp @@ -1,5 +1,7 @@ +#ifdef BPPU_CPP + void bPPU::latch_counters() { - regs.hcounter = cpu.hcounter(); + regs.hcounter = cpu.hdot(); regs.vcounter = cpu.vcounter(); regs.counters_latched = true; } @@ -21,61 +23,36 @@ uint16 bPPU::get_vram_address() { //write occurs during the very last clock cycle of vblank. uint8 bPPU::vram_mmio_read(uint16 addr) { - if(regs.display_disabled == true) { - return vram_read(addr); - } + if(regs.display_disabled == true) return vram_read(addr); -uint16 v = cpu.vcounter(); -uint16 hc = cpu.hclock(); -uint16 ls = (cpu.region_scanlines() >> 1) - 1; - if(cpu.interlace() && !cpu.interlace_field())ls++; - - if(v == ls && hc == 1362) { + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); + uint16 ls = ((snes.region() == SNES::NTSC ? 525 : 625) >> 1) - 1; + if(interlace() && !field()) ls++; + if(v == ls && h == 1362) return 0x00; + if(v < (!overscan() ? 224 : 239)) return 0x00; + if(v == (!overscan() ? 224 : 239)) { + if(h == 1362) return vram_read(addr); return 0x00; } - - if(v < (!cpu.overscan() ? 224 : 239)) { - return 0x00; - } - - if(v == (!cpu.overscan() ? 224 : 239)) { - if(hc == 1362) { - return vram_read(addr); - } - return 0x00; - } - return vram_read(addr); } void bPPU::vram_mmio_write(uint16 addr, uint8 data) { - if(regs.display_disabled == true) { - return vram_write(addr, data); - } + if(regs.display_disabled == true) return vram_write(addr, data); -uint16 v = cpu.vcounter(); -uint16 hc = cpu.hclock(); + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); if(v == 0) { - if(hc <= 4) { - return vram_write(addr, data); - } - if(hc == 6) { - return vram_write(addr, cpu.regs.mdr); - } + if(h <= 4) return vram_write(addr, data); + if(h == 6) return vram_write(addr, cpu.regs.mdr); return; } - - if(v < (!cpu.overscan() ? 225 : 240)) { - return; - } - - if(v == (!cpu.overscan() ? 225 : 240)) { - if(hc <= 4) { - return; - } + if(v < (!overscan() ? 225 : 240)) return; + if(v == (!overscan() ? 225 : 240)) { + if(h <= 4) return; return vram_write(addr, data); } - vram_write(addr, data); } @@ -99,11 +76,8 @@ uint8 bPPU::oam_mmio_read(uint16 addr) { return oam_read(addr); } -uint16 v = cpu.vcounter(); - if(v < (!cpu.overscan() ? 225 : 240)) { - return oam_read(0x0218); - } - + uint16 v = cpu.vcounter(); + if(v < (!overscan() ? 225 : 240)) return oam_read(0x0218); return oam_read(addr); } @@ -112,11 +86,8 @@ void bPPU::oam_mmio_write(uint16 addr, uint8 data) { return oam_write(addr, data); } -uint16 v = cpu.vcounter(); - if(v < (!cpu.overscan() ? 225 : 240)) { - return oam_write(0x0218, data); - } - + uint16 v = cpu.vcounter(); + if(v < (!overscan() ? 225 : 240)) return oam_write(0x0218, data); oam_write(addr, data); } @@ -131,12 +102,11 @@ uint8 bPPU::cgram_mmio_read(uint16 addr) { return cgram_read(addr); } -uint16 v = cpu.vcounter(); -uint16 hc = cpu.hclock(); - if(v < (!cpu.overscan() ? 225 : 240) && hc >= 72 && hc < 1096) { + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); + if(v < (!overscan() ? 225 : 240) && h >= 72 && h < 1096) { return cgram_read(0x01ff); } - return cgram_read(addr); } @@ -145,18 +115,17 @@ void bPPU::cgram_mmio_write(uint16 addr, uint8 data) { return cgram_write(addr, data); } -uint16 v = cpu.vcounter(); -uint16 hc = cpu.hclock(); - if(v < (!cpu.overscan() ? 225 : 240) && hc >= 72 && hc < 1096) { + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); + if(v < (!overscan() ? 225 : 240) && h >= 72 && h < 1096) { return cgram_write(0x01ff, data); } - cgram_write(addr, data); } //INIDISP void bPPU::mmio_w2100(uint8 value) { - if(regs.display_disabled == true && cpu.vcounter() == (!cpu.overscan() ? 225 : 240)) { + if(regs.display_disabled == true && cpu.vcounter() == (!overscan() ? 225 : 240)) { regs.oam_addr = regs.oam_baseaddr << 1; regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; } @@ -563,11 +532,13 @@ void bPPU::mmio_w2131(uint8 value) { //COLDATA void bPPU::mmio_w2132(uint8 value) { - if(value & 0x80)regs.color_b = value & 0x1f; - if(value & 0x40)regs.color_g = value & 0x1f; - if(value & 0x20)regs.color_r = value & 0x1f; + if(value & 0x80) regs.color_b = value & 0x1f; + if(value & 0x40) regs.color_g = value & 0x1f; + if(value & 0x20) regs.color_r = value & 0x1f; - regs.color_rgb = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10); + regs.color_rgb = (regs.color_r) + | (regs.color_g << 5) + | (regs.color_b << 10); } //SETINI @@ -576,9 +547,9 @@ void bPPU::mmio_w2133(uint8 value) { regs.pseudo_hires = !!(value & 0x08); regs.overscan = !!(value & 0x04); regs.oam_interlace = !!(value & 0x02); - regs.interlace = !!(value & 0x01); - - cpu.set_overscan(regs.overscan); + regs.interlace = !!(value & 0x01); + + display.overscan = regs.overscan; } //MPYL @@ -707,7 +678,7 @@ uint8 r = 0x00; regs.latch_hcounter = 0; regs.latch_vcounter = 0; - r |= cpu.interlace_field() << 7; + r |= field() << 7; if(!(cpu.pio_status() & 0x80)) { r |= 0x40; } else if(regs.counters_latched == true) { @@ -816,3 +787,5 @@ void bPPU::mmio_write(uint addr, uint8 data) { case 0x2133: mmio_w2133(data); return; //SETINI } } + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render.cpp b/src/ppu/bppu/bppu_render.cpp index 834892a05..305390ee6 100644 --- a/src/ppu/bppu/bppu_render.cpp +++ b/src/ppu/bppu/bppu_render.cpp @@ -1,3 +1,5 @@ +#ifdef BPPU_CPP + #include "bppu_render_cache.cpp" #include "bppu_render_windows.cpp" #include "bppu_render_bg.cpp" @@ -173,3 +175,5 @@ void bPPU::render_line() { render_line_output(); } + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render_addsub.cpp b/src/ppu/bppu/bppu_render_addsub.cpp index c54158e19..a6a3e3348 100644 --- a/src/ppu/bppu/bppu_render_addsub.cpp +++ b/src/ppu/bppu/bppu_render_addsub.cpp @@ -1,13 +1,8 @@ +#ifdef BPPU_CPP + /***** * Color Addition / Subtraction * Thanks to blargg for the optimized algorithms - * - * clock() counts for 32768x32768 iterations of addsub(), - * taken on an Athlon 3500+/DDR266 system: - * add = 10594 - * half_add = 6516 - * sub = 10579 - * half_sub = 11860 *****/ inline uint16 bPPU::addsub(uint32 x, uint32 y, bool halve) { if(!regs.color_mode) { @@ -28,3 +23,5 @@ inline uint16 bPPU::addsub(uint32 x, uint32 y, bool halve) { } } } + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render_bg.cpp b/src/ppu/bppu/bppu_render_bg.cpp index b663b3283..53639ce8a 100644 --- a/src/ppu/bppu/bppu_render_bg.cpp +++ b/src/ppu/bppu/bppu_render_bg.cpp @@ -1,3 +1,5 @@ +#ifdef BPPU_CPP + //called once at the start of every rendered scanline void bPPU::update_bg_info() { uint hires = (regs.bg_mode == 5 || regs.bg_mode == 6); @@ -88,9 +90,7 @@ uint width = (!hires) ? 256 : 512; if(hires) { hscroll <<= 1; - if(regs.interlace) { - y = (y << 1) + line.interlace_field; - } + if(regs.interlace) y = (y << 1) + field(); } uint16 *mtable = mosaic_table[(regs.mosaic_enabled[bg]) ? regs.mosaic_size : 0]; @@ -212,3 +212,5 @@ uint16 prev_x = 0xffff, prev_y = 0xffff; #undef setpixel_main #undef setpixel_sub + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render_cache.cpp b/src/ppu/bppu/bppu_render_cache.cpp index 79113b460..d668b3ac4 100644 --- a/src/ppu/bppu/bppu_render_cache.cpp +++ b/src/ppu/bppu/bppu_render_cache.cpp @@ -1,3 +1,5 @@ +#ifdef BPPU_CPP + #define render_bg_tile_line_2bpp(mask) \ col = !!(d0 & mask) << 0; \ col += !!(d1 & mask) << 1; \ @@ -132,3 +134,5 @@ void bPPU::clear_tiledata_cache() { memset(bg_tiledata_state[TILE_4BIT], 0, 2048); memset(bg_tiledata_state[TILE_8BIT], 0, 1024); } + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render_line.cpp b/src/ppu/bppu/bppu_render_line.cpp index 9204e7eab..c85a3bf25 100644 --- a/src/ppu/bppu/bppu_render_line.cpp +++ b/src/ppu/bppu/bppu_render_line.cpp @@ -1,3 +1,5 @@ +#ifdef BPPU_CPP + inline uint16 bPPU::get_palette(uint8 index) { return read16(cgram, index << 1); } @@ -83,7 +85,7 @@ uint8 bg_sub; inline void bPPU::render_line_output() { uint16 *ptr = (uint16*)output + (line.y * 1024) + - ((line.interlace && line.interlace_field) ? 512 : 0); + ((interlace() && field()) ? 512 : 0); uint16 *luma_b = light_table_b[regs.display_brightness]; uint16 *luma_gr = light_table_gr[regs.display_brightness]; uint16 curr, prev; @@ -128,7 +130,9 @@ uint16 curr, prev; inline void bPPU::render_line_clear() { uint16 *ptr = (uint16*)output + (line.y * 1024) + - ((line.interlace && line.interlace_field) ? 512 : 0); + ((interlace() && field()) ? 512 : 0); uint16 width = (!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) ? 256 : 512; memset(ptr, 0, width * 2 * sizeof(uint16)); } + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render_mode7.cpp b/src/ppu/bppu/bppu_render_mode7.cpp index 9d16a8bef..c255e72be 100644 --- a/src/ppu/bppu/bppu_render_mode7.cpp +++ b/src/ppu/bppu/bppu_render_mode7.cpp @@ -1,3 +1,5 @@ +#ifdef BPPU_CPP + /***** * bsnes mode7 renderer * @@ -142,3 +144,5 @@ void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) { } #undef CLIP + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render_oam.cpp b/src/ppu/bppu/bppu_render_oam.cpp index 2cf3184e3..ea671434b 100644 --- a/src/ppu/bppu/bppu_render_oam.cpp +++ b/src/ppu/bppu/bppu_render_oam.cpp @@ -1,3 +1,5 @@ +#ifdef BPPU_CPP + void bPPU::build_sprite_list() { uint8 *tableA = oam, *tableB = oam + 512; uint8 y_offset = (config::ppu.hack.obj_cache == true) ? 0 : 1; @@ -78,7 +80,7 @@ int y = line.y - spr->y; } if(regs.oam_interlace == true) { - y = (spr->vflip == false) ? (y + line.interlace_field) : (y - line.interlace_field); + y = (spr->vflip == false) ? (y + field()) : (y - field()); } x &= 511; @@ -218,3 +220,5 @@ int pri_tbl[4] = { pri0_pos, pri1_pos, pri2_pos, pri3_pos }; #undef setpixel_main #undef setpixel_sub + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/bppu/bppu_render_windows.cpp b/src/ppu/bppu/bppu_render_windows.cpp index 7bea657f4..dd34dafb6 100644 --- a/src/ppu/bppu/bppu_render_windows.cpp +++ b/src/ppu/bppu/bppu_render_windows.cpp @@ -1,3 +1,5 @@ +#ifdef BPPU_CPP + void bPPU::build_window_table(uint8 bg, bool mainscreen) { uint8 set = 1, clr = 0; uint8 *wtbl = (mainscreen == true) ? window[bg].main : window[bg].sub; @@ -84,3 +86,5 @@ void bPPU::build_window_tables(uint8 bg) { build_window_table(bg, true); build_window_table(bg, false); } + +#endif //ifdef BPPU_CPP diff --git a/src/ppu/ppu.cpp b/src/ppu/ppu.cpp index b3773bbff..c3be2bde9 100644 --- a/src/ppu/ppu.cpp +++ b/src/ppu/ppu.cpp @@ -1,18 +1,13 @@ #include "../base.h" -void PPU::get_scanline_info(scanline_info *info) { - info->hires = scanline_is_hires(); - info->interlace = cpu.interlace(); -} - void PPU::enable_renderer(bool r) { status.render_output = r; } bool PPU::renderer_enabled() { return status.render_output; } void PPU::frame() { status.frame_executed = true; -static int32 fr = 0, fe = 0; -static time_t prev, curr; + static int32 fr = 0, fe = 0; + static time_t prev, curr; fe++; if(status.render_output)fr++; @@ -46,5 +41,5 @@ PPU::PPU() { } PPU::~PPU() { - safe_free(output); + free(output); } diff --git a/src/ppu/ppu.h b/src/ppu/ppu.h index 255af9d65..16010d16e 100644 --- a/src/ppu/ppu.h +++ b/src/ppu/ppu.h @@ -1,34 +1,32 @@ class PPU : public MMIO { public: -uint16 *output; + uint16 *output; -//this struct should be read-only to -//functions outside of this class -struct { - bool render_output; + //this struct should be read-only to + //functions outside of this class + struct { + bool render_output; - bool frame_executed; - bool frames_updated; - uint32 frames_rendered; - uint32 frames_executed; -} status; + bool frame_executed; + bool frames_updated; + uint32 frames_rendered; + uint32 frames_executed; + } status; -//PPU1 version number -//* 1 is known -//* reported by $213e -uint8 ppu1_version; + //PPU1 version number + //* 1 is known + //* reported by $213e + uint8 ppu1_version; -//PPU2 version number -//* 1 and 3 are known -//* reported by $213f -uint8 ppu2_version; + //PPU2 version number + //* 1 and 3 are known + //* reported by $213f + uint8 ppu2_version; -struct scanline_info { - bool hires; - bool interlace; -}; - virtual bool scanline_is_hires() = 0; - virtual void get_scanline_info(scanline_info *info); + virtual bool field() = 0; + virtual bool interlace() = 0; + virtual bool overscan() = 0; + virtual bool hires() = 0; virtual uint8 vram_read (uint16 addr) = 0; virtual void vram_write (uint16 addr, uint8 value) = 0; @@ -39,7 +37,6 @@ struct scanline_info { virtual void latch_counters() = 0; - virtual void run() = 0; virtual void render_scanline() = 0; virtual void scanline() = 0; virtual void frame(); diff --git a/src/reader/filereader.cpp b/src/reader/filereader.cpp index b7cfe85a1..62b19c722 100644 --- a/src/reader/filereader.cpp +++ b/src/reader/filereader.cpp @@ -1,27 +1,30 @@ +#ifdef READER_CPP + #include "filereader.h" -uint32 FileReader::size() { - return fsize; +unsigned FileReader::size() { + return filesize; } //This function will allocate memory even if open() fails. //This is needed so that when SRAM files do not exist, the //memory for the SRAM data will be allocated still. //The memory is flushed to 0x00 when no file is opened. -uint8 *FileReader::read(uint32 length) { -uint8 *data; +uint8_t* FileReader::read(unsigned length) { + uint8_t *data = 0; + if(length == 0) { - //read the entire file into RAM - data = (uint8*)malloc(fsize); - memset(data, 0, fsize); - if(fp)fread(data, 1, fsize, fp); - } else if(length > fsize) { - //read the entire file into RAM, pad the rest with 0x00s + //read the entire file into RAM + data = (uint8*)malloc(filesize); + memset(data, 0, filesize); + if(fp) fread(data, 1, filesize, fp); + } else if(length > filesize) { + //read the entire file into RAM, pad the rest with 0x00s data = (uint8*)malloc(length); memset(data, 0, length); - if(fp)fread(data, 1, fsize, fp); - } else { //fsize >= length - //read only what was requested + if(fp)fread(data, 1, filesize, fp); + } else { //filesize >= length + //read only what was requested data = (uint8*)malloc(length); memset(data, 0, length); if(fp)fread(data, 1, length, fp); @@ -35,14 +38,14 @@ bool FileReader::ready() { FileReader::FileReader(const char *fn) { fp = fopen(fn, "rb"); - if(!fp)return; + if(!fp) return; fseek(fp, 0, SEEK_END); - fsize = ftell(fp); - fseek(fp, 0, SEEK_SET); + filesize = ftell(fp); + rewind(fp); -//empty file? - if(fsize == 0) { + //empty file? + if(filesize == 0) { fclose(fp); fp = 0; } @@ -55,9 +58,8 @@ FileReader::~FileReader() { } } -void FileWriter::write(uint8 *buffer, uint32 length) { - if(!fp)return; - +void FileWriter::write(uint8_t *buffer, unsigned length) { + if(!fp) return; fwrite(buffer, 1, length, fp); } @@ -75,3 +77,5 @@ FileWriter::~FileWriter() { fp = 0; } } + +#endif //ifdef READER_CPP diff --git a/src/reader/filereader.h b/src/reader/filereader.h index 964744e5c..a04f13850 100644 --- a/src/reader/filereader.h +++ b/src/reader/filereader.h @@ -1,12 +1,12 @@ class FileReader : public Reader { private: -FILE *fp; -uint32 fsize; + FILE *fp; + unsigned filesize; public: - uint32 size(); - uint8 *read(uint32 length = 0); - bool ready(); + unsigned size(); + uint8_t* read(unsigned length = 0); + bool ready(); FileReader(const char *fn); ~FileReader(); @@ -14,10 +14,10 @@ public: class FileWriter : public Writer { private: -FILE *fp; + FILE *fp; public: - void write(uint8 *buffer, uint32 length); + void write(uint8_t *buffer, unsigned length); bool ready(); FileWriter(const char *fn); diff --git a/src/reader/gzreader.cpp b/src/reader/gzreader.cpp index 00798166b..cae1f5eed 100644 --- a/src/reader/gzreader.cpp +++ b/src/reader/gzreader.cpp @@ -1,31 +1,35 @@ +#ifdef READER_CPP + #include "gzreader.h" -uint32 GZReader::size() { - return fsize; +unsigned GZReader::size() { + return filesize; } //This function will allocate memory even if open() fails. //This is needed so that when SRAM files do not exist, the //memory for the SRAM data will be allocated still. //The memory is flushed to 0x00 when no file is opened. -uint8 *GZReader::read(uint32 length) { -uint8 *data; +uint8_t* GZReader::read(unsigned length) { + uint8_t *data = 0; + if(length == 0) { - //read the entire file into RAM - data = (uint8*)malloc(fsize); - memset(data, 0, fsize); - if(gp)gzread(gp, data, fsize); - } else if(length > fsize) { - //read the entire file into RAM, pad the rest with 0x00s + //read the entire file into RAM + data = (uint8*)malloc(filesize); + memset(data, 0, filesize); + if(gp)gzread(gp, data, filesize); + } else if(length > filesize) { + //read the entire file into RAM, pad the rest with 0x00s data = (uint8*)malloc(length); memset(data, 0, length); - if(gp)gzread(gp, data, fsize); - } else { //fsize >= length - //read only what was requested + if(gp)gzread(gp, data, filesize); + } else { //filesize >= length + //read only what was requested data = (uint8*)malloc(length); memset(data, 0, length); if(gp)gzread(gp, data, length); } + return data; } @@ -35,14 +39,13 @@ bool GZReader::ready() { GZReader::GZReader(const char *fn) { gp = 0; - -FILE *fp = fopen(fn, "rb"); + FILE *fp = fopen(fn, "rb"); if(!fp)return; fseek(fp, 0, SEEK_END); - fsize = ftell(fp); + filesize = ftell(fp); - if(fsize < 4) { + if(filesize < 4) { fclose(fp); fp = 0; return; @@ -62,11 +65,11 @@ uint32 gzsize; if(!gp)return; if(!gzdirect(gp)) { - fsize = gzsize; + filesize = gzsize; } -//empty file? - if(fsize == 0) { + //empty file? + if(filesize == 0) { gzclose(gp); gp = 0; return; @@ -79,3 +82,5 @@ GZReader::~GZReader() { gp = 0; } } + +#endif //ifdef READER_CPP diff --git a/src/reader/gzreader.h b/src/reader/gzreader.h index 53ccc074f..a49682be3 100644 --- a/src/reader/gzreader.h +++ b/src/reader/gzreader.h @@ -2,13 +2,13 @@ class GZReader : public Reader { private: -gzFile gp; -uint32 fsize; + gzFile gp; + uint32 filesize; public: - uint32 size(); - uint8 *read(uint32 length = 0); - bool ready(); + unsigned size(); + uint8_t* read(unsigned length = 0); + bool ready(); GZReader(const char *fn); ~GZReader(); diff --git a/src/reader/jmareader.cpp b/src/reader/jmareader.cpp index 15e93daaa..13fff44e2 100644 --- a/src/reader/jmareader.cpp +++ b/src/reader/jmareader.cpp @@ -1,44 +1,41 @@ -//created by Nach - +#ifdef READER_CPP + #include "jmareader.h" #include "jma/jma.h" -uint32 JMAReader::size() { - return fsize; +unsigned JMAReader::size() { + return filesize; } #define MAXROM 0x800000 -uint8 *JMAReader::read(uint32 length) -{ - uint8 *data; - if (!fsize) { return 0; } - if (length <= fsize) - { +uint8_t* JMAReader::read(unsigned length) { + uint8_t *data = 0; + if(!filesize) return 0; + + if(length <= filesize) { //read the entire file into RAM - data = (uint8*)malloc(fsize); + data = (uint8_t*)malloc(filesize); JMAFile.extract_file(cname, data); - } - else if (length > fsize) - { + } else if(length > filesize) { //read the entire file into RAM, pad the rest with 0x00s - data = (uint8*)malloc(length); + data = (uint8_t*)malloc(length); memset(data, 0, length); JMAFile.extract_file(cname, data); - } + } + return data; } -JMAReader::JMAReader(const char *fn) : JMAFile(fn), fsize(0) -{ +JMAReader::JMAReader(const char *fn) : JMAFile(fn), filesize(0) { std::vector file_info = JMAFile.get_files_info(); - for (std::vector::iterator i = file_info.begin(); i != file_info.end(); i++) - { + for(std::vector::iterator i = file_info.begin(); i != file_info.end(); i++) { //Check for valid ROM based on size - if ((i->size <= MAXROM+512) && (i->size > fsize)) - { + if((i->size <= MAXROM + 512) && (i->size > filesize)) { cname = i->name; - fsize = i->size; + filesize = i->size; } } } + +#endif //ifdef READER_CPP diff --git a/src/reader/jmareader.h b/src/reader/jmareader.h index 78eb19a58..bb3d64507 100644 --- a/src/reader/jmareader.h +++ b/src/reader/jmareader.h @@ -1,17 +1,14 @@ -//created by Nach - #include "jma/jma.h" class JMAReader : public Reader { -private: -JMA::jma_open JMAFile; -uint32 fsize; -std::string cname; - public: - uint32 size(); - uint8 *read(uint32 length = 0); + unsigned size(); + uint8_t* read(unsigned length = 0); - JMAReader(const char *fn); - ~JMAReader() { } + JMAReader(const char *fn); + +private: + JMA::jma_open JMAFile; + uint32 filesize; + std::string cname; }; diff --git a/src/reader/reader.cpp b/src/reader/reader.cpp index 1f96c1dec..00095ab6d 100644 --- a/src/reader/reader.cpp +++ b/src/reader/reader.cpp @@ -1,23 +1,36 @@ -#include "../base.h" +#include "../base.h" +#define READER_CPP #include "filereader.cpp" + #if defined(GZIP_SUPPORT) #include "gzreader.cpp" #include "zipreader.cpp" #endif + #if defined(JMA_SUPPORT) #include "jmareader.cpp" -#endif - -uint Reader::detect(const char *fn) { -int len = strlen(fn); - if(len >= 4 && !stricmp(fn + len - 3, ".gz")) { - return RF_GZ; - } else if(len >= 5 && !stricmp(fn + len - 4, ".zip")) { - return RF_ZIP; - } else if(len >= 5 && !stricmp(fn + len - 4, ".jma")) { - return RF_JMA; - } else { - return RF_NORMAL; - } +#endif + +Reader::Type Reader::detect(const char *fn) { + FILE *fp = fopen(fn, "rb"); + if(!fp) return Unknown; + + uint8_t p[8]; + memset(p, 0, sizeof p); + fread(p, 1, 8, fp); + fclose(fp); + + if(config::file.autodetect_type == true) { + //inspect file header to determine type + if(p[0] == 0x1f && p[1] == 0x8b && p[2] == 0x08 && p[3] <= 0x1f) return GZIP; + if(p[0] == 0x50 && p[1] == 0x4b && p[2] == 0x03 && p[3] == 0x04) return ZIP; + if(p[0] == 0x4a && p[1] == 0x4d && p[2] == 0x41 && p[3] == 0x00 && p[4] == 0x4e) return JMA; + } else { + //check file extension to determine type + if(striend(fn, ".gz")) return GZIP; + if(striend(fn, ".zip") || striend(fn, ".z")) return ZIP; + if(striend(fn, ".jma")) return JMA; + } + return Normal; } diff --git a/src/reader/reader.h b/src/reader/reader.h index 4c4e8e5b1..97c8d46c7 100644 --- a/src/reader/reader.h +++ b/src/reader/reader.h @@ -1,27 +1,21 @@ class Reader { public: -enum { - RF_NORMAL = 0, - RF_GZ = 1, - RF_ZIP = 2, - RF_JMA = 3 -}; + enum Type { + Unknown, + Normal, + GZIP, + ZIP, + JMA, + }; -//attemps to determine filetype by extension, -//RF_NORMAL is returned on failure as a failsafe - static uint detect(const char *fn); - virtual uint32 size() = 0; - -//return is 0 on failure, caller must deallocate memory manually - virtual uint8 *read(uint32 length = 0) = 0; - -//returns whether or not read() will work (e.g. for FileReader, -//if the file handle is open and ready to be read from) - virtual bool ready() { return true; } + static Type detect(const char *fn); + virtual unsigned size() = 0; + virtual uint8_t* read(unsigned length = 0) = 0; + virtual bool ready() { return true; } //can only call read() when ready() returns true }; class Writer { public: - virtual void write(uint8 *buffer, uint32 length) = 0; + virtual void write(uint8_t *buffer, uint32 length) = 0; virtual bool ready() { return true; } }; diff --git a/src/reader/zipreader.cpp b/src/reader/zipreader.cpp index 9ea5ca22a..140ae1e0a 100644 --- a/src/reader/zipreader.cpp +++ b/src/reader/zipreader.cpp @@ -1,56 +1,59 @@ -//created by Nach - +#ifdef READER_CPP + #include "zipreader.h" -uint32 ZipReader::size() { - return fsize; +unsigned ZipReader::size() { + return filesize; } #define MAXROM 0x800000 -uint8 *ZipReader::read(uint32 length) -{ - uint8 *data; - if (!fsize) { return 0; } - if (length <= fsize) - { +uint8_t* ZipReader::read(unsigned length) { + uint8_t *data = 0; + + if(!filesize) return 0; + + if(length <= filesize) { //read the entire file into RAM - data = (uint8*)malloc(fsize); - unzReadCurrentFile(zipfile, data, fsize); - } - else if (length > fsize) - { + data = (uint8_t*)malloc(filesize); + unzReadCurrentFile(zipfile, data, filesize); + } else if(length > filesize) { //read the entire file into RAM, pad the rest with 0x00s - data = (uint8*)malloc(length); + data = (uint8_t*)malloc(length); memset(data, 0, length); - unzReadCurrentFile(zipfile, data, fsize); - } + unzReadCurrentFile(zipfile, data, filesize); + } + return data; } -ZipReader::ZipReader(const char *fn) : fsize(0) -{ +ZipReader::ZipReader(const char *fn) : filesize(0) { unz_file_info cFileInfo; //Create variable to hold info for a compressed file char cFileName[sizeof(cname)]; - if (zipfile = unzOpen(fn)) //Open zip file - { - for (int cFile = unzGoToFirstFile(zipfile); cFile == UNZ_OK; cFile = unzGoToNextFile(zipfile)) - { + if(zipfile = unzOpen(fn)) { //Open zip file + for(int cFile = unzGoToFirstFile(zipfile); cFile == UNZ_OK; cFile = unzGoToNextFile(zipfile)) { //Gets info on current file, and places it in cFileInfo unzGetCurrentFileInfo(zipfile, &cFileInfo, cFileName, sizeof(cname), 0, 0, 0, 0); - if ((cFileInfo.uncompressed_size <= MAXROM+512) && (cFileInfo.uncompressed_size > fsize)) - { + if((cFileInfo.uncompressed_size <= MAXROM+512) && (cFileInfo.uncompressed_size > filesize)) { strcpy(cname, cFileName); - fsize = cFileInfo.uncompressed_size; + filesize = cFileInfo.uncompressed_size; } } - if (fsize) - { + if(filesize) { unzLocateFile(zipfile, cname, 1); unzOpenCurrentFile(zipfile); } } } + +ZipReader::~ZipReader() { + if(zipfile) { + unzCloseCurrentFile(zipfile); + unzClose(zipfile); + } +} + +#endif //ifdef READER_CPP diff --git a/src/reader/zipreader.h b/src/reader/zipreader.h index 05a909468..0db3bdf7b 100644 --- a/src/reader/zipreader.h +++ b/src/reader/zipreader.h @@ -1,27 +1,18 @@ -//created by Nach - #include "zlib/unzip.h" //Could be up to 65536 #define ZIP_MAX_FILE_NAME 4096 class ZipReader : public Reader { -private: -unzFile zipfile; -uint32 fsize; -char cname[4096]; - public: - uint32 size(); - uint8 *read(uint32 length = 0); + unsigned size(); + uint8_t* read(unsigned length = 0); ZipReader(const char *fn); - ~ZipReader() - { - if (zipfile) - { - unzCloseCurrentFile(zipfile); - unzClose(zipfile); - } - } + ~ZipReader(); + +private: + unzFile zipfile; + uint32 filesize; + char cname[4096]; }; diff --git a/src/smp/dsmp.cpp b/src/smp/dsmp.cpp index 9ed0c5877..e7644b5e1 100644 --- a/src/smp/dsmp.cpp +++ b/src/smp/dsmp.cpp @@ -1,3 +1,5 @@ +#ifdef SMP_CPP + //virtual function, see src/cpu/dcpu.cpp //for explanation of this function bool SMP::in_opcode() { return false; } @@ -304,3 +306,5 @@ uint16 opw, opdp0, opdp1; (regs.p.c) ? 'C' : 'c'); strcat(s, t); } + +#endif //ifdef SMP_CPP diff --git a/src/smp/smp.cpp b/src/smp/smp.cpp index bbe6bab78..f55e0fd22 100644 --- a/src/smp/smp.cpp +++ b/src/smp/smp.cpp @@ -1,3 +1,5 @@ -#include "../base.h" +#include "../base.h" +#define SMP_CPP + #include "iplrom.h" #include "dsmp.cpp" diff --git a/src/smp/smp.h b/src/smp/smp.h index cf792492e..77fd8edeb 100644 --- a/src/smp/smp.h +++ b/src/smp/smp.h @@ -4,26 +4,25 @@ class SMP { public: virtual void enter() = 0; -public: -SMPRegs regs; -uint8 spcram[65536]; -static const uint8 iplrom[64]; + SMPRegs regs; + uint8 spcram[65536]; + static const uint8 iplrom[64]; enum { FLAG_N = 0x80, FLAG_V = 0x40, FLAG_P = 0x20, FLAG_B = 0x10, - FLAG_H = 0x08, FLAG_I = 0x04, FLAG_Z = 0x02, FLAG_C = 0x01 + FLAG_H = 0x08, FLAG_I = 0x04, FLAG_Z = 0x02, FLAG_C = 0x01, }; - virtual uint8 ram_read (uint16 addr) = 0; - virtual void ram_write(uint16 addr, uint8 value) = 0; -//$f4-$f7 - virtual uint8 port_read (uint8 port) = 0; - virtual void port_write(uint8 port, uint8 value) = 0; + virtual uint8 ram_read(uint16 addr) = 0; + virtual void ram_write(uint16 addr, uint8 value) = 0; + //$f4-$f7 + virtual uint8 port_read(uint8 port) = 0; + virtual void port_write(uint8 port, uint8 value) = 0; - virtual uint8 *get_spcram_handle() { return spcram; } - virtual void power() = 0; - virtual void reset() = 0; + virtual uint8* get_spcram_handle() { return spcram; } + virtual void power() = 0; + virtual void reset() = 0; -//debugging functions + //debugging functions virtual bool in_opcode(); void disassemble_opcode(char *output); inline uint16 __relb(int8 offset, int op_len); diff --git a/src/smp/smpregs.h b/src/smp/smpregs.h index 993f3a44b..587cc35b1 100644 --- a/src/smp/smpregs.h +++ b/src/smp/smpregs.h @@ -1,11 +1,11 @@ class SMPRegFlags { public: -union { - uint8 data; - struct { - bool order_msb8(n:1, v:1, p:1, b:1, h:1, i:1, z:1, c:1); + union { + uint8 data; + struct { + bool order_msb8(n:1, v:1, p:1, b:1, h:1, i:1, z:1, c:1); + }; }; -}; inline operator unsigned() const { return data; } template inline unsigned operator = (const T i) { data = i; return data; } @@ -18,11 +18,11 @@ union { class SMPRegs { public: -uint16 pc; -union { - uint16 ya; - struct { uint8 order_lsb2(a, y); }; -}; -uint8 x, sp; -SMPRegFlags p; + uint16 pc; + union { + uint16 ya; + struct { uint8 order_lsb2(a, y); }; + }; + uint8 x, sp; + SMPRegFlags p; }; diff --git a/src/smp/ssmp/core/core.cpp b/src/smp/ssmp/core/core.cpp index b06b11742..50c2ed0f2 100644 --- a/src/smp/ssmp/core/core.cpp +++ b/src/smp/ssmp/core/core.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + #include "opfn.cpp" #include "op_mov.cpp" @@ -15,3 +17,5 @@ void sSMP::enter() { loop: goto loop; } + +#endif //ifdef SSMP_CPP diff --git a/src/smp/ssmp/core/opfn.cpp b/src/smp/ssmp/core/opfn.cpp index 3f2ca3e44..c60279018 100644 --- a/src/smp/ssmp/core/opfn.cpp +++ b/src/smp/ssmp/core/opfn.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + uint8 sSMP::op_adc(uint8 x, uint8 y) { int16 r = x + y + regs.p.c; regs.p.n = !!(r & 0x80); @@ -120,3 +122,5 @@ uint8 carry = (uint8)regs.p.c << 7; regs.p.z = (x == 0); return x; } + +#endif //ifdef SSMP_CPP diff --git a/src/smp/ssmp/memory/memory.cpp b/src/smp/ssmp/memory/memory.cpp index b8a2285b2..5f17105b4 100644 --- a/src/smp/ssmp/memory/memory.cpp +++ b/src/smp/ssmp/memory/memory.cpp @@ -1,13 +1,15 @@ +#ifdef SSMP_CPP + alwaysinline uint8 sSMP::ram_read(uint16 addr) { - if(addr < 0xffc0)return spcram[addr]; - if(status.iplrom_enabled == false)return spcram[addr]; + if(addr < 0xffc0) return spcram[addr]; + if(status.iplrom_enabled == false) return spcram[addr]; return iplrom[addr & 0x3f]; } alwaysinline void sSMP::ram_write(uint16 addr, uint8 data) { -//writes to $ffc0-$ffff always go to spcram, even if the iplrom is enabled + //writes to $ffc0-$ffff always go to spcram, even if the iplrom is enabled spcram[addr] = data; } @@ -27,65 +29,63 @@ void sSMP::port_write(uint8 port, uint8 data) { alwaysinline uint8 sSMP::op_busread(uint16 addr) { -uint8 r; + uint8 r; if((addr & 0xfff0) == 0x00f0) { - //addr >= 0x00f0 && addr <= 0x00ff + //addr >= 0x00f0 && addr <= 0x00ff switch(addr) { + case 0xf0: { //TEST -- write-only register + r = 0x00; + } break; - case 0xf0: { //TEST -- write-only register - r = 0x00; - } break; + case 0xf1: { //CONTROL -- write-only register + r = 0x00; + } break; - case 0xf1: { //CONTROL -- write-only register - r = 0x00; - } break; + case 0xf2: { //DSPADDR + r = status.dsp_addr; + } break; - case 0xf2: { //DSPADDR - r = status.dsp_addr; - } break; + case 0xf3: { //DSPDATA + //0x80-0xff are read-only mirrors of 0x00-0x7f + r = dsp.read(status.dsp_addr & 0x7f); + } break; - case 0xf3: { //DSPDATA - //0x80-0xff are read-only mirrors of 0x00-0x7f - r = dsp.read(status.dsp_addr & 0x7f); - } break; + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: { //CPUIO3 + scheduler.sync_smpcpu(); + r = cpu.port_read(addr & 3); + } break; - case 0xf4: //CPUIO0 - case 0xf5: //CPUIO1 - case 0xf6: //CPUIO2 - case 0xf7: { //CPUIO3 - scheduler.sync_smpcpu(); - r = cpu.port_read(addr & 3); - } break; + case 0xf8: { //??? + r = status.smp_f8; + } break; - case 0xf8: { //??? - r = status.smp_f8; - } break; + case 0xf9: { //??? + r = status.smp_f9; + } break; - case 0xf9: { //??? - r = status.smp_f9; - } break; + case 0xfa: //T0TARGET + case 0xfb: //T1TARGET + case 0xfc: { //T2TARGET -- write-only registers + r = 0x00; + } break; - case 0xfa: //T0TARGET - case 0xfb: //T1TARGET - case 0xfc: { //T2TARGET -- write-only registers - r = 0x00; - } break; + case 0xfd: { //T0OUT -- 4-bit counter value + r = t0.stage3_ticks & 15; + t0.stage3_ticks = 0; + } break; - case 0xfd: { //T0OUT -- 4-bit counter value - r = t0.stage3_ticks & 15; - t0.stage3_ticks = 0; - } break; - - case 0xfe: { //T1OUT -- 4-bit counter value - r = t1.stage3_ticks & 15; - t1.stage3_ticks = 0; - } break; - - case 0xff: { //T2OUT -- 4-bit counter value - r = t2.stage3_ticks & 15; - t2.stage3_ticks = 0; - } break; + case 0xfe: { //T1OUT -- 4-bit counter value + r = t1.stage3_ticks & 15; + t1.stage3_ticks = 0; + } break; + case 0xff: { //T2OUT -- 4-bit counter value + r = t2.stage3_ticks & 15; + t2.stage3_ticks = 0; + } break; } } else if(addr < 0xffc0) { r = spcram[addr]; @@ -103,115 +103,112 @@ uint8 r; alwaysinline void sSMP::op_buswrite(uint16 addr, uint8 data) { if((addr & 0xfff0) == 0x00f0) { - //addr >= 0x00f0 && addr >= 0x00ff - if(status.mmio_disabled == true)return; + //addr >= 0x00f0 && addr >= 0x00ff + if(status.mmio_disabled == true) return; switch(addr) { + case 0xf0: { //TEST + if(regs.p.p) break; //writes only valid when P flag is clear - case 0xf0: { //TEST - if(regs.p.p)break; //writes only valid when P flag clear + //multiplier table may not be 100% accurate, some settings crash + //the processor due to S-SMP <> S-DSP bus access misalignment + static uint8 clock_speed_tbl[16] = + { 3, 5, 9, 17, 4, 6, 10, 18, 6, 8, 12, 20, 10, 12, 16, 24 }; - //multiplier table may not be 100% accurate, some settings crash - //the processor due to S-SMP <> S-DSP bus access misalignment - static uint8 clock_speed_tbl[16] = - { 3, 5, 9, 17, 4, 6, 10, 18, 6, 8, 12, 20, 10, 12, 16, 24 }; + status.clock_speed = 24 * clock_speed_tbl[data >> 4] / 3; + status.mmio_disabled = !!(data & 0x04); + status.ram_writable = !!(data & 0x02); - status.clock_speed = 24 * clock_speed_tbl[data >> 4] / 3; - status.mmio_disabled = !!(data & 0x04); - status.ram_writable = !!(data & 0x02); + if((data >> 4) != 0) { + dprintf(source::smp, "* S-SMP critical warning: $00f0 (TEST) clock speed control modified!"); + dprintf(source::smp, "* S-SMP may crash on hardware as a result!"); + } + } break; - if((data >> 4) != 0) { - dprintf(source::smp, "* S-SMP critical warning: $00f0 (TEST) clock speed control modified!"); - dprintf(source::smp, "* S-SMP may crash on hardware as a result!"); - } + case 0xf1: { //CONTROL + status.iplrom_enabled = !!(data & 0x80); - } break; + if(data & 0x30) { + //one-time clearing of APU port read registers, + //emulated by simulating CPU writes of 0x00 + scheduler.sync_smpcpu(); + if(data & 0x20) { + cpu.port_write(2, 0x00); + cpu.port_write(3, 0x00); + } + if(data & 0x10) { + cpu.port_write(0, 0x00); + cpu.port_write(1, 0x00); + } + } - case 0xf1: { //CONTROL - status.iplrom_enabled = !!(data & 0x80); + //0->1 transistion resets timers + if(t2.enabled == false && (data & 0x04)) { + t2.stage2_ticks = 0; + t2.stage3_ticks = 0; + } + t2.enabled = !!(data & 0x04); - if(data & 0x30) { - //one-time clearing of APU port read registers, - //emulated by simulating CPU writes of 0x00 + if(t1.enabled == false && (data & 0x02)) { + t1.stage2_ticks = 0; + t1.stage3_ticks = 0; + } + t1.enabled = !!(data & 0x02); + + if(t0.enabled == false && (data & 0x01)) { + t0.stage2_ticks = 0; + t0.stage3_ticks = 0; + } + t0.enabled = !!(data & 0x01); + } break; + + case 0xf2: { //DSPADDR + status.dsp_addr = data; + } break; + + case 0xf3: { //DSPDATA + //0x80-0xff is a read-only mirror of 0x00-0x7f + if(!(status.dsp_addr & 0x80)) { + dsp.write(status.dsp_addr & 0x7f, data); + } + } break; + + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: { //CPUIO3 scheduler.sync_smpcpu(); - if(data & 0x20) { - cpu.port_write(2, 0x00); - cpu.port_write(3, 0x00); - } - if(data & 0x10) { - cpu.port_write(0, 0x00); - cpu.port_write(1, 0x00); - } - } + port_write(addr & 3, data); + } break; - //0->1 transistion resets timers - if(t2.enabled == false && (data & 0x04)) { - t2.stage2_ticks = 0; - t2.stage3_ticks = 0; - } - t2.enabled = !!(data & 0x04); + case 0xf8: { //??? + status.smp_f8 = data; + } break; - if(t1.enabled == false && (data & 0x02)) { - t1.stage2_ticks = 0; - t1.stage3_ticks = 0; - } - t1.enabled = !!(data & 0x02); + case 0xf9: { //??? + status.smp_f9 = data; + } break; - if(t0.enabled == false && (data & 0x01)) { - t0.stage2_ticks = 0; - t0.stage3_ticks = 0; - } - t0.enabled = !!(data & 0x01); - } break; + case 0xfa: { //T0TARGET + t0.target = data; + } break; - case 0xf2: { //DSPADDR - status.dsp_addr = data; - } break; + case 0xfb: { //T1TARGET + t1.target = data; + } break; - case 0xf3: { //DSPDATA - //0x80-0xff is a read-only mirror of 0x00-0x7f - if(!(status.dsp_addr & 0x80)) { - dsp.write(status.dsp_addr & 0x7f, data); - } - } break; - - case 0xf4: //CPUIO0 - case 0xf5: //CPUIO1 - case 0xf6: //CPUIO2 - case 0xf7: { //CPUIO3 - scheduler.sync_smpcpu(); - port_write(addr & 3, data); - } break; - - case 0xf8: { //??? - status.smp_f8 = data; - } break; - - case 0xf9: { //??? - status.smp_f9 = data; - } break; - - case 0xfa: { //T0TARGET - t0.target = data; - } break; - - case 0xfb: { //T1TARGET - t1.target = data; - } break; - - case 0xfc: { //T2TARGET - t2.target = data; - } break; - - case 0xfd: //T0OUT - case 0xfe: //T1OUT - case 0xff: { //T2OUT -- read-only registers - } break; + case 0xfc: { //T2TARGET + t2.target = data; + } break; + case 0xfd: //T0OUT + case 0xfe: //T1OUT + case 0xff: { //T2OUT -- read-only registers + } break; } } -//all writes, even to MMIO registers, appear on bus + //all writes, even to MMIO registers, appear on bus if(status.ram_writable == true) { ram_write(addr, data); } @@ -226,7 +223,7 @@ void sSMP::op_io() { uint8 sSMP::op_read(uint16 addr) { add_clocks(12); -uint8 r = op_busread(addr); + uint8 r = op_busread(addr); add_clocks(12); tick_timers(); return r; @@ -274,3 +271,5 @@ alwaysinline void sSMP::op_writedp(uint8 addr, uint8 data) { op_write((uint(regs.p.p) << 8) + addr, data); } + +#endif //ifdef SSMP_CPP diff --git a/src/smp/ssmp/memory/memory.h b/src/smp/ssmp/memory/memory.h index ca6e1f8d3..39ba859df 100644 --- a/src/smp/ssmp/memory/memory.h +++ b/src/smp/ssmp/memory/memory.h @@ -1,29 +1,29 @@ - uint8 ram_read (uint16 addr); - void ram_write(uint16 addr, uint8 data); + uint8 ram_read(uint16 addr); + void ram_write(uint16 addr, uint8 data); - uint8 port_read (uint8 port); - void port_write(uint8 port, uint8 data); + uint8 port_read(uint8 port); + void port_write(uint8 port, uint8 data); /***** * core SMP bus functions *****/ - uint8 op_busread (uint16 addr); - void op_buswrite(uint16 addr, uint8 data); + uint8 op_busread(uint16 addr); + void op_buswrite(uint16 addr, uint8 data); - void op_io (); - uint8 op_read (uint16 addr); - void op_write(uint16 addr, uint8 data); + void op_io(); + uint8 op_read(uint16 addr); + void op_write(uint16 addr, uint8 data); /***** * helper memory addressing functions used by SMP core *****/ - uint8 op_readpc (); + uint8 op_readpc(); - uint8 op_readstack (); - void op_writestack(uint8 data); + uint8 op_readstack(); + void op_writestack(uint8 data); - uint8 op_readaddr (uint16 addr); - void op_writeaddr (uint16 addr, uint8 data); + uint8 op_readaddr(uint16 addr); + void op_writeaddr(uint16 addr, uint8 data); - uint8 op_readdp (uint8 addr); - void op_writedp (uint8 addr, uint8 data); + uint8 op_readdp(uint8 addr); + void op_writedp(uint8 addr, uint8 data); diff --git a/src/smp/ssmp/ssmp.cpp b/src/smp/ssmp/ssmp.cpp index c7c237c3c..16b03b00c 100644 --- a/src/smp/ssmp/ssmp.cpp +++ b/src/smp/ssmp/ssmp.cpp @@ -1,18 +1,20 @@ -#include "../../base.h" +#include "../../base.h" +#define SSMP_CPP #include "core/core.cpp" #include "memory/memory.cpp" #include "timing/timing.cpp" -void sSMP::power() { -//for(int i = 0; i < 65536; i += 64) { +void sSMP::power() { +//SNES hardware SPCRAM contains pseudo-random data upon power up +//for(unsigned i = 0; i < 65536; i += 64) { // memset(spcram + i, 0x00, 32); // memset(spcram + i + 32, 0xff, 32); //} memset(spcram, 0x00, 65536); -//targets not initialized/changed upon reset + //targets not initialized/changed upon reset t0.target = 0; t1.target = 0; t2.target = 0; @@ -31,18 +33,18 @@ void sSMP::reset() { status.clock_counter = 0; status.dsp_counter = 0; -//$00f0 + //$00f0 status.clock_speed = 24 * 3 / 3; status.mmio_disabled = false; status.ram_writable = true; -//$00f1 + //$00f1 status.iplrom_enabled = true; -//$00f2 + //$00f2 status.dsp_addr = 0x00; -//$00f8,$00f9 + //$00f8,$00f9 status.smp_f8 = 0x00; status.smp_f9 = 0x00; diff --git a/src/smp/ssmp/ssmp.h b/src/smp/ssmp/ssmp.h index db612227a..e412520f2 100644 --- a/src/smp/ssmp/ssmp.h +++ b/src/smp/ssmp/ssmp.h @@ -3,36 +3,36 @@ public: void enter(); public: -#include "core/core.h" -#include "memory/memory.h" -#include "timing/timing.h" + #include "core/core.h" + #include "memory/memory.h" + #include "timing/timing.h" -struct { - uint8 opcode; - bool in_opcode; + struct { + uint8 opcode; + bool in_opcode; -//timing - uint32 clock_counter; - uint32 dsp_counter; + //timing + uint32 clock_counter; + uint32 dsp_counter; -//$00f0 - uint8 clock_speed; - bool mmio_disabled; - bool ram_writable; + //$00f0 + uint8 clock_speed; + bool mmio_disabled; + bool ram_writable; -//$00f1 - bool iplrom_enabled; + //$00f1 + bool iplrom_enabled; -//$00f2 - uint8 dsp_addr; + //$00f2 + uint8 dsp_addr; -//$00f8,$00f9 - uint8 smp_f8, smp_f9; -} status; + //$00f8,$00f9 + uint8 smp_f8, smp_f9; + } status; -//ssmp.cpp - void power(); - void reset(); + //ssmp.cpp + void power(); + void reset(); sSMP(); ~sSMP(); diff --git a/src/smp/ssmp/timing/timing.cpp b/src/smp/ssmp/timing/timing.cpp index 22f1cc543..508a2d66d 100644 --- a/src/smp/ssmp/timing/timing.cpp +++ b/src/smp/ssmp/timing/timing.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + alwaysinline void sSMP::add_clocks(uint clocks) { scheduler.addclocks_smp(clocks); @@ -9,3 +11,5 @@ void sSMP::tick_timers() { t1.tick(); t2.tick(); } + +#endif //ifdef SSMP_CPP diff --git a/src/smp/ssmp/timing/timing.h b/src/smp/ssmp/timing/timing.h index afb88d61e..0f7376be6 100644 --- a/src/smp/ssmp/timing/timing.h +++ b/src/smp/ssmp/timing/timing.h @@ -1,33 +1,34 @@ -template class sSMPTimer { +template +class sSMPTimer { public: -uint8 target; -uint8 stage1_ticks, stage2_ticks, stage3_ticks; -bool enabled; + uint8 target; + uint8 stage1_ticks, stage2_ticks, stage3_ticks; + bool enabled; void tick() { - //stage 1 increment + //stage 1 increment stage1_ticks++; - if(stage1_ticks < cycle_frequency)return; + if(stage1_ticks < cycle_frequency) return; stage1_ticks -= cycle_frequency; - if(enabled == false)return; + if(enabled == false) return; - //stage 2 increment + //stage 2 increment stage2_ticks++; - if(stage2_ticks != target)return; + if(stage2_ticks != target) return; - //stage 3 increment + //stage 3 increment stage2_ticks = 0; stage3_ticks++; stage3_ticks &= 15; } }; -sSMPTimer<128> t0; -sSMPTimer<128> t1; -sSMPTimer< 16> t2; + sSMPTimer<128> t0; + sSMPTimer<128> t1; + sSMPTimer< 16> t2; - void add_clocks(uint clocks); - void tick_timers(); + void add_clocks(uint clocks); + void tick_timers(); uint32 clocks_executed(); diff --git a/src/snes/audio/audio.cpp b/src/snes/audio/audio.cpp index e6469b28c..30fa12043 100644 --- a/src/snes/audio/audio.cpp +++ b/src/snes/audio/audio.cpp @@ -1,6 +1,8 @@ +#ifdef SNES_CPP + //TODO: move audio logging code to SNESInterface class -void SNES::audio_update(uint16 l_sample, uint16 r_sample) { +void SNES::Audio::update(uint16 l_sample, uint16 r_sample) { if(pcmfp) { fput(pcmfp, l_sample, 2); fput(pcmfp, r_sample, 2); @@ -9,21 +11,21 @@ void SNES::audio_update(uint16 l_sample, uint16 r_sample) { snesinterface.audio_sample(l_sample, r_sample); } -void SNES::log_audio_enable(const char *fn) { - if(pcmfp) { log_audio_disable(); } +void SNES::Audio::log_enable(const char *fn) { + if(pcmfp) log_disable(); -char tfn[256]; + char tfn[256]; if(!fn) { int i = 0; while(i < 1000) { sprintf(tfn, "audio%0.3d.wav", i); pcmfp = fopen(tfn, "rb"); - if(!pcmfp)break; + if(!pcmfp) break; fclose(pcmfp); pcmfp = 0; i++; } - if(i >= 1000)return; + if(i >= 1000) return; } else { strcpy(tfn, fn); } @@ -31,41 +33,50 @@ char tfn[256]; pcmfp = fopen(tfn, "wb"); if(!pcmfp)return; -//header - fwrite("RIFF", 1, 4, pcmfp); -//file size + //header + fwrite("RIFF", 1, 4, pcmfp); + + //file size fputc(0, pcmfp); fputc(0, pcmfp); fputc(0, pcmfp); fputc(0, pcmfp); -//format + + //format fwrite("WAVE", 1, 4, pcmfp); fwrite("fmt ", 1, 4, pcmfp); -//fmt size + + //fmt size fputc(0x12, pcmfp); fputc(0x00, pcmfp); fputc(0x00, pcmfp); fputc(0x00, pcmfp); -//fmt type (PCM) + + //fmt type (PCM) fputc(1, pcmfp); fputc(0, pcmfp); -//channels + + //channels fputc(2, pcmfp); fputc(0, pcmfp); -//sample rate (32000hz) + + //sample rate (32000hz) fputc(0x00, pcmfp); fputc(0x7d, pcmfp); fputc(0x00, pcmfp); fputc(0x00, pcmfp); -//byte rate (32000 * 2 * (16 / 8) + + //byte rate (32000 * 2 * (16 / 8) fputc(0x00, pcmfp); fputc(0xf4, pcmfp); fputc(0x01, pcmfp); fputc(0x00, pcmfp); -//block align (bytes per sample) (4) + + //block align (bytes per sample) (4) fputc(4, pcmfp); fputc(0, pcmfp); -//??? + + //??? fputc(0x10, pcmfp); fputc(0x00, pcmfp); fputc(0x00, pcmfp); @@ -79,18 +90,20 @@ char tfn[256]; fputc(0xf4, pcmfp); fputc(0x01, pcmfp); fputc(0x00, pcmfp); -//data + + //data fwrite("data", 1, 4, pcmfp); -//data size + + //data size fputc(0, pcmfp); fputc(0, pcmfp); fputc(0, pcmfp); fputc(0, pcmfp); } -void SNES::log_audio_disable() { +void SNES::Audio::log_disable() { if(pcmfp) { - int fsize, t; + int fsize, t; fseek(pcmfp, 0, SEEK_END); fsize = ftell(pcmfp); fseek(pcmfp, 4, SEEK_SET); @@ -110,10 +123,12 @@ void SNES::log_audio_disable() { } } -void SNES::audio_init() { +void SNES::Audio::init() { pcmfp = 0; } -void SNES::audio_term() { - log_audio_disable(); +void SNES::Audio::term() { + log_disable(); } + +#endif //ifdef SNES_CPP diff --git a/src/snes/audio/audio.h b/src/snes/audio/audio.h index 7b51c6a5a..fe51f3eb8 100644 --- a/src/snes/audio/audio.h +++ b/src/snes/audio/audio.h @@ -1,10 +1,14 @@ -FILE *pcmfp; +class Audio { +public: + //if a filename is not specified, one will be generated + //automatically ("audio%0.3d.wav") + void log_enable(const char *fn = 0); + void log_disable(); -//if a filename is not specified, one will be generated -//automatically ("audio%0.3d.wav") - void log_audio_enable(const char *fn = 0); - void log_audio_disable(); - - void audio_update(uint16 l_sample, uint16 r_sample); - void audio_init(); - void audio_term(); + void update(uint16 l_sample, uint16 r_sample); + void init(); + void term(); + +private: + FILE *pcmfp; +} audio; diff --git a/src/snes/input/input.cpp b/src/snes/input/input.cpp index 123438ca2..d1ef7fb8a 100644 --- a/src/snes/input/input.cpp +++ b/src/snes/input/input.cpp @@ -1,42 +1,45 @@ -bool SNES::port_read(bool port) { +#ifdef SNES_CPP + +bool SNES::Input::port_read(bool port) { if(port == 0) { switch(input.port0_device) { - case DEVICE_NONE: - return false; + case DeviceNone: return false; - default: - if(input.port0_devicebitpos < input.port0_devicebits) { - return input.port0_bits[input.port0_devicebitpos++]; - } else { - return true; + default: { + if(input.port0_devicebitpos < input.port0_devicebits) { + return input.port0_bits[input.port0_devicebitpos++]; + } else { + return true; + } } } } else { switch(input.port1_device) { - case DEVICE_NONE: - return false; + case DeviceNone: return false; - default: - if(input.port1_devicebitpos < input.port1_devicebits) { - return input.port1_bits[input.port1_devicebitpos++]; - } else { - return true; + default: { + if(input.port1_devicebitpos < input.port1_devicebits) { + return input.port1_bits[input.port1_devicebitpos++]; + } else { + return true; + } } } } } -void SNES::port_set_deviceid(bool port, uint deviceid) { +void SNES::Input::port_set_deviceid(bool port, uint deviceid) { if(port == 0) { switch(deviceid) { - case DEVICEID_NONE: - input.port0_device = DEVICE_NONE; - break; - - case DEVICEID_JOYPAD1: - case DEVICEID_JOYPAD2: - input.port0_device = DEVICE_JOYPAD; - input.port0_devicebits = 16; + case DeviceIDNone: { + input.port0_device = DeviceNone; + } break; + + case DeviceIDJoypad1: + case DeviceIDJoypad2: { + input.port0_device = DeviceJoypad; + input.port0_devicebits = 16; + } break; } memset(input.port0_bits, 0, sizeof(input.port0_bits)); @@ -44,14 +47,15 @@ void SNES::port_set_deviceid(bool port, uint deviceid) { input.port0_deviceid = deviceid; } else { switch(deviceid) { - case DEVICEID_NONE: - input.port1_device = DEVICE_NONE; - break; + case DeviceIDNone: { + input.port1_device = DeviceNone; + } break; - case DEVICEID_JOYPAD1: - case DEVICEID_JOYPAD2: - input.port1_device = DEVICE_JOYPAD; - input.port1_devicebits = 16; + case DeviceIDJoypad1: + case DeviceIDJoypad2: { + input.port1_device = DeviceJoypad; + input.port1_devicebits = 16; + } break; } memset(input.port1_bits, 0, sizeof(input.port1_bits)); @@ -60,34 +64,39 @@ void SNES::port_set_deviceid(bool port, uint deviceid) { } } -void SNES::poll_input() { +void SNES::Input::poll() { snesinterface.input_poll(); -bool *p0 = input.port0_bits; -bool *p1 = input.port1_bits; + bool *p0 = input.port0_bits; + bool *p1 = input.port1_bits; + switch(input.port0_device) { - case DEVICE_NONE: - break; + case DeviceNone: break; - default: - for(int i = 0; i < input.port0_devicebits; i++) { *p0++ = snesinterface.input_poll(input.port0_deviceid, i); } - break; + default: { + for(int i = 0; i < input.port0_devicebits; i++) { + *p0++ = snesinterface.input_poll(input.port0_deviceid, i); + } + } break; } switch(input.port1_device) { - case DEVICE_NONE: - break; + case DeviceNone: break; - default: - for(int i = 0; i < input.port1_devicebits; i++) { *p1++ = snesinterface.input_poll(input.port1_deviceid, i); } - break; + default: { + for(int i = 0; i < input.port1_devicebits; i++) { + *p1++ = snesinterface.input_poll(input.port1_deviceid, i); + } + } break; } input.port0_devicebitpos = 0; input.port1_devicebitpos = 0; } -void SNES::input_init() { +void SNES::Input::init() { port_set_deviceid(0, config::snes.controller_port0); port_set_deviceid(1, config::snes.controller_port1); } + +#endif //ifdef SNES_CPP diff --git a/src/snes/input/input.h b/src/snes/input/input.h index e5a94a312..38effaf47 100644 --- a/src/snes/input/input.h +++ b/src/snes/input/input.h @@ -1,32 +1,35 @@ -enum { - DEVICE_NONE = 0, - DEVICE_JOYPAD, -}; +class Input { +public: + enum Device { + DeviceNone, + DeviceJoypad, + }; -enum { - DEVICEID_NONE = 0, - DEVICEID_JOYPAD1, - DEVICEID_JOYPAD2, -}; + enum { + DeviceIDNone, + DeviceIDJoypad1, + DeviceIDJoypad2, + }; -enum { - JOYPAD_B = 0, JOYPAD_Y = 1, - JOYPAD_SELECT = 2, JOYPAD_START = 3, - JOYPAD_UP = 4, JOYPAD_DOWN = 5, - JOYPAD_LEFT = 6, JOYPAD_RIGHT = 7, - JOYPAD_A = 8, JOYPAD_X = 9, - JOYPAD_L = 10, JOYPAD_R = 11, -}; + enum { + JoypadB = 0, JoypadY = 1, + JoypadSelect = 2, JoypadStart = 3, + JoypadUp = 4, JoypadDown = 5, + JoypadLeft = 6, JoypadRight = 7, + JoypadA = 8, JoypadX = 9, + JoypadL = 10, JoypadR = 11, + }; -struct { - uint port0_device, port0_devicebits, port0_devicebitpos, port0_deviceid; - uint port1_device, port1_devicebits, port1_devicebitpos, port1_deviceid; + struct { + uint port0_device, port0_devicebits, port0_devicebitpos, port0_deviceid; + uint port1_device, port1_devicebits, port1_devicebitpos, port1_deviceid; - bool port0_bits[256]; - bool port1_bits[256]; -} input; + bool port0_bits[256]; + bool port1_bits[256]; + } input; bool port_read(bool port); void port_set_deviceid(bool port, uint deviceid); - void input_init(); - void poll_input(); + void init(); + void poll(); +} input; diff --git a/src/snes/interface/interface.h b/src/snes/interface/interface.h index e10a29504..447efb117 100644 --- a/src/snes/interface/interface.h +++ b/src/snes/interface/interface.h @@ -6,15 +6,13 @@ *****/ class SNESInterface { public: - bool video_lock(uint16 *&data, uint &pitch); - void video_unlock(); - void video_refresh(); + void video_refresh(uint16_t *data, unsigned pitch, unsigned *line, unsigned width, unsigned height); - void audio_sample(uint16 l_sample, uint16 r_sample); + void audio_sample(uint16_t l_sample, uint16_t r_sample); -function input_ready; + function input_ready; void input_poll(); - bool input_poll(uint deviceid, uint button); + bool input_poll(unsigned deviceid, unsigned button); void init(); void term(); diff --git a/src/snes/scheduler/scheduler.cpp b/src/snes/scheduler/scheduler.cpp index 6120a23f7..0bf4ea9cb 100644 --- a/src/snes/scheduler/scheduler.cpp +++ b/src/snes/scheduler/scheduler.cpp @@ -1,14 +1,12 @@ +#ifdef SNES_CPP + Scheduler scheduler; -// - void threadentry_cpu() { cpu.enter(); } void threadentry_smp() { smp.enter(); } -void threadentry_ppu() { } //currently unused +void threadentry_ppu() { } void threadentry_dsp() { dsp.enter(); } -// - void Scheduler::enter() { switch(clock.active) { case THREAD_CPU: co_switch(thread_cpu); break; @@ -23,14 +21,12 @@ void Scheduler::exit() { } void Scheduler::init() { - clock.cpu_freq = snes.region() == SNES::NTSC ? - config::cpu.ntsc_clock_rate : - config::cpu.pal_clock_rate; - clock.smp_freq = snes.region() == SNES::NTSC ? - config::smp.ntsc_clock_rate : - config::smp.pal_clock_rate; - clock.smp_freq &= ~7; //smp_freq must be divisible by eight for dsp_freq - clock.dsp_freq = clock.smp_freq >> 3; + clock.cpu_freq = snes.region() == SNES::NTSC + ? config::cpu.ntsc_clock_rate + : config::cpu.pal_clock_rate; + clock.smp_freq = snes.region() == SNES::NTSC + ? config::smp.ntsc_clock_rate + : config::smp.pal_clock_rate; clock.active = THREAD_CPU; clock.cpusmp = 0; @@ -47,9 +43,7 @@ void Scheduler::init() { thread_ppu = co_create(sizeof(void*) * 64 * 1024, threadentry_ppu); thread_dsp = co_create(sizeof(void*) * 64 * 1024, threadentry_dsp); } - -// - + Scheduler::Scheduler() { thread_snes = 0; thread_cpu = 0; @@ -57,3 +51,5 @@ Scheduler::Scheduler() { thread_ppu = 0; thread_dsp = 0; } + +#endif //ifdef SNES_CPP diff --git a/src/snes/scheduler/scheduler.h b/src/snes/scheduler/scheduler.h index 5a89e9744..d1fb5d282 100644 --- a/src/snes/scheduler/scheduler.h +++ b/src/snes/scheduler/scheduler.h @@ -1,31 +1,28 @@ class Scheduler { public: + cothread_t thread_snes; + cothread_t thread_cpu; + cothread_t thread_smp; + cothread_t thread_ppu; //currently unused + cothread_t thread_dsp; -cothread_t thread_snes; -cothread_t thread_cpu; -cothread_t thread_smp; -cothread_t thread_ppu; //currently unused -cothread_t thread_dsp; + enum ActiveThread { + THREAD_CPU, + THREAD_SMP, + THREAD_PPU, + THREAD_DSP, + }; -enum ActiveThread { - THREAD_CPU, - THREAD_SMP, - THREAD_PPU, - THREAD_DSP, -}; + struct { + uint cpu_freq; + uint smp_freq; -struct { - uint cpu_freq; - uint smp_freq; - uint ppu_freq; - uint dsp_freq; + ActiveThread active; + int64 cpusmp; + int64 smpdsp; + } clock; - ActiveThread active; - int64 cpusmp; - int64 smpdsp; -} clock; - -// + // CPU <> SMP alwaysinline void sync_cpusmp() { if(clock.cpusmp < 0) { @@ -41,7 +38,7 @@ struct { } } -// + // SMP <> DSP alwaysinline void sync_smpdsp() { if(clock.smpdsp < 0) { @@ -57,27 +54,25 @@ struct { } } -// + // Timing alwaysinline void addclocks_cpu(uint clocks) { clock.cpusmp -= clocks * (uint64)clock.smp_freq; - if(clock.cpusmp < -(250000 * (int64)20000000)) { sync_cpusmp(); } + if(clock.cpusmp < -(250000 * (int64)20000000)) sync_cpusmp(); } alwaysinline void addclocks_smp(uint clocks) { clock.cpusmp += clocks * (uint64)clock.cpu_freq; - if(clock.cpusmp > +(250000 * (int64)20000000)) { sync_smpcpu(); } - clock.smpdsp -= clocks * (uint64)clock.dsp_freq; + if(clock.cpusmp > +(250000 * (int64)20000000)) sync_smpcpu(); + clock.smpdsp -= clocks; sync_smpdsp(); } alwaysinline void addclocks_dsp(uint clocks) { - clock.smpdsp += clocks * (uint64)clock.smp_freq; + clock.smpdsp += clocks; sync_dspsmp(); } -// - void enter(); void exit(); void init(); diff --git a/src/snes/snes.cpp b/src/snes/snes.cpp index de5a1357e..4cd7f5b89 100644 --- a/src/snes/snes.cpp +++ b/src/snes/snes.cpp @@ -1,7 +1,6 @@ #include "../base.h" +#define SNES_CPP -cothread_t co_active_ = 0; - SNES snes; BSXBase bsxbase; BSXCart bsxcart; @@ -43,14 +42,14 @@ void SNES::init() { obc1.init(); st010.init(); - video_init(); - audio_init(); - input_init(); + video.init(); + audio.init(); + input.init(); snesinterface.init(); } void SNES::term() { - audio_term(); + audio.term(); snesinterface.term(); } @@ -76,12 +75,12 @@ void SNES::power() { if(cartridge.info.obc1) obc1.power(); if(cartridge.info.st010) st010.power(); - for(int i = 0x2100; i <= 0x213f; i++) memory::mmio.map(i, ppu); - for(int i = 0x2140; i <= 0x217f; i++) memory::mmio.map(i, cpu); - for(int i = 0x2180; i <= 0x2183; i++) memory::mmio.map(i, cpu); - for(int i = 0x4016; i <= 0x4017; i++) memory::mmio.map(i, cpu); - for(int i = 0x4200; i <= 0x421f; i++) memory::mmio.map(i, cpu); - for(int i = 0x4300; i <= 0x437f; i++) memory::mmio.map(i, cpu); + for(uint16_t i = 0x2100; i <= 0x213f; i++) memory::mmio.map(i, ppu); + for(uint16_t i = 0x2140; i <= 0x217f; i++) memory::mmio.map(i, cpu); + for(uint16_t i = 0x2180; i <= 0x2183; i++) memory::mmio.map(i, cpu); + for(uint16_t i = 0x4016; i <= 0x4017; i++) memory::mmio.map(i, cpu); + for(uint16_t i = 0x4200; i <= 0x421f; i++) memory::mmio.map(i, cpu); + for(uint16_t i = 0x4300; i <= 0x437f; i++) memory::mmio.map(i, cpu); if(cartridge.info.bsxbase) bsxbase.enable(); if(cartridge.info.bsxcart) bsxcart.enable(); @@ -96,7 +95,7 @@ void SNES::power() { if(cartridge.info.obc1) obc1.enable(); if(cartridge.info.st010) st010.enable(); - video_update(); + video.update(); } void SNES::reset() { @@ -121,36 +120,19 @@ void SNES::reset() { if(cartridge.info.obc1) obc1.reset(); if(cartridge.info.st010) st010.reset(); - video_update(); + video.update(); } void SNES::scanline() { - video_scanline(); + video.scanline(); -//draw before the start of the next frame, to make the -//video output seem more responsive to controller input if(cpu.vcounter() == 241) { - video_update(); + video.update(); scheduler.exit(); } } void SNES::frame() {} - -/***** - * PAL/NTSC - *****/ - -void SNES::set_region(uint8 new_region) { - if(new_region == NTSC) { - snes_region = NTSC; - } else if(new_region == PAL) { - snes_region = PAL; - } else { - alert("Unsupported region : %0.2x", new_region); - } -} - -uint8 SNES::region() { return snes_region; } - +void SNES::set_region(Region region) { snes_region = region; } +SNES::Region SNES::region() { return snes_region; } SNES::SNES() {} diff --git a/src/snes/snes.h b/src/snes/snes.h index 65348e570..a52aaba6c 100644 --- a/src/snes/snes.h +++ b/src/snes/snes.h @@ -5,13 +5,10 @@ class VideoFilter; class SNES { -protected: -uint8 snes_region; - public: -enum { NTSC = 0, PAL = 1 }; + enum Region { NTSC = 0, PAL = 1 }; -//system functions + //system functions virtual void run(); virtual void runtoframe(); @@ -23,18 +20,19 @@ enum { NTSC = 0, PAL = 1 }; virtual void frame(); virtual void scanline(); -//PAL/NTSC - uint8 region(); - void set_region(uint8 new_region); + //PAL/NTSC + Region region(); + void set_region(Region); -#include "video/video.h" -#include "audio/audio.h" -#include "input/input.h" + #include "video/video.h" + #include "audio/audio.h" + #include "input/input.h" SNES(); - virtual ~SNES() {} + virtual ~SNES() {} + +private: + Region snes_region; }; extern SNES snes; - -#include "video/filter.h" diff --git a/src/snes/tracer/tracer.cpp b/src/snes/tracer/tracer.cpp index a7e7c6f4a..4f7f1bc92 100644 --- a/src/snes/tracer/tracer.cpp +++ b/src/snes/tracer/tracer.cpp @@ -1,3 +1,5 @@ +#ifdef SNES_CPP + Tracer tracer; void tprintf(const char *s, ...) { @@ -91,3 +93,5 @@ Tracer::Tracer() { Tracer::~Tracer() { } + +#endif //ifdef SNES_CPP diff --git a/src/snes/video/filter.cpp b/src/snes/video/filter.cpp deleted file mode 100644 index 80950ddb8..000000000 --- a/src/snes/video/filter.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "video_colortable.cpp" -#include "video_normalize.cpp" -#include "filter_direct.cpp" -#include "filter_ntsc.cpp" -#include "filter_hq2x.cpp" -#include "filter_scale2x.cpp" diff --git a/src/snes/video/filter.h b/src/snes/video/filter.h deleted file mode 100644 index a8f2c2ceb..000000000 --- a/src/snes/video/filter.h +++ /dev/null @@ -1,35 +0,0 @@ -enum { - VIDEOFILTER_DIRECT, - VIDEOFILTER_NTSC, - VIDEOFILTER_HQ2X, - VIDEOFILTER_SCALE2X, -}; - -//all video filters must derive from this class -class VideoFilter { -public: -/*[run] - * uint32 *colortbl - Color lookup table to convert BGR555 to current pixel format - * uint16 *data - Input data buffer (always in system memory) - * uint32 width - Input width (always 256 or 512) - * uint32 height - Input height (<=240 = progressive, >240 = interlace) - * uint32 pitch - Input data buffer bytes per scanline (always 1024) - * uint16 *output - Output data buffer (sometimes in video memory, never read from here!) - * uint32 max_width - Output data buffer width limit (do not write past buffer) - * uint32 max_height - Output data buffer height limit (do not write past buffer) - * uint32 output_pitch - Output data buffer bytes per scanline - * uint32 req_width - Requested output width (can be ignored if filter resizes to fixed size) - * uint32 req_height - Requested output height (can be ignored if filter resizes to fixed size) - * uint32 &result_width - Actual rendered width by filter (input is undefined, write only) - * uint32 &result_height - Actual rendered height by filter (input is undefined, write only) - */ - virtual void run(uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, - uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, - uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, uint16 *scanline_widths = 0) = 0; - virtual ~VideoFilter() {} -}; - -#include "filter_direct.h" -#include "filter_ntsc.h" -#include "filter_hq2x.h" -#include "filter_scale2x.h" diff --git a/src/snes/video/filter_direct.cpp b/src/snes/video/filter_direct.cpp deleted file mode 100644 index bf3f2d1e2..000000000 --- a/src/snes/video/filter_direct.cpp +++ /dev/null @@ -1,27 +0,0 @@ -void DirectVideoFilter::run( -uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, -uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, -uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, -uint16 *scanline_widths -) { - pitch >>= 1; - output_pitch >>= 1; - - for(int y = 0; y < height; y++) { - if(width == 512 && scanline_widths[y] == 256) { - for(int x = 0; x < 256; x++) { - *output++ = colortbl[*data]; - *output++ = colortbl[*data++]; - } - data += 256; - } else { - for(int x = 0; x < width; x++) { - *output++ = colortbl[*data++]; - } - } - data += pitch - width; - output += output_pitch - width; - } - result_width = width; - result_height = height; -} diff --git a/src/snes/video/filter_direct.h b/src/snes/video/filter_direct.h deleted file mode 100644 index 97c762997..000000000 --- a/src/snes/video/filter_direct.h +++ /dev/null @@ -1,6 +0,0 @@ -class DirectVideoFilter : public VideoFilter { -public: - void run(uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, - uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, - uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, uint16 *scanline_widths = 0); -}; diff --git a/src/snes/video/filter_hq2x.cpp b/src/snes/video/filter_hq2x.cpp deleted file mode 100644 index 5688fc22e..000000000 --- a/src/snes/video/filter_hq2x.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/***** - * HQ2x Algorithm (C) 2003 Maxim Stepin - * License: LGPL - * - * Optimizations (C) 2006 Shay Green, byuu - *****/ - -#define diff(x, y) ((yuvtable[x] - yuvtable[y] + diff_offset) & diff_mask) -#define hdiff(x, y) ((x - yuvtable[y]) & diff_mask) -#define expand_rgb(n) { n |= n << 16; n &= 0x03e07c1f; } -#define pack_rgb(n) { n &= 0x03e07c1f; n |= n >> 16; } - -static uint16 blend1(uint32 c1, uint32 c2) { - expand_rgb(c1); - expand_rgb(c2); - c1 = (c1 * 3 + c2) >> 2; - pack_rgb(c1); - return c1; -} - -static uint16 blend2(uint32 c1, uint32 c2, uint32 c3) { -//c1 = (c1 * 2 + c2 + c3) >> 2; - c2 = (c2 + c3 - ((c2 ^ c3) & 0x0421)) >> 1; - c1 = (c1 + c2 - ((c1 ^ c2) & 0x0421)) >> 1; - return c1; -} - -static uint16 blend6(uint32 c1, uint32 c2, uint32 c3) { - expand_rgb(c1); - expand_rgb(c2); - expand_rgb(c3); - c1 = (c1 * 5 + c2 * 2 + c3) >> 3; - pack_rgb(c1); - return c1; -} - -static uint16 blend7(uint32 c1, uint32 c2, uint32 c3) { - expand_rgb(c1); - expand_rgb(c2); - expand_rgb(c3); - c1 = (c1 * 6 + c2 + c3) >> 3; - pack_rgb(c1); - return c1; -} - -static uint16 blend9(uint32 c1, uint32 c2, uint32 c3) { - expand_rgb(c1); - expand_rgb(c2); - expand_rgb(c3); - c1 = (c1 * 2 + (c2 + c3) * 3) >> 3; - pack_rgb(c1); - return c1; -} - -static uint16 blend10(uint32 c1, uint32 c2, uint32 c3) { - expand_rgb(c1); - expand_rgb(c2); - expand_rgb(c3); - c1 = (c1 * 14 + c2 + c3) >> 4; - pack_rgb(c1); - return c1; -} - -void HQ2xVideoFilter::run( -uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, -uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, -uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, -uint16 *scanline_widths -) { - pitch >>= 1; - output_pitch >>= 1; - - if(width == 256 && height <= 240) { - lores_progressive(colortbl, data, height, pitch, output, output_pitch); - result_width = 512; - result_height = height * 2; - return; - } - - for(int y = 0; y < height; y++) { - if(width == 512 && scanline_widths[y] == 256) { - for(int x = 0; x < 256; x++) { - *output++ = colortbl[*data]; - *output++ = colortbl[*data++]; - } - data += 256; - } else { - for(int x = 0; x < width; x++) { - *output++ = colortbl[*data++]; - } - } - data += pitch - width; - output += output_pitch - width; - } - result_width = width; - result_height = height; -} - -void HQ2xVideoFilter::lores_progressive( -uint32 *colortbl, uint16 *data, uint32 height, uint32 pitch, -uint16 *output, uint32 output_pitch -) { -uint16 *out0 = (uint16*)(output); -uint16 *out1 = (uint16*)(output + output_pitch); -#define W1 data[-1 - (SNES::VIDEOPITCH_LORES >> 1)] -#define W2 data[ 0 - (SNES::VIDEOPITCH_LORES >> 1)] -#define W3 data[+1 - (SNES::VIDEOPITCH_LORES >> 1)] -#define W4 data[-1] -#define W5 data[ 0] -#define W6 data[+1] -#define W7 data[-1 + (SNES::VIDEOPITCH_LORES >> 1)] -#define W8 data[ 0 + (SNES::VIDEOPITCH_LORES >> 1)] -#define W9 data[+1 + (SNES::VIDEOPITCH_LORES >> 1)] - - data += pitch; - memset(out0, 0, 1024); out0 += output_pitch << 1; - memset(out1, 0, 1024); out1 += output_pitch << 1; - - for(int y = height - 2; y; --y) { - data++; - *(uint32*)out0 = 0; out0 += 2; - *(uint32*)out1 = 0; out1 += 2; - - int32 pattern = diff(W5, W4) ? 0x10 : 0x00; - for(int x = 256 - 2; x; --x) { - uint32 center = yuvtable[W5] + diff_offset; - //W4 for pixel x+1 is the same as W6 for pixel x - pattern = (pattern & 0x10) >> 1; - pattern |= hdiff(center, W1) ? 0x01 : 0x00; - pattern |= hdiff(center, W2) ? 0x02 : 0x00; - pattern |= hdiff(center, W3) ? 0x04 : 0x00; - //pattern |= hdiff(center, W4) ? 0x08 : 0x00; - pattern |= hdiff(center, W6) ? 0x10 : 0x00; - pattern |= hdiff(center, W7) ? 0x20 : 0x00; - pattern |= hdiff(center, W8) ? 0x40 : 0x00; - pattern |= hdiff(center, W9) ? 0x80 : 0x00; - - switch(pattern) { - #include "filter_hq2x_lookuptbl.h" - } - - data++; - out0 += 2; - out1 += 2; - } - - data++; - *(uint32*)out0 = 0; out0 += 2; - *(uint32*)out1 = 0; out1 += 2; - - data += pitch - 256; - out0 += output_pitch + output_pitch - 512; - out1 += output_pitch + output_pitch - 512; - } - - memset(out0, 0, 1024); - memset(out1, 0, 1024); -} - -HQ2xVideoFilter::HQ2xVideoFilter() { - for(int i = 0; i < 32768; i++) { - int ir = (i) & 0x1f; - int ig = (i >> 5) & 0x1f; - int ib = (i >> 10) & 0x1f; - - //bgr555->bgr888 - double r = (ir << 3) | (ir >> 2); - double g = (ig << 3) | (ig >> 2); - double b = (ib << 3) | (ib >> 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] = (int(y) << 21) + (int(u) << 11) + (int(v)); - } - - diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407; - diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0; -} diff --git a/src/snes/video/filter_hq2x.h b/src/snes/video/filter_hq2x.h deleted file mode 100644 index 324191319..000000000 --- a/src/snes/video/filter_hq2x.h +++ /dev/null @@ -1,13 +0,0 @@ -class HQ2xVideoFilter : public VideoFilter { -public: -uint32 yuvtable[32768]; -uint32 diff_offset, diff_mask; - void run(uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, - uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, - uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, uint16 *scanline_widths = 0); - - void lores_progressive(uint32 *colortbl, uint16 *data, uint32 height, uint32 pitch, - uint16 *output, uint32 output_pitch); - - HQ2xVideoFilter(); -}; diff --git a/src/snes/video/filter_ntsc.cpp b/src/snes/video/filter_ntsc.cpp deleted file mode 100644 index e2532d056..000000000 --- a/src/snes/video/filter_ntsc.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "ntsc/snes_ntsc.c" - -NtscVideoFilter::NtscVideoFilter() { - ntsc = 0; - -//to do: defer initialization? - adjust(0, 0, 0, 0, 0, bool(config::snes.ntsc_merge_fields), 0); -} - -NtscVideoFilter::~NtscVideoFilter() { - safe_free(ntsc); -} - -void NtscVideoFilter::adjust(float hue, float saturation, float contrast, -float brightness, float sharpness, bool merge_fields, uint32 *colortbl) { -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 = (unsigned long*)colortbl; - - if(!ntsc) { - ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc); - if(!ntsc) { - return; //to do: report out of memory error - } - } - - burst = 0; - burst_toggle = (merge_fields ? 0 : 1); // don't toggle burst when fields are merged - snes_ntsc_init(ntsc, &setup); -} - -void NtscVideoFilter::run( -uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, -uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, -uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, -uint16 *scanline_widths) -{ - if(!ntsc)return; - -int const out_width = SNES_NTSC_OUT_WIDTH(256); -int const out_height = height; - result_width = out_width; - result_height = out_height; - burst ^= burst_toggle; - - if(!scanline_widths) { - if(width == 256) { - snes_ntsc_blit(ntsc, data, (pitch >> 1), burst, out_width, out_height, output, output_pitch); - } else { - snes_ntsc_blit_hires(ntsc, data, (pitch >> 1), burst, out_width, out_height, output, output_pitch); - } - } else { - //blit multiple scanlines of same width, rather than one at a time - int run_start = 0; - int run_width = scanline_widths[0]; - int line = 0; - - while(1) { - if(run_width != scanline_widths[line] || line >= out_height) { - uint16 const *in = (uint16*)((uint8*)data + pitch * run_start); - uint16 *out = (uint16*)((uint8*)output + output_pitch * run_start); - int height = line - run_start; - int line_burst = (burst + run_start) % 3; - if(run_width == 256) { - snes_ntsc_blit(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, output_pitch); - } else { - snes_ntsc_blit_hires(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, output_pitch); - } - if(line >= out_height)break; - run_width = scanline_widths[line]; - run_start = line; - } - line++; - } - } -} diff --git a/src/snes/video/filter_ntsc.h b/src/snes/video/filter_ntsc.h deleted file mode 100644 index 7a79b43ef..000000000 --- a/src/snes/video/filter_ntsc.h +++ /dev/null @@ -1,24 +0,0 @@ -#include "ntsc/snes_ntsc.h" - -class NtscVideoFilter : public VideoFilter { -private: -struct snes_ntsc_t *ntsc; -int burst, burst_toggle; - -public: -// - Use 0 for any parameter to use default value -// - Colortbl must map to 16-bit RGB - void adjust(float hue, float saturation, float contrast, float brightness, - float sharpness, bool merge_fields, uint32 *colortbl); - -// - Output is currently always 16-bit RGB -// - Scanline_widths [i] contains the number of source pixels for scanline i, -// where 0 < i < height - void run(uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, - uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, - uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, - uint16 *scanline_widths = 0); - - NtscVideoFilter(); - ~NtscVideoFilter(); -}; diff --git a/src/snes/video/filter_scale2x.cpp b/src/snes/video/filter_scale2x.cpp deleted file mode 100644 index 47f9aa0b7..000000000 --- a/src/snes/video/filter_scale2x.cpp +++ /dev/null @@ -1,64 +0,0 @@ -void Scale2xVideoFilter::run( -uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, -uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, -uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, -uint16 *scanline_widths -) { - pitch >>= 1; - output_pitch >>= 1; - if(width == 256 && height <= 240) { - lores_progressive(colortbl, data, height, pitch, output, output_pitch); - result_width = 512; - result_height = height * 2; - } else { - int w = (width <= max_width) ? width : max_width; - int h = (height <= max_height) ? height : max_height; - for(int y = 0; y < h; y++) { - for(int x = 0; x < w; x++) { - *output++ = colortbl[*data++]; - } - data += pitch - w; - output += output_pitch - w; - } - result_width = width; - result_height = height; - } -} - -void Scale2xVideoFilter::lores_progressive( -uint32 *colortbl, uint16 *data, uint32 height, uint32 pitch, -uint16 *output, uint32 output_pitch -) { -uint16 A, B, C, D, P; -int32 prevline, nextline; -//.A. ->.AA. -//BpC ->BppC -//.D. ->BppC -// ->.DD. - for(int y = 0; y < height; y++) { - prevline = (y > 0) ? -pitch : 0; - nextline = (y < height - 1) ? pitch : 0; - for(int x = 0; x < 256; x++) { - A = *(data + prevline); - B = (x > 0) ? *(data - 1) : *data; - C = (x < 255) ? *(data + 1) : *data; - D = *(data + nextline); - P = colortbl[*(data)]; - if(A != D && B != C) { - *(output) = A == B ? colortbl[A] : P; - *(output + 1) = A == C ? colortbl[A] : P; - *(output + output_pitch) = D == B ? colortbl[D] : P; - *(output + output_pitch + 1) = D == C ? colortbl[D] : P; - } else { - *(output) = P; - *(output + 1) = P; - *(output + output_pitch) = P; - *(output + output_pitch + 1) = P; - } - data++; - output += 2; - } - data += pitch - 256; - output += output_pitch + output_pitch - 512; - } -} diff --git a/src/snes/video/filter_scale2x.h b/src/snes/video/filter_scale2x.h deleted file mode 100644 index dd338f54b..000000000 --- a/src/snes/video/filter_scale2x.h +++ /dev/null @@ -1,9 +0,0 @@ -class Scale2xVideoFilter : public VideoFilter { -public: - void run(uint32 *colortbl, uint16 *data, uint32 width, uint32 height, uint32 pitch, - uint16 *output, uint32 max_width, uint32 max_height, uint32 output_pitch, - uint32 req_width, uint32 req_height, uint &result_width, uint &result_height, uint16 *scanline_widths = 0); - - void lores_progressive(uint32 *colortbl, uint16 *data, uint32 height, uint32 pitch, - uint16 *output, uint32 output_pitch); -}; diff --git a/src/snes/video/video.cpp b/src/snes/video/video.cpp index 212c4b6e1..596fb648f 100644 --- a/src/snes/video/video.cpp +++ b/src/snes/video/video.cpp @@ -1,118 +1,58 @@ -#include "filter.cpp" - -void SNES::set_video_filter(uint video_filter) { - video_format.filter = video_filter; - video_format.modified = true; +#ifdef SNES_CPP + +void SNES::Video::set_mode(Mode mode_) { + mode = mode_; } -void SNES::set_video_standard(uint video_standard) { - video_format.video_standard = video_standard; - video_format.modified = true; -} - -void SNES::set_video_pixel_format(uint pixel_format) { - video_format.pixel_format = pixel_format; - video_format.modified = true; -} - -/***** - * Internal function called at the start of each frame. - * Use SNES::set_video_format to modify these options. - *****/ -void SNES::update_video_format() { - if(video_format.modified == false)return; - video_format.modified = false; - - video.filter = video_format.filter; - safe_delete(video_filter); - switch(video.filter) { - default: - case VIDEOFILTER_DIRECT: video_filter = new DirectVideoFilter(); break; - case VIDEOFILTER_NTSC: video_filter = new NtscVideoFilter(); break; - case VIDEOFILTER_HQ2X: video_filter = new HQ2xVideoFilter(); break; - case VIDEOFILTER_SCALE2X: video_filter = new Scale2xVideoFilter(); break; - } - - video.video_standard = video_format.video_standard; - video.pixel_format = video_format.pixel_format; - update_color_lookup_table(); -} - -void SNES::get_video_info(video_info *info) { - info->filter = video.filter; - info->video_standard = video.video_standard; - info->pixel_format = video.pixel_format; - info->width = video.width; - info->height = video.height; -} - -void SNES::video_update() { - if(ppu.renderer_enabled()) { - update_video_format(); - - video.ppu_data = (uint16*)ppu.output; -// video_normalize(); - - switch(video.video_standard) { - default: - case VIDEOSTANDARD_NTSC: - video.raster_width = 256; - video.raster_height = 224; - video.ppu_data += (int(cpu.overscan()) << 13) + 1024; - break; - case VIDEOSTANDARD_PAL: - video.raster_width = 256; - video.raster_height = 239; - video.ppu_data += 1024; - break; - } - - if(video.frame_hires) { video.raster_width <<= 1; } - if(video.frame_interlace) { video.raster_height <<= 1; } - - if(snesinterface.video_lock(video.data, video.pitch) == true) { - video_filter->run(color_lookup_table, video.ppu_data, - video.raster_width, video.raster_height, - video.raster_height <= 240 ? 2048 : 1024, - video.data, 512, 480, video.pitch, - 512, 480, video.width, video.height, - video.raster_height <= 240 ? (pline_width + 1) : (iline_width + 2)); - snesinterface.video_unlock(); +void SNES::Video::update() { + uint16_t *data = (uint16_t*)ppu.output; + unsigned width, height; + + switch(mode) { default: + case ModeNTSC: { + width = 256; + height = 224; + data += ((int)ppu.overscan() << 13) + 1024; + } break; + case ModePAL: { + width = 256; + height = 239; + data += 1024; + break; } } - snesinterface.video_refresh(); + if(frame_hires) width <<= 1; + if(frame_interlace) height <<= 1; + + snesinterface.video_refresh( + data, + /* pitch = */ height <= 240 ? 2048 : 1024, + /* *line = */ height <= 240 ? (pline_width + 1) : (iline_width + 2), + width, height + ); - video.frame_hires = false; - video.frame_interlace = false; + frame_hires = false; + frame_interlace = false; } -void SNES::video_scanline() { -int y = cpu.vcounter(); -int o = (video.video_standard == VIDEOSTANDARD_NTSC) ? (int(cpu.overscan()) << 3) : 0; - if(y <= (0 + o) || y >= (225 + o))return; +void SNES::Video::scanline() { + int y = cpu.vcounter(); + int o = (mode == ModeNTSC) ? ((int)ppu.overscan() << 3) : 0; + if(y <= (0 + o) || y >= (225 + o)) return; y -= o; -PPU::scanline_info si; - ppu.get_scanline_info(&si); - - pline_width[y] = iline_width[y * 2 + int(cpu.interlace_field())] = - (si.hires == false) ? 256 : 512; - video.frame_hires |= si.hires; - video.frame_interlace |= si.interlace; + pline_width[y] = iline_width[y * 2 + (int)ppu.field()] = (ppu.hires() == false) ? 256 : 512; + frame_hires |= ppu.hires(); + frame_interlace |= ppu.interlace(); } -void SNES::video_init() { - for(int i = 0; i < 240; i++)pline_width[i] = 256; - for(int i = 0; i < 480; i++)iline_width[i] = 256; - video.frame_hires = false; - video.frame_interlace = false; - - video.raster_data = (uint16*)malloc(512 * 480 * sizeof(uint16)); - memset(video.raster_data, 0, 512 * 480 * sizeof(uint16)); - video_filter = 0; - set_video_filter(VIDEOFILTER_DIRECT); - set_video_standard(VIDEOSTANDARD_NTSC); - set_video_pixel_format(PIXELFORMAT_RGB565); - update_video_format(); +void SNES::Video::init() { + for(unsigned i = 0; i < 240; i++) pline_width[i] = 256; + for(unsigned i = 0; i < 480; i++) iline_width[i] = 256; + frame_hires = false; + frame_interlace = false; + set_mode(ModeNTSC); } + +#endif //ifdef SNES_CPP diff --git a/src/snes/video/video.h b/src/snes/video/video.h index 8dfb15d75..5766bcf0c 100644 --- a/src/snes/video/video.h +++ b/src/snes/video/video.h @@ -1,62 +1,22 @@ -enum { - VIDEOSTANDARD_NTSC, - VIDEOSTANDARD_PAL, -}; - -enum { - PIXELFORMAT_RGB444, - PIXELFORMAT_RGB555, - PIXELFORMAT_RGB565, - PIXELFORMAT_RGB888, -}; - -enum { - VIDEOPITCH_LORES = 2048, - VIDEOPITCH_HIRES = 1024, -}; - -VideoFilter *video_filter; - -static const uint8 gamma_ramp_table[32]; -uint32 color_lookup_table[32768]; - -struct { - uint16 *data, *raster_data, *ppu_data; - uint raster_width, raster_height; - uint width, height; - uint filter, video_standard, pixel_format; - uint pitch; - - bool frame_hires, frame_interlace; -} video; - -struct { - bool modified; - uint filter, video_standard, pixel_format; -} video_format; - -uint16 pline_width[240], iline_width[480]; - -struct video_info { - uint filter, video_standard, pixel_format, width, height; -}; - - void contrast_adjust(int32 &input); - void brightness_adjust(int32 &input); - void gamma_adjust(int32 &input); -//public functions - void update_color_lookup_table(); - - void set_video_filter(uint video_filter); - void set_video_standard(uint video_standard); - void set_video_pixel_format(uint pixel_format); - void get_video_info(video_info *info); - -//private functions +class Video { +public: + enum Mode { + ModeNTSC, + ModePAL, + }; + void set_mode(Mode); + private: - void update_video_format(); - void video_normalize(); - void video_update(); - void video_scanline(); - void video_init(); -public: + Mode mode; + bool frame_hires; + bool frame_interlace; + + unsigned pline_width[240]; //progressive + unsigned iline_width[480]; //interlace + + void update(); + void scanline(); + void init(); + + friend class SNES; +} video; diff --git a/src/snes/video/video_colortable.cpp b/src/snes/video/video_colortable.cpp deleted file mode 100644 index 5f5ce24ea..000000000 --- a/src/snes/video/video_colortable.cpp +++ /dev/null @@ -1,103 +0,0 @@ -//Overload's gamma curve adjustment table -const uint8 SNES::gamma_ramp_table[32] = { - 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, - 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, - 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, - 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff -}; - -void SNES::contrast_adjust(int32 &input) { -double lmin, lmax; - lmin = 0.0 - (double)((int32)config::snes.contrast); - lmax = 255.0 + (double)((int32)config::snes.contrast); -int32 result = (int32)(lmin + (double)input * ((lmax - lmin) / 256.0)); - input = minmax<0, 255>(result); -} - -void SNES::brightness_adjust(int32 &input) { -int32 result; - result = input + (int32)config::snes.brightness; - input = minmax<0, 255>(result); -} - -void SNES::gamma_adjust(int32 &input) { -int32 result; - result = (int32)(pow(((double)(input + 1) / 256.0), (double)config::snes.gamma / 100.0) * 256.0); - input = minmax<0, 255>(result); -} - -void SNES::update_color_lookup_table() { -int32 l, r, g, b; -double kr = 0.2126, kb = 0.0722, kg = (1.0 - kr - kb); //luminance -uint32 col; - for(int i = 0; i < 32768; i++) { - //bgr555->rgb888 - col = ((i & 0x001f) << 19) | ((i & 0x001c) << 14) | - ((i & 0x03e0) << 6) | ((i & 0x0380) << 1) | - ((i & 0x7c00) >> 7) | ((i & 0x7000) >> 12); - - r = (col >> 16) & 0xff; - g = (col >> 8) & 0xff; - b = (col ) & 0xff; - - if((bool)config::snes.gamma_ramp == true) { - r = gamma_ramp_table[r >> 3]; - g = gamma_ramp_table[g >> 3]; - b = gamma_ramp_table[b >> 3]; - } - - contrast_adjust(r); brightness_adjust(r); gamma_adjust(r); - contrast_adjust(g); brightness_adjust(g); gamma_adjust(g); - contrast_adjust(b); brightness_adjust(b); gamma_adjust(b); - - if((bool)config::snes.sepia == true) { - l = (int32)((double)r * kr + (double)g * kg + (double)b * kb); - l = (l > 255) ? 255 : (l < 0) ? 0 : l; - r = (int32)((double)l * (1.0 + 0.300)); - g = (int32)((double)l * (1.0 - 0.055)); - b = (int32)((double)l * (1.0 - 0.225)); - r = minmax<0, 255>(r); - g = minmax<0, 255>(g); - b = minmax<0, 255>(b); - } - - if((bool)config::snes.grayscale == true) { - l = (int32)((double)r * kr + (double)g * kg + (double)b * kb); - l = minmax<0, 255>(l); - r = g = b = l; - } - - if((bool)config::snes.invert == true) { - r ^= 0xff; - g ^= 0xff; - b ^= 0xff; - } - - switch(video.pixel_format) { - case PIXELFORMAT_RGB444: - r >>= 4; - g >>= 4; - b >>= 4; - color_lookup_table[i] = (r << 8) | (g << 4) | (b); - break; - case PIXELFORMAT_RGB555: - r >>= 3; - g >>= 3; - b >>= 3; - color_lookup_table[i] = (r << 10) | (g << 5) | (b); - break; - case PIXELFORMAT_RGB565: - r >>= 3; - g >>= 2; - b >>= 3; - color_lookup_table[i] = (r << 11) | (g << 5) | (b); - break; - case PIXELFORMAT_RGB888: - color_lookup_table[i] = (r << 16) | (g << 8) | (b); - break; - default: - color_lookup_table[i] = (uint)-1; - break; - } - } -} diff --git a/src/snes/video/video_normalize.cpp b/src/snes/video/video_normalize.cpp deleted file mode 100644 index df6ea2eb7..000000000 --- a/src/snes/video/video_normalize.cpp +++ /dev/null @@ -1,150 +0,0 @@ -void SNES::video_normalize() { -} - -/* -void SNES::video_normalize_256x223() { -uint16 *src = video.ppu_data + 1024; -uint16 *dest = video.raster_data; - for(int y = 1; y < 224; y++) { - if(video_frame[y].hires == false) { - for(int x = 0; x < 256; x++) { - *dest++ = *src++; - } - src += 768; - } else { - for(int x = 0; x < 256; x++) { - *dest++ = *src; - src += 2; - } - } - dest += 256; - } -} - -void SNES::video_normalize_512x223() { -uint16 *src = video.ppu_data + 1024; -uint16 *dest = video.raster_data; - for(int y = 1; y < 224; y++) { - if(video_frame[y].hires == false) { - for(int x = 0; x < 256; x++) { - *dest++ = *src; - *dest++ = *src++; - } - src += 768; - } else { - for(int x = 0; x < 512; x++) { - *dest++ = *src++; - } - src += 512; - } - } -} - -void SNES::video_normalize_256x446() { -uint16 *src = video.ppu_data + 1024; -uint16 *dest = video.raster_data; -bool field = !r_cpu->interlace_field(); - for(int y = 1; y < 224; y++) { - if(video_frame[y].interlace == false) { - if(video_frame[y].hires == false) { - for(int x = 0; x < 256; x++) { - *dest++ = *(src + x); - } - dest += 256; - for(int x = 0; x < 256; x++) { - *dest++ = *(src + x); - } - dest += 256; - } else { - for(int x = 0; x < 256; x++) { - *dest++ = *(src + (x << 1)); - } - dest += 256; - for(int x = 0; x < 256; x++) { - *dest++ = *(src + (x << 1)); - } - dest += 256; - } - src += 1024; - } else { - if(field) { - dest += 512; - src += 512; - } - - if(video_frame[y].hires == false) { - for(int x = 0; x < 256; x++) { - *dest++ = *src++; - } - src += 256; - } else { - for(int x = 0; x < 256; x++) { - *dest++ = *src; - src += 2; - } - } - dest += 256; - - if(!field) { - dest += 512; - src += 512; - } - } - } -} - -void SNES::video_normalize_512x446() { -uint16 *src = video.ppu_data + 1024; -uint16 *dest = video.raster_data; -bool field = !r_cpu->interlace_field(); - for(int y = 1; y < 224; y++) { - if(video_frame[y].interlace == false) { - if(video_frame[y].hires == false) { - for(int x = 0; x < 256; x++) { - *dest++ = *(src + x); - *dest++ = *(src + x); - } - dest += 512; - for(int x = 0; x < 256; x++) { - *dest++ = *(src + x); - *dest++ = *(src + x); - } - dest += 512; - } else { - for(int x = 0; x < 512; x++) { - *dest++ = *(src + x); - } - dest += 512; - for(int x = 0; x < 512; x++) { - *dest++ = *(src + x); - } - dest += 512; - } - src += 1024; - } else { - if(field) { - dest += 512; - src += 512; - } - - if(video_frame[y].hires == false) { - for(int x = 0; x < 256; x++) { - *dest++ = *(src + x); - *dest++ = *(src + x); - } - src += 512; - } else { - for(int x = 0; x < 512; x++) { - *dest++ = *src++; - } - } - dest += 512; - - if(!field) { - dest += 512; - src += 512; - } - } - } -} -*/ diff --git a/src/ui/base/about.cpp b/src/ui/base/about.cpp new file mode 100644 index 000000000..ff8256f38 --- /dev/null +++ b/src/ui/base/about.cpp @@ -0,0 +1,40 @@ +const char AboutWindow::about_text[1024] = "" + "bsnes -- version " BSNES_VERSION "\n" + "Author: byuu\n" + "Project began: October 14th, 2004"; + +const char AboutWindow::contributors_text[1024] = + "Contributors:\n" + " anomie, blargg, DMV27, GIGO, kode54, Nach,\n" + " Overload, Richard Bannister, TRAC, zones"; + +uintptr_t AboutWindow::close(Event) { + hide(); + return false; +} + +void AboutWindow::setup() { + create(Window::AutoCenter, 350, 125, "About bsnes ..."); + set_icon(48, 48, (uint32_t*)resource::icon48); + + icon.create(0, 48, 48); + about.create(0, 287, 48, about_text); + contributors.create(0, 340, 48, contributors_text); + + attach(icon, 5, 5); + attach(about, 58, 5); + attach(contributors, 5, 58); + + on_close = bind(&AboutWindow::close, this); + + uint8_t *buffer = new uint8_t[48 * 48 * 4]; + memcpy(buffer, resource::icon48, 48 * 48 * 4); + for(unsigned i = 0; i < 48 * 48; i++) { + uint8_t alpha = buffer[i * 4 + 3]; + buffer[i * 4 + 2] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 2]); + buffer[i * 4 + 1] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 1]); + buffer[i * 4 + 0] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 0]); + } + memcpy(icon.buffer(), buffer, 48 * 48 * 4); + delete[] buffer; +} diff --git a/src/ui/base/about.h b/src/ui/base/about.h new file mode 100644 index 000000000..c07de0797 --- /dev/null +++ b/src/ui/base/about.h @@ -0,0 +1,11 @@ +class AboutWindow : public Window { +public: + Canvas icon; + Label about; + Label contributors; + static const char about_text[1024]; + static const char contributors_text[1024]; + + void setup(); + uintptr_t close(Event); +} window_about; diff --git a/src/ui/ui_main.cpp b/src/ui/base/main.cpp similarity index 84% rename from src/ui/ui_main.cpp rename to src/ui/base/main.cpp index f62219988..adbd057d2 100644 --- a/src/ui/ui_main.cpp +++ b/src/ui/base/main.cpp @@ -4,341 +4,350 @@ bool MainWindow::input_ready() { //allow input if config set to never block input if(config::input.capture_mode == 0) return true; //block input - return false; -} - -uintptr_t MainWindow::close(Event) { - _term_ = true; - window_about.hide(); - window_message.hide(); - window_settings.hide(); - window_bsxloader.hide(); - window_stloader.hide(); - hide(); - return false; -} - -uintptr_t MainWindow::event(Event e) { - if(e.type == Event::Tick) { - if(e.widget == &menu_file_load) { - event::load_rom(); - } - - if(e.widget == &menu_file_load_bsx) { - window_bsxloader.mode = BSXLoaderWindow::ModeBSX; - window_bsxloader.set_text("Load BS-X Cartridge"); - window_bsxloader.tbase.set_text(config::path.bsx); - window_bsxloader.focus(); - } - - if(e.widget == &menu_file_load_bsc) { - window_bsxloader.mode = BSXLoaderWindow::ModeBSC; - window_bsxloader.set_text("Load BS-X Slotted Cartridge"); - window_bsxloader.tbase.set_text(""); - window_bsxloader.focus(); - } - - if(e.widget == &menu_file_load_st) { - window_stloader.tbase.set_text(config::path.st); - window_stloader.focus(); - } - - if(e.widget == &menu_file_unload) { - event::unload_rom(); - } - - if(e.widget == &menu_file_reset) { - event::reset(); - } - - if(e.widget == &menu_file_power) { - event::power(); - } - - if(e.widget == &menu_file_exit) { - event(Event(Event::Close)); - } - - if(locked == false) { - //set locked to true to update below menu item check statuses without triggering events - if(e.widget == &menu_settings_videomode_1x) { event::update_multiplier(1); } - if(e.widget == &menu_settings_videomode_2x) { event::update_multiplier(2); } - if(e.widget == &menu_settings_videomode_3x) { event::update_multiplier(3); } - if(e.widget == &menu_settings_videomode_4x) { event::update_multiplier(4); } - if(e.widget == &menu_settings_videomode_5x) { event::update_multiplier(5); } - - if(e.widget == &menu_settings_videomode_aspect_correction) { - event::update_aspect_correction(menu_settings_videomode_aspect_correction.checked()); - } - - if(e.widget == &menu_settings_videomode_ntsc) { event::update_region(0); } - if(e.widget == &menu_settings_videomode_pal) { event::update_region(1); } - - if(e.widget == &menu_settings_videofilter_hwpoint) { event::update_hardware_filter(0); } - if(e.widget == &menu_settings_videofilter_hwlinear) { event::update_hardware_filter(1); } - - if(e.widget == &menu_settings_videofilter_swnone) { event::update_software_filter(0); } - if(e.widget == &menu_settings_videofilter_swntsc) { event::update_software_filter(1); } - if(e.widget == &menu_settings_videofilter_swhq2x) { event::update_software_filter(2); } - if(e.widget == &menu_settings_videofilter_swscale2x) { event::update_software_filter(3); } - - if(e.widget == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; } - if(e.widget == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; } - if(e.widget == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; } - if(e.widget == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; } - if(e.widget == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; } - if(e.widget == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; } - if(e.widget == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; } - if(e.widget == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; } - if(e.widget == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; } - if(e.widget == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; } - - if(e.widget == &menu_settings_mute) { - config::audio.mute = menu_settings_mute.checked(); - } - - if(e.widget == &menu_settings_speedreg_enable) { - config::system.regulate_speed = menu_settings_speedreg_enable.checked(); - audio.set(Audio::Synchronize, (bool)config::system.regulate_speed); - } - - if(e.widget == &menu_settings_speedreg_slowest) { event::update_speed_regulation(1); } - if(e.widget == &menu_settings_speedreg_slow) { event::update_speed_regulation(2); } - if(e.widget == &menu_settings_speedreg_normal) { event::update_speed_regulation(3); } - if(e.widget == &menu_settings_speedreg_fast) { event::update_speed_regulation(4); } - if(e.widget == &menu_settings_speedreg_fastest) { event::update_speed_regulation(5); } - } - - if(e.widget == &menu_settings_config) { window_settings.show(); } - - if(e.widget == &menu_misc_logaudio) { - (menu_misc_logaudio.checked() == true) ? snes.log_audio_enable() : snes.log_audio_disable(); - } - - if(e.widget == &menu_misc_showstatus) { - status.show(config::misc.show_status = menu_misc_showstatus.checked()); - } - - if(e.widget == &menu_misc_about) { - window_about.focus(); - } - } - - return true; -} - -uintptr_t MainWindow::block(Event) { - audio.clear(); - return true; -} - -void MainWindow::setup() { - locked = true; - - create(Window::AutoCenter, 256, 224, BSNES_TITLE); - set_background_color(0, 0, 0); - -MenuRadioItemGroup group; - attach(menu_file.create("File")); - menu_file.attach(menu_file_load.create("Load Cartridge ...")); - menu_file.attach(menu_file_load_special.create("Load Special")); - menu_file_load_special.attach(menu_file_load_bsx.create("Load BS-X Cartridge ...")); - menu_file_load_special.attach(menu_file_load_bsc.create("Load BS-X Slotted Cartridge ...")); - menu_file_load_special.attach(menu_file_load_st.create("Load ST Cartridge ...")); - menu_file.attach(menu_file_unload.create("Unload Cartridge")); - menu_file.attach(menu_file_sep1.create()); - menu_file.attach(menu_file_reset.create("Reset System")); - menu_file.attach(menu_file_power.create("Power Cycle System")); - menu_file.attach(menu_file_sep2.create()); - menu_file.attach(menu_file_exit.create("Exit")); - - attach(menu_settings.create("Settings")); - menu_settings.attach(menu_settings_videomode.create("Video Mode")); - group.add(&menu_settings_videomode_1x); - group.add(&menu_settings_videomode_2x); - group.add(&menu_settings_videomode_3x); - group.add(&menu_settings_videomode_4x); - group.add(&menu_settings_videomode_5x); - menu_settings_videomode.attach(menu_settings_videomode_1x.create(group, "Scale 1x")); - menu_settings_videomode.attach(menu_settings_videomode_2x.create(group, "Scale 2x")); - menu_settings_videomode.attach(menu_settings_videomode_3x.create(group, "Scale 3x")); - menu_settings_videomode.attach(menu_settings_videomode_4x.create(group, "Scale 4x")); - menu_settings_videomode.attach(menu_settings_videomode_5x.create(group, "Scale 5x")); - group.reset(); - menu_settings_videomode.attach(menu_settings_videomode_sep1.create()); - menu_settings_videomode.attach(menu_settings_videomode_aspect_correction.create("Correct Aspect Ratio")); - menu_settings_videomode.attach(menu_settings_videomode_sep2.create()); - group.add(&menu_settings_videomode_ntsc); - group.add(&menu_settings_videomode_pal); - menu_settings_videomode.attach(menu_settings_videomode_ntsc.create(group, "NTSC")); - menu_settings_videomode.attach(menu_settings_videomode_pal.create(group, "PAL")); - group.reset(); - - menu_settings.attach(menu_settings_videofilter.create("Video Filter")); - group.add(&menu_settings_videofilter_hwpoint); - group.add(&menu_settings_videofilter_hwlinear); - menu_settings_videofilter.attach(menu_settings_videofilter_hwpoint.create(group, "Point")); - menu_settings_videofilter.attach(menu_settings_videofilter_hwlinear.create(group, "Linear")); - group.reset(); - menu_settings_videofilter.attach(menu_settings_videofilter_sep1.create()); - group.add(&menu_settings_videofilter_swnone); - group.add(&menu_settings_videofilter_swntsc); - group.add(&menu_settings_videofilter_swhq2x); - group.add(&menu_settings_videofilter_swscale2x); - menu_settings_videofilter.attach(menu_settings_videofilter_swnone.create(group, "None")); - menu_settings_videofilter.attach(menu_settings_videofilter_swntsc.create(group, "NTSC")); - menu_settings_videofilter.attach(menu_settings_videofilter_swhq2x.create(group, "HQ2x")); - menu_settings_videofilter.attach(menu_settings_videofilter_swscale2x.create(group, "Scale2x")); - group.reset(); - - menu_settings.attach(menu_settings_videoframeskip.create("Video Frameskip")); - group.add(&menu_settings_videoframeskip_0); - group.add(&menu_settings_videoframeskip_1); - group.add(&menu_settings_videoframeskip_2); - group.add(&menu_settings_videoframeskip_3); - group.add(&menu_settings_videoframeskip_4); - group.add(&menu_settings_videoframeskip_5); - group.add(&menu_settings_videoframeskip_6); - group.add(&menu_settings_videoframeskip_7); - group.add(&menu_settings_videoframeskip_8); - group.add(&menu_settings_videoframeskip_9); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_0.create(group, "0")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_sep1.create()); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_1.create(group, "1")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_2.create(group, "2")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_3.create(group, "3")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_4.create(group, "4")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_5.create(group, "5")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_6.create(group, "6")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_7.create(group, "7")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_8.create(group, "8")); - menu_settings_videoframeskip.attach(menu_settings_videoframeskip_9.create(group, "9")); - group.reset(); - - menu_settings.attach(menu_settings_sep1.create()); - menu_settings.attach(menu_settings_mute.create("Mute Sound Output")); - menu_settings.attach(menu_settings_sep2.create()); - - menu_settings.attach(menu_settings_speedreg.create("Speed Regulation")); - menu_settings_speedreg.attach(menu_settings_speedreg_enable.create("Enable")); - menu_settings_speedreg.attach(menu_settings_speedreg_sep1.create()); - group.add(&menu_settings_speedreg_slowest); - group.add(&menu_settings_speedreg_slow); - group.add(&menu_settings_speedreg_normal); - group.add(&menu_settings_speedreg_fast); - group.add(&menu_settings_speedreg_fastest); - menu_settings_speedreg.attach(menu_settings_speedreg_slowest.create(group, "Slowest")); - menu_settings_speedreg.attach(menu_settings_speedreg_slow.create(group, "Slow")); - menu_settings_speedreg.attach(menu_settings_speedreg_normal.create(group, "Normal")); - menu_settings_speedreg.attach(menu_settings_speedreg_fast.create(group, "Fast")); - menu_settings_speedreg.attach(menu_settings_speedreg_fastest.create(group, "Fastest")); - group.reset(); - - menu_settings.attach(menu_settings_sep3.create()); - menu_settings.attach(menu_settings_config.create("Configuration ...")); - - attach(menu_misc.create("Misc")); - menu_misc.attach(menu_misc_logaudio.create("Log Audio Data")); - menu_misc.attach(menu_misc_showstatus.create("Show Statusbar")); - menu_misc.attach(menu_misc_sep1.create()); - menu_misc.attach(menu_misc_about.create("About ...")); - - view.create(0, 256, 224); - attach(view, 0, 0); - - on_close = bind(&MainWindow::close, this); - on_block = bind(&MainWindow::block, this); - - menu_file_exit.on_tick = bind(&MainWindow::close, this); - - menu_file_load.on_tick = - menu_file_load_bsx.on_tick = - menu_file_load_bsc.on_tick = - menu_file_load_st.on_tick = - menu_file_unload.on_tick = - menu_file_reset.on_tick = - menu_file_power.on_tick = - - menu_settings_videomode_1x.on_tick = - menu_settings_videomode_2x.on_tick = - menu_settings_videomode_3x.on_tick = - menu_settings_videomode_4x.on_tick = - menu_settings_videomode_5x.on_tick = - menu_settings_videomode_aspect_correction.on_tick = - menu_settings_videomode_ntsc.on_tick = - menu_settings_videomode_pal.on_tick = - - menu_settings_videofilter_hwpoint.on_tick = - menu_settings_videofilter_hwlinear.on_tick = - menu_settings_videofilter_swnone.on_tick = - menu_settings_videofilter_swntsc.on_tick = - menu_settings_videofilter_swhq2x.on_tick = - menu_settings_videofilter_swscale2x.on_tick = - - menu_settings_videoframeskip_0.on_tick = - menu_settings_videoframeskip_1.on_tick = - menu_settings_videoframeskip_2.on_tick = - menu_settings_videoframeskip_3.on_tick = - menu_settings_videoframeskip_4.on_tick = - menu_settings_videoframeskip_5.on_tick = - menu_settings_videoframeskip_6.on_tick = - menu_settings_videoframeskip_7.on_tick = - menu_settings_videoframeskip_8.on_tick = - menu_settings_videoframeskip_9.on_tick = - - menu_settings_mute.on_tick = - menu_settings_speedreg_enable.on_tick = - menu_settings_speedreg_slowest.on_tick = - menu_settings_speedreg_slow.on_tick = - menu_settings_speedreg_normal.on_tick = - menu_settings_speedreg_fast.on_tick = - menu_settings_speedreg_fastest.on_tick = - menu_settings_config.on_tick = - - menu_misc_logaudio.on_tick = - menu_misc_showstatus.on_tick = - menu_misc_about.on_tick = - - bind(&MainWindow::event, this); -} - -void MainWindow::update_menu_settings() { - locked = true; - event::load_video_settings(); - - switch(event::video_settings.multiplier) { default: - case 1: menu_settings_videomode_1x.check(); break; - case 2: menu_settings_videomode_2x.check(); break; - case 3: menu_settings_videomode_3x.check(); break; - case 4: menu_settings_videomode_4x.check(); break; - case 5: menu_settings_videomode_5x.check(); break; - } - - menu_settings_videomode_aspect_correction.check(event::video_settings.aspect_correction); - - switch(event::video_settings.region) { default: - case 0: menu_settings_videomode_ntsc.check(); break; - case 1: menu_settings_videomode_pal.check(); break; - } - - switch(event::video_settings.hardware_filter) { default: - case 0: menu_settings_videofilter_hwpoint.check(); break; - case 1: menu_settings_videofilter_hwlinear.check(); break; - } - - switch(event::video_settings.software_filter) { default: - case 0: menu_settings_videofilter_swnone.check(); break; - case 1: menu_settings_videofilter_swntsc.check(); break; - case 2: menu_settings_videofilter_swhq2x.check(); break; - case 3: menu_settings_videofilter_swscale2x.check(); break; - } - - menu_settings_mute.check(config::audio.mute); - - menu_settings_speedreg_enable.check(config::system.regulate_speed); - menu_settings_speedreg_normal.check(); - - menu_misc_showstatus.check(config::misc.show_status); - - locked = false; -} + return false; +} + +uintptr_t MainWindow::close(Event) { + app.term = true; + window_about.hide(); + window_message.hide(); + window_settings.hide(); + window_bsxloader.hide(); + window_stloader.hide(); + hide(); + return false; +} + +uintptr_t MainWindow::event(Event e) { + if(e.type == Event::Tick) { + if(e.widget == &menu_file_load) { + event::load_rom(); + } + + if(e.widget == &menu_file_load_bsx) { + window_bsxloader.mode = BSXLoaderWindow::ModeBSX; + window_bsxloader.set_text("Load BS-X Cartridge"); + window_bsxloader.tbase.set_text(config::path.bsx); + window_bsxloader.focus(); + } + + if(e.widget == &menu_file_load_bsc) { + window_bsxloader.mode = BSXLoaderWindow::ModeBSC; + window_bsxloader.set_text("Load BS-X Slotted Cartridge"); + window_bsxloader.tbase.set_text(""); + window_bsxloader.focus(); + } + + if(e.widget == &menu_file_load_st) { + window_stloader.tbase.set_text(config::path.st); + window_stloader.focus(); + } + + if(e.widget == &menu_file_unload) { + event::unload_rom(); + } + + if(e.widget == &menu_file_reset) { + event::reset(); + } + + if(e.widget == &menu_file_power) { + event::power(); + } + + if(e.widget == &menu_file_exit) { + event(Event(Event::Close)); + } + + if(locked == false) { + //set locked to true to update below menu item check statuses without triggering events + if(e.widget == &menu_settings_videomode_1x) { event::update_multiplier(1); } + if(e.widget == &menu_settings_videomode_2x) { event::update_multiplier(2); } + if(e.widget == &menu_settings_videomode_3x) { event::update_multiplier(3); } + if(e.widget == &menu_settings_videomode_4x) { event::update_multiplier(4); } + if(e.widget == &menu_settings_videomode_5x) { event::update_multiplier(5); } + + if(e.widget == &menu_settings_videomode_aspect_correction) { + event::update_aspect_correction(menu_settings_videomode_aspect_correction.checked()); + } + + if(e.widget == &menu_settings_videomode_ntsc) { event::update_region(0); } + if(e.widget == &menu_settings_videomode_pal) { event::update_region(1); } + + if(e.widget == &menu_settings_videofilter_hwpoint) { event::update_hardware_filter(0); } + if(e.widget == &menu_settings_videofilter_hwlinear) { event::update_hardware_filter(1); } + + if(e.widget == &menu_settings_videofilter_swnone) { event::update_software_filter(0); } + if(e.widget == &menu_settings_videofilter_swscanline) { event::update_software_filter(1); } + if(e.widget == &menu_settings_videofilter_swscale2x) { event::update_software_filter(2); } + if(e.widget == &menu_settings_videofilter_swhq2x) { event::update_software_filter(3); } + if(e.widget == &menu_settings_videofilter_swntsc) { event::update_software_filter(4); } + + if(e.widget == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; } + if(e.widget == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; } + if(e.widget == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; } + if(e.widget == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; } + if(e.widget == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; } + if(e.widget == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; } + if(e.widget == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; } + if(e.widget == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; } + if(e.widget == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; } + if(e.widget == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; } + + if(e.widget == &menu_settings_mute) { + config::audio.mute = menu_settings_mute.checked(); + } + + if(e.widget == &menu_settings_speedreg_disabled) { event::update_speed_regulation(0); } + if(e.widget == &menu_settings_speedreg_slowest) { event::update_speed_regulation(1); } + if(e.widget == &menu_settings_speedreg_slow) { event::update_speed_regulation(2); } + if(e.widget == &menu_settings_speedreg_normal) { event::update_speed_regulation(3); } + if(e.widget == &menu_settings_speedreg_fast) { event::update_speed_regulation(4); } + if(e.widget == &menu_settings_speedreg_fastest) { event::update_speed_regulation(5); } + } + + if(e.widget == &menu_settings_config) { window_settings.show(); } + + if(e.widget == &menu_misc_logaudio) { + (menu_misc_logaudio.checked() == true) ? snes.audio.log_enable() : snes.audio.log_disable(); + } + + if(e.widget == &menu_misc_showstatus) { + status.show(config::misc.status_enable = menu_misc_showstatus.checked()); + } + + if(e.widget == &menu_misc_about) { + window_about.focus(); + } + } + + return true; +} + +uintptr_t MainWindow::block(Event) { + audio.clear(); + return true; +} + +void MainWindow::setup() { + locked = true; + + create(Window::AutoCenter, 256, 224, BSNES_TITLE); + set_background_color(0, 0, 0); + set_icon(48, 48, (uint32_t*)resource::icon48); + +MenuRadioItemGroup group; + attach(menu_file.create("File")); + menu_file.attach(menu_file_load.create("Load Cartridge ...")); + menu_file.attach(menu_file_load_special.create("Load Special")); + menu_file_load_special.attach(menu_file_load_bsx.create("Load BS-X Cartridge ...")); + menu_file_load_special.attach(menu_file_load_bsc.create("Load BS-X Slotted Cartridge ...")); + menu_file_load_special.attach(menu_file_load_st.create("Load ST Cartridge ...")); + menu_file.attach(menu_file_unload.create("Unload Cartridge")); + menu_file.attach(menu_file_sep1.create()); + menu_file.attach(menu_file_reset.create("Reset System")); + menu_file.attach(menu_file_power.create("Power Cycle System")); + menu_file.attach(menu_file_sep2.create()); + menu_file.attach(menu_file_exit.create("Exit")); + + attach(menu_settings.create("Settings")); + menu_settings.attach(menu_settings_videomode.create("Video Mode")); + group.add(&menu_settings_videomode_1x); + group.add(&menu_settings_videomode_2x); + group.add(&menu_settings_videomode_3x); + group.add(&menu_settings_videomode_4x); + group.add(&menu_settings_videomode_5x); + menu_settings_videomode.attach(menu_settings_videomode_1x.create(group, "Scale 1x")); + menu_settings_videomode.attach(menu_settings_videomode_2x.create(group, "Scale 2x")); + menu_settings_videomode.attach(menu_settings_videomode_3x.create(group, "Scale 3x")); + menu_settings_videomode.attach(menu_settings_videomode_4x.create(group, "Scale 4x")); + menu_settings_videomode.attach(menu_settings_videomode_5x.create(group, "Scale 5x")); + group.reset(); + menu_settings_videomode.attach(menu_settings_videomode_sep1.create()); + menu_settings_videomode.attach(menu_settings_videomode_aspect_correction.create("Correct Aspect Ratio")); + menu_settings_videomode.attach(menu_settings_videomode_sep2.create()); + group.add(&menu_settings_videomode_ntsc); + group.add(&menu_settings_videomode_pal); + menu_settings_videomode.attach(menu_settings_videomode_ntsc.create(group, "NTSC")); + menu_settings_videomode.attach(menu_settings_videomode_pal.create(group, "PAL")); + group.reset(); + + menu_settings.attach(menu_settings_videofilter.create("Video Filter")); + group.add(&menu_settings_videofilter_hwpoint); + group.add(&menu_settings_videofilter_hwlinear); + menu_settings_videofilter.attach(menu_settings_videofilter_hwpoint.create(group, "Point")); + menu_settings_videofilter.attach(menu_settings_videofilter_hwlinear.create(group, "Linear")); + group.reset(); + menu_settings_videofilter.attach(menu_settings_videofilter_sep1.create()); + group.add(&menu_settings_videofilter_swnone); + group.add(&menu_settings_videofilter_swscanline); + group.add(&menu_settings_videofilter_swscale2x); + group.add(&menu_settings_videofilter_swhq2x); + group.add(&menu_settings_videofilter_swntsc); + menu_settings_videofilter.attach(menu_settings_videofilter_swnone.create(group, "None")); + menu_settings_videofilter.attach(menu_settings_videofilter_swscanline.create(group, "Scanline")); + menu_settings_videofilter.attach(menu_settings_videofilter_swscale2x.create(group, "Scale2x")); + menu_settings_videofilter.attach(menu_settings_videofilter_swhq2x.create(group, "HQ2x")); + menu_settings_videofilter.attach(menu_settings_videofilter_swntsc.create(group, "NTSC")); + group.reset(); + + menu_settings.attach(menu_settings_videoframeskip.create("Video Frameskip")); + group.add(&menu_settings_videoframeskip_0); + group.add(&menu_settings_videoframeskip_1); + group.add(&menu_settings_videoframeskip_2); + group.add(&menu_settings_videoframeskip_3); + group.add(&menu_settings_videoframeskip_4); + group.add(&menu_settings_videoframeskip_5); + group.add(&menu_settings_videoframeskip_6); + group.add(&menu_settings_videoframeskip_7); + group.add(&menu_settings_videoframeskip_8); + group.add(&menu_settings_videoframeskip_9); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_0.create(group, "0")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_sep1.create()); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_1.create(group, "1")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_2.create(group, "2")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_3.create(group, "3")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_4.create(group, "4")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_5.create(group, "5")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_6.create(group, "6")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_7.create(group, "7")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_8.create(group, "8")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_9.create(group, "9")); + group.reset(); + + menu_settings.attach(menu_settings_sep1.create()); + menu_settings.attach(menu_settings_mute.create("Mute Sound Output")); + menu_settings.attach(menu_settings_sep2.create()); + + menu_settings.attach(menu_settings_speedreg.create("Speed Regulation")); + group.add(&menu_settings_speedreg_disabled); + group.add(&menu_settings_speedreg_slowest); + group.add(&menu_settings_speedreg_slow); + group.add(&menu_settings_speedreg_normal); + group.add(&menu_settings_speedreg_fast); + group.add(&menu_settings_speedreg_fastest); + menu_settings_speedreg.attach(menu_settings_speedreg_disabled.create(group, "Disabled")); + menu_settings_speedreg.attach(menu_settings_speedreg_sep1.create()); + menu_settings_speedreg.attach(menu_settings_speedreg_slowest.create(group, "Slowest")); + menu_settings_speedreg.attach(menu_settings_speedreg_slow.create(group, "Slow")); + menu_settings_speedreg.attach(menu_settings_speedreg_normal.create(group, "Normal")); + menu_settings_speedreg.attach(menu_settings_speedreg_fast.create(group, "Fast")); + menu_settings_speedreg.attach(menu_settings_speedreg_fastest.create(group, "Fastest")); + group.reset(); + + menu_settings.attach(menu_settings_sep3.create()); + menu_settings.attach(menu_settings_config.create("Configuration ...")); + + attach(menu_misc.create("Misc")); + menu_misc.attach(menu_misc_logaudio.create("Log Audio Data")); + menu_misc.attach(menu_misc_showstatus.create("Show Statusbar")); + menu_misc.attach(menu_misc_sep1.create()); + menu_misc.attach(menu_misc_about.create("About ...")); + + view.create(0, 256, 224); + attach(view, 0, 0); + + on_close = bind(&MainWindow::close, this); + on_block = bind(&MainWindow::block, this); + + menu_file_exit.on_tick = bind(&MainWindow::close, this); + + menu_file_load.on_tick = + menu_file_load_bsx.on_tick = + menu_file_load_bsc.on_tick = + menu_file_load_st.on_tick = + menu_file_unload.on_tick = + menu_file_reset.on_tick = + menu_file_power.on_tick = + + menu_settings_videomode_1x.on_tick = + menu_settings_videomode_2x.on_tick = + menu_settings_videomode_3x.on_tick = + menu_settings_videomode_4x.on_tick = + menu_settings_videomode_5x.on_tick = + menu_settings_videomode_aspect_correction.on_tick = + menu_settings_videomode_ntsc.on_tick = + menu_settings_videomode_pal.on_tick = + + menu_settings_videofilter_hwpoint.on_tick = + menu_settings_videofilter_hwlinear.on_tick = + menu_settings_videofilter_swnone.on_tick = + menu_settings_videofilter_swscanline.on_tick = + menu_settings_videofilter_swscale2x.on_tick = + menu_settings_videofilter_swhq2x.on_tick = + menu_settings_videofilter_swntsc.on_tick = + + menu_settings_videoframeskip_0.on_tick = + menu_settings_videoframeskip_1.on_tick = + menu_settings_videoframeskip_2.on_tick = + menu_settings_videoframeskip_3.on_tick = + menu_settings_videoframeskip_4.on_tick = + menu_settings_videoframeskip_5.on_tick = + menu_settings_videoframeskip_6.on_tick = + menu_settings_videoframeskip_7.on_tick = + menu_settings_videoframeskip_8.on_tick = + menu_settings_videoframeskip_9.on_tick = + + menu_settings_mute.on_tick = + menu_settings_speedreg_disabled.on_tick = + menu_settings_speedreg_slowest.on_tick = + menu_settings_speedreg_slow.on_tick = + menu_settings_speedreg_normal.on_tick = + menu_settings_speedreg_fast.on_tick = + menu_settings_speedreg_fastest.on_tick = + menu_settings_config.on_tick = + + menu_misc_logaudio.on_tick = + menu_misc_showstatus.on_tick = + menu_misc_about.on_tick = + + bind(&MainWindow::event, this); +} + +void MainWindow::update_menu_settings() { + locked = true; + event::load_video_settings(); + + switch(event::video_settings.multiplier) { default: + case 1: menu_settings_videomode_1x.check(); break; + case 2: menu_settings_videomode_2x.check(); break; + case 3: menu_settings_videomode_3x.check(); break; + case 4: menu_settings_videomode_4x.check(); break; + case 5: menu_settings_videomode_5x.check(); break; + } + + menu_settings_videomode_aspect_correction.check(event::video_settings.aspect_correction); + + switch(event::video_settings.region) { default: + case 0: menu_settings_videomode_ntsc.check(); break; + case 1: menu_settings_videomode_pal.check(); break; + } + + switch(event::video_settings.hardware_filter) { default: + case 0: menu_settings_videofilter_hwpoint.check(); break; + case 1: menu_settings_videofilter_hwlinear.check(); break; + } + + switch(event::video_settings.software_filter) { default: + case 0: menu_settings_videofilter_swnone.check(); break; + case 1: menu_settings_videofilter_swscanline.check(); break; + case 2: menu_settings_videofilter_swscale2x.check(); break; + case 3: menu_settings_videofilter_swhq2x.check(); break; + case 4: menu_settings_videofilter_swntsc.check(); break; + } + + menu_settings_mute.check(config::audio.mute); + + switch(config::system.speed_regulation) { + case 0: menu_settings_speedreg_disabled.check(); break; + case 1: menu_settings_speedreg_slowest.check(); break; + case 2: menu_settings_speedreg_slow.check(); break; + case 3: menu_settings_speedreg_normal.check(); break; + case 4: menu_settings_speedreg_fast.check(); break; + case 5: menu_settings_speedreg_fastest.check(); break; + } + + menu_misc_showstatus.check(config::misc.status_enable); + + locked = false; +} diff --git a/src/ui/ui_main.h b/src/ui/base/main.h similarity index 93% rename from src/ui/ui_main.h rename to src/ui/base/main.h index 1a3dd7d2f..412759a27 100644 --- a/src/ui/ui_main.h +++ b/src/ui/base/main.h @@ -30,9 +30,10 @@ public: MenuRadioItem menu_settings_videofilter_hwlinear; MenuSeparator menu_settings_videofilter_sep1; MenuRadioItem menu_settings_videofilter_swnone; - MenuRadioItem menu_settings_videofilter_swntsc; - MenuRadioItem menu_settings_videofilter_swhq2x; + MenuRadioItem menu_settings_videofilter_swscanline; MenuRadioItem menu_settings_videofilter_swscale2x; + MenuRadioItem menu_settings_videofilter_swhq2x; + MenuRadioItem menu_settings_videofilter_swntsc; MenuGroup menu_settings_videoframeskip; MenuRadioItem menu_settings_videoframeskip_0; MenuSeparator menu_settings_videoframeskip_sep1; @@ -49,7 +50,7 @@ public: MenuCheckItem menu_settings_mute; MenuSeparator menu_settings_sep2; MenuGroup menu_settings_speedreg; - MenuCheckItem menu_settings_speedreg_enable; + MenuRadioItem menu_settings_speedreg_disabled; MenuSeparator menu_settings_speedreg_sep1; MenuRadioItem menu_settings_speedreg_slowest; MenuRadioItem menu_settings_speedreg_slow; @@ -71,7 +72,7 @@ public: bool input_ready(); void setup(); - void update_menu_settings(); + void update_menu_settings(); uintptr_t close(Event); uintptr_t event(Event); uintptr_t block(Event); diff --git a/src/ui/ui_message.cpp b/src/ui/base/message.cpp similarity index 100% rename from src/ui/ui_message.cpp rename to src/ui/base/message.cpp diff --git a/src/ui/ui_message.h b/src/ui/base/message.h similarity index 100% rename from src/ui/ui_message.h rename to src/ui/base/message.h diff --git a/src/ui/bsnes.Manifest b/src/ui/bsnes.Manifest new file mode 100644 index 000000000..4602d4fe1 --- /dev/null +++ b/src/ui/bsnes.Manifest @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/ui/bsnes.rc b/src/ui/bsnes.rc index 9a76d7070..c53b45aa0 100644 --- a/src/ui/bsnes.rc +++ b/src/ui/bsnes.rc @@ -1,3 +1,4 @@ #define IDI_APP_ICON 100 -IDI_APP_ICON ICON DISCARDABLE "../data/bsnes.ico" +1 24 "ui/bsnes.Manifest" +IDI_APP_ICON ICON DISCARDABLE "data/bsnes.ico" diff --git a/src/ui/config.cpp b/src/ui/config.cpp index a82f40b91..2c3008b20 100644 --- a/src/ui/config.cpp +++ b/src/ui/config.cpp @@ -4,15 +4,38 @@ char filename[PATH_MAX + 16] = "bsnes.cfg"; struct System { static string_setting video, audio, input; - static integral_setting regulate_speed, speed; + static integral_setting speed_regulation; + static integral_setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma; } system; - + string_setting System::video(config(), "system.video", "Video hardware interface", ""); string_setting System::audio(config(), "system.audio", "Audio hardware interface", ""); string_setting System::input(config(), "system.input", "Input hardware interface", ""); -integral_setting System::regulate_speed(config(), "system.regulate_speed", "Regulate speed to 60hz (NTSC) / 50hz (PAL)", integral_setting::boolean, true); -integral_setting System::speed("system.speed", "Current speed regulation setting (1-5)", integral_setting::decimal, 3); +integral_setting System::speed_regulation(config(), "system.speed_regulation", + "Speed regulation setting\n" + "0 = Disabled\n" + "1 = Slowest\n" + "2 = Slow\n" + "3 = Normal\n" + "4 = Fast\n" + "5 = Fastest", + integral_setting::decimal, 3); + +integral_setting System::gamma_ramp(config(), "system.colorfilter.gamma_ramp", + "Use precalculated TV-style gamma ramp", integral_setting::boolean, true); +integral_setting System::sepia(config(), "system.colorfilter.sepia", + "Convert color to sepia tone", integral_setting::boolean, false); +integral_setting System::grayscale(config(), "system.colorfilter.grayscale", + "Convert color to grayscale tone", integral_setting::boolean, false); +integral_setting System::invert(config(), "system.colorfilter.invert", + "Invert output image colors", integral_setting::boolean, false); +integral_setting System::contrast(config(), "system.colorfilter.contrast", + "Contrast", integral_setting::decimal, 0); +integral_setting System::brightness(config(), "system.colorfilter.brightness", + "Brightness", integral_setting::decimal, 0); +integral_setting System::gamma(config(), "system.colorfilter.gamma", + "Gamma", integral_setting::decimal, 80); struct Video { static integral_setting mode; @@ -26,7 +49,6 @@ struct Video { } fullscreen; static integral_setting aspect_ntsc_x, aspect_ntsc_y, aspect_pal_x, aspect_pal_y; static integral_setting frameskip; - static integral_setting use_vram; } video; //0 = windowed, 1 = fullscreen, 2 = exclusive @@ -52,9 +74,10 @@ integral_setting Video::Windowed::hardware_filter(config(), "video.windowed.hard integral_setting::decimal, 1); integral_setting Video::Windowed::software_filter(config(), "video.windowed.software_filter", "Video software filter\n" "0 = None\n" - "1 = NTSC\n" - "2 = HQ2x\n" - "3 = Scale2x\n", + "1 = Scanline\n" + "2 = Scale2x\n" + "3 = HQ2x\n" + "4 = NTSC\n", integral_setting::decimal, 0); integral_setting Video::Fullscreen::synchronize (config(), "video.fullscreen.synchronize", "", integral_setting::boolean, false); @@ -70,20 +93,16 @@ integral_setting Video::aspect_pal_x (config(), "video.aspect_pal_x", "", integ integral_setting Video::aspect_pal_y (config(), "video.aspect_pal_y", "", integral_setting::decimal, 23); integral_setting Video::frameskip("video.frameskip", "Video frameskip", integral_setting::decimal, 0); -integral_setting Video::use_vram(config(), "video.use_vram", "Use Video RAM instead of System RAM when possible", integral_setting::boolean, true); struct Audio { static integral_setting synchronize; - static integral_setting frequency; static integral_setting mute; } audio; integral_setting Audio::synchronize(config(), "audio.synchronize", "Synchronize to audio sample rate", integral_setting::boolean, true); -integral_setting Audio::frequency(config(), "audio.frequency", "Default audio playback frequency", integral_setting::decimal, 32000); integral_setting Audio::mute(config(), "audio.mute", "Mute audio playback", integral_setting::boolean, false); -struct Input { +struct Input { static integral_setting capture_mode; - static integral_setting axis_resistance; static integral_setting allow_invalid_input; struct Joypad1 { @@ -92,41 +111,31 @@ struct Input { struct Joypad2 { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; - } joypad2; - - struct GUI { - static string_setting load; - static string_setting pause; - static string_setting reset; - static string_setting power; - static string_setting toggle_fullscreen; - static string_setting toggle_menubar; - static string_setting toggle_statusbar; + } joypad2; + + struct GUI { + static string_setting load; + static string_setting pause; + static string_setting reset; + static string_setting power; + static string_setting toggle_fullscreen; + static string_setting toggle_menubar; + static string_setting toggle_statusbar; } gui; -} input; - -integral_setting Input::capture_mode(config(), "input.capture_mode", - "Capture method for input to main emulation window\n" - "When emulation window does not have focus:\n" - "0 = Allow input\n" - "1 = Ignore input\n" - "2 = Pause emulator", +} input; + +integral_setting Input::capture_mode(config(), "input.capture_mode", + "Capture method for input to main emulation window\n" + "When emulation window does not have focus:\n" + "0 = Allow input\n" + "1 = Ignore input\n" + "2 = Pause emulator", integral_setting::decimal, 2); -integral_setting Input::axis_resistance(config(), "input.axis_resistance", - "Axis resistance for all analog joypads\n" - "Affects responsiveness of analog stick movement by specifying what percentage\n" - "in any given direction the axis must be pressed to trigger a button press.\n" - "In other words, this determines how hard you have to press the analog stick to\n" - "simulate pressing e.g. left or right on a digital joypad.\n" - "Value is a percentage, from 0 (axis will trigger with virtually any axis movement)\n" - "up to 100 (axis must be pressed fully to given corner).\n" - "Value affects all four directions of the axis equally.\n" - "Note: Values below 10 or above 90 are not recommended and may not work at all.", - integral_setting::decimal, 75); - integral_setting Input::allow_invalid_input(config(), "input.allow_invalid_input", - "Allow up+down and left+right combinations (not recommended)", + "Allow up+down and left+right combinations (not recommended.)\n" + "This is not possible on an actual SNES controller, due to its design.\n" + "Enabling this option can trigger bugs in certain games.\n", integral_setting::boolean, false); string_setting Input::Joypad1::up (config(), "input.joypad1.up", "", "up"); @@ -153,20 +162,29 @@ string_setting Input::Joypad2::y (config(), "input.joypad2.y", "", "u") string_setting Input::Joypad2::l (config(), "input.joypad2.l", "", "o"); string_setting Input::Joypad2::r (config(), "input.joypad2.r", "", "l"); string_setting Input::Joypad2::select(config(), "input.joypad2.select", "", "lbracket"); -string_setting Input::Joypad2::start (config(), "input.joypad2.start", "", "rbracket"); - -string_setting Input::GUI::load (config(), "input.gui.load", "", "none"); -string_setting Input::GUI::pause (config(), "input.gui.pause", "", "f12"); -string_setting Input::GUI::reset (config(), "input.gui.reset", "", "none"); -string_setting Input::GUI::power (config(), "input.gui.power", "", "none"); -string_setting Input::GUI::toggle_fullscreen(config(), "input.gui.toggle_fullscreen", "", "f11"); -string_setting Input::GUI::toggle_menubar (config(), "input.gui.toggle_menubar", "", "escape"); +string_setting Input::Joypad2::start (config(), "input.joypad2.start", "", "rbracket"); + +string_setting Input::GUI::load (config(), "input.gui.load", "", "none"); +string_setting Input::GUI::pause (config(), "input.gui.pause", "", "f12"); +string_setting Input::GUI::reset (config(), "input.gui.reset", "", "none"); +string_setting Input::GUI::power (config(), "input.gui.power", "", "none"); +string_setting Input::GUI::toggle_fullscreen(config(), "input.gui.toggle_fullscreen", "", "f11"); +string_setting Input::GUI::toggle_menubar (config(), "input.gui.toggle_menubar", "", "escape"); string_setting Input::GUI::toggle_statusbar (config(), "input.gui.toggle_statusbar", "", "escape"); struct Misc { - static integral_setting show_status; + static integral_setting opacity; + static integral_setting status_enable; + static string_setting status_text; } misc; -integral_setting Misc::show_status(config(), "misc.show_status", "Display information statusbar", integral_setting::boolean, true); - +integral_setting Misc::opacity(config(), "misc.opacity", "Opacity of user interface windows", integral_setting::decimal, 100); +integral_setting Misc::status_enable(config(), "misc.status_enable", "Display information statusbar", integral_setting::boolean, true); +string_setting Misc::status_text(config(), "misc.status_text", + "Text to print inside statusbar\n" + "%n = cartridge file name\n" + "%t = internal cartridge header name\n" + "%f = executed frames per second\n" + "%m = maximum frames per second" + "", "%n : %f / %m"); }; diff --git a/src/ui/event.cpp b/src/ui/event.cpp index d51e1490a..020f5230c 100644 --- a/src/ui/event.cpp +++ b/src/ui/event.cpp @@ -4,10 +4,10 @@ void keydown(uint16_t key) { if(window_main.focused()) { if(key == input_manager.gui.load) load_rom(); if(key == input_manager.gui.pause) { - _pause_ = !_pause_; //toggle pause state - if(_pause_) { + app.pause = !app.pause; //toggle pause state + if(app.pause) { audio.clear(); - if(cartridge.loaded()) window_main.status.set_text("(Paused)"); + if(cartridge.loaded()) update_status(); } } if(key == input_manager.gui.reset) reset(); @@ -100,41 +100,59 @@ void update_software_filter(uint software_filter) { } void update_speed_regulation(uint speed) { - config::system.speed = max(1U, min(speed, 5U)); + config::system.speed_regulation = speed <= 5 ? speed : 0; + + //adjust audio frequency to match selected speed setting if(audio.cap(Audio::Frequency)) { - switch(config::system.speed) { - case 1: audio.set(Audio::Frequency, 16000); break; - case 2: audio.set(Audio::Frequency, 24000); break; - case 3: audio.set(Audio::Frequency, 32000); break; - case 4: audio.set(Audio::Frequency, 48000); break; - case 5: audio.set(Audio::Frequency, 64000); break; + switch(config::system.speed_regulation) { + case 0: audio.set(Audio::Frequency, 32000); break; //disabled + case 1: audio.set(Audio::Frequency, 16000); break; //slowest (50%) + case 2: audio.set(Audio::Frequency, 24000); break; //slow (75%) + case 3: audio.set(Audio::Frequency, 32000); break; //normal (100%) + case 4: audio.set(Audio::Frequency, 48000); break; //fast (150%) + case 5: audio.set(Audio::Frequency, 64000); break; //fastest (200%) } } + + //do not regulate speed when speed regulation is disabled + if(audio.cap(Audio::Synchronize)) { + audio.set(Audio::Synchronize, config::system.speed_regulation != 0); + } } -void update_frame_counter() { +void update_status() { if(!cartridge.loaded()) { window_main.status.set_text(""); - return; - } - - if(_pause_ || _autopause_) return; - - if(ppu.status.frames_updated) { + } else if(app.pause || app.autopause) { + window_main.status.set_text("(paused)"); + } else if(ppu.status.frames_updated) { ppu.status.frames_updated = false; - window_main.status.set_text(string() - << (int)ppu.status.frames_executed - << (snes.region() == SNES::NTSC ? " / 60 fps" : " / 50 fps") - ); + + unsigned max_framerate = snes.region() == SNES::NTSC ? 60 : 50; + switch(config::system.speed_regulation) { + case 0: max_framerate = 0; break; + case 1: max_framerate = unsigned(0.50 * max_framerate); break; + case 2: max_framerate = unsigned(0.75 * max_framerate); break; + case 3: break; + case 4: max_framerate = unsigned(1.50 * max_framerate); break; + case 5: max_framerate = unsigned(2.00 * max_framerate); break; + } + + string output = (const char*)config::misc.status_text; + replace(output, "%f", string() << (int)ppu.status.frames_executed); + replace(output, "%m", string() << (int)max_framerate); + replace(output, "%n", cartridge.info.filename); + replace(output, "%t", cartridge.info.name); + window_main.status.set_text(output); } } void update_video_settings() { load_video_settings(); -uint width = 256; -uint height = video_settings.region == 0 ? 224 : 239; -uint multiplier = minmax<1, 5>(video_settings.multiplier); + uint width = 256; + uint height = video_settings.region == 0 ? 224 : 239; + uint multiplier = minmax<1, 5>(video_settings.multiplier); width *= multiplier; height *= multiplier; if(video_settings.aspect_correction == true) { @@ -171,29 +189,45 @@ uint multiplier = minmax<1, 5>(video_settings.multiplier); } break; } -uint filter, standard; + libfilter::FilterInterface::FilterType filter; switch(video_settings.software_filter) { default: - case 0: filter = VIDEOFILTER_DIRECT; break; - case 1: filter = VIDEOFILTER_NTSC; break; - case 2: filter = VIDEOFILTER_HQ2X; break; - case 3: filter = VIDEOFILTER_SCALE2X; break; + case 0: filter = libfilter::FilterInterface::Direct; break; + case 1: filter = libfilter::FilterInterface::Scanline; break; + case 2: filter = libfilter::FilterInterface::Scale2x; break; + case 3: filter = libfilter::FilterInterface::HQ2x; break; + case 4: filter = libfilter::FilterInterface::NTSC; break; } + libfilter::filter.set(filter); + + SNES::Video::Mode mode; switch(video_settings.region) { default: - case 0: standard = SNES::VIDEOSTANDARD_NTSC; break; - case 1: standard = SNES::VIDEOSTANDARD_PAL; break; + case 0: mode = SNES::Video::ModeNTSC; break; + case 1: mode = SNES::Video::ModePAL; break; } - snes.set_video_filter(filter); - snes.set_video_standard(standard); + snes.video.set_mode(mode); video.set(Video::Synchronize, video_settings.synchronize); video.set(Video::Filter, video_settings.hardware_filter); -//update main window video mode checkbox settings + //update main window video mode checkbox settings window_main.update_menu_settings(); } +void update_opacity() { + //convert opacity from 50-100 (percentage) to 128-255 (8-bit alpha) + unsigned opacity = max(50, min(100, config::misc.opacity)); + opacity = unsigned(256.0 / 100.0 * opacity); + opacity = max(128, min(255, opacity)); + + window_settings.set_opacity(opacity); + window_input_capture.set_opacity(opacity); + window_bsxloader.set_opacity(opacity); + window_stloader.set_opacity(opacity); + window_about.set_opacity(opacity); +} + void toggle_fullscreen() { if(config::video.mode != 1) { //switch to fullscreen mode if not already in it config::video.mode = 1; @@ -224,7 +258,7 @@ bool load_rom(char *fn) { replace(dir[0], "\\", "/"); if(strlen(dir[0]) && !strend(dir[0], "/")) strcat(dir[0], "/"); -//append base path if rom path is relative + //append base path if rom path is relative if(strbegin(dir[0], "./")) { ltrim(dir[0], "./"); strcpy(dir[1], dir[0]); @@ -232,20 +266,21 @@ bool load_rom(char *fn) { strcat(dir[0], dir[1]); } - return hiro().file_load(0, fn, + return hiro().file_open(0, fn, + dir[0], "SNES images;*.smc,*.sfc,*.swc,*.fig,*.bs,*.st" - #if defined(GZIP_SUPPORT) + #if defined(GZIP_SUPPORT) ",*.gz,*.z,*.zip" - #endif - #if defined(JMA_SUPPORT) + #endif + #if defined(JMA_SUPPORT) ",*.jma" - #endif - "|All files;*.*", - dir[0]); + #endif + "|All files;*.*" + ); } void load_rom() { -char fn[PATH_MAX]; + char fn[PATH_MAX]; if(load_rom(fn) == false) return; load_cart_normal(fn); } @@ -262,7 +297,7 @@ void load_cart_normal(const char *filename) { if(cartridge.info.st011) alert("Warning: unsupported ST011 chip detected."); if(cartridge.info.st018) alert("Warning: unsupported ST018 chip detected."); - _pause_ = false; + app.pause = false; snes.power(); window_cheat_editor.refresh(); } @@ -273,7 +308,7 @@ void load_cart_bsx(const char *base, const char *slot) { if(cartridge.loaded() == true) cartridge.unload(); cartridge.load_cart_bsx(base, slot); - _pause_ = false; + app.pause = false; snes.power(); window_cheat_editor.refresh(); } @@ -284,7 +319,7 @@ void load_cart_bsc(const char *base, const char *slot) { if(cartridge.loaded() == true) cartridge.unload(); cartridge.load_cart_bsc(base, slot); - _pause_ = false; + app.pause = false; snes.power(); window_cheat_editor.refresh(); } @@ -295,7 +330,7 @@ void load_cart_st(const char *base, const char *slotA, const char *slotB) { if(cartridge.loaded() == true) cartridge.unload(); cartridge.load_cart_st(base, slotA, slotB); - _pause_ = false; + app.pause = false; snes.power(); window_cheat_editor.refresh(); } @@ -306,7 +341,7 @@ void unload_rom() { video.clear(); audio.clear(); } - window_main.status.set_text(""); + event::update_status(); window_cheat_editor.refresh(); } diff --git a/src/ui/event.h b/src/ui/event.h index 2e4b6e27e..29b080bbd 100644 --- a/src/ui/event.h +++ b/src/ui/event.h @@ -22,8 +22,9 @@ void update_software_filter(uint); void update_speed_regulation(uint); -void update_frame_counter(); +void update_status(); void update_video_settings(); +void update_opacity(); void toggle_fullscreen(); void toggle_menubar(); void toggle_statusbar(); diff --git a/src/ui/inputmgr.cpp b/src/ui/inputmanager.cpp similarity index 75% rename from src/ui/inputmgr.cpp rename to src/ui/inputmanager.cpp index 038b8cd1b..f11be3aba 100644 --- a/src/ui/inputmgr.cpp +++ b/src/ui/inputmanager.cpp @@ -123,37 +123,37 @@ void InputManager::poll() { bool InputManager::get_status(uint device, uint button) { switch(device) { - case SNES::DEVICEID_JOYPAD1: { + case SNES::Input::DeviceIDJoypad1: { switch(button) { - case SNES::JOYPAD_UP: return joypad1.up.state; - case SNES::JOYPAD_DOWN: return joypad1.down.state; - case SNES::JOYPAD_LEFT: return joypad1.left.state; - case SNES::JOYPAD_RIGHT: return joypad1.right.state; - case SNES::JOYPAD_A: return joypad1.a.state; - case SNES::JOYPAD_B: return joypad1.b.state; - case SNES::JOYPAD_X: return joypad1.x.state; - case SNES::JOYPAD_Y: return joypad1.y.state; - case SNES::JOYPAD_L: return joypad1.l.state; - case SNES::JOYPAD_R: return joypad1.r.state; - case SNES::JOYPAD_SELECT: return joypad1.select.state; - case SNES::JOYPAD_START: return joypad1.start.state; + case SNES::Input::JoypadUp: return joypad1.up.state; + case SNES::Input::JoypadDown: return joypad1.down.state; + case SNES::Input::JoypadLeft: return joypad1.left.state; + case SNES::Input::JoypadRight: return joypad1.right.state; + case SNES::Input::JoypadA: return joypad1.a.state; + case SNES::Input::JoypadB: return joypad1.b.state; + case SNES::Input::JoypadX: return joypad1.x.state; + case SNES::Input::JoypadY: return joypad1.y.state; + case SNES::Input::JoypadL: return joypad1.l.state; + case SNES::Input::JoypadR: return joypad1.r.state; + case SNES::Input::JoypadSelect: return joypad1.select.state; + case SNES::Input::JoypadStart: return joypad1.start.state; } } break; - case SNES::DEVICEID_JOYPAD2: { + case SNES::Input::DeviceIDJoypad2: { switch(button) { - case SNES::JOYPAD_UP: return joypad2.up.state; - case SNES::JOYPAD_DOWN: return joypad2.down.state; - case SNES::JOYPAD_LEFT: return joypad2.left.state; - case SNES::JOYPAD_RIGHT: return joypad2.right.state; - case SNES::JOYPAD_A: return joypad2.a.state; - case SNES::JOYPAD_B: return joypad2.b.state; - case SNES::JOYPAD_X: return joypad2.x.state; - case SNES::JOYPAD_Y: return joypad2.y.state; - case SNES::JOYPAD_L: return joypad2.l.state; - case SNES::JOYPAD_R: return joypad2.r.state; - case SNES::JOYPAD_SELECT: return joypad2.select.state; - case SNES::JOYPAD_START: return joypad2.start.state; + case SNES::Input::JoypadUp: return joypad2.up.state; + case SNES::Input::JoypadDown: return joypad2.down.state; + case SNES::Input::JoypadLeft: return joypad2.left.state; + case SNES::Input::JoypadRight: return joypad2.right.state; + case SNES::Input::JoypadA: return joypad2.a.state; + case SNES::Input::JoypadB: return joypad2.b.state; + case SNES::Input::JoypadX: return joypad2.x.state; + case SNES::Input::JoypadY: return joypad2.y.state; + case SNES::Input::JoypadL: return joypad2.l.state; + case SNES::Input::JoypadR: return joypad2.r.state; + case SNES::Input::JoypadSelect: return joypad2.select.state; + case SNES::Input::JoypadStart: return joypad2.start.state; } } break; } diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index f7b061882..2b0405269 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -9,21 +9,18 @@ SNESInterface snesinterface; //video -bool SNESInterface::video_lock(uint16 *&data, uint &pitch) { - return video.lock(data, pitch); -} - -void SNESInterface::video_unlock() { - video.unlock(); -} - static uint frameskip_counter = 0; -void SNESInterface::video_refresh() { +void SNESInterface::video_refresh(uint16_t *data, unsigned pitch, unsigned *line, unsigned width, unsigned height) { if(ppu.renderer_enabled() == true) { - SNES::video_info vi; - snes.get_video_info(&vi); - video.refresh(vi.width, vi.height); + uint32_t *output; + unsigned opitch; + if(video.lock(output, opitch) == true) { + unsigned owidth, oheight; + libfilter::filter.render(output, opitch, owidth, oheight, data, pitch, line, width, height); + video.unlock(); + video.refresh(owidth, oheight); + } } frameskip_counter++; @@ -33,10 +30,10 @@ void SNESInterface::video_refresh() { //audio -void SNESInterface::audio_sample(uint16 l_sample, uint16 r_sample) { - if(config::audio.mute == true) { - l_sample = 0; - r_sample = 0; +void SNESInterface::audio_sample(uint16 l_sample, uint16 r_sample) { + if(config::audio.mute == true) { + l_sample = 0; + r_sample = 0; } audio.sample(l_sample, r_sample); } @@ -60,6 +57,15 @@ bool SNESInterface::input_poll(uint deviceid, uint button) { void SNESInterface::init() { input_manager.bind(); + libfilter::colortable.set_format(libfilter::Colortable::RGB888); + libfilter::colortable.set_contrast(config::system.contrast); + libfilter::colortable.set_brightness(config::system.brightness); + libfilter::colortable.set_gamma(config::system.gamma); + libfilter::colortable.enable_gamma_ramp(config::system.gamma_ramp); + libfilter::colortable.enable_sepia(config::system.sepia); + libfilter::colortable.enable_grayscale(config::system.grayscale); + libfilter::colortable.enable_invert(config::system.invert); + libfilter::colortable.update(); } void SNESInterface::term() { diff --git a/src/ui/loader/ui_bsxloader.cpp b/src/ui/loader/bsxloader.cpp similarity index 97% rename from src/ui/loader/ui_bsxloader.cpp rename to src/ui/loader/bsxloader.cpp index 00853038c..5cf85b14c 100644 --- a/src/ui/loader/ui_bsxloader.cpp +++ b/src/ui/loader/bsxloader.cpp @@ -52,6 +52,7 @@ uintptr_t BSXLoaderWindow::cancel_tick(Event) { void BSXLoaderWindow::setup() { create(Window::AutoCenter, 640, 150, "Load BS-X Cartridge"); + set_icon(48, 48, (uint32_t*)resource::icon48); lbase.create(0, 630, 20, "Base cartridge:"); tbase.create(0, 420, 30); diff --git a/src/ui/loader/ui_bsxloader.h b/src/ui/loader/bsxloader.h similarity index 100% rename from src/ui/loader/ui_bsxloader.h rename to src/ui/loader/bsxloader.h diff --git a/src/ui/loader/ui_stloader.cpp b/src/ui/loader/stloader.cpp similarity index 98% rename from src/ui/loader/ui_stloader.cpp rename to src/ui/loader/stloader.cpp index a133b5ad9..73bed7ffd 100644 --- a/src/ui/loader/ui_stloader.cpp +++ b/src/ui/loader/stloader.cpp @@ -62,6 +62,7 @@ uintptr_t STLoaderWindow::cancel_tick(Event) { void STLoaderWindow::setup() { create(Window::AutoCenter, 640, 205, "Load Sufami Turbo Cartridge"); + set_icon(48, 48, (uint32_t*)resource::icon48); lbase.create(0, 630, 20, "Base cartridge:"); tbase.create(0, 420, 30); diff --git a/src/ui/loader/ui_stloader.h b/src/ui/loader/stloader.h similarity index 100% rename from src/ui/loader/ui_stloader.h rename to src/ui/loader/stloader.h diff --git a/src/ui/main.cpp b/src/ui/main.cpp index 239fec643..e5196f979 100644 --- a/src/ui/main.cpp +++ b/src/ui/main.cpp @@ -1,6 +1,8 @@ #define INTERFACE_MAIN #include "../base.h" + +#include "main.h" #include "config.cpp" void init_snes(); @@ -13,24 +15,22 @@ void term_snes(); #include using namespace ruby; -#include "inputmgr.cpp" +#include + +#include "inputmanager.cpp" #include "interface.cpp" /***** * platform abstraction layer *****/ -#include +#include using namespace libhiro; /***** * core *****/ -bool _term_ = false; -bool _pause_ = false; -bool _autopause_ = false; - #include "ui.h" #include "event.h" @@ -94,37 +94,37 @@ void get_base_path(const char *image) { } } - if(strend(t, "/") == false) { strcat(t, "/"); } + if(strend(t, "/") == false) strcat(t, "/"); config::path.base = t; } void run() { while(hiro().pending()) hiro().run(); input_manager.refresh(); - event::update_frame_counter(); if(config::input.capture_mode == 2) { bool inactive = window_main.focused() == false; - if(_autopause_ == false && inactive == true) { + if(app.autopause == false && inactive == true) { + app.autopause = true; audio.clear(); - if(cartridge.loaded()) window_main.status.set_text("(Paused)"); - _autopause_ = true; - } else if(_autopause_ == true && inactive == false) { - _autopause_ = false; + if(cartridge.loaded()) event::update_status(); + } else if(app.autopause == true && inactive == false) { + app.autopause = false; } } else { - _autopause_ = false; + app.autopause = false; } - if(cartridge.loaded() == false || _pause_ == true || _autopause_ == true) { + if(cartridge.loaded() == false || app.pause == true || app.autopause == true) { //prevent bsnes from consuming 100% CPU resources when idle #if defined(PLATFORM_WIN) Sleep(20); #elif defined(PLATFORM_X) - usleep(20); + usleep(20 * 1000); #endif } else { snes.runtoframe(); + event::update_status(); } } @@ -140,24 +140,22 @@ int main(int argc, char *argv[]) { */ set_config_filename(); get_base_path(argv[0]); - hiro().init(); config::config().load(config::filename); if(fexists(config::filename) == false) { - //in case program crashes on first run, save config file - //settings, so that they can be modified by hand ... + //in case program crashes on first run, save config file + //settings, so that they can be modified by hand ... config::config().save(config::filename); } - snes.init(); + hiro().init(); ui_init(); + snes.init(); if(argc >= 2) { cartridge.load_cart_normal(argv[1]); snes.power(); } - while(_term_ == false) { - run(); - } + while(app.term == false) run(); event::unload_rom(); diff --git a/src/ui/main.h b/src/ui/main.h new file mode 100644 index 000000000..a2ae77143 --- /dev/null +++ b/src/ui/main.h @@ -0,0 +1,7 @@ +struct Application { + bool term; + bool pause; + bool autopause; + + Application() : term(false), pause(false), autopause(false) {} +} app; diff --git a/src/ui/resource.cpp b/src/ui/resource.cpp new file mode 100644 index 000000000..d43743d46 --- /dev/null +++ b/src/ui/resource.cpp @@ -0,0 +1,36 @@ +namespace resource { + +#include "../data/icon48.h" +#include "../data/controller.h" + +static uint8_t *icon48; +static uint8_t *controller; + +//call once at program startup +void init() { + uint8_t *lzssdata; + uint8_t *rawdata; + unsigned length; + + base64::decode(lzssdata, length, enc_icon48); + lzss::decode(icon48, lzssdata, 48 * 48 * 4); + delete[] lzssdata; + + //controller data stored as 24-bit RGB888 + //expand to 32-bit ARGB8888 for direct use with hiro::Canvas + base64::decode(lzssdata, length, enc_controller); + lzss::decode(rawdata, lzssdata, 372 * 178 * 3); + delete[] lzssdata; + controller = new uint8_t[372 * 178 * 4]; + for(unsigned dp = 0, sp = 0, y = 0; y < 178; y++) { + for(unsigned x = 0; x < 372; x++) { + controller[dp++] = rawdata[sp++]; //blue + controller[dp++] = rawdata[sp++]; //green + controller[dp++] = rawdata[sp++]; //red + controller[dp++] = 255; //alpha + } + } + delete[] rawdata; +} + +} //namespace resource diff --git a/src/ui/settings/advanced.cpp b/src/ui/settings/advanced.cpp new file mode 100644 index 000000000..ff1aa7cb7 --- /dev/null +++ b/src/ui/settings/advanced.cpp @@ -0,0 +1,113 @@ +uintptr_t AdvancedWindow::list_change(Event) { + int pos = list.get_selection(); + edit_val.enable(pos >= 0); + set_val.enable(pos >= 0); + set_def.enable(pos >= 0); + if(pos >= 0) { + unsigned i = lookup[pos]; + string default_; + config::config().list[i]->get_default(default_); + desc.set_text(string() << "(default = " << default_ << ")\n" << config::config().list[i]->description); + string value_; + config::config().list[i]->get(value_); + edit_val.set_text(value_); + } + return true; +} + +uintptr_t AdvancedWindow::setval_tick(Event) { + char t[4096]; + edit_val.get_text(t, sizeof t); + update(list.get_selection(), t); + return true; +} + +uintptr_t AdvancedWindow::setdef_tick(Event) { + update(list.get_selection(), 0); + return true; +} + +void AdvancedWindow::update(uint pos, const char *data) { + unsigned i = lookup[pos]; + string default_; + config::config().list[i]->get_default(default_); + config::config().list[i]->set(data ? data : (const char*)default_); + string value_; + config::config().list[i]->get(value_); + edit_val.set_text(value_); + list.set_item(pos, string() + << config::config().list[i]->name + << (value_ == default_ ? "" : " (*)") + << "\t" + << (config::config().list[i]->type == setting::string_type ? "string" : "integral") + << "\t" + << value_ + ); + list.autosize_columns(); +} + +void AdvancedWindow::load() { + lookup.reset(); + + for(unsigned i = 0; i < config::config().list.size(); i++) { + string name = config::config().list[i]->name; + + //blacklist (omit/hide options that can be configured through the standard UI) + if(name == "file.autodetect_type") continue; + if(strbegin(name, "path.")) continue; + if(strbegin(name, "snes.controller_port_")) continue; + if(strpos(name, "colorfilter.") >= 0) continue; + if(name == "misc.status_enable") continue; + if(name == "system.regulate_speed") continue; + if(strbegin(name, "video.windowed.") && name != "video.windowed.synchronize") continue; + if(strbegin(name, "video.fullscreen.") && name != "video.fullscreen.synchronize") continue; + if(name == "audio.mute") continue; + if(name == "input.capture_mode") continue; + if(strbegin(name, "input.joypad")) continue; + if(strbegin(name, "input.gui")) continue; + + string value_, default_; + config::config().list[i]->get(value_); + config::config().list[i]->get_default(default_); + list.add_item(string() + << name + << (value_ == default_ ? "" : " (*)") + << "\t" + << (config::config().list[i]->type == setting::string_type ? "string" : "integral") + << "\t" + << value_ + ); + lookup.add(i); + } +} + +void AdvancedWindow::setup() { + create(0, 475, 355); + + list.create(Listbox::Header | Listbox::VerticalScrollAlways, 475, 235, "Name\tType\tValue"); + desc.create(Editbox::Multiline | Editbox::VerticalScrollAlways | Editbox::Readonly, 475, 80, + "Note: modification of certain variables will not take effect until\n" + "bsnes is restarted. (*) = modified" + ); + edit_val.create(0, 265, 30, ""); + set_val.create (0, 100, 30, "Set"); + set_def.create (0, 100, 30, "Default"); + + unsigned y = 0; + attach(list, 0, y); y += 235 + 5; + attach(desc, 0, y); y += 80 + 5; + attach(edit_val, 0, y); + attach(set_val, 270, y); + attach(set_def, 375, y); y += 30 + 5; + + load(); + list.autosize_columns(); + + edit_val.disable(); + set_val.disable(); + set_def.disable(); + + list.on_change = bind(&AdvancedWindow::list_change, this); + set_val.on_tick = bind(&AdvancedWindow::setval_tick, this); + set_def.on_tick = bind(&AdvancedWindow::setdef_tick, this); +} diff --git a/src/ui/settings/ui_advanced.h b/src/ui/settings/advanced.h similarity index 84% rename from src/ui/settings/ui_advanced.h rename to src/ui/settings/advanced.h index 561d0514d..1068b77f9 100644 --- a/src/ui/settings/ui_advanced.h +++ b/src/ui/settings/advanced.h @@ -5,9 +5,10 @@ public: Editbox edit_val; Button set_val; Button set_def; - - void read_config(uint pos, string &data); - void update(uint pos, const char *data); + + array lookup; + void update(uint pos, const char *data); + void load(); void setup(); uintptr_t list_change(Event); uintptr_t setval_tick(Event); diff --git a/src/ui/settings/ui_cheateditor.cpp b/src/ui/settings/cheateditor.cpp similarity index 81% rename from src/ui/settings/ui_cheateditor.cpp rename to src/ui/settings/cheateditor.cpp index 9594d09e0..dee76f63e 100644 --- a/src/ui/settings/ui_cheateditor.cpp +++ b/src/ui/settings/cheateditor.cpp @@ -8,7 +8,7 @@ void CheatEditorWindow::setup() { code.create(0, 155, 30, ""); desc.create(0, 315, 30, ""); -uint y = 0; + unsigned y = 0; attach(list, 0, y); y += 285 + 5; attach(add_code, 0, y); attach(toggle_code, 160, y); @@ -28,10 +28,10 @@ void CheatEditorWindow::refresh() { list.reset(); for(uint i = 0; i < cheat.count(); i++) { - bool enabled; - uint32 addr; - uint8 data; - char s_code[256], s_desc[256]; + bool enabled; + uint32 addr; + uint8 data; + char s_code[256], s_desc[256]; cheat.get(i, enabled, addr, data, s_code, s_desc); list.add_item(string() << (enabled ? "Enabled" : "Disabled") << "\t" @@ -41,21 +41,23 @@ void CheatEditorWindow::refresh() { list.autosize_columns(); -//enable controls only if cartridge is loaded -bool loaded = cartridge.loaded(); + //enable controls only if cartridge is loaded + bool loaded = cartridge.loaded(); + code.enable(loaded); + desc.enable(loaded); add_code.enable(loaded); toggle_code.enable(loaded); delete_code.enable(loaded); } uintptr_t CheatEditorWindow::toggle_event(Event) { -int index = list.get_selection(); + int index = list.get_selection(); if(index >= 0 && index < cheat.count()) { cheat.enabled(index) ? cheat.disable(index) : cheat.enable(index); - bool enabled; - uint32 addr; - uint8 data; - char s_code[256], s_desc[256]; + bool enabled; + uint32 addr; + uint8 data; + char s_code[256], s_desc[256]; cheat.get(index, enabled, addr, data, s_code, s_desc); list.set_item(index, string() << (enabled ? "Enabled" : "Disabled") << "\t" @@ -66,7 +68,7 @@ int index = list.get_selection(); } uintptr_t CheatEditorWindow::add_tick(Event) { -char s_code[256], s_desc[256]; + char s_code[256], s_desc[256]; code.get_text(s_code, sizeof s_code); desc.get_text(s_desc, sizeof s_desc); cheat.add(false, s_code, s_desc); //param 0 = false, meaning: new codes disabled by default @@ -75,7 +77,7 @@ char s_code[256], s_desc[256]; } uintptr_t CheatEditorWindow::delete_tick(Event) { -int index = list.get_selection(); + int index = list.get_selection(); if(index >= 0 && index < cheat.count()) { cheat.remove(index); refresh(); diff --git a/src/ui/settings/ui_cheateditor.h b/src/ui/settings/cheateditor.h similarity index 100% rename from src/ui/settings/ui_cheateditor.h rename to src/ui/settings/cheateditor.h diff --git a/src/ui/settings/ui_inputconfig.cpp b/src/ui/settings/inputconfig.cpp similarity index 91% rename from src/ui/settings/ui_inputconfig.cpp rename to src/ui/settings/inputconfig.cpp index ed3278e64..6473245d4 100644 --- a/src/ui/settings/ui_inputconfig.cpp +++ b/src/ui/settings/inputconfig.cpp @@ -18,7 +18,7 @@ void InputConfigWindow::setup() { clrkey.create(0, 235, 30, "Unassign Key"); clrkey.disable(); -uint y = 0; + unsigned y = 0; attach(capture_mode, 0, y); y += 15 + 5; attach(capture_always, 0, y); attach(capture_focus, 160, y); @@ -39,13 +39,13 @@ uint y = 0; else if(config::input.capture_mode == 2) capture_pause.check(); else config::input.capture_mode = 0; //capture_always - for(uint i = 0; i < list_size; i++) list.add_item("???\t???"); + for(unsigned i = 0; i < list_size; i++) list.add_item("???\t???"); refresh_list(); window_input_capture.setup(); } void InputConfigWindow::refresh_list() { - for(uint i = 0; i < list_size; i++) { + for(unsigned i = 0; i < list_size; i++) { list.set_item(i, string() << list_index[i] << "\t" << input_find(get_value(i))); } list.autosize_columns(); @@ -59,23 +59,24 @@ uintptr_t InputConfigWindow::capture_change(Event e) { } uintptr_t InputConfigWindow::list_change(Event) { -int pos = list.get_selection(); + int pos = list.get_selection(); setkey.enable(pos >= 0); clrkey.enable(pos >= 0); return true; } uintptr_t InputConfigWindow::set_tick(Event) { -int pos = list.get_selection(); + int pos = list.get_selection(); if(pos < 0) return true; window_input_capture.index = pos; window_input_capture.label.set_text(string() << "Press a key to assign to " << list_index[pos] << " ..."); + window_input_capture.canvas.show(pos < 24); //only show joypad graphic if setting joypad 1/2 button window_input_capture.show(); return true; } uintptr_t InputConfigWindow::clr_tick(Event) { -int pos = list.get_selection(); + int pos = list.get_selection(); if(pos < 0) return true; set_value(pos, keyboard::none); refresh_list(); @@ -105,9 +106,12 @@ uintptr_t InputCaptureWindow::close(Event) { } void InputCaptureWindow::setup() { - create(Window::AutoCenter, 350, 100, "bsnes Key Capture"); - label.create(0, 340, 90); + create(Window::AutoCenter, 382, 208, "bsnes Key Capture"); + label.create(0, 340, 20); + canvas.create(0, 372, 178); + memcpy(canvas.buffer(), resource::controller, 372 * 178 * 4); attach(label, 5, 5); + attach(canvas, 5, 25); on_close = bind(&InputCaptureWindow::close, this); } diff --git a/src/ui/settings/ui_inputconfig.h b/src/ui/settings/inputconfig.h similarity index 94% rename from src/ui/settings/ui_inputconfig.h rename to src/ui/settings/inputconfig.h index 370601472..3efcca91c 100644 --- a/src/ui/settings/ui_inputconfig.h +++ b/src/ui/settings/inputconfig.h @@ -24,7 +24,8 @@ public: class InputCaptureWindow : public Window { public: - Label label; + Label label; + Canvas canvas; bool waiting; bool locked; diff --git a/src/ui/settings/pathsettings.cpp b/src/ui/settings/pathsettings.cpp new file mode 100644 index 000000000..f515cb277 --- /dev/null +++ b/src/ui/settings/pathsettings.cpp @@ -0,0 +1,94 @@ +uintptr_t PathSettingsWindow::selectpath_rom(Event) { + char t[PATH_MAX]; + if(hiro().folder_select(&window_settings, t) == true) { + config::path.rom = t; + rompath.set_text(config::path.rom); + } + return true; +} + +uintptr_t PathSettingsWindow::defaultpath_rom(Event) { + config::path.rom = ""; + rompath.set_text(""); +} + +uintptr_t PathSettingsWindow::selectpath_save(Event) { + char t[PATH_MAX]; + if(hiro().folder_select(&window_settings, t) == true) { + config::path.save = t; + savepath.set_text(config::path.save); + } + return true; +} + +uintptr_t PathSettingsWindow::defaultpath_save(Event) { + config::path.save = ""; + savepath.set_text(""); +} + +uintptr_t PathSettingsWindow::selectpath_cheat(Event) { + char t[PATH_MAX]; + if(hiro().folder_select(&window_settings, t) == true) { + config::path.cheat = t; + cheatpath.set_text(config::path.cheat); + } + return true; +} + +uintptr_t PathSettingsWindow::defaultpath_cheat(Event) { + config::path.cheat = ""; + cheatpath.set_text(""); +} + +uintptr_t PathSettingsWindow::autodetect_tick(Event) { + config::file.autodetect_type = autodetect.checked(); +} + +void PathSettingsWindow::setup() { + create(0, 475, 355); + + lrompath.create(0, 475, 20, "Default game ROM path:"); + rompath.create(Editbox::Readonly, 265, 30); + romselect.create(0, 100, 30, "Select"); + romdefault.create(0, 100, 30, "Default"); + + lsavepath.create(0, 475, 20, "Default save RAM path:"); + savepath.create(Editbox::Readonly, 265, 30); + saveselect.create(0, 100, 30, "Select"); + savedefault.create(0, 100, 30, "Default"); + + lcheatpath.create(0, 475, 20, "Default cheat file path:"); + cheatpath.create(Editbox::Readonly, 265, 30); + cheatselect.create(0, 100, 30, "Select"); + cheatdefault.create(0, 100, 30, "Default"); + + autodetect.create(0, 475, 20, "Auto-detect file compression type (ignore file extension)"); + + unsigned y = 0; + attach(lrompath, 0, y); y += 20; + attach(rompath, 0, y); + attach(romselect, 270, y); + attach(romdefault, 375, y); y += 35; + attach(lsavepath, 0, y); y += 20; + attach(savepath, 0, y); + attach(saveselect, 270, y); + attach(savedefault, 375, y); y += 35; + attach(lcheatpath, 0, y); y += 20; + attach(cheatpath, 0, y); + attach(cheatselect, 270, y); + attach(cheatdefault, 375, y); y += 35; + attach(autodetect, 0, y); y += 20; + + romselect.on_tick = bind(&PathSettingsWindow::selectpath_rom, this); + romdefault.on_tick = bind(&PathSettingsWindow::defaultpath_rom, this); + saveselect.on_tick = bind(&PathSettingsWindow::selectpath_save, this); + savedefault.on_tick = bind(&PathSettingsWindow::defaultpath_save, this); + cheatselect.on_tick = bind(&PathSettingsWindow::selectpath_cheat, this); + cheatdefault.on_tick = bind(&PathSettingsWindow::defaultpath_cheat, this); + autodetect.on_tick = bind(&PathSettingsWindow::autodetect_tick, this); + + rompath.set_text(config::path.rom); + savepath.set_text(config::path.save); + cheatpath.set_text(config::path.cheat); + autodetect.check(config::file.autodetect_type); +} diff --git a/src/ui/settings/pathsettings.h b/src/ui/settings/pathsettings.h new file mode 100644 index 000000000..d1fb95bd3 --- /dev/null +++ b/src/ui/settings/pathsettings.h @@ -0,0 +1,28 @@ +class PathSettingsWindow : public Window { +public: + Label lrompath; + Editbox rompath; + Button romselect; + Button romdefault; + + Label lsavepath; + Editbox savepath; + Button saveselect; + Button savedefault; + + Label lcheatpath; + Editbox cheatpath; + Button cheatselect; + Button cheatdefault; + + Checkbox autodetect; + + uintptr_t selectpath_rom(Event); + uintptr_t defaultpath_rom(Event); + uintptr_t selectpath_save(Event); + uintptr_t defaultpath_save(Event); + uintptr_t selectpath_cheat(Event); + uintptr_t defaultpath_cheat(Event); + uintptr_t autodetect_tick(Event); + void setup(); +} window_path_settings; diff --git a/src/ui/settings/ui_rastersettings.cpp b/src/ui/settings/rastersettings.cpp similarity index 54% rename from src/ui/settings/ui_rastersettings.cpp rename to src/ui/settings/rastersettings.cpp index 45840b0ea..c077564e8 100644 --- a/src/ui/settings/ui_rastersettings.cpp +++ b/src/ui/settings/rastersettings.cpp @@ -15,7 +15,7 @@ void RasterSettingsWindow::setup() { preset_standard.create(0, 235, 30, "Standard Preset"); sync_ui(); -uint y = 0; + uint y = 0; attach(lcontrast, 0, y); y += 20; attach(contrast, 0, y); y += 30; attach(lbrightness, 0, y); y += 20; @@ -43,96 +43,105 @@ uint y = 0; //update all UI controls to match config file values ... void RasterSettingsWindow::sync_ui() { ui_lock = true; //supress event messages while syncing UI elements, prevents infinite recursion - contrast.set_position(config::snes.contrast + 96); - lcontrast.set_text(string() << "Contrast: " << (int)config::snes.contrast); - brightness.set_position(config::snes.brightness + 96); - lbrightness.set_text(string() << "Brightness: " << (int)config::snes.brightness); - gamma.set_position(config::snes.gamma - 10); - lgamma.set_text(string() << "Gamma: " << (int)config::snes.gamma); //TODO: print gamma as "%0.2f" / 100.0 - gamma_ramp.check(config::snes.gamma_ramp); - sepia.check(config::snes.sepia); - grayscale.check(config::snes.grayscale); - invert.check(config::snes.invert); - snes.update_color_lookup_table(); + contrast.set_position(config::system.contrast + 96); + lcontrast.set_text(string() << "Contrast: " << (int)config::system.contrast); + brightness.set_position(config::system.brightness + 96); + lbrightness.set_text(string() << "Brightness: " << (int)config::system.brightness); + gamma.set_position(config::system.gamma - 10); + lgamma.set_text(string() << "Gamma: " << (int)config::system.gamma); //TODO: print gamma as "%0.2f" / 100.0 + gamma_ramp.check(config::system.gamma_ramp); + sepia.check(config::system.sepia); + grayscale.check(config::system.grayscale); + invert.check(config::system.invert); + + libfilter::colortable.set_contrast(config::system.contrast); + libfilter::colortable.set_brightness(config::system.brightness); + libfilter::colortable.set_gamma(config::system.gamma); + libfilter::colortable.enable_gamma_ramp(config::system.gamma_ramp); + libfilter::colortable.enable_sepia(config::system.sepia); + libfilter::colortable.enable_grayscale(config::system.grayscale); + libfilter::colortable.enable_invert(config::system.invert); + libfilter::colortable.update(); + ui_lock = false; } uintptr_t RasterSettingsWindow::contrast_change(Event) { - if(!ui_lock && config::snes.contrast != contrast.get_position() - 96) { - config::snes.contrast = contrast.get_position() - 96; + if(!ui_lock && config::system.contrast != contrast.get_position() - 96) { + config::system.contrast = contrast.get_position() - 96; sync_ui(); } return true; } uintptr_t RasterSettingsWindow::brightness_change(Event) { - if(!ui_lock && config::snes.brightness != brightness.get_position() - 96) { - config::snes.brightness = brightness.get_position() - 96; + if(!ui_lock && config::system.brightness != brightness.get_position() - 96) { + config::system.brightness = brightness.get_position() - 96; sync_ui(); } return true; } uintptr_t RasterSettingsWindow::gamma_change(Event) { - if(!ui_lock && config::snes.gamma != gamma.get_position() + 10) { - config::snes.gamma = gamma.get_position() + 10; + if(!ui_lock && config::system.gamma != gamma.get_position() + 10) { + config::system.gamma = gamma.get_position() + 10; sync_ui(); } return true; } uintptr_t RasterSettingsWindow::gammaramp_tick(Event) { - if(!ui_lock && config::snes.gamma_ramp != gamma_ramp.checked()) { - config::snes.gamma_ramp = gamma_ramp.checked(); + if(!ui_lock && config::system.gamma_ramp != gamma_ramp.checked()) { + config::system.gamma_ramp = gamma_ramp.checked(); sync_ui(); } return true; } uintptr_t RasterSettingsWindow::sepia_tick(Event) { - if(!ui_lock && config::snes.sepia != sepia.checked()) { - config::snes.sepia = sepia.checked(); + if(!ui_lock && config::system.sepia != sepia.checked()) { + config::system.sepia = sepia.checked(); sync_ui(); } return true; } uintptr_t RasterSettingsWindow::grayscale_tick(Event) { - if(!ui_lock && config::snes.grayscale != grayscale.checked()) { - config::snes.grayscale = grayscale.checked(); + if(!ui_lock && config::system.grayscale != grayscale.checked()) { + config::system.grayscale = grayscale.checked(); sync_ui(); } return true; } uintptr_t RasterSettingsWindow::invert_tick(Event) { - if(!ui_lock && config::snes.invert != invert.checked()) { - config::snes.invert = invert.checked(); + if(!ui_lock && config::system.invert != invert.checked()) { + config::system.invert = invert.checked(); sync_ui(); } return true; } uintptr_t RasterSettingsWindow::optimal_tick(Event) { - config::snes.contrast = 0; - config::snes.brightness = 0; - config::snes.gamma = 80; - config::snes.gamma_ramp = true; - config::snes.sepia = false; - config::snes.grayscale = false; - config::snes.invert = false; + config::system.contrast = 0; + config::system.brightness = 0; + config::system.gamma = 80; + config::system.gamma_ramp = true; + config::system.sepia = false; + config::system.grayscale = false; + config::system.invert = false; sync_ui(); return true; } uintptr_t RasterSettingsWindow::standard_tick(Event) { - config::snes.contrast = 0; - config::snes.brightness = 0; - config::snes.gamma = 100; - config::snes.gamma_ramp = false; - config::snes.sepia = false; - config::snes.grayscale = false; - config::snes.invert = false; + config::system.contrast = 0; + config::system.brightness = 0; + config::system.gamma = 100; + config::system.gamma_ramp = false; + config::system.sepia = false; + config::system.grayscale = false; + config::system.invert = false; sync_ui(); return true; } diff --git a/src/ui/settings/ui_rastersettings.h b/src/ui/settings/rastersettings.h similarity index 100% rename from src/ui/settings/ui_rastersettings.h rename to src/ui/settings/rastersettings.h diff --git a/src/ui/settings/ui_settings.cpp b/src/ui/settings/settings.cpp similarity index 76% rename from src/ui/settings/ui_settings.cpp rename to src/ui/settings/settings.cpp index f88a3eae1..b738cde77 100644 --- a/src/ui/settings/ui_settings.cpp +++ b/src/ui/settings/settings.cpp @@ -1,21 +1,23 @@ void SettingsWindow::setup() { create(Window::AutoCenter, 640, 365, "bsnes Configuration Settings"); + set_icon(48, 48, (uint32_t*)resource::icon48); panel_list.create(0, 150, 355); panel_list.add_item("Raster Settings"); panel_list.add_item("Input Configuration"); - panel_list.add_item("Cheat Code Editor"); + panel_list.add_item("Path Settings"); + panel_list.add_item("Cheat Code Editor"); panel_list.add_item("Advanced"); attach(panel_list, 5, 5); attach(window_raster_settings, 160, 5); attach(window_input_config, 160, 5); + attach(window_path_settings, 160, 5); attach(window_cheat_editor, 160, 5); attach(window_advanced, 160, 5); on_close = bind(&SettingsWindow::close, this); panel_list.on_change = bind(&SettingsWindow::list_change, this); - panel_list.set_selection(0); } @@ -27,14 +29,16 @@ uintptr_t SettingsWindow::close(Event) { uintptr_t SettingsWindow::list_change(Event) { window_raster_settings.hide(); window_input_config.hide(); + window_path_settings.hide(); window_cheat_editor.hide(); window_advanced.hide(); switch(panel_list.get_selection()) { case 0: window_raster_settings.show(); break; case 1: window_input_config.show(); break; - case 2: window_cheat_editor.show(); break; - case 3: window_advanced.show(); break; + case 2: window_path_settings.show(); break; + case 3: window_cheat_editor.show(); break; + case 4: window_advanced.show(); break; } panel_list.focus(); diff --git a/src/ui/settings/ui_settings.h b/src/ui/settings/settings.h similarity index 100% rename from src/ui/settings/ui_settings.h rename to src/ui/settings/settings.h diff --git a/src/ui/settings/ui_advanced.cpp b/src/ui/settings/ui_advanced.cpp deleted file mode 100644 index c6c4340d2..000000000 --- a/src/ui/settings/ui_advanced.cpp +++ /dev/null @@ -1,93 +0,0 @@ -uintptr_t AdvancedWindow::list_change(Event) { -int pos = list.get_selection(); - set_val.enable(pos >= 0); - set_def.enable(pos >= 0); - if(pos >= 0 && pos < config::config().list.size()) { - string default_; - config::config().list[pos]->get_default(default_); - desc.set_text(string() << "(default = " << default_ << ")\n" << config::config().list[pos]->description); - string value_; - config::config().list[pos]->get(value_); - edit_val.set_text(value_); - } - return true; -} - -uintptr_t AdvancedWindow::setval_tick(Event) { -char t[4096]; - edit_val.get_text(t, sizeof t); - update(list.get_selection(), t); - return true; -} - -uintptr_t AdvancedWindow::setdef_tick(Event) { - update(list.get_selection(), 0); - return true; -} - -void AdvancedWindow::read_config(uint pos, string &data) { - data = "?\t?\t?"; - if(pos >= config::config().list.size()) return; - - string name, value_; - name = config::config().list[pos]->name; - config::config().list[pos]->get(value_); - string default_; - config::config().list[pos]->get_default(default_); - if(value_ != default_) { strcat(name, " (*)"); } - data = string() - << name << "\t" - << (config::config().list[pos]->type == setting::string_type ? "string" : "integral") << "\t" - << value_; -} - -void AdvancedWindow::update(uint pos, const char *data) { - if(pos >= config::config().list.size()) return; - - string default_; - config::config().list[pos]->get_default(default_); - config::config().list[pos]->set(data ? data : (const char*)default_); - string value_; - config::config().list[pos]->get(value_); - edit_val.set_text(value_); - read_config(pos, value_); - list.set_item(pos, value_); - list.autosize_columns(); -} - -void AdvancedWindow::setup() { - create(0, 475, 355); - - list.create(Listbox::Header | Listbox::VerticalScrollAlways, 475, 235, "Name\tType\tValue"); - desc.create(Editbox::Multiline | Editbox::VerticalScrollAlways | Editbox::Readonly, 475, 80, - "\n" - "Warning: modifification of certain variables will not take effect until\n" - "bsnes is restarted, and corresponding UI elements will not be updated\n" - "to reflect changes here. (*) = modified" - ); - edit_val.create(0, 265, 30, ""); - set_val.create (0, 100, 30, "Set"); - set_def.create (0, 100, 30, "Default"); - -uint y = 0; - attach(list, 0, y); y += 235 + 5; - attach(desc, 0, y); y += 80 + 5; - attach(edit_val, 0, y); - attach(set_val, 270, y); - attach(set_def, 375, y); y += 30 + 5; - - for(int i = 0; i < config::config().list.size(); i++) { - string val; - read_config(i, val); - list.add_item(val); - } - - list.autosize_columns(); - - set_val.disable(); - set_def.disable(); - - list.on_change = bind(&AdvancedWindow::list_change, this); - set_val.on_tick = bind(&AdvancedWindow::setval_tick, this); - set_def.on_tick = bind(&AdvancedWindow::setdef_tick, this); -} diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 5761be2a3..045ec5d58 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -1,17 +1,23 @@ -#include "ui_main.cpp" -#include "ui_about.cpp" -#include "ui_message.cpp" +#include "resource.cpp" + +#include "base/main.cpp" +#include "base/about.cpp" +#include "base/message.cpp" -#include "loader/ui_bsxloader.cpp" -#include "loader/ui_stloader.cpp" +#include "loader/bsxloader.cpp" +#include "loader/stloader.cpp" -#include "settings/ui_settings.cpp" -#include "settings/ui_rastersettings.cpp" -#include "settings/ui_inputconfig.cpp" -#include "settings/ui_cheateditor.cpp" -#include "settings/ui_advanced.cpp" +#include "settings/settings.cpp" +#include "settings/rastersettings.cpp" +#include "settings/inputconfig.cpp" +#include "settings/pathsettings.cpp" +#include "settings/cheateditor.cpp" +#include "settings/advanced.cpp" + +void ui_init() { + hiro().disable_screensaver(); + resource::init(); -void ui_init() { window_main.setup(); window_about.setup(); window_message.setup(); @@ -20,18 +26,17 @@ void ui_init() { window_stloader.setup(); window_raster_settings.setup(); - window_input_config.setup(); - window_cheat_editor.setup(); + window_input_config.setup(); + window_path_settings.setup(); + window_cheat_editor.setup(); window_advanced.setup(); window_settings.setup(); - + + event::update_opacity(); event::update_video_settings(); //call first time to resize main window and update menubar window_main.show(); while(hiro().pending()) hiro().run(); - //needed only by VideoGDI (default is RGB565) - if(config::system.video == "gdi") snes.set_video_pixel_format(SNES::PIXELFORMAT_RGB555); - video.driver(config::system.video); audio.driver(config::system.audio); input.driver(config::system.input); @@ -39,7 +44,7 @@ void ui_init() { video.set(Video::Handle, window_main.view.handle()); video.set(Video::Synchronize, false); audio.set(Audio::Handle, window_main.handle()); - audio.set(Audio::Synchronize, (bool)config::system.regulate_speed); + audio.set(Audio::Synchronize, config::system.speed_regulation != 0); audio.set(Audio::Frequency, 32000); input.set(Input::Handle, window_main.handle()); diff --git a/src/ui/ui.h b/src/ui/ui.h index dd9715d8a..eaef00741 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -1,12 +1,16 @@ -#include "ui_main.h" -#include "ui_about.h" -#include "ui_message.h" +#include +#include -#include "loader/ui_bsxloader.h" -#include "loader/ui_stloader.h" +#include "base/main.h" +#include "base/about.h" +#include "base/message.h" -#include "settings/ui_settings.h" -#include "settings/ui_rastersettings.h" -#include "settings/ui_inputconfig.h" -#include "settings/ui_cheateditor.h" -#include "settings/ui_advanced.h" +#include "loader/bsxloader.h" +#include "loader/stloader.h" + +#include "settings/settings.h" +#include "settings/rastersettings.h" +#include "settings/inputconfig.h" +#include "settings/pathsettings.h" +#include "settings/cheateditor.h" +#include "settings/advanced.h" diff --git a/src/ui/ui_about.cpp b/src/ui/ui_about.cpp deleted file mode 100644 index 51742a19c..000000000 --- a/src/ui/ui_about.cpp +++ /dev/null @@ -1,21 +0,0 @@ -const char AboutWindow::about_text[4096] = "" - "bsnes -- version " BSNES_VERSION "\n" - "Author: byuu\n" - "Project began: October 14th, 2004\n" - "\n\n" - "Contributors:\n" - " anomie, blargg, DMV27, GIGO, kode54, Nach,\n" - " Overload, Richard Bannister, TRAC, zones"; - -uintptr_t AboutWindow::close(Event) { - hide(); - return false; -} - -void AboutWindow::setup() { - create(Window::AutoCenter, 400, 200, "About bsnes ..."); - about.create(0, 390, 190, about_text); - attach(about, 5, 5); - - on_close = bind(&AboutWindow::close, this); -} diff --git a/src/ui/ui_about.h b/src/ui/ui_about.h deleted file mode 100644 index 04707d76e..000000000 --- a/src/ui/ui_about.h +++ /dev/null @@ -1,8 +0,0 @@ -class AboutWindow : public Window { -public: - Label about; - static const char about_text[4096]; - - void setup(); - uintptr_t close(Event); -} window_about;